]> git.pld-linux.org Git - packages/mysql.git/blame - memory_dynamic_rows.patch
- mention innodb_file_per_table
[packages/mysql.git] / memory_dynamic_rows.patch
CommitLineData
db82db79
AM
1--- a/include/heap.h
2+++ b/include/heap.h
3@@ -34,7 +34,17 @@
4 #include "my_compare.h"
5 #include "my_tree.h"
6
7- /* defines used by heap-funktions */
8+/* Define index limits to be identical to MyISAM ones for compatibility. */
9+
10+#if MAX_INDEXES > HA_MAX_POSSIBLE_KEY
11+#define HP_MAX_KEY HA_MAX_POSSIBLE_KEY /* Max allowed keys */
12+#else
13+#define HP_MAX_KEY MAX_INDEXES /* Max allowed keys */
14+#endif
15+
16+#define HP_MAX_KEY_LENGTH 1000 /* Max length in bytes */
17+
18+/* defines used by heap-funktions */
19
20 #define HP_MAX_LEVELS 4 /* 128^5 records is enough */
21 #define HP_PTRS_IN_NOD 128
22@@ -130,22 +140,58 @@
23 uint (*get_key_length)(struct st_hp_keydef *keydef, const uchar *key);
24 } HP_KEYDEF;
25
26-typedef struct st_heap_share
27+typedef struct st_heap_columndef /* column information */
28+{
29+ int16 type; /* en_fieldtype */
30+ uint32 length; /* length of field */
31+ uint32 offset; /* Offset to position in row */
32+ uint8 null_bit; /* If column may be 0 */
33+ uint16 null_pos; /* position for null marker */
34+ uint8 length_bytes; /* length of the size, 1 o 2 bytes */
35+} HP_COLUMNDEF;
36+
37+typedef struct st_heap_dataspace /* control data for data space */
38 {
39 HP_BLOCK block;
40+ /* Total chunks ever allocated in this dataspace */
41+ uint chunk_count;
42+ uint del_chunk_count; /* Deleted chunks count */
43+ uchar *del_link; /* Link to last deleted chunk */
44+ uint chunk_length; /* Total length of one chunk */
45+ /* Length of payload that will be placed into one chunk */
46+ uint chunk_dataspace_length;
47+ /* Offset of the status flag relative to the chunk start */
48+ uint offset_status;
49+ /* Offset of the linking pointer relative to the chunk start */
50+ uint offset_link;
51+ /* Test whether records have variable size and so "next" pointer */
52+ uint is_variable_size;
53+ /* Total size allocated within this data space */
54+ ulonglong total_data_length;
55+} HP_DATASPACE;
56+
57+typedef struct st_heap_share
58+{
59 HP_KEYDEF *keydef;
60+ HP_COLUMNDEF *column_defs;
61+ /* Describes "block", which contains actual records */
62+ HP_DATASPACE recordspace;
63 ulong min_records,max_records; /* Params to open */
64- ulonglong data_length,index_length,max_table_size;
65+ ulonglong index_length, max_table_size;
66 uint key_stat_version; /* version to indicate insert/delete */
67- uint records; /* records */
68- uint blength; /* records rounded up to 2^n */
69- uint deleted; /* Deleted records in database */
70- uint reclength; /* Length of one record */
71+ uint records; /* Actual record (row) count */
72+ uint blength; /* used_chunk_count rounded up to 2^n */
73+ /*
74+ Length of record's fixed part, which contains keys and always fits into the
75+ first chunk.
76+ */
77+ uint fixed_data_length;
78+ uint fixed_column_count; /* Number of columns stored in fixed_data_length */
79 uint changed;
80 uint keys,max_key_length;
81+ uint column_count;
82 uint currently_disabled_keys; /* saved value from "keys" when disabled */
83 uint open_count;
84- uchar *del_link; /* Link to next block with del. rec */
85 char * name; /* Name of "memory-file" */
86 THR_LOCK lock;
87 mysql_mutex_t intern_lock; /* Locking for use with _locking */
88@@ -154,6 +200,7 @@
89 uint auto_key;
90 uint auto_key_type; /* real type of the auto key segment */
91 ulonglong auto_increment;
92+ uint blobs; /* Number of blobs in table */
93 } HP_SHARE;
94
95 struct st_hp_hash_info;
96@@ -163,7 +210,7 @@
97 HP_SHARE *s;
98 uchar *current_ptr;
99 struct st_hp_hash_info *current_hash_ptr;
100- ulong current_record,next_block;
101+ ulong current_record;
102 int lastinx,errkey;
103 int mode; /* Mode of file (READONLY..) */
104 uint opt_flag,update;
105@@ -176,6 +223,9 @@
106 my_bool implicit_emptied;
107 THR_LOCK_DATA lock;
108 LIST open_list;
109+ uchar *blob_buffer; /* Temporary buffer used to return BLOB values */
110+ uint blob_size; /* Current blob_buffer size */
111+ uint blob_offset; /* Current offset in blob_buffer */
112 } HP_INFO;
113
114
115@@ -197,6 +247,14 @@
116 open_count to 1. Is only looked at if not internal_table.
117 */
118 my_bool pin_share;
119+ uint columns;
120+ HP_COLUMNDEF *columndef;
121+ uint fixed_key_fieldnr;
122+ uint fixed_data_size;
123+ uint keys_memory_size;
124+ uint max_chunk_size;
125+ uint is_dynamic;
126+ uint blobs;
127 } HP_CREATE_INFO;
128
129 /* Prototypes for heap-functions */
130@@ -213,9 +271,8 @@
131 extern int heap_scan(register HP_INFO *info, uchar *record);
132 extern int heap_delete(HP_INFO *info,const uchar *buff);
133 extern int heap_info(HP_INFO *info,HEAPINFO *x,int flag);
134-extern int heap_create(const char *name,
135- HP_CREATE_INFO *create_info, HP_SHARE **share,
136- my_bool *created_new_share);
137+extern int heap_create(const char *name, HP_CREATE_INFO *create_info,
138+ HP_SHARE **res, my_bool *created_new_share);
139 extern int heap_delete_table(const char *name);
140 extern void heap_drop_table(HP_INFO *info);
141 extern int heap_extra(HP_INFO *info,enum ha_extra_function function);
142--- a/mysql-test/r/create.result
143+++ b/mysql-test/r/create.result
144@@ -33,10 +33,7 @@
145 create table t1 (b char(0) not null, index(b));
146 ERROR 42000: The used storage engine can't index column 'b'
147 create table t1 (a int not null,b text) engine=heap;
148-ERROR 42000: The used table type doesn't support BLOB/TEXT columns
149 drop table if exists t1;
150-Warnings:
151-Note 1051 Unknown table 't1'
152 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) engine=heap;
153 ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key
154 create table not_existing_database.test (a int);
155--- a/mysql-test/r/ctype_utf8mb4_heap.result
156+++ b/mysql-test/r/ctype_utf8mb4_heap.result
157@@ -1124,6 +1124,8 @@
158 a varchar(255) NOT NULL default '',
159 KEY a (a)
160 ) ENGINE=heap DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
161+Warnings:
162+Warning 1071 Specified key was too long; max key length is 1000 bytes
163 insert into t1 values (_utf8mb4 0xe880bd);
164 insert into t1 values (_utf8mb4 0x5b);
165 select hex(a) from t1;
166@@ -1162,6 +1164,8 @@
167 Warnings:
168 Note 1051 Unknown table 't1'
169 CREATE TABLE t1(a VARCHAR(255), KEY(a)) ENGINE=heap DEFAULT CHARSET=utf8mb4;
170+Warnings:
171+Warning 1071 Specified key was too long; max key length is 1000 bytes
172 INSERT INTO t1 VALUES('uuABCDEFGHIGKLMNOPRSTUVWXYZ̈bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
173 INSERT INTO t1 VALUES('uu');
174 check table t1;
175--- a/mysql-test/t/create.test
176+++ b/mysql-test/t/create.test
177@@ -33,7 +33,7 @@
178 drop table if exists t1,t2;
179 --error 1167
180 create table t1 (b char(0) not null, index(b));
181---error 1163
182+# BLOB/TEXT fields are now supported by HEAP
183 create table t1 (a int not null,b text) engine=heap;
184 drop table if exists t1;
185
186--- a/storage/heap/CMakeLists.txt
187+++ b/storage/heap/CMakeLists.txt
188@@ -20,6 +20,7 @@
189 ha_heap.cc
190 hp_delete.c hp_extra.c hp_hash.c hp_info.c hp_open.c hp_panic.c
191 hp_rename.c hp_rfirst.c hp_rkey.c hp_rlast.c hp_rnext.c hp_rprev.c
192+ hp_dspace.c hp_record.c
193 hp_rrnd.c hp_rsame.c hp_scan.c hp_static.c hp_update.c hp_write.c)
194
195 MYSQL_ADD_PLUGIN(heap ${HEAP_SOURCES} STORAGE_ENGINE MANDATORY RECOMPILE_FOR_EMBEDDED)
196--- a/storage/heap/_check.c
197+++ b/storage/heap/_check.c
198@@ -43,7 +43,7 @@
199 {
200 int error;
201 uint key;
202- ulong records=0, deleted=0, pos, next_block;
203+ ulong records= 0, deleted= 0, chunk_count= 0, pos, next_block;
204 HP_SHARE *share=info->s;
205 HP_INFO save_info= *info; /* Needed because scan_init */
206 DBUG_ENTER("heap_check_heap");
207@@ -64,31 +64,55 @@
208 {
209 if (pos < next_block)
210 {
211- info->current_ptr+= share->block.recbuffer;
212+ info->current_ptr+= share->recordspace.block.recbuffer;
213 }
214 else
215 {
216- next_block+= share->block.records_in_block;
217- if (next_block >= share->records+share->deleted)
218+ next_block+= share->recordspace.block.records_in_block;
219+ if (next_block >= share->recordspace.chunk_count)
220 {
221- next_block= share->records+share->deleted;
222- if (pos >= next_block)
223- break; /* End of file */
224+ next_block= share->recordspace.chunk_count;
225+ if (pos >= next_block)
226+ break; /* End of file */
227 }
228 }
229 hp_find_record(info,pos);
230
231- if (!info->current_ptr[share->reclength])
232+ switch (get_chunk_status(&share->recordspace, info->current_ptr)) {
233+ case CHUNK_STATUS_DELETED:
234 deleted++;
235- else
236+ chunk_count++;
237+ break;
238+ case CHUNK_STATUS_ACTIVE:
239 records++;
240+ chunk_count++;
241+ break;
242+ case CHUNK_STATUS_LINKED:
243+ chunk_count++;
244+ break;
245+ default:
246+ DBUG_PRINT("error",
247+ ("Unknown record status: Record: 0x%lx Status %lu",
248+ (long) info->current_ptr,
249+ (ulong) get_chunk_status(&share->recordspace,
250+ info->current_ptr)));
251+ error|= 1;
252+ break;
253+ }
254 }
255
256- if (records != share->records || deleted != share->deleted)
257- {
258- DBUG_PRINT("error",("Found rows: %lu (%lu) deleted %lu (%lu)",
259- records, (ulong) share->records,
260- deleted, (ulong) share->deleted));
261+ /* TODO: verify linked chunks (no orphans, no cycles, no bad links) */
262+
263+ if (records != share->records ||
264+ chunk_count != share->recordspace.chunk_count ||
265+ deleted != share->recordspace.del_chunk_count)
266+ {
267+ DBUG_PRINT("error",
268+ ("Found rows: %lu (%lu) total chunks %lu (%lu) deleted chunks "
269+ "%lu (%lu)",
270+ records, (ulong) share->records,
271+ chunk_count, (ulong) share->recordspace.chunk_count,
272+ deleted, (ulong) share->recordspace.del_chunk_count));
273 error= 1;
274 }
275 *info= save_info;
276@@ -177,7 +201,7 @@
277 do
278 {
279 memcpy(&recpos, key + (*keydef->get_key_length)(keydef,key), sizeof(uchar*));
280- key_length= hp_rb_make_key(keydef, info->recbuf, recpos, 0);
281+ key_length= hp_rb_make_key(keydef, info->recbuf, recpos, 0, TRUE);
282 if (ha_key_cmp(keydef->seg, (uchar*) info->recbuf, (uchar*) key,
283 key_length, SEARCH_FIND | SEARCH_SAME, not_used))
284 {
285--- a/storage/heap/_rectest.c
286+++ b/storage/heap/_rectest.c
287@@ -22,7 +22,9 @@
288 {
289 DBUG_ENTER("hp_rectest");
290
291- if (memcmp(info->current_ptr,old,(size_t) info->s->reclength))
292+ if (hp_process_record_data_to_chunkset(info->s, old,
293+ info->current_ptr,
294+ 1))
295 {
296 DBUG_RETURN((my_errno=HA_ERR_RECORD_CHANGED)); /* Record have changed */
297 }
298--- a/storage/heap/ha_heap.cc
299+++ b/storage/heap/ha_heap.cc
300@@ -114,6 +114,7 @@
301
302 rc= heap_create(name, &create_info, &internal_share, &created_new_share);
303 my_free(create_info.keydef);
304+ my_free(create_info.columndef);
305 if (rc)
306 goto end;
307
308@@ -195,6 +196,12 @@
309 {
310 if (table->key_info[i].algorithm == HA_KEY_ALG_BTREE)
311 btree_keys.set_bit(i);
312+ /*
313+ Reset per-key block size specification so they are not shown
314+ in SHOW CREATE TABLE.
315+ */
316+ table->key_info[i].block_size= 0;
317+ table->key_info[i].flags&= ~HA_USES_BLOCK_SIZE;
318 }
319 }
320
321@@ -428,6 +435,13 @@
322 return 0;
323 }
324
325+enum row_type ha_heap::get_row_type() const
326+{
327+ if (file->s->recordspace.is_variable_size)
328+ return ROW_TYPE_DYNAMIC;
329+
330+ return ROW_TYPE_FIXED;
331+}
332
333 int ha_heap::extra(enum ha_extra_function operation)
334 {
335@@ -645,23 +659,70 @@
336 heap_prepare_hp_create_info(TABLE *table_arg, bool internal_table,
337 HP_CREATE_INFO *hp_create_info)
338 {
339- uint key, parts, mem_per_row= 0, keys= table_arg->s->keys;
340+ uint key, parts, mem_per_row_keys= 0, keys= table_arg->s->keys;
341 uint auto_key= 0, auto_key_type= 0;
342- ha_rows max_rows;
343+ uint fixed_key_fieldnr = 0, fixed_data_size = 0, next_field_pos = 0;
344+ uint column_idx, column_count= table_arg->s->fields;
345+ HP_COLUMNDEF *columndef;
346 HP_KEYDEF *keydef;
347 HA_KEYSEG *seg;
348 TABLE_SHARE *share= table_arg->s;
349 bool found_real_auto_increment= 0;
350+ uint blobs= 0;
351
352 bzero(hp_create_info, sizeof(*hp_create_info));
353
354+ if (!(columndef= (HP_COLUMNDEF*) my_malloc(column_count *
355+ sizeof(HP_COLUMNDEF),
356+ MYF(MY_WME))))
357+ return my_errno;
358+
359+ for (column_idx= 0; column_idx < column_count; column_idx++)
360+ {
361+ Field* field= *(table_arg->field + column_idx);
362+ HP_COLUMNDEF* column= columndef + column_idx;
363+ column->type= (uint16) field->type();
364+ column->length= field->pack_length();
365+ column->offset= field->offset(table_arg->record[0]);
366+
367+ if (field->null_bit)
368+ {
369+ column->null_bit= field->null_bit;
370+ column->null_pos= (uint) (field->null_ptr -
371+ (uchar*) table_arg->record[0]);
372+ }
373+ else
374+ {
375+ column->null_bit= 0;
376+ column->null_pos= 0;
377+ }
378+
379+ if (field->type() == MYSQL_TYPE_VARCHAR)
380+ {
381+ column->length_bytes= (uint8) (((Field_varstring *) field)->length_bytes);
382+ }
383+ else if (field->type() == MYSQL_TYPE_BLOB)
384+ {
385+ blobs++;
386+ column->length_bytes= (uint8)
387+ (((Field_blob *) field)->pack_length_no_ptr());
388+ }
389+ else
390+ {
391+ column->length_bytes= 0;
392+ }
393+ }
394+
395 for (key= parts= 0; key < keys; key++)
396 parts+= table_arg->key_info[key].key_parts;
397
398 if (!(keydef= (HP_KEYDEF*) my_malloc(keys * sizeof(HP_KEYDEF) +
399 parts * sizeof(HA_KEYSEG),
400 MYF(MY_WME))))
401+ {
402+ my_free((uchar *) columndef);
403 return my_errno;
404+ }
405 seg= reinterpret_cast<HA_KEYSEG*>(keydef + keys);
406 for (key= 0; key < keys; key++)
407 {
408@@ -677,11 +738,11 @@
409 case HA_KEY_ALG_UNDEF:
410 case HA_KEY_ALG_HASH:
411 keydef[key].algorithm= HA_KEY_ALG_HASH;
412- mem_per_row+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
413+ mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
414 break;
415 case HA_KEY_ALG_BTREE:
416 keydef[key].algorithm= HA_KEY_ALG_BTREE;
417- mem_per_row+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*);
418+ mem_per_row_keys+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*);
419 break;
420 default:
421 DBUG_ASSERT(0); // cannot happen
422@@ -706,6 +767,16 @@
423 seg->length= (uint) key_part->length;
424 seg->flag= key_part->key_part_flag;
425
426+ next_field_pos= seg->start;
427+ if (field->type() == MYSQL_TYPE_VARCHAR)
428+ {
429+ Field *orig_field= *(table_arg->field + key_part->field->field_index);
430+ next_field_pos+= orig_field->pack_length();
431+ }
432+ else
433+ {
434+ next_field_pos+= seg->length;
435+ }
436 if (field->flags & (ENUM_FLAG | SET_FLAG))
437 seg->charset= &my_charset_bin;
438 else
439@@ -731,9 +802,75 @@
440 auto_key= key+ 1;
441 auto_key_type= field->key_type();
442 }
443+
444+ switch (seg->type) {
445+ case HA_KEYTYPE_SHORT_INT:
446+ case HA_KEYTYPE_LONG_INT:
447+ case HA_KEYTYPE_FLOAT:
448+ case HA_KEYTYPE_DOUBLE:
449+ case HA_KEYTYPE_USHORT_INT:
450+ case HA_KEYTYPE_ULONG_INT:
451+ case HA_KEYTYPE_LONGLONG:
452+ case HA_KEYTYPE_ULONGLONG:
453+ case HA_KEYTYPE_INT24:
454+ case HA_KEYTYPE_UINT24:
455+ case HA_KEYTYPE_INT8:
456+ seg->flag|= HA_SWAP_KEY;
457+ break;
458+ case HA_KEYTYPE_VARBINARY1:
459+ /* Case-insensitiveness is handled in coll->hash_sort */
460+ seg->type= HA_KEYTYPE_VARTEXT1;
461+ /* fall through */
462+ case HA_KEYTYPE_VARTEXT1:
463+ keydef[key].flag|= HA_VAR_LENGTH_KEY;
464+ /* Save number of bytes used to store length */
465+ if (seg->flag & HA_BLOB_PART)
466+ seg->bit_start= field->pack_length() - share->blob_ptr_size;
467+ else
468+ seg->bit_start= 1;
469+ break;
470+ case HA_KEYTYPE_VARBINARY2:
471+ /* Case-insensitiveness is handled in coll->hash_sort */
472+ /* fall_through */
473+ case HA_KEYTYPE_VARTEXT2:
474+ keydef[key].flag|= HA_VAR_LENGTH_KEY;
475+ /* Save number of bytes used to store length */
476+ if (seg->flag & HA_BLOB_PART)
477+ seg->bit_start= field->pack_length() - share->blob_ptr_size;
478+ else
479+ seg->bit_start= 2;
480+ /*
481+ Make future comparison simpler by only having to check for
482+ one type
483+ */
484+ seg->type= HA_KEYTYPE_VARTEXT1;
485+ break;
486+ default:
487+ break;
488+ }
489+
490+ if (next_field_pos > fixed_data_size)
491+ {
492+ fixed_data_size= next_field_pos;
493+ }
494+
495+
496+ if (field->field_index >= fixed_key_fieldnr)
497+ {
498+ /*
499+ Do not use seg->fieldnr as it's not reliable in case of temp tables
500+ */
501+ fixed_key_fieldnr= field->field_index + 1;
502+ }
503 }
504 }
505- mem_per_row+= MY_ALIGN(share->reclength + 1, sizeof(char*));
506+
507+ if (fixed_data_size < share->null_bytes)
508+ {
509+ /* Make sure to include null fields regardless of the presense of keys */
510+ fixed_data_size = share->null_bytes;
511+ }
512+
513 if (table_arg->found_next_number_field)
514 {
515 keydef[share->next_number_index].flag|= HA_AUTO_KEY;
516@@ -744,16 +881,19 @@
517 hp_create_info->max_table_size=current_thd->variables.max_heap_table_size;
518 hp_create_info->with_auto_increment= found_real_auto_increment;
519 hp_create_info->internal_table= internal_table;
520-
521- max_rows= (ha_rows) (hp_create_info->max_table_size / mem_per_row);
522- if (share->max_rows && share->max_rows < max_rows)
523- max_rows= share->max_rows;
524-
525- hp_create_info->max_records= (ulong) max_rows;
526+ hp_create_info->max_chunk_size= share->key_block_size;
527+ hp_create_info->is_dynamic= (share->row_type == ROW_TYPE_DYNAMIC);
528+ hp_create_info->columns= column_count;
529+ hp_create_info->columndef= columndef;
530+ hp_create_info->fixed_key_fieldnr= fixed_key_fieldnr;
531+ hp_create_info->fixed_data_size= fixed_data_size;
532+ hp_create_info->max_records= (ulong) share->max_rows;
533 hp_create_info->min_records= (ulong) share->min_rows;
534 hp_create_info->keys= share->keys;
535 hp_create_info->reclength= share->reclength;
536+ hp_create_info->keys_memory_size= mem_per_row_keys;
537 hp_create_info->keydef= keydef;
538+ hp_create_info->blobs= blobs;
539 return 0;
540 }
541
542@@ -773,6 +913,7 @@
543 create_info->auto_increment_value - 1 : 0);
544 error= heap_create(name, &hp_create_info, &internal_share, &created);
545 my_free(hp_create_info.keydef);
546+ my_free(hp_create_info.columndef);
547 DBUG_ASSERT(file == 0);
548 return (error);
549 }
550@@ -783,6 +924,13 @@
551 table->file->info(HA_STATUS_AUTO);
552 if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
553 create_info->auto_increment_value= stats.auto_increment_value;
554+ if (!(create_info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
555+ {
556+ if (file->s->recordspace.is_variable_size)
557+ create_info->key_block_size= file->s->recordspace.chunk_length;
558+ else
559+ create_info->key_block_size= 0;
560+ }
561 }
562
563 void ha_heap::get_auto_increment(ulonglong offset, ulonglong increment,
564--- a/storage/heap/ha_heap.h
565+++ b/storage/heap/ha_heap.h
566@@ -47,12 +47,11 @@
567 return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
568 "BTREE" : "HASH");
569 }
570- /* Rows also use a fixed-size format */
571- enum row_type get_row_type() const { return ROW_TYPE_FIXED; }
572+ enum row_type get_row_type() const;
573 const char **bas_ext() const;
574 ulonglong table_flags() const
575 {
576- return (HA_FAST_KEY_READ | HA_NO_BLOBS | HA_NULL_IN_KEY |
577+ return (HA_FAST_KEY_READ | HA_NULL_IN_KEY |
578 HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
579 HA_REC_NOT_IN_SEQ | HA_CAN_INSERT_DELAYED | HA_NO_TRANSACTIONS |
580 HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT);
581@@ -64,8 +63,9 @@
582 HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
583 }
584 const key_map *keys_to_use_for_scanning() { return &btree_keys; }
585- uint max_supported_keys() const { return MAX_KEY; }
586- uint max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
587+ uint max_supported_keys() const { return HP_MAX_KEY; }
588+ uint max_supported_key_length() const { return HP_MAX_KEY_LENGTH; }
589+ uint max_supported_key_part_length() const { return HP_MAX_KEY_LENGTH; }
590 double scan_time()
591 { return (double) (stats.records+stats.deleted) / 20.0+10; }
592 double read_time(uint index, uint ranges, ha_rows rows)
593--- a/storage/heap/heapdef.h
594+++ b/storage/heap/heapdef.h
595@@ -32,6 +32,13 @@
596 #define HP_MIN_RECORDS_IN_BLOCK 16
597 #define HP_MAX_RECORDS_IN_BLOCK 8192
598
599+/* this chunk has been deleted and can be reused */
600+#define CHUNK_STATUS_DELETED 0
601+/* this chunk represents the first part of a live record */
602+#define CHUNK_STATUS_ACTIVE 1
603+/* this chunk is a continuation from another chunk (part of chunkset) */
604+#define CHUNK_STATUS_LINKED 2
605+
606 /* Some extern variables */
607
608 extern LIST *heap_open_list,*heap_share_list;
609@@ -42,7 +49,14 @@
610 #define hp_find_hash(A,B) ((HASH_INFO*) hp_find_block((A),(B)))
611
612 /* Find pos for record and update it in info->current_ptr */
613-#define hp_find_record(info,pos) (info)->current_ptr= hp_find_block(&(info)->s->block,pos)
614+#define hp_find_record(info,pos) \
615+ (info)->current_ptr= hp_find_block(&(info)->s->recordspace.block,pos)
616+
617+#define get_chunk_status(info,ptr) (ptr[(info)->offset_status])
618+
619+#define get_chunk_count(info,rec_length) \
620+ ((rec_length + (info)->chunk_dataspace_length - 1) / \
621+ (info)->chunk_dataspace_length)
622
623 typedef struct st_hp_hash_info
624 {
625@@ -90,7 +104,7 @@
626 const uchar *key);
627 extern void hp_make_key(HP_KEYDEF *keydef,uchar *key,const uchar *rec);
628 extern uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key,
629- const uchar *rec, uchar *recpos);
630+ const uchar *rec, uchar *recpos, my_bool packed);
631 extern uint hp_rb_key_length(HP_KEYDEF *keydef, const uchar *key);
632 extern uint hp_rb_null_key_length(HP_KEYDEF *keydef, const uchar *key);
633 extern uint hp_rb_var_key_length(HP_KEYDEF *keydef, const uchar *key);
634@@ -100,6 +114,23 @@
635 extern void hp_clear_keys(HP_SHARE *info);
636 extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
637 key_part_map keypart_map);
638+extern uint hp_calc_blob_length(uint length, const uchar *pos);
639+
640+/* Chunkset management (alloc/free/encode/decode) functions */
641+extern uchar *hp_allocate_chunkset(HP_DATASPACE *info, uint chunk_count);
642+extern int hp_reallocate_chunkset(HP_DATASPACE *info, uint chunk_count,
643+ uchar *pos);
644+extern void hp_free_chunks(HP_DATASPACE *info, uchar *pos);
645+extern void hp_clear_dataspace(HP_DATASPACE *info);
646+
647+extern uint hp_get_encoded_data_length(HP_SHARE *info, const uchar *record,
648+ uint *chunk_count);
649+extern void hp_copy_record_data_to_chunkset(HP_SHARE *info, const uchar *record,
650+ uchar *pos);
651+extern int hp_extract_record(HP_INFO *info, uchar *record, const uchar *pos);
652+extern uint hp_process_record_data_to_chunkset(HP_SHARE *info,
653+ const uchar *record, uchar *pos,
654+ uint is_compare);
655
656 extern mysql_mutex_t THR_LOCK_heap;
657
658--- a/storage/heap/hp_clear.c
659+++ b/storage/heap/hp_clear.c
660@@ -31,16 +31,11 @@
661 {
662 DBUG_ENTER("hp_clear");
663
664- if (info->block.levels)
665- (void) hp_free_level(&info->block,info->block.levels,info->block.root,
666- (uchar*) 0);
667- info->block.levels=0;
668+ hp_clear_dataspace(&info->recordspace);
669 hp_clear_keys(info);
670- info->records= info->deleted= 0;
671- info->data_length= 0;
672+ info->records= 0;
673 info->blength=1;
674 info->changed=0;
675- info->del_link=0;
676 DBUG_VOID_RETURN;
677 }
678
679@@ -158,7 +153,7 @@
680 int error= 0;
681 HP_SHARE *share= info->s;
682
683- if (share->data_length || share->index_length)
684+ if (share->recordspace.total_data_length || share->index_length)
685 error= HA_ERR_CRASHED;
686 else
687 if (share->currently_disabled_keys)
688--- a/storage/heap/hp_close.c
689+++ b/storage/heap/hp_close.c
690@@ -46,6 +46,10 @@
691 heap_open_list=list_delete(heap_open_list,&info->open_list);
692 if (!--info->s->open_count && info->s->delete_on_close)
693 hp_free(info->s); /* Table was deleted */
694+ if (info->blob_buffer)
695+ {
696+ my_free(info->blob_buffer);
697+ }
698 my_free(info);
699 DBUG_RETURN(error);
700 }
701--- a/storage/heap/hp_create.c
702+++ b/storage/heap/hp_create.c
703@@ -14,11 +14,21 @@
704 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
705
706 #include "heapdef.h"
707+#include <mysql_com.h>
708+#include <mysqld_error.h>
709
710 static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2);
711-static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
712+static void init_block(HP_BLOCK *block,uint chunk_length, ulong min_records,
713 ulong max_records);
714
715+#define FIXED_REC_OVERHEAD (sizeof(uchar))
716+#define VARIABLE_REC_OVERHEAD (sizeof(uchar **) + sizeof(uchar))
717+
718+/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
719+#define VARIABLE_MIN_CHUNK_SIZE \
720+ ((sizeof(uchar **) + VARIABLE_REC_OVERHEAD + sizeof(uchar **) - 1) & \
721+ ~(sizeof(uchar **) - 1))
722+
723 /* Create a heap table */
724
725 int heap_create(const char *name, HP_CREATE_INFO *create_info,
726@@ -32,6 +42,7 @@
727 uint keys= create_info->keys;
728 ulong min_records= create_info->min_records;
729 ulong max_records= create_info->max_records;
730+ ulong max_rows_for_stated_memory;
731 DBUG_ENTER("heap_create");
732
733 if (!create_info->internal_table)
734@@ -48,15 +59,147 @@
735
736 if (!share)
737 {
738+ uint chunk_dataspace_length, chunk_length, is_variable_size;
739+ uint fixed_data_length, fixed_column_count;
740 HP_KEYDEF *keyinfo;
741 DBUG_PRINT("info",("Initializing new table"));
742-
743+
744+ if (create_info->max_chunk_size)
745+ {
746+ uint configured_chunk_size= create_info->max_chunk_size;
747+
748+ /* User requested variable-size records, let's see if they're possible */
749+
750+ if (configured_chunk_size < create_info->fixed_data_size)
751+ {
752+ /*
753+ The resulting chunk_size cannot be smaller than fixed data part
754+ at the start of the first chunk which allows faster copying
755+ with a single memcpy().
756+ */
757+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "key_block_size");
758+ goto err;
759+ }
760+
761+ if (reclength > configured_chunk_size + VARIABLE_REC_OVERHEAD ||
762+ create_info->blobs > 0)
763+ {
764+ /*
765+ Allow variable size only if we're saving some space, i.e.
766+ if a fixed-size record would take more space than variable-size
767+ one plus the variable-size overhead.
768+ There has to be at least one field after indexed fields.
769+ Note that NULL bits are already included in key_part_size.
770+ */
771+ is_variable_size= 1;
772+ chunk_dataspace_length= configured_chunk_size;
773+ }
774+ else
775+ {
776+ /* max_chunk_size is near the full reclength, let's use fixed size */
777+ is_variable_size= 0;
778+ chunk_dataspace_length= reclength;
779+ }
780+ }
781+ else if ((create_info->is_dynamic && reclength >
782+ 256 + VARIABLE_REC_OVERHEAD)
783+ || create_info->blobs > 0)
784+ {
785+ /*
786+ User asked for dynamic records - use 256 as the chunk size, if that
787+ will may save some memory. Otherwise revert to fixed size format.
788+ */
789+ if ((create_info->fixed_data_size + VARIABLE_REC_OVERHEAD) > 256)
790+ chunk_dataspace_length= create_info->fixed_data_size;
791+ else
792+ chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
793+
794+ is_variable_size= 1;
795+ }
796+ else
797+ {
798+ /*
799+ If max_chunk_size is not specified, put the whole record in one chunk
800+ */
801+ is_variable_size= 0;
802+ chunk_dataspace_length= reclength;
803+ }
804+
805+ if (is_variable_size)
806+ {
807+ /* Check whether we have any variable size records past key data */
808+ uint has_variable_fields= 0;
809+
810+ fixed_data_length= create_info->fixed_data_size;
811+ fixed_column_count= create_info->fixed_key_fieldnr;
812+
813+ for (i= create_info->fixed_key_fieldnr; i < create_info->columns; i++)
814+ {
815+ HP_COLUMNDEF *column= create_info->columndef + i;
816+ if ((column->type == MYSQL_TYPE_VARCHAR &&
817+ (column->length - column->length_bytes) >= 32) ||
818+ column->type == MYSQL_TYPE_BLOB)
819+ {
820+ /*
821+ The field has to be either blob or >= 5.0.3 true VARCHAR
822+ and have substantial length.
823+ TODO: do we want to calculate minimum length?
824+ */
825+ has_variable_fields= 1;
826+ break;
827+ }
828+
829+ if (has_variable_fields)
830+ {
831+ break;
832+ }
833+
834+ if ((column->offset + column->length) <= chunk_dataspace_length)
835+ {
836+ /* Still no variable-size columns, add one fixed-length */
837+ fixed_column_count= i + 1;
838+ fixed_data_length= column->offset + column->length;
839+ }
840+ }
841+
842+ if (!has_variable_fields && create_info->blobs == 0)
843+ {
844+ /*
845+ There is no need to use variable-size records without variable-size
846+ columns.
847+ Reset sizes if it's not variable size anymore.
848+ */
849+ is_variable_size= 0;
850+ chunk_dataspace_length= reclength;
851+ fixed_data_length= reclength;
852+ fixed_column_count= create_info->columns;
853+ }
854+ }
855+ else
856+ {
857+ fixed_data_length= reclength;
858+ fixed_column_count= create_info->columns;
859+ }
860+
861 /*
862- We have to store sometimes uchar* del_link in records,
863- so the record length should be at least sizeof(uchar*)
864+ We store uchar* del_link inside the data area of deleted records,
865+ so the data length should be at least sizeof(uchar*)
866 */
867- set_if_bigger(reclength, sizeof (uchar*));
868-
869+ set_if_bigger(chunk_dataspace_length, sizeof (uchar **));
870+
871+ if (is_variable_size)
872+ {
873+ chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
874+ }
875+ else
876+ {
877+ chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
878+ }
879+
880+ /* Align chunk length to the next pointer */
881+ chunk_length= (uint) (chunk_length + sizeof(uchar **) - 1) &
882+ ~(sizeof(uchar **) - 1);
883+
884 for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
885 {
886 bzero((char*) &keyinfo->block,sizeof(keyinfo->block));
887@@ -73,42 +216,11 @@
888 keyinfo->rb_tree.size_of_element++;
889 }
890 switch (keyinfo->seg[j].type) {
891- case HA_KEYTYPE_SHORT_INT:
892- case HA_KEYTYPE_LONG_INT:
893- case HA_KEYTYPE_FLOAT:
894- case HA_KEYTYPE_DOUBLE:
895- case HA_KEYTYPE_USHORT_INT:
896- case HA_KEYTYPE_ULONG_INT:
897- case HA_KEYTYPE_LONGLONG:
898- case HA_KEYTYPE_ULONGLONG:
899- case HA_KEYTYPE_INT24:
900- case HA_KEYTYPE_UINT24:
901- case HA_KEYTYPE_INT8:
902- keyinfo->seg[j].flag|= HA_SWAP_KEY;
903- break;
904 case HA_KEYTYPE_VARBINARY1:
905- /* Case-insensitiveness is handled in coll->hash_sort */
906- keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
907- /* fall_through */
908 case HA_KEYTYPE_VARTEXT1:
909- keyinfo->flag|= HA_VAR_LENGTH_KEY;
910- length+= 2;
911- /* Save number of bytes used to store length */
912- keyinfo->seg[j].bit_start= 1;
913- break;
914 case HA_KEYTYPE_VARBINARY2:
915- /* Case-insensitiveness is handled in coll->hash_sort */
916- /* fall_through */
917 case HA_KEYTYPE_VARTEXT2:
918- keyinfo->flag|= HA_VAR_LENGTH_KEY;
919 length+= 2;
920- /* Save number of bytes used to store length */
921- keyinfo->seg[j].bit_start= 2;
922- /*
923- Make future comparison simpler by only having to check for
924- one type
925- */
926- keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
927 break;
928 default:
929 break;
930@@ -133,13 +245,34 @@
931 }
932 if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
933 keys*sizeof(HP_KEYDEF)+
934+ (create_info->columns *
935+ sizeof(HP_COLUMNDEF)) +
936 key_segs*sizeof(HA_KEYSEG),
937 MYF(MY_ZEROFILL))))
938 goto err;
939- share->keydef= (HP_KEYDEF*) (share + 1);
940+
941+ /*
942+ Max_records is used for estimating block sizes and for enforcement.
943+ Calculate the very maximum number of rows (if everything was one chunk)
944+ and then take either that value or configured max_records (pick smallest
945+ one).
946+ */
947+ max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
948+ (create_info->keys_memory_size +
949+ chunk_length));
950+ max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
951+ max_records : max_rows_for_stated_memory);
952+
953+ share->column_defs= (HP_COLUMNDEF*) (share + 1);
954+ memcpy(share->column_defs, create_info->columndef,
955+ (size_t) (sizeof(create_info->columndef[0]) *
956+ create_info->columns));
957+
958+ share->keydef= (HP_KEYDEF*) (share->column_defs + create_info->columns);
959 share->key_stat_version= 1;
960 keyseg= (HA_KEYSEG*) (share->keydef + keys);
961- init_block(&share->block, reclength + 1, min_records, max_records);
962+ init_block(&share->recordspace.block, chunk_length, min_records,
963+ max_records);
964 /* Fix keys */
965 memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
966 for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
967@@ -177,15 +310,35 @@
968 share->min_records= min_records;
969 share->max_records= max_records;
970 share->max_table_size= create_info->max_table_size;
971- share->data_length= share->index_length= 0;
972- share->reclength= reclength;
973+ share->index_length= 0;
974 share->blength= 1;
975 share->keys= keys;
976 share->max_key_length= max_length;
977+ share->column_count= create_info->columns;
978 share->changed= 0;
979 share->auto_key= create_info->auto_key;
980 share->auto_key_type= create_info->auto_key_type;
981 share->auto_increment= create_info->auto_increment;
982+
983+ share->fixed_data_length= fixed_data_length;
984+ share->fixed_column_count= fixed_column_count;
985+ share->blobs= create_info->blobs;
986+
987+ share->recordspace.chunk_length= chunk_length;
988+ share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
989+ share->recordspace.is_variable_size= is_variable_size;
990+ share->recordspace.total_data_length= 0;
991+
992+ if (is_variable_size) {
993+ share->recordspace.offset_link= chunk_dataspace_length;
994+ share->recordspace.offset_status= share->recordspace.offset_link +
995+ sizeof(uchar **);
996+ } else {
997+ /* Make it likely to fail if anyone uses this offset */
998+ share->recordspace.offset_link= 1 << 22;
999+ share->recordspace.offset_status= chunk_dataspace_length;
1000+ }
1001+
1002 /* Must be allocated separately for rename to work */
1003 if (!(share->name= my_strdup(name,MYF(0))))
1004 {
1005@@ -227,7 +380,7 @@
1006 param->search_flag, not_used);
1007 }
1008
1009-static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
1010+static void init_block(HP_BLOCK *block, uint chunk_length, ulong min_records,
1011 ulong max_records)
1012 {
1013 uint i,recbuffer,records_in_block;
1014@@ -235,7 +388,12 @@
1015 max_records= max(min_records,max_records);
1016 if (!max_records)
1017 max_records= 1000; /* As good as quess as anything */
1018- recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
1019+ /*
1020+ We want to start each chunk at 8 bytes boundary, round recbuffer to the
1021+ next 8.
1022+ */
1023+ recbuffer= (uint) (chunk_length + sizeof(uchar**) - 1) &
1024+ ~(sizeof(uchar**) - 1);
1025 records_in_block= max_records / 10;
1026 if (records_in_block < 10 && max_records)
1027 records_in_block= 10;
1028--- a/storage/heap/hp_delete.c
1029+++ b/storage/heap/hp_delete.c
1030@@ -22,6 +22,8 @@
1031 uchar *pos;
1032 HP_SHARE *share=info->s;
1033 HP_KEYDEF *keydef, *end, *p_lastinx;
1034+ uint rec_length, chunk_count;
1035+
1036 DBUG_ENTER("heap_delete");
1037 DBUG_PRINT("enter",("info: 0x%lx record: 0x%lx", (long) info, (long) record));
1038
1039@@ -31,6 +33,8 @@
1040 DBUG_RETURN(my_errno); /* Record changed */
1041 share->changed=1;
1042
1043+ rec_length = hp_get_encoded_data_length(share, record, &chunk_count);
1044+
1045 if ( --(share->records) < share->blength >> 1) share->blength>>=1;
1046 pos=info->current_ptr;
1047
1048@@ -43,10 +47,7 @@
1049 }
1050
1051 info->update=HA_STATE_DELETED;
1052- *((uchar**) pos)=share->del_link;
1053- share->del_link=pos;
1054- pos[share->reclength]=0; /* Record deleted */
1055- share->deleted++;
1056+ hp_free_chunks(&share->recordspace, pos);
1057 info->current_hash_ptr=0;
1058 #if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
1059 DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
1060@@ -75,7 +76,8 @@
1061 info->last_pos= NULL; /* For heap_rnext/heap_rprev */
1062
1063 custom_arg.keyseg= keyinfo->seg;
1064- custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
1065+ custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos,
1066+ FALSE);
1067 custom_arg.search_flag= SEARCH_SAME;
1068 old_allocated= keyinfo->rb_tree.allocated;
1069 res= tree_delete(&keyinfo->rb_tree, info->recbuf, custom_arg.key_length,
1070@@ -112,6 +114,7 @@
1071 blength=share->blength;
1072 if (share->records+1 == blength)
1073 blength+= blength;
1074+
1075 lastpos=hp_find_hash(&keyinfo->block,share->records);
1076 last_ptr=0;
1077
1078--- /dev/null
1079+++ b/storage/heap/hp_dspace.c
1080@@ -0,0 +1,440 @@
1081+/* Copyright (C) 2000-2002 MySQL AB
1082+ Copyright (C) 2008 eBay, Inc
1083+
1084+ This program is free software; you can redistribute it and/or modify
1085+ it under the terms of the GNU General Public License as published by
1086+ the Free Software Foundation; version 2 of the License.
1087+
1088+ This program is distributed in the hope that it will be useful,
1089+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1090+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1091+ GNU General Public License for more details.
1092+
1093+ You should have received a copy of the GNU General Public License
1094+ along with this program; if not, write to the Free Software
1095+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1096+
1097+/*
1098+ Implements various base dataspace-related functions - allocate, free, clear
1099+*/
1100+
1101+#include "heapdef.h"
1102+
1103+
1104+/*
1105+ MySQL Heap tables keep data in arrays of fixed-size chunks.
1106+ These chunks are organized into two groups of HP_BLOCK structures:
1107+ - group1 contains indexes, with one HP_BLOCK per key
1108+ (part of HP_KEYDEF)
1109+ - group2 contains record data, with single HP_BLOCK
1110+ for all records, referenced by HP_SHARE.recordspace.block
1111+
1112+ While columns used in index are usually small, other columns
1113+ in the table may need to accomodate larger data. Typically,
1114+ larger data is placed into VARCHAR or BLOB columns. With actual
1115+ sizes varying, Heap Engine has to support variable-sized records
1116+ in memory. Heap Engine implements the concept of dataspace
1117+ (HP_DATASPACE), which incorporates HP_BLOCK for the record data,
1118+ and adds more information for managing variable-sized records.
1119+
1120+ Variable-size records are stored in multiple "chunks",
1121+ which means that a single record of data (database "row") can
1122+ consist of multiple chunks organized into one "set". HP_BLOCK
1123+ contains chunks. In variable-size format, one record
1124+ is represented as one or many chunks, depending on the actual
1125+ data, while in fixed-size mode, one record is always represented
1126+ as one chunk. The index structures would always point to the first
1127+ chunk in the chunkset.
1128+
1129+ At the time of table creation, Heap Engine attempts to find out if
1130+ variable-size records are desired. A user can request
1131+ variable-size records by providing either row_type=dynamic or
1132+ key_block_size=NNN table create option. Heap Engine will check
1133+ whether key_block_size provides enough space in the first chunk
1134+ to keep all null bits and columns that are used in indexes.
1135+ If key_block_size is too small, table creation will be aborted
1136+ with an error. Heap Engine will revert to fixed-size allocation
1137+ mode if key_block_size provides no memory benefits (if the
1138+ fixed-size record would always be shorter then the first chunk
1139+ in the chunkset with the specified key_block_size).
1140+
1141+ In order to improve index search performance, Heap Engine needs
1142+ to keep all null flags and all columns used as keys inside
1143+ the first chunk of a chunkset. In particular, this means that
1144+ all columns used as keys should be defined first in the table
1145+ creation SQL. The length of data used by null bits and key columns
1146+ is stored as fixed_data_length inside HP_SHARE. fixed_data_length
1147+ will extend past last key column if more fixed-length fields can
1148+ fit into the first chunk.
1149+
1150+ Variable-size records are necessary only in the presence of
1151+ variable-size columns. Heap Engine will be looking for BLOB
1152+ columns or VARCHAR columns, which declare length of 32 or more. If
1153+ no such columns are found, table will be switched to fixed-size
1154+ format. You should always try to put such columns at the end of
1155+ the table definition.
1156+
1157+ Whenever data is being inserted or updated in the table
1158+ Heap Engine will calculate how many chunks are necessary.
1159+ For insert operations, Heap Engine allocates new chunkset in
1160+ the recordspace. For update operations it will modify length of
1161+ the existing chunkset, unlinking unnecessary chunks at the end,
1162+ or allocating and adding more if larger length is necessary.
1163+
1164+ When writing data to chunks or copying data back to record,
1165+ fixed-size columns are copied in their full format. VARCHARs and
1166+ BLOBs are copied based on their actual length. Any NULL values
1167+ after fixed_data_length are skipped.
1168+
1169+ The allocation and contents of the actual chunks varies between
1170+ fixed and variable-size modes. Total chunk length is always
1171+ aligned to the next sizeof(uchar*). Here is the format of
1172+ fixed-size chunk:
1173+ uchar[] - sizeof=chunk_dataspace_length, but at least
1174+ sizeof(uchar*) bytes. Keeps actual data or pointer
1175+ to the next deleted chunk.
1176+ chunk_dataspace_length equals to full record length
1177+ uchar - status field (1 means "in use", 0 means "deleted")
1178+
1179+ Variable-size chunk uses different format:
1180+ uchar[] - sizeof=chunk_dataspace_length, but at least
1181+ sizeof(uchar*) bytes. Keeps actual data or pointer
1182+ to the next deleted chunk.
1183+ chunk_dataspace_length is set according to table
1184+ setup (key_block_size)
1185+ uchar* - pointer to the next chunk in this chunkset,
1186+ or NULL for the last chunk
1187+ uchar - status field (1 means "first", 0 means "deleted",
1188+ 2 means "linked")
1189+
1190+ When allocating a new chunkset of N chunks, Heap Engine will try
1191+ to allocate chunks one-by-one, linking them as they become
1192+ allocated. Allocation of a single chunk will attempt to reuse
1193+ a deleted (freed) chunk. If no free chunks are available,
1194+ it will attempt to allocate a new area inside HP_BLOCK.
1195+ Freeing chunks will place them at the front of free list
1196+ referenced by del_link in HP_DATASPACE. The newly freed chunk
1197+ will contain reference to the previously freed chunk in its first
1198+ sizeof(uchar*) of the payload space.
1199+
1200+ Here is open issues:
1201+ - It is not very nice to require people to keep key columns
1202+ at the beginning of the table creation SQL. There are three
1203+ proposed resolutions:
1204+ a. Leave it as is. It's a reasonable limitation
1205+ b. Add new HA_KEEP_KEY_COLUMNS_TO_FRONT flag to handler.h and
1206+ make table.cpp align columns when it creates the table
1207+ c. Make HeapEngine reorder columns in the chunk data, so that
1208+ key columns go first. Add parallel HA_KEYSEG structures
1209+ to distinguish positions in record vs. positions in
1210+ the first chunk. Copy all data field-by-field rather than
1211+ using single memcpy unless DBA kept key columns to
1212+ the beginning.
1213+ - heap_check_heap needs verify linked chunks, looking for
1214+ issues such as orphans, cycles, and bad links. However,
1215+ Heap Engine today does not do similar things even for
1216+ free list.
1217+ - In a more sophisticated implementation, some space can
1218+ be saved even with all fixed-size columns if many of them
1219+ have NULL value, as long as these columns are not used
1220+ in indexes
1221+ - In variable-size format status should be moved to lower
1222+ bits of the "next" pointer. Pointer is always aligned
1223+ to sizeof(byte*), which is at least 4, leaving 2 lower
1224+ bits free. This will save 8 bytes per chunk
1225+ on 64-bit platform.
1226+ - As we do not want to modify FRM format or to add new SQL
1227+ keywords, KEY_BLOCK_SIZE option of "CREATE TABLE" is reused
1228+ to specify block size for Heap Engine tables.
1229+ - since all key columns must fit in the first chunk, having keys
1230+ on BLOB columns is currently impossible. This limitation is
1231+ relatively easiy to remove in future.
1232+*/
1233+
1234+static uchar *hp_allocate_one_chunk(HP_DATASPACE *info);
1235+
1236+
1237+/**
1238+ Clear a dataspace
1239+
1240+ Frees memory and zeros-out any relevant counters in the dataspace
1241+
1242+ @param info the dataspace to clear
1243+*/
1244+
1245+void hp_clear_dataspace(HP_DATASPACE *info)
1246+{
1247+ if (info->block.levels)
1248+ {
1249+ hp_free_level(&info->block,info->block.levels,info->block.root,
1250+ (uchar *) 0);
1251+ }
1252+ info->block.levels= 0;
1253+ info->del_chunk_count= info->chunk_count= 0;
1254+ info->del_link= 0;
1255+ info->total_data_length= 0;
1256+}
1257+
1258+
1259+/**
1260+ Allocate or reallocate a chunkset in the dataspace
1261+
1262+ Attempts to allocate a new chunkset or change the size of an existing chunkset
1263+
1264+ @param info the hosting dataspace
1265+ @param chunk_count the number of chunks that we expect as the result
1266+ @param existing_set non-null value asks function to resize existing
1267+ chunkset, return value would point to this set
1268+
1269+ @return Pointer to the first chunk in the new or updated chunkset, or NULL
1270+ if unsuccessful
1271+*/
1272+
1273+static uchar *hp_allocate_variable_chunkset(HP_DATASPACE *info,
1274+ uint chunk_count,
1275+ uchar *existing_set)
1276+{
1277+ int alloc_count= chunk_count, i;
1278+ uchar *first_chunk= 0, *curr_chunk= 0, *prev_chunk= 0;
1279+ uchar *last_existing_chunk= 0;
1280+
1281+ DBUG_ASSERT(alloc_count);
1282+
1283+ if (existing_set)
1284+ {
1285+ first_chunk= existing_set;
1286+
1287+ curr_chunk= existing_set;
1288+ while (curr_chunk && alloc_count)
1289+ {
1290+ prev_chunk= curr_chunk;
1291+ curr_chunk= *((uchar **) (curr_chunk + info->offset_link));
1292+ alloc_count--;
1293+ }
1294+
1295+ if (!alloc_count)
1296+ {
1297+ if (curr_chunk)
1298+ {
1299+ /*
1300+ We came through all chunks and there is more left, let's truncate the
1301+ list.
1302+ */
1303+ *((uchar **) (prev_chunk + info->offset_link))= NULL;
1304+ hp_free_chunks(info, curr_chunk);
1305+ }
1306+
1307+ return first_chunk;
1308+ }
1309+
1310+ last_existing_chunk= prev_chunk;
1311+ }
1312+
1313+ /*
1314+ We can reach this point only if we're allocating new chunkset or more chunks
1315+ in existing set.
1316+ */
1317+
1318+ for (i= 0; i < alloc_count; i++)
1319+ {
1320+ curr_chunk= hp_allocate_one_chunk(info);
1321+ if (!curr_chunk)
1322+ {
1323+ /* no space in the current block */
1324+
1325+ if (last_existing_chunk)
1326+ {
1327+ /* Truncate whatever was added at the end of the existing chunkset */
1328+ prev_chunk= last_existing_chunk;
1329+ curr_chunk= *((uchar **)(prev_chunk + info->offset_link));
1330+ *((uchar **)(prev_chunk + info->offset_link))= NULL;
1331+ hp_free_chunks(info, curr_chunk);
1332+ }
1333+ else if (first_chunk)
1334+ {
1335+ /* free any chunks previously allocated */
1336+ hp_free_chunks(info, first_chunk);
1337+ }
1338+
1339+ return NULL;
1340+ }
1341+
1342+ /* mark as if this chunk is last in the chunkset */
1343+ *((uchar **) (curr_chunk + info->offset_link))= 0;
1344+
1345+ if (prev_chunk)
1346+ {
1347+ /* tie them into a linked list */
1348+ *((uchar **) (prev_chunk + info->offset_link))= curr_chunk;
1349+ /* Record linked from active */
1350+ curr_chunk[info->offset_status]= CHUNK_STATUS_LINKED;
1351+ }
1352+ else
1353+ {
1354+ /* Record active */
1355+ curr_chunk[info->offset_status]= CHUNK_STATUS_ACTIVE;
1356+ }
1357+
1358+ if (!first_chunk)
1359+ {
1360+ first_chunk= curr_chunk;
1361+ }
1362+
1363+ prev_chunk= curr_chunk;
1364+}
1365+
1366+ return first_chunk;
1367+}
1368+
1369+
1370+/**
1371+ Allocate a new chunkset in the dataspace
1372+
1373+ Attempts to allocate a new chunkset
1374+
1375+ @param info the hosting dataspace
1376+ @param chunk_count the number of chunks that we expect as the result
1377+
1378+ @return Pointer to the first chunk in the new or updated chunkset, or NULL if
1379+ unsuccessful
1380+*/
1381+
1382+uchar *hp_allocate_chunkset(HP_DATASPACE *info, uint chunk_count)
1383+{
1384+ uchar *result;
1385+
1386+ DBUG_ENTER("hp_allocate_chunks");
1387+
1388+ if (info->is_variable_size)
1389+ {
1390+ result = hp_allocate_variable_chunkset(info, chunk_count, NULL);
1391+ }
1392+ else
1393+ {
1394+ result= hp_allocate_one_chunk(info);
1395+ if (result)
1396+ {
1397+ result[info->offset_status]= CHUNK_STATUS_ACTIVE;
1398+ }
1399+
1400+ DBUG_RETURN(result);
1401+ }
1402+
1403+ DBUG_RETURN(result);
1404+}
1405+
1406+
1407+/**
1408+ Reallocate an existing chunkset in the dataspace
1409+
1410+ Attempts to change the size of an existing chunkset
1411+
1412+ @param info the hosting dataspace
1413+ @param chunk_count the number of chunks that we expect as the result
1414+ @param pos pointer to the existing chunkset
1415+
1416+ @return Error code or zero if successful
1417+*/
1418+
1419+int hp_reallocate_chunkset(HP_DATASPACE *info, uint chunk_count, uchar *pos)
1420+{
1421+ DBUG_ENTER("hp_reallocate_chunks");
1422+
1423+ if (!info->is_variable_size)
1424+ {
1425+ /* Update should never change chunk_count in fixed-size mode */
1426+ my_errno= HA_ERR_WRONG_COMMAND;
1427+ return my_errno;
1428+ }
1429+
1430+ /* Reallocate never moves the first chunk */
1431+ if (!hp_allocate_variable_chunkset(info, chunk_count, pos))
1432+ DBUG_RETURN(my_errno);
1433+
1434+ DBUG_RETURN(0);
1435+}
1436+
1437+
1438+/**
1439+ Allocate a single chunk in the dataspace
1440+
1441+ Attempts to allocate a new chunk or reuse one from deleted list
1442+
1443+ @param info the hosting dataspace
1444+
1445+ @return Pointer to the chunk, or NULL if unsuccessful
1446+*/
1447+
1448+static uchar *hp_allocate_one_chunk(HP_DATASPACE *info)
1449+{
1450+ uchar *curr_chunk;
1451+ size_t length;
1452+ ulong block_pos;
1453+
1454+ if (info->del_link)
1455+ {
1456+ curr_chunk= info->del_link;
1457+ info->del_link= *((uchar **) curr_chunk);
1458+ info->del_chunk_count--;
1459+
1460+ DBUG_PRINT("hp_allocate_one_chunk",
1461+ ("Used old position: 0x%lx",(long) curr_chunk));
1462+ return curr_chunk;
1463+ }
1464+
1465+ block_pos= (info->chunk_count % info->block.records_in_block);
1466+ if (!block_pos)
1467+ {
1468+ if (hp_get_new_block(&info->block, &length))
1469+ {
1470+ /* no space in the current block */
1471+ return NULL;
1472+ }
1473+
1474+ info->total_data_length+= length;
1475+ }
1476+
1477+ info->chunk_count++;
1478+ curr_chunk= ((uchar *) info->block.level_info[0].last_blocks +
1479+ block_pos * info->block.recbuffer);
1480+
1481+ DBUG_PRINT("hp_allocate_one_chunk",
1482+ ("Used new position: 0x%lx", (long) curr_chunk));
1483+
1484+ return curr_chunk;
1485+}
1486+
1487+
1488+/**
1489+ Free a list of chunks
1490+
1491+ Reclaims all chunks linked by the pointer,
1492+ which could be the whole chunkset or a part of an existing chunkset
1493+
1494+ @param info the hosting dataspace
1495+ @param pos pointer to the head of the chunkset
1496+*/
1497+
1498+void hp_free_chunks(HP_DATASPACE *info, uchar *pos)
1499+{
1500+ uchar *curr_chunk= pos;
1501+
1502+ while (curr_chunk)
1503+ {
1504+ info->del_chunk_count++;
1505+ *((uchar **) curr_chunk)= info->del_link;
1506+ info->del_link= curr_chunk;
1507+
1508+ curr_chunk[info->offset_status]= CHUNK_STATUS_DELETED;
1509+
1510+ DBUG_PRINT("hp_free_chunks",("Freed position: 0x%lx", (long) curr_chunk));
1511+
1512+ if (!info->is_variable_size)
1513+ {
1514+ break;
1515+ }
1516+
1517+ /* Delete next chunk in this chunkset */
1518+ curr_chunk= *((uchar **)(curr_chunk + info->offset_link));
1519+ }
1520+}
1521--- a/storage/heap/hp_extra.c
1522+++ b/storage/heap/hp_extra.c
1523@@ -56,7 +56,6 @@
1524 info->current_record= (ulong) ~0L;
1525 info->current_hash_ptr=0;
1526 info->update=0;
1527- info->next_block=0;
1528 return 0;
1529 }
1530
1531--- a/storage/heap/hp_hash.c
1532+++ b/storage/heap/hp_hash.c
1533@@ -336,16 +336,26 @@
1534 {
1535 CHARSET_INFO *cs= seg->charset;
1536 uint pack_length= seg->bit_start;
1537- uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
1538+ uint length= hp_calc_blob_length(pack_length, pos);
1539+
1540+ if (seg->flag & HA_BLOB_PART)
1541+ {
1542+ memcpy(&pos, pos + pack_length, sizeof(char *));
1543+ }
1544+ else
1545+ {
1546+ pos+= pack_length;
1547+ }
1548+
1549 if (cs->mbmaxlen > 1)
1550 {
1551 uint char_length;
1552- char_length= my_charpos(cs, pos + pack_length,
1553- pos + pack_length + length,
1554+ char_length= my_charpos(cs, pos,
1555+ pos + length,
1556 seg->length/cs->mbmaxlen);
1557 set_if_smaller(length, char_length);
1558 }
1559- cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
1560+ cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
1561 }
1562 else
1563 {
1564@@ -545,18 +555,18 @@
1565 uint char_length1, char_length2;
1566 uint pack_length= seg->bit_start;
1567 CHARSET_INFO *cs= seg->charset;
1568- if (pack_length == 1)
1569- {
1570- char_length1= (uint) *(uchar*) pos1++;
1571- char_length2= (uint) *(uchar*) pos2++;
1572- }
1573- else
1574+
1575+ char_length1= hp_calc_blob_length(pack_length, pos1);
1576+ char_length2= hp_calc_blob_length(pack_length, pos2);
1577+ pos1+= pack_length;
1578+ pos2+= pack_length;
1579+
1580+ if (seg->flag & HA_BLOB_PART)
1581 {
1582- char_length1= uint2korr(pos1);
1583- char_length2= uint2korr(pos2);
1584- pos1+= 2;
1585- pos2+= 2;
1586+ memcpy(&pos1, pos1, sizeof(char *));
1587+ memcpy(&pos2, pos2, sizeof(char *));
1588 }
1589+
1590 if (cs->mbmaxlen > 1)
1591 {
1592 uint safe_length1= char_length1;
1593@@ -668,6 +678,34 @@
1594 }
1595
1596
1597+/**
1598+ Returns a BLOB length stored in the specified number of bytes at the
1599+ specified location.
1600+
1601+ @param length the number of bytes used to store length
1602+ @param pos pointer to length bytes
1603+
1604+ @return Length of BLOB data.
1605+*/
1606+
1607+uint hp_calc_blob_length(uint bytes, const uchar *pos)
1608+{
1609+ switch (bytes) {
1610+ case 1:
1611+ return (uint) *pos;
1612+ case 2:
1613+ return uint2korr(pos);
1614+ case 3:
1615+ return uint3korr(pos);
1616+ case 4:
1617+ return uint4korr(pos);
1618+ default:
1619+ break;
1620+ }
1621+
1622+ return 0; /* Impossible */
1623+}
1624+
1625 /* Copy a key from a record to a keybuffer */
1626
1627 void hp_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec)
1628@@ -678,18 +716,37 @@
1629 {
1630 CHARSET_INFO *cs= seg->charset;
1631 uint char_length= seg->length;
1632- uchar *pos= (uchar*) rec + seg->start;
1633+ const uchar *pos= rec + seg->start;
1634 if (seg->null_bit)
1635 *key++= test(rec[seg->null_pos] & seg->null_bit);
1636- if (cs->mbmaxlen > 1)
1637+
1638+ if (seg->flag & HA_BLOB_PART)
1639 {
1640- char_length= my_charpos(cs, pos, pos + seg->length,
1641- char_length / cs->mbmaxlen);
1642- set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
1643+ uint tmp_length= hp_calc_blob_length(seg->bit_start, pos);
1644+ uint length= min(seg->length, tmp_length);
1645+
1646+ memcpy(&pos, rec + seg->bit_start, sizeof(char *));
1647+ if (cs->mbmaxlen > 1)
1648+ {
1649+ char_length= my_charpos(cs, pos, pos + seg->length,
1650+ char_length / cs->mbmaxlen);
1651+ set_if_smaller(char_length, length); /* QQ: ok to remove? */
1652+ }
1653+ store_key_length_inc(key, char_length);
1654 }
1655- if (seg->type == HA_KEYTYPE_VARTEXT1)
1656- char_length+= seg->bit_start; /* Copy also length */
1657- memcpy(key,rec+seg->start,(size_t) char_length);
1658+ else
1659+ {
1660+ if (cs->mbmaxlen > 1)
1661+ {
1662+ char_length= my_charpos(cs, pos, pos + seg->length,
1663+ char_length / cs->mbmaxlen);
1664+ set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
1665+ }
1666+ if (seg->type == HA_KEYTYPE_VARTEXT1)
1667+ char_length+= seg->bit_start; /* Copy also length */
1668+ }
1669+
1670+ memcpy(key, pos, (size_t) char_length);
1671 key+= char_length;
1672 }
1673 }
1674@@ -702,8 +759,8 @@
1675 } while(0)
1676
1677
1678-uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key,
1679- const uchar *rec, uchar *recpos)
1680+uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key,
1681+ const uchar *rec, uchar *recpos, my_bool packed)
1682 {
1683 uchar *start_key= key;
1684 HA_KEYSEG *seg, *endseg;
1685@@ -772,6 +829,29 @@
1686 key+= char_length;
1687 continue;
1688 }
1689+ else if (seg->flag & HA_BLOB_PART)
1690+ {
1691+ uchar *pos= (uchar*) rec + seg->start;
1692+ uint tmp_length= hp_calc_blob_length(seg->bit_start, pos);
1693+ uint length= min(seg->length, tmp_length);
1694+ CHARSET_INFO *cs= seg->charset;
1695+ char_length= seg->length / cs->mbmaxlen;
1696+
1697+ /* check_one_rb_key() calls hp_rb_make_key() for already packed records */
1698+ if (!packed)
1699+ {
1700+ memcpy(&pos, pos + seg->bit_start, sizeof(char *));
1701+ }
1702+ else
1703+ {
1704+ pos+= seg->bit_start;
1705+ }
1706+ FIX_LENGTH(cs, pos, length, char_length);
1707+ store_key_length_inc(key, char_length);
1708+ memcpy(key, pos, (size_t) char_length);
1709+ key+= char_length;
1710+ continue;
1711+ }
1712
1713 char_length= seg->length;
1714 if (seg->charset->mbmaxlen > 1)
1715--- a/storage/heap/hp_info.c
1716+++ b/storage/heap/hp_info.c
1717@@ -47,9 +47,22 @@
1718 {
1719 DBUG_ENTER("heap_info");
1720 x->records = info->s->records;
1721- x->deleted = info->s->deleted;
1722- x->reclength = info->s->reclength;
1723- x->data_length = info->s->data_length;
1724+ x->deleted = info->s->recordspace.del_chunk_count;
1725+
1726+ if (info->s->recordspace.is_variable_size)
1727+ {
1728+ if (info->s->records)
1729+ x->reclength = (uint) (info->s->recordspace.total_data_length /
1730+ (ulonglong) info->s->records);
1731+ else
1732+ x->reclength = info->s->recordspace.chunk_length;
1733+ }
1734+ else
1735+ {
1736+ x->reclength = info->s->recordspace.chunk_dataspace_length;
1737+ }
1738+
1739+ x->data_length = info->s->recordspace.total_data_length;
1740 x->index_length = info->s->index_length;
1741 x->max_records = info->s->max_records;
1742 x->errkey = info->errkey;
1743--- a/storage/heap/hp_open.c
1744+++ b/storage/heap/hp_open.c
1745@@ -47,9 +47,9 @@
1746 #ifndef DBUG_OFF
1747 info->opt_flag= READ_CHECK_USED; /* Check when changing */
1748 #endif
1749- DBUG_PRINT("exit",("heap: 0x%lx reclength: %d records_in_block: %d",
1750- (long) info, share->reclength,
1751- share->block.records_in_block));
1752+ DBUG_PRINT("exit",("heap: 0x%lx chunk_length: %d records_in_block: %d",
1753+ (long) info, share->recordspace.chunk_length,
1754+ share->recordspace.block.records_in_block));
1755 DBUG_RETURN(info);
1756 }
1757
1758--- /dev/null
1759+++ b/storage/heap/hp_record.c
1760@@ -0,0 +1,498 @@
1761+/* Copyright (C) 2000-2002 MySQL AB
1762+ Copyright (C) 2008 eBay, Inc
1763+
1764+ This program is free software; you can redistribute it and/or modify
1765+ it under the terms of the GNU General Public License as published by
1766+ the Free Software Foundation; version 2 of the License.
1767+
1768+ This program is distributed in the hope that it will be useful,
1769+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1770+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1771+ GNU General Public License for more details.
1772+
1773+ You should have received a copy of the GNU General Public License
1774+ along with this program; if not, write to the Free Software
1775+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1776+
1777+/*
1778+ Implements various base record-related functions, such as encode and decode
1779+ into chunks.
1780+*/
1781+
1782+#include "heapdef.h"
1783+#include <mysql_com.h>
1784+
1785+/**
1786+ Calculate size of the record for the purpose of storing in chunks
1787+
1788+ Walk through the fields of the record and calculates the exact space
1789+ needed in chunks as well the the total chunk count
1790+
1791+ @param info the hosting table
1792+ @param record the record in standard unpacked format
1793+ @param[out] chunk_count the number of chunks needed for this record
1794+
1795+ @return The size of the required storage in bytes
1796+*/
1797+
1798+uint hp_get_encoded_data_length(HP_SHARE *info, const uchar *record,
1799+ uint *chunk_count)
1800+{
1801+ uint i, dst_offset;
1802+
1803+ dst_offset= info->fixed_data_length;
1804+
1805+ if (!info->recordspace.is_variable_size)
1806+ {
1807+ /* Nothing more to copy */
1808+ *chunk_count= 1;
1809+ return dst_offset;
1810+ }
1811+
1812+ for (i= info->fixed_column_count; i < info->column_count; i++)
1813+ {
1814+ uint src_offset, length;
1815+
1816+ HP_COLUMNDEF *column= info->column_defs + i;
1817+
1818+ if (column->null_bit)
1819+ {
1820+ if (record[column->null_pos] & column->null_bit)
1821+ {
1822+ /* Skip all NULL values */
1823+ continue;
1824+ }
1825+ }
1826+
1827+ src_offset= column->offset;
1828+ if (column->type == MYSQL_TYPE_VARCHAR)
1829+ {
1830+ uint pack_length;
1831+
1832+ /* >= 5.0.3 true VARCHAR */
1833+
1834+ pack_length= column->length_bytes;
1835+ length= pack_length + (pack_length == 1 ?
1836+ (uint) *(uchar *) (record + src_offset) :
1837+ uint2korr(record + src_offset));
1838+ }
1839+ else if (column->type == MYSQL_TYPE_BLOB)
1840+ {
1841+ uint pack_length= column->length_bytes;
1842+
1843+ length= pack_length + hp_calc_blob_length(pack_length,
1844+ record + src_offset);
1845+ }
1846+ else
1847+ {
1848+ length= column->length;
1849+ }
1850+
1851+ dst_offset+= length;
1852+ }
1853+
1854+ *chunk_count= get_chunk_count(&info->recordspace, dst_offset);
1855+
1856+ return dst_offset;
1857+}
1858+
1859+
1860+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
1861+static void dump_chunk(HP_SHARE *info, const uchar *curr_chunk)
1862+{
1863+ uint i;
1864+ fprintf(stdout, "Chunk dump at 0x%lx: ", (long) curr_chunk);
1865+ for (i= 0; i < info->recordspace.chunk_dataspace_length; i++)
1866+ {
1867+ uint b= *((uchar *)(curr_chunk + i));
1868+ if (b < 0x10)
1869+ {
1870+ fprintf(stdout, "0");
1871+ }
1872+ fprintf(stdout, "%lx ", (long) b);
1873+ }
1874+ fprintf(stdout, ". Next = 0x%lx, Status = %d\n",
1875+ (long) (*((uchar **) (curr_chunk + info->recordspace.offset_link))),
1876+ (uint) (*((uchar *) (curr_chunk + info->recordspace.offset_status))));
1877+}
1878+#endif
1879+
1880+/**
1881+ Stores data from packed field into the preallocated chunkset,
1882+ or performs data comparison
1883+
1884+ @param info the hosting table
1885+ @param data the field data in packed format
1886+ @param length the field data length
1887+ @param pos_ptr the target chunkset
1888+ @param off_ptr the pointer to the offset within the current chunkset
1889+ @param is_compare flag indicating whether we should compare data or store
1890+ it
1891+
1892+ @return Status of comparison
1893+ @retval non-zero if comparison found data differences
1894+ @retval zero otherwise
1895+*/
1896+
1897+static inline uint
1898+hp_process_field_data_to_chunkset(HP_SHARE *info, const uchar *data,
1899+ uint length, uchar **pos_ptr, uint *off_ptr,
1900+ uint is_compare)
1901+{
1902+ uint to_copy;
1903+ uchar *curr_chunk= *pos_ptr;
1904+ uint dst_offset= *off_ptr;
1905+ uint rc= 1;
1906+
1907+ while (length > 0)
1908+ {
1909+
1910+ to_copy= info->recordspace.chunk_dataspace_length - dst_offset;
1911+ if (to_copy == 0)
1912+ {
1913+ /* Jump to the next chunk */
1914+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
1915+ dump_chunk(info, curr_chunk);
1916+#endif
1917+ curr_chunk= *((uchar **) (curr_chunk + info->recordspace.offset_link));
1918+ dst_offset= 0;
1919+ continue;
1920+ }
1921+
1922+ to_copy= min(length, to_copy);
1923+
1924+ if (is_compare)
1925+ {
1926+ if (memcmp(curr_chunk + dst_offset, data, (size_t) to_copy))
1927+ {
1928+ goto end;
1929+ }
1930+ }
1931+ else
1932+ {
1933+ memcpy(curr_chunk + dst_offset, data, (size_t) to_copy);
1934+ }
1935+
1936+ data+= to_copy;
1937+ dst_offset+= to_copy;
1938+ length-= to_copy;
1939+ }
1940+
1941+ rc= 0;
1942+
1943+end:
1944+ *pos_ptr= curr_chunk;
1945+ *off_ptr= dst_offset;
1946+
1947+ return rc;
1948+}
1949+
1950+/**
1951+ Encodes or compares record
1952+
1953+ Copies data from original unpacked record into the preallocated chunkset,
1954+ or performs data comparison
1955+
1956+ @param info the hosting table
1957+ @param record the record in standard unpacked format
1958+ @param pos the target chunkset
1959+ @param is_compare flag indicating whether we should compare data or store
1960+ it
1961+
1962+ @return Status of comparison
1963+ @retval non-zero if comparison fond data differences
1964+ @retval zero otherwise
1965+*/
1966+
1967+uint hp_process_record_data_to_chunkset(HP_SHARE *info, const uchar *record,
1968+ uchar *pos, uint is_compare)
1969+{
1970+ uint i, dst_offset;
1971+ uchar *curr_chunk= pos;
1972+
1973+ if (is_compare)
1974+ {
1975+ if (memcmp(curr_chunk, record, (size_t) info->fixed_data_length))
1976+ {
1977+ return 1;
1978+ }
1979+ }
1980+ else
1981+ {
1982+ memcpy(curr_chunk, record, (size_t) info->fixed_data_length);
1983+ }
1984+
1985+ if (!info->recordspace.is_variable_size)
1986+ {
1987+ /* Nothing more to copy */
1988+ return 0;
1989+ }
1990+
1991+ dst_offset= info->fixed_data_length;
1992+
1993+ for (i= info->fixed_column_count; i < info->column_count; i++)
1994+ {
1995+ uint length;
1996+ const uchar *data;
1997+
1998+ HP_COLUMNDEF *column= info->column_defs + i;
1999+
2000+ if (column->null_bit)
2001+ {
2002+ if (record[column->null_pos] & column->null_bit)
2003+ {
2004+ /* Skip all NULL values */
2005+ continue;
2006+ }
2007+ }
2008+
2009+ data= record + column->offset;
2010+ if (column->type == MYSQL_TYPE_VARCHAR)
2011+ {
2012+ uint pack_length;
2013+
2014+ /* >= 5.0.3 true VARCHAR */
2015+
2016+ /* Make sure to copy length indicator and actuals string bytes */
2017+ pack_length= column->length_bytes;
2018+ length= pack_length + (pack_length == 1 ? (uint) *data : uint2korr(data));
2019+ }
2020+ else if (column->type == MYSQL_TYPE_BLOB)
2021+ {
2022+ uint pack_length;
2023+
2024+ pack_length= column->length_bytes;
2025+ /* Just want to store the length, so not interested in the return code */
2026+ (void) hp_process_field_data_to_chunkset(info, data, pack_length,
2027+ &curr_chunk, &dst_offset, 0);
2028+ length= hp_calc_blob_length(pack_length, data);
2029+ memcpy(&data, data + pack_length, sizeof(char *));
2030+ }
2031+ else
2032+ {
2033+ length= column->length;
2034+ }
2035+
2036+ if (hp_process_field_data_to_chunkset(info, data, length, &curr_chunk,
2037+ &dst_offset, is_compare))
2038+ {
2039+ return 1;
2040+ }
2041+ }
2042+
2043+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
2044+ dump_chunk(info, curr_chunk);
2045+#endif
2046+
2047+ return 0;
2048+}
2049+
2050+
2051+/**
2052+ Stores record in the heap table chunks
2053+
2054+ Copies data from original unpacked record into the preallocated chunkset
2055+
2056+ @param info the hosting table
2057+ @param record the record in standard unpacked format
2058+ @param pos the target chunkset
2059+*/
2060+
2061+void hp_copy_record_data_to_chunkset(HP_SHARE *info, const uchar *record,
2062+ uchar *pos)
2063+{
2064+ DBUG_ENTER("hp_copy_record_data_to_chunks");
2065+
2066+ hp_process_record_data_to_chunkset(info, record, pos, 0);
2067+
2068+ DBUG_VOID_RETURN;
2069+}
2070+
2071+
2072+/*
2073+ Macro to switch curr_chunk to the next chunk in the chunkset and reset
2074+ src_offset.
2075+*/
2076+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
2077+#define SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset) \
2078+ { \
2079+ curr_chunk= *((uchar**) (curr_chunk + share->recordspace.offset_link)); \
2080+ src_offset= 0; \
2081+ dump_chunk(share, curr_chunk); \
2082+ }
2083+#else
2084+#define SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset) \
2085+ { \
2086+ curr_chunk= *((uchar**) (curr_chunk + share->recordspace.offset_link)); \
2087+ src_offset= 0; \
2088+ }
2089+#endif
2090+
2091+/**
2092+ Copies record data from storage to unpacked record format
2093+
2094+ Copies data from chunkset into its original unpacked record
2095+
2096+ @param info the hosting table
2097+ @param[out] record the target record in standard unpacked format
2098+ @param pos the source chunkset
2099+
2100+ @return Status of conversion
2101+ @retval 0 success
2102+ @retval 1 out of memory
2103+*/
2104+
2105+int hp_extract_record(HP_INFO *info, uchar *record, const uchar *pos)
2106+{
2107+ uint i, src_offset;
2108+ const uchar *curr_chunk= pos;
2109+ HP_SHARE *share= info->s;
2110+ uint *rec_offsets= NULL;
2111+ uint *buf_offsets= NULL;
2112+ uint nblobs= 0;
2113+ uint init_offset= share->blobs * sizeof(uint) * 2;
2114+
2115+ DBUG_ENTER("hp_extract_record");
2116+
2117+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
2118+ if (share->recordspace.is_variable_size)
2119+ {
2120+ dump_chunk(share, curr_chunk);
2121+ }
2122+#endif
2123+
2124+ memcpy(record, curr_chunk, (size_t) share->fixed_data_length);
2125+
2126+ if (!share->recordspace.is_variable_size)
2127+ {
2128+ /* Nothing more to copy */
2129+ DBUG_RETURN(0);
2130+ }
2131+
2132+ /* Reserve space for rec_offsets and buf_offsets.*/
2133+ info->blob_offset= init_offset;
2134+ src_offset= share->fixed_data_length;
2135+
2136+ for (i= share->fixed_column_count; i < share->column_count; i++)
2137+ {
2138+ uint length, is_null= 0;
2139+ uchar *to;
2140+
2141+ HP_COLUMNDEF *column= share->column_defs + i;
2142+
2143+ if (column->null_bit)
2144+ {
2145+ if (record[column->null_pos] & column->null_bit)
2146+ {
2147+ is_null= 1;
2148+ }
2149+ }
2150+
2151+ if (is_null)
2152+ {
2153+ /* TODO: is memset really needed? */
2154+ memset(record + column->offset, 0, column->length);
2155+ continue;
2156+ }
2157+
2158+ to= record + column->offset;
2159+ if (column->type == MYSQL_TYPE_VARCHAR || column->type == MYSQL_TYPE_BLOB)
2160+ {
2161+ uint pack_length, i;
2162+ uchar *tmp= to;
2163+
2164+ pack_length= column->length_bytes;
2165+
2166+ for (i= 0; i < pack_length; i++)
2167+ {
2168+ if (src_offset == share->recordspace.chunk_dataspace_length)
2169+ {
2170+ SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset);
2171+ }
2172+ *to++= curr_chunk[src_offset++];
2173+ }
2174+ /*
2175+ We copy byte-by-byte and then use hp_calc_blob_length to combine bytes
2176+ in the right order.
2177+ */
2178+ length= hp_calc_blob_length(pack_length, tmp);
2179+
2180+ if (column->type == MYSQL_TYPE_BLOB && length == 0)
2181+ {
2182+ /*
2183+ Store a zero pointer for zero-length BLOBs because the server
2184+ relies on that (see Field_blob::val_*().
2185+ */
2186+ *(uchar **) to= 0;
2187+ }
2188+ else if (column->type == MYSQL_TYPE_BLOB && length > 0)
2189+ {
2190+ uint newsize= info->blob_offset + length;
2191+
2192+ DBUG_ASSERT(share->blobs > 0);
2193+ /*
2194+ Make sure we have enough space in blob_buffer and store the pointer
2195+ to this blob in record.
2196+ */
2197+ if (info->blob_size < newsize)
2198+ {
2199+ uchar *ptr;
2200+ ptr= my_realloc(info->blob_buffer, newsize, MYF(MY_ALLOW_ZERO_PTR));
2201+ if (ptr == NULL)
2202+ {
2203+ DBUG_RETURN(1);
2204+ }
2205+
2206+ if (info->blob_buffer == NULL)
2207+ {
2208+ memset(ptr, 0, init_offset);
2209+ }
2210+ info->blob_buffer= ptr;
2211+ info->blob_size= newsize;
2212+ }
2213+
2214+ rec_offsets= (uint *) info->blob_buffer;
2215+ buf_offsets= rec_offsets + share->blobs;
2216+
2217+ rec_offsets[nblobs]= (uint) (to - record);
2218+ buf_offsets[nblobs]= info->blob_offset;
2219+ nblobs++;
2220+
2221+ /* Change 'to' so blob data is copied into blob_buffer */
2222+ to= info->blob_buffer + info->blob_offset;
2223+ info->blob_offset= newsize;
2224+ }
2225+ }
2226+ else
2227+ {
2228+ length= column->length;
2229+ }
2230+
2231+ while (length > 0)
2232+ {
2233+ uint to_copy;
2234+
2235+ to_copy= share->recordspace.chunk_dataspace_length - src_offset;
2236+ if (to_copy == 0)
2237+ {
2238+ SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset);
2239+ to_copy= share->recordspace.chunk_dataspace_length;
2240+ }
2241+
2242+ to_copy= min(length, to_copy);
2243+
2244+ memcpy(to, curr_chunk + src_offset, (size_t) to_copy);
2245+ src_offset+= to_copy;
2246+ to+= to_copy;
2247+ length-= to_copy;
2248+ }
2249+ }
2250+
2251+ /* Store pointers to blob data in record */
2252+ for (i= 0; i < nblobs; i++)
2253+ {
2254+ *(uchar **) (record + rec_offsets[i]) = info->blob_buffer + buf_offsets[i];
2255+ }
2256+
2257+ DBUG_RETURN(0);
2258+}
2259--- a/storage/heap/hp_rfirst.c
2260+++ b/storage/heap/hp_rfirst.c
2261@@ -34,7 +34,10 @@
2262 memcpy(&pos, pos + (*keyinfo->get_key_length)(keyinfo, pos),
2263 sizeof(uchar*));
2264 info->current_ptr = pos;
2265- memcpy(record, pos, (size_t)share->reclength);
2266+ if (hp_extract_record(info, record, pos))
2267+ {
2268+ DBUG_RETURN(my_errno);
2269+ }
2270 /*
2271 If we're performing index_first on a table that was taken from
2272 table cache, info->lastkey_len is initialized to previous query.
2273--- a/storage/heap/hp_rkey.c
2274+++ b/storage/heap/hp_rkey.c
2275@@ -67,7 +67,10 @@
2276 if (!(keyinfo->flag & HA_NOSAME))
2277 memcpy(info->lastkey, key, (size_t) keyinfo->length);
2278 }
2279- memcpy(record, pos, (size_t) share->reclength);
2280+ if (hp_extract_record(info, record, pos))
2281+ {
2282+ DBUG_RETURN(my_errno);
2283+ }
2284 info->update= HA_STATE_AKTIV;
2285 DBUG_RETURN(0);
2286 }
2287--- a/storage/heap/hp_rlast.c
2288+++ b/storage/heap/hp_rlast.c
2289@@ -35,7 +35,10 @@
2290 memcpy(&pos, pos + (*keyinfo->get_key_length)(keyinfo, pos),
2291 sizeof(uchar*));
2292 info->current_ptr = pos;
2293- memcpy(record, pos, (size_t)share->reclength);
2294+ if (hp_extract_record(info, record, pos))
2295+ {
2296+ DBUG_RETURN(my_errno);
2297+ }
2298 info->update = HA_STATE_AKTIV;
2299 }
2300 else
2301--- a/storage/heap/hp_rnext.c
2302+++ b/storage/heap/hp_rnext.c
2303@@ -109,7 +109,10 @@
2304 my_errno=HA_ERR_END_OF_FILE;
2305 DBUG_RETURN(my_errno);
2306 }
2307- memcpy(record,pos,(size_t) share->reclength);
2308+ if (hp_extract_record(info, record, pos))
2309+ {
2310+ DBUG_RETURN(my_errno);
2311+ }
2312 info->update=HA_STATE_AKTIV | HA_STATE_NEXT_FOUND;
2313 DBUG_RETURN(0);
2314 }
2315--- a/storage/heap/hp_rprev.c
2316+++ b/storage/heap/hp_rprev.c
2317@@ -77,7 +77,10 @@
2318 my_errno=HA_ERR_END_OF_FILE;
2319 DBUG_RETURN(my_errno);
2320 }
2321- memcpy(record,pos,(size_t) share->reclength);
2322+ if (hp_extract_record(info, record, pos))
2323+ {
2324+ DBUG_RETURN(my_errno);
2325+ }
2326 info->update=HA_STATE_AKTIV | HA_STATE_PREV_FOUND;
2327 DBUG_RETURN(0);
2328 }
2329--- a/storage/heap/hp_rrnd.c
2330+++ b/storage/heap/hp_rrnd.c
2331@@ -36,13 +36,18 @@
2332 info->update= 0;
2333 DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
2334 }
2335- if (!info->current_ptr[share->reclength])
2336+ if (get_chunk_status(&share->recordspace, info->current_ptr) !=
2337+ CHUNK_STATUS_ACTIVE)
2338 {
2339+ /* treat deleted and linked chunks as deleted */
2340 info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND;
2341 DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
2342 }
2343 info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
2344- memcpy(record,info->current_ptr,(size_t) share->reclength);
2345+ if (hp_extract_record(info, record, info->current_ptr))
2346+ {
2347+ DBUG_RETURN(my_errno);
2348+ }
2349 DBUG_PRINT("exit", ("found record at 0x%lx", (long) info->current_ptr));
2350 info->current_hash_ptr=0; /* Can't use rnext */
2351 DBUG_RETURN(0);
2352@@ -70,17 +75,17 @@
2353 {
2354 pos= ++info->current_record;
2355 if (pos % share->block.records_in_block && /* Quick next record */
2356- pos < share->records+share->deleted &&
2357- (info->update & HA_STATE_PREV_FOUND))
2358+ pos < share->used_chunk_count + share->deleted_chunk_count &&
2359+ (info->update & HA_STATE_PREV_FOUND))
2360 {
2361- info->current_ptr+=share->block.recbuffer;
2362+ info->current_ptr+= share->block.recbufferlen;
2363 goto end;
2364 }
2365 }
2366 else
2367 info->current_record=pos;
2368
2369- if (pos >= share->records+share->deleted)
2370+ if (pos >= share->used_chunk_count + share->deleted_chunk_count)
2371 {
2372 info->update= 0;
2373 DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
2374@@ -90,13 +95,17 @@
2375 hp_find_record(info, pos);
2376
2377 end:
2378- if (!info->current_ptr[share->reclength])
2379+ if (GET_CHUNK_STATUS(info, info->current_ptr) != CHUNK_STATUS_ACTIVE)
2380 {
2381+ /* treat deleted and linked chunks as deleted */
2382 info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND;
2383 DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
2384 }
2385 info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
2386- memcpy(record,info->current_ptr,(size_t) share->reclength);
2387+ if (hp_extract_record(info, record, info->current_ptr))
2388+ {
2389+ DBUG_RETURN(my_errno);
2390+ }
2391 DBUG_PRINT("exit",("found record at 0x%lx",info->current_ptr));
2392 info->current_hash_ptr=0; /* Can't use rnext */
2393 DBUG_RETURN(0);
2394--- a/storage/heap/hp_rsame.c
2395+++ b/storage/heap/hp_rsame.c
2396@@ -31,7 +31,8 @@
2397 DBUG_ENTER("heap_rsame");
2398
2399 test_active(info);
2400- if (info->current_ptr[share->reclength])
2401+ if (get_chunk_status(&share->recordspace, info->current_ptr) ==
2402+ CHUNK_STATUS_ACTIVE)
2403 {
2404 if (inx < -1 || inx >= (int) share->keys)
2405 {
2406@@ -47,9 +48,15 @@
2407 DBUG_RETURN(my_errno);
2408 }
2409 }
2410- memcpy(record,info->current_ptr,(size_t) share->reclength);
2411+ if (hp_extract_record(info, record, info->current_ptr))
2412+ {
2413+ DBUG_RETURN(my_errno);
2414+ }
2415 DBUG_RETURN(0);
2416 }
2417+
2418+ /* treat deleted and linked chunks as deleted */
2419+
2420 info->update=0;
2421
2422 DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
2423--- a/storage/heap/hp_scan.c
2424+++ b/storage/heap/hp_scan.c
2425@@ -30,7 +30,6 @@
2426 info->lastinx= -1;
2427 info->current_record= (ulong) ~0L; /* No current record */
2428 info->update=0;
2429- info->next_block=0;
2430 DBUG_RETURN(0);
2431 }
2432
2433@@ -41,32 +40,26 @@
2434 DBUG_ENTER("heap_scan");
2435
2436 pos= ++info->current_record;
2437- if (pos < info->next_block)
2438+ if (pos >= share->recordspace.chunk_count)
2439 {
2440- info->current_ptr+=share->block.recbuffer;
2441+ info->update= 0;
2442+ DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
2443 }
2444- else
2445- {
2446- info->next_block+=share->block.records_in_block;
2447- if (info->next_block >= share->records+share->deleted)
2448- {
2449- info->next_block= share->records+share->deleted;
2450- if (pos >= info->next_block)
2451- {
2452- info->update= 0;
2453- DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
2454- }
2455- }
2456- hp_find_record(info, pos);
2457- }
2458- if (!info->current_ptr[share->reclength])
2459+
2460+ hp_find_record(info, pos);
2461+
2462+ if (get_chunk_status(&share->recordspace, info->current_ptr) !=
2463+ CHUNK_STATUS_ACTIVE)
2464 {
2465- DBUG_PRINT("warning",("Found deleted record"));
2466+ DBUG_PRINT("warning",("Found deleted record or secondary chunk"));
2467 info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND;
2468 DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
2469 }
2470 info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
2471- memcpy(record,info->current_ptr,(size_t) share->reclength);
2472+ if (hp_extract_record(info, record, info->current_ptr))
2473+ {
2474+ DBUG_RETURN(my_errno);
2475+ }
2476 info->current_hash_ptr=0; /* Can't use read_next */
2477 DBUG_RETURN(0);
2478 } /* heap_scan */
2479--- a/storage/heap/hp_test1.c
2480+++ b/storage/heap/hp_test1.c
2481@@ -22,6 +22,7 @@
2482 #include <my_global.h>
2483 #include <my_sys.h>
2484 #include <m_string.h>
2485+#include <mysql_com.h>
2486 #include "heap.h"
2487
2488 static int get_options(int argc, char *argv[]);
2489@@ -35,6 +36,7 @@
2490 uchar record[128],key[32];
2491 const char *filename;
2492 HP_KEYDEF keyinfo[10];
2493+ HP_COLUMNDEF columndef[2];
2494 HA_KEYSEG keyseg[4];
2495 HP_CREATE_INFO hp_create_info;
2496 HP_SHARE *tmp_share;
2497@@ -51,6 +53,10 @@
2498 hp_create_info.reclength= 30;
2499 hp_create_info.max_records= (ulong) flag*100000L;
2500 hp_create_info.min_records= 10UL;
2501+ hp_create_info.columns= 2;
2502+ hp_create_info.columndef= columndef;
2503+ hp_create_info.fixed_key_fieldnr= 30;
2504+ hp_create_info.fixed_data_size= sizeof(char*) * 2;
2505
2506 keyinfo[0].keysegs=1;
2507 keyinfo[0].seg=keyseg;
2508@@ -62,11 +68,20 @@
2509 keyinfo[0].seg[0].null_bit= 0;
2510 keyinfo[0].flag = HA_NOSAME;
2511
2512+ memset(columndef, 0, 2 * sizeof(HP_COLUMNDEF));
2513+ columndef[0].type= MYSQL_TYPE_STRING;
2514+ columndef[0].offset= 1;
2515+ columndef[0].length= 6;
2516+ columndef[1].type= MYSQL_TYPE_STRING;
2517+ columndef[1].offset= 7;
2518+ columndef[1].length= 23;
2519+
2520 deleted=0;
2521 bzero((uchar*) flags,sizeof(flags));
2522
2523 printf("- Creating heap-file\n");
2524- if (heap_create(filename, &hp_create_info, &tmp_share, &unused) ||
2525+ if (heap_create(filename, &hp_create_info,
2526+ &tmp_share, &unused) ||
2527 !(file= heap_open(filename, 2)))
2528 goto err;
2529 printf("- Writing records:s\n");
2530--- a/storage/heap/hp_test2.c
2531+++ b/storage/heap/hp_test2.c
2532@@ -18,6 +18,7 @@
2533
2534 #include "heapdef.h" /* Because of hp_find_block */
2535 #include <signal.h>
2536+#include <mysql_com.h>
2537
2538 #define MAX_RECORDS 100000
2539 #define MAX_KEYS 4
2540@@ -44,6 +45,7 @@
2541 register uint i,j;
2542 uint ant,n1,n2,n3;
2543 uint write_count,update,opt_delete,check2,dupp_keys,found_key;
2544+ uint mem_per_keys;
2545 int error;
2546 ulong pos;
2547 unsigned long key_check;
2548@@ -53,6 +55,7 @@
2549 HP_SHARE *tmp_share;
2550 HP_KEYDEF keyinfo[MAX_KEYS];
2551 HA_KEYSEG keyseg[MAX_KEYS*5];
2552+ HP_COLUMNDEF columndef[4];
2553 HEAP_PTR UNINIT_VAR(position);
2554 HP_CREATE_INFO hp_create_info;
2555 CHARSET_INFO *cs= &my_charset_latin1;
2556@@ -65,12 +68,16 @@
2557 get_options(argc,argv);
2558
2559 bzero(&hp_create_info, sizeof(hp_create_info));
2560- hp_create_info.max_table_size= 1024L*1024L;
2561+ hp_create_info.max_table_size= 1024L*1024L*1024L;
2562 hp_create_info.keys= keys;
2563 hp_create_info.keydef= keyinfo;
2564 hp_create_info.reclength= reclength;
2565 hp_create_info.max_records= (ulong) flag*100000L;
2566 hp_create_info.min_records= (ulong) recant/2;
2567+ hp_create_info.columns= 4;
2568+ hp_create_info.columndef= columndef;
2569+ hp_create_info.fixed_key_fieldnr= 4;
2570+ hp_create_info.fixed_data_size= 39;
2571
2572 write_count=update=opt_delete=0;
2573 key_check=0;
2574@@ -118,11 +125,30 @@
2575 keyinfo[3].seg[0].null_pos=38;
2576 keyinfo[3].seg[0].charset=cs;
2577
2578+ memset(columndef, 0, 4 * sizeof(HP_COLUMNDEF));
2579+ columndef[0].type= MYSQL_TYPE_STRING;
2580+ columndef[0].offset= 0;
2581+ columndef[0].length= 6;
2582+ columndef[1].type= MYSQL_TYPE_STRING;
2583+ columndef[1].offset= 7;
2584+ columndef[1].length= 6;
2585+ columndef[2].type= MYSQL_TYPE_STRING;
2586+ columndef[2].offset= 12;
2587+ columndef[2].length= 8;
2588+ columndef[3].type= MYSQL_TYPE_TINY;
2589+ columndef[3].offset= 37;
2590+ columndef[3].length= 1;
2591+ columndef[3].null_bit= 1;
2592+ columndef[3].null_pos= 38;
2593+
2594+ mem_per_keys= (sizeof(char*) * 2) * 4;
2595+
2596 bzero((char*) key1,sizeof(key1));
2597 bzero((char*) key3,sizeof(key3));
2598
2599 printf("- Creating heap-file\n");
2600- if (heap_create(filename, &hp_create_info, &tmp_share, &unused) ||
2601+ if (heap_create(filename, &hp_create_info,
2602+ &tmp_share, &unused) ||
2603 !(file= heap_open(filename, 2)))
2604 goto err;
2605 signal(SIGINT,endprog);
2606--- a/storage/heap/hp_write.c
2607+++ b/storage/heap/hp_write.c
2608@@ -26,7 +26,6 @@
2609 #define HIGHFIND 4
2610 #define HIGHUSED 8
2611
2612-static uchar *next_free_record_pos(HP_SHARE *info);
2613 static HASH_INFO *hp_find_free_hash(HP_SHARE *info, HP_BLOCK *block,
2614 ulong records);
2615
2616@@ -35,6 +34,8 @@
2617 HP_KEYDEF *keydef, *end;
2618 uchar *pos;
2619 HP_SHARE *share=info->s;
2620+ uint rec_length, chunk_count;
2621+
2622 DBUG_ENTER("heap_write");
2623 #ifndef DBUG_OFF
2624 if (info->mode & O_RDONLY)
2625@@ -42,7 +43,18 @@
2626 DBUG_RETURN(my_errno=EACCES);
2627 }
2628 #endif
2629- if (!(pos=next_free_record_pos(share)))
2630+
2631+ if ((share->records >= share->max_records && share->max_records) ||
2632+ (share->recordspace.total_data_length + share->index_length >=
2633+ share->max_table_size))
2634+ {
2635+ my_errno= HA_ERR_RECORD_FILE_FULL;
2636+ DBUG_RETURN(my_errno);
2637+ }
2638+
2639+ rec_length= hp_get_encoded_data_length(share, record, &chunk_count);
2640+
2641+ if (!(pos= hp_allocate_chunkset(&share->recordspace, chunk_count)))
2642 DBUG_RETURN(my_errno);
2643 share->changed=1;
2644
2645@@ -53,8 +65,8 @@
2646 goto err;
2647 }
2648
2649- memcpy(pos,record,(size_t) share->reclength);
2650- pos[share->reclength]=1; /* Mark record as not deleted */
2651+ hp_copy_record_data_to_chunkset(share, record, pos);
2652+
2653 if (++share->records == share->blength)
2654 share->blength+= share->blength;
2655 info->current_ptr=pos;
2656@@ -88,10 +100,7 @@
2657 keydef--;
2658 }
2659
2660- share->deleted++;
2661- *((uchar**) pos)=share->del_link;
2662- share->del_link=pos;
2663- pos[share->reclength]=0; /* Record deleted */
2664+ hp_free_chunks(&share->recordspace, pos);
2665
2666 DBUG_RETURN(my_errno);
2667 } /* heap_write */
2668@@ -107,7 +116,8 @@
2669 uint old_allocated;
2670
2671 custom_arg.keyseg= keyinfo->seg;
2672- custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
2673+ custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos,
2674+ FALSE);
2675 if (keyinfo->flag & HA_NOSAME)
2676 {
2677 custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE;
2678@@ -129,42 +139,6 @@
2679 return 0;
2680 }
2681
2682- /* Find where to place new record */
2683-
2684-static uchar *next_free_record_pos(HP_SHARE *info)
2685-{
2686- int block_pos;
2687- uchar *pos;
2688- size_t length;
2689- DBUG_ENTER("next_free_record_pos");
2690-
2691- if (info->del_link)
2692- {
2693- pos=info->del_link;
2694- info->del_link= *((uchar**) pos);
2695- info->deleted--;
2696- DBUG_PRINT("exit",("Used old position: 0x%lx",(long) pos));
2697- DBUG_RETURN(pos);
2698- }
2699- if (!(block_pos=(info->records % info->block.records_in_block)))
2700- {
2701- if ((info->records > info->max_records && info->max_records) ||
2702- (info->data_length + info->index_length >= info->max_table_size))
2703- {
2704- my_errno=HA_ERR_RECORD_FILE_FULL;
2705- DBUG_RETURN(NULL);
2706- }
2707- if (hp_get_new_block(&info->block,&length))
2708- DBUG_RETURN(NULL);
2709- info->data_length+=length;
2710- }
2711- DBUG_PRINT("exit",("Used new position: 0x%lx",
2712- (long) ((uchar*) info->block.level_info[0].last_blocks+
2713- block_pos * info->block.recbuffer)));
2714- DBUG_RETURN((uchar*) info->block.level_info[0].last_blocks+
2715- block_pos*info->block.recbuffer);
2716-}
2717-
2718
2719 /*
2720 Write a hash-key to the hash-index
2721--- a/storage/heap/hp_update.c
2722+++ b/storage/heap/hp_update.c
2723@@ -17,43 +17,66 @@
2724
2725 #include "heapdef.h"
2726
2727-int heap_update(HP_INFO *info, const uchar *old, const uchar *heap_new)
2728+int heap_update(HP_INFO *info, const uchar *old_record, const uchar *new_record)
2729 {
2730 HP_KEYDEF *keydef, *end, *p_lastinx;
2731 uchar *pos;
2732 my_bool auto_key_changed= 0;
2733 HP_SHARE *share= info->s;
2734+ uint old_length, new_length;
2735+ uint old_chunk_count, new_chunk_count;
2736+
2737 DBUG_ENTER("heap_update");
2738
2739 test_active(info);
2740 pos=info->current_ptr;
2741
2742- if (info->opt_flag & READ_CHECK_USED && hp_rectest(info,old))
2743+ if (info->opt_flag & READ_CHECK_USED && hp_rectest(info, old_record))
2744 DBUG_RETURN(my_errno); /* Record changed */
2745+
2746+ old_length = hp_get_encoded_data_length(share, old_record, &old_chunk_count);
2747+ new_length = hp_get_encoded_data_length(share, new_record, &new_chunk_count);
2748+
2749+ if (new_chunk_count > old_chunk_count)
2750+ {
2751+ /* extend the old chunkset size as necessary, but do not shrink yet */
2752+ if (hp_reallocate_chunkset(&share->recordspace, new_chunk_count, pos))
2753+ {
2754+ DBUG_RETURN(my_errno); /* Out of memory or table space */
2755+ }
2756+ }
2757+
2758 if (--(share->records) < share->blength >> 1) share->blength>>= 1;
2759 share->changed=1;
2760
2761 p_lastinx= share->keydef + info->lastinx;
2762 for (keydef= share->keydef, end= keydef + share->keys; keydef < end; keydef++)
2763 {
2764- if (hp_rec_key_cmp(keydef, old, heap_new, 0))
2765+ if (hp_rec_key_cmp(keydef, old_record, new_record, 0))
2766 {
2767- if ((*keydef->delete_key)(info, keydef, old, pos, keydef == p_lastinx) ||
2768- (*keydef->write_key)(info, keydef, heap_new, pos))
2769+ if ((*keydef->delete_key)(info, keydef, old_record, pos,
2770+ keydef == p_lastinx) ||
2771+ (*keydef->write_key)(info, keydef, new_record, pos))
2772 goto err;
2773 if (share->auto_key == (uint) (keydef - share->keydef + 1))
2774 auto_key_changed= 1;
2775 }
2776 }
2777
2778- memcpy(pos,heap_new,(size_t) share->reclength);
2779+ hp_copy_record_data_to_chunkset(share, new_record, pos);
2780 if (++(share->records) == share->blength) share->blength+= share->blength;
2781
2782+ if (new_chunk_count < old_chunk_count)
2783+ {
2784+ /* Shrink the chunkset to its new size */
2785+ hp_reallocate_chunkset(&share->recordspace, new_chunk_count, pos);
2786+ }
2787+
2788 #if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
2789 DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
2790 #endif
2791 if (auto_key_changed)
2792- heap_update_auto_increment(info, heap_new);
2793+ heap_update_auto_increment(info, new_record);
2794 DBUG_RETURN(0);
2795
2796 err:
2797@@ -63,7 +86,7 @@
2798 if (keydef->algorithm == HA_KEY_ALG_BTREE)
2799 {
2800 /* we don't need to delete non-inserted key from rb-tree */
2801- if ((*keydef->write_key)(info, keydef, old, pos))
2802+ if ((*keydef->write_key)(info, keydef, old_record, pos))
2803 {
2804 if (++(share->records) == share->blength)
2805 share->blength+= share->blength;
2806@@ -73,10 +96,10 @@
2807 }
2808 while (keydef >= share->keydef)
2809 {
2810- if (hp_rec_key_cmp(keydef, old, heap_new, 0))
2811+ if (hp_rec_key_cmp(keydef, old_record, new_record, 0))
2812 {
2813- if ((*keydef->delete_key)(info, keydef, heap_new, pos, 0) ||
2814- (*keydef->write_key)(info, keydef, old, pos))
2815+ if ((*keydef->delete_key)(info, keydef, new_record, pos, 0) ||
2816+ (*keydef->write_key)(info, keydef, old_record, pos))
2817 break;
2818 }
2819 keydef--;
2820@@ -84,5 +107,12 @@
2821 }
2822 if (++(share->records) == share->blength)
2823 share->blength+= share->blength;
2824+
2825+ if (new_chunk_count > old_chunk_count)
2826+ {
2827+ /* Shrink the chunkset to its original size */
2828+ hp_reallocate_chunkset(&share->recordspace, old_chunk_count, pos);
2829+ }
2830+
2831 DBUG_RETURN(my_errno);
2832 } /* heap_update */
48b678b4
AM
2833--- /dev/null
2834+++ b/mysql-test/r/percona_heap_blob.result
2835@@ -0,0 +1,952 @@
2836+SET @old_default_storage_engine=@@default_storage_engine;
2837+SET default_storage_engine=MEMORY;
2838+drop table if exists t1,t2,t3,t4,t5,t6,t7;
2839+CREATE TABLE t1 (a blob, b text, c blob(250), d text(70000), e text(70000000));
2840+show columns from t1;
2841+Field Type Null Key Default Extra
2842+a blob YES NULL
2843+b text YES NULL
2844+c tinyblob YES NULL
2845+d mediumtext YES NULL
2846+e longtext YES NULL
2847+CREATE TABLE t2 (a char(255), b varbinary(70000), c varchar(70000000));
2848+Warnings:
2849+Note 1246 Converting column 'b' from VARBINARY to BLOB
2850+Note 1246 Converting column 'c' from VARCHAR to TEXT
2851+CREATE TABLE t4 (c varchar(65530) character set utf8 not null);
2852+Warnings:
2853+Note 1246 Converting column 'c' from VARCHAR to TEXT
2854+show columns from t2;
2855+Field Type Null Key Default Extra
2856+a char(255) YES NULL
2857+b mediumblob YES NULL
2858+c longtext YES NULL
2859+create table t3 (a long, b long byte);
2860+show create TABLE t3;
2861+Table Create Table
2862+t3 CREATE TABLE `t3` (
2863+ `a` mediumtext,
2864+ `b` mediumblob
2865+) ENGINE=MEMORY DEFAULT CHARSET=latin1
2866+show create TABLE t4;
2867+Table Create Table
2868+t4 CREATE TABLE `t4` (
2869+ `c` mediumtext CHARACTER SET utf8 NOT NULL
2870+) ENGINE=MEMORY DEFAULT CHARSET=latin1
2871+drop table t1,t2,t3,t4;
2872+CREATE TABLE t1 (a char(257) default "hello");
2873+ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead
2874+CREATE TABLE t2 (a char(256));
2875+ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead
2876+CREATE TABLE t1 (a varchar(70000) default "hello");
2877+ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead
2878+CREATE TABLE t2 (a blob default "hello");
2879+ERROR 42000: BLOB/TEXT column 'a' can't have a default value
2880+drop table if exists t1,t2;
2881+create table t1 (nr int(5) not null auto_increment,b blob,str char(10), primary key (nr));
2882+insert into t1 values (null,"a","A");
2883+insert into t1 values (null,"bbb","BBB");
2884+insert into t1 values (null,"ccc","CCC");
2885+select last_insert_id();
2886+last_insert_id()
2887+3
2888+select * from t1,t1 as t2;
2889+nr b str nr b str
2890+1 a A 1 a A
2891+2 bbb BBB 1 a A
2892+3 ccc CCC 1 a A
2893+1 a A 2 bbb BBB
2894+2 bbb BBB 2 bbb BBB
2895+3 ccc CCC 2 bbb BBB
2896+1 a A 3 ccc CCC
2897+2 bbb BBB 3 ccc CCC
2898+3 ccc CCC 3 ccc CCC
2899+drop table t1;
2900+create table t1 (a text);
2901+insert into t1 values ('where');
2902+update t1 set a='Where';
2903+select * from t1;
2904+a
2905+Where
2906+drop table t1;
2907+create table t1 (t text,c char(10),b blob, d varbinary(10));
2908+insert into t1 values (NULL,NULL,NULL,NULL);
2909+insert into t1 values ("","","","");
2910+insert into t1 values ("hello","hello","hello","hello");
2911+insert into t1 values ("HELLO","HELLO","HELLO","HELLO");
2912+insert into t1 values ("HELLO MY","HELLO MY","HELLO MY","HELLO MY");
2913+insert into t1 values ("a","a","a","a");
2914+insert into t1 values (1,1,1,1);
2915+insert into t1 values (NULL,NULL,NULL,NULL);
2916+update t1 set c="",b=null where c="1";
2917+lock tables t1 READ;
2918+show full fields from t1;
2919+Field Type Collation Null Key Default Extra Privileges Comment
2920+t text latin1_swedish_ci YES NULL #
2921+c char(10) latin1_swedish_ci YES NULL #
2922+b blob NULL YES NULL #
2923+d varbinary(10) NULL YES NULL #
2924+lock tables t1 WRITE;
2925+show full fields from t1;
2926+Field Type Collation Null Key Default Extra Privileges Comment
2927+t text latin1_swedish_ci YES NULL #
2928+c char(10) latin1_swedish_ci YES NULL #
2929+b blob NULL YES NULL #
2930+d varbinary(10) NULL YES NULL #
2931+unlock tables;
2932+select t from t1 where t like "hello";
2933+t
2934+hello
2935+HELLO
2936+select c from t1 where c like "hello";
2937+c
2938+hello
2939+HELLO
2940+select b from t1 where b like "hello";
2941+b
2942+hello
2943+select d from t1 where d like "hello";
2944+d
2945+hello
2946+select c from t1 having c like "hello";
2947+c
2948+hello
2949+HELLO
2950+select d from t1 having d like "hello";
2951+d
2952+hello
2953+select t from t1 where t like "%HELLO%";
2954+t
2955+hello
2956+HELLO
2957+HELLO MY
2958+select c from t1 where c like "%HELLO%";
2959+c
2960+hello
2961+HELLO
2962+HELLO MY
2963+select b from t1 where b like "%HELLO%";
2964+b
2965+HELLO
2966+HELLO MY
2967+select d from t1 where d like "%HELLO%";
2968+d
2969+HELLO
2970+HELLO MY
2971+select c from t1 having c like "%HELLO%";
2972+c
2973+hello
2974+HELLO
2975+HELLO MY
2976+select d from t1 having d like "%HELLO%";
2977+d
2978+HELLO
2979+HELLO MY
2980+select d from t1 having d like "%HE%LLO%";
2981+d
2982+HELLO
2983+HELLO MY
2984+select t from t1 order by t;
2985+t
2986+NULL
2987+NULL
2988+
2989+1
2990+a
2991+hello
2992+HELLO
2993+HELLO MY
2994+select c from t1 order by c;
2995+c
2996+NULL
2997+NULL
2998+
2999+
3000+a
3001+hello
3002+HELLO
3003+HELLO MY
3004+select b from t1 order by b;
3005+b
3006+NULL
3007+NULL
3008+NULL
3009+
3010+HELLO
3011+HELLO MY
3012+a
3013+hello
3014+select d from t1 order by d;
3015+d
3016+NULL
3017+NULL
3018+
3019+1
3020+HELLO
3021+HELLO MY
3022+a
3023+hello
3024+select distinct t from t1;
3025+t
3026+NULL
3027+
3028+hello
3029+HELLO MY
3030+a
3031+1
3032+select distinct b from t1;
3033+b
3034+NULL
3035+
3036+hello
3037+HELLO
3038+HELLO MY
3039+a
3040+select distinct t from t1 order by t;
3041+t
3042+NULL
3043+
3044+1
3045+a
3046+hello
3047+HELLO MY
3048+select distinct b from t1 order by b;
3049+b
3050+NULL
3051+
3052+HELLO
3053+HELLO MY
3054+a
3055+hello
3056+select t from t1 group by t;
3057+t
3058+NULL
3059+
3060+1
3061+a
3062+hello
3063+HELLO MY
3064+select b from t1 group by b;
3065+b
3066+NULL
3067+
3068+HELLO
3069+HELLO MY
3070+a
3071+hello
3072+set option sql_big_tables=1;
3073+select distinct t from t1;
3074+t
3075+NULL
3076+
3077+hello
3078+HELLO MY
3079+a
3080+1
3081+select distinct b from t1;
3082+b
3083+NULL
3084+
3085+hello
3086+HELLO
3087+HELLO MY
3088+a
3089+select distinct t from t1 order by t;
3090+t
3091+NULL
3092+
3093+1
3094+a
3095+hello
3096+HELLO MY
3097+select distinct b from t1 order by b;
3098+b
3099+NULL
3100+
3101+HELLO
3102+HELLO MY
3103+a
3104+hello
3105+select distinct c from t1;
3106+c
3107+NULL
3108+
3109+hello
3110+HELLO MY
3111+a
3112+select distinct d from t1;
3113+d
3114+NULL
3115+
3116+hello
3117+HELLO
3118+HELLO MY
3119+a
3120+1
3121+select distinct c from t1 order by c;
3122+c
3123+NULL
3124+
3125+a
3126+hello
3127+HELLO MY
3128+select distinct d from t1 order by d;
3129+d
3130+NULL
3131+
3132+1
3133+HELLO
3134+HELLO MY
3135+a
3136+hello
3137+select c from t1 group by c;
3138+c
3139+NULL
3140+
3141+a
3142+hello
3143+HELLO MY
3144+select d from t1 group by d;
3145+d
3146+NULL
3147+
3148+1
3149+HELLO
3150+HELLO MY
3151+a
3152+hello
3153+set option sql_big_tables=0;
3154+select distinct * from t1;
3155+t c b d
3156+NULL NULL NULL NULL
3157+
3158+hello hello hello hello
3159+HELLO HELLO HELLO HELLO
3160+HELLO MY HELLO MY HELLO MY HELLO MY
3161+a a a a
3162+1 NULL 1
3163+select t,count(*) from t1 group by t;
3164+t count(*)
3165+NULL 2
3166+ 1
3167+1 1
3168+a 1
3169+hello 2
3170+HELLO MY 1
3171+select b,count(*) from t1 group by b;
3172+b count(*)
3173+NULL 3
3174+ 1
3175+HELLO 1
3176+HELLO MY 1
3177+a 1
3178+hello 1
3179+select c,count(*) from t1 group by c;
3180+c count(*)
3181+NULL 2
3182+ 2
3183+a 1
3184+hello 2
3185+HELLO MY 1
3186+select d,count(*) from t1 group by d;
3187+d count(*)
3188+NULL 2
3189+ 1
3190+1 1
3191+HELLO 1
3192+HELLO MY 1
3193+a 1
3194+hello 1
3195+drop table t1;
3196+CREATE TABLE t1 (
3197+t1_id bigint(21) NOT NULL auto_increment,
3198+_field_72 varchar(128) DEFAULT '' NOT NULL,
3199+_field_95 varchar(32),
3200+_field_115 tinyint(4) DEFAULT '0' NOT NULL,
3201+_field_122 tinyint(4) DEFAULT '0' NOT NULL,
3202+_field_126 tinyint(4),
3203+_field_134 tinyint(4),
3204+PRIMARY KEY (t1_id),
3205+UNIQUE _field_72 (_field_72),
3206+KEY _field_115 (_field_115),
3207+KEY _field_122 (_field_122)
3208+);
3209+INSERT INTO t1 VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',0,1,NULL,NULL);
3210+INSERT INTO t1 VALUES (2,'hroberts','7415275a8c95952901e42b13a6b78566',0,1,NULL,NULL);
3211+INSERT INTO t1 VALUES (3,'guest','d41d8cd98f00b204e9800998ecf8427e',1,0,NULL,NULL);
3212+CREATE TABLE t2 (
3213+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
3214+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
3215+PRIMARY KEY (seq_0_id,seq_1_id)
3216+);
3217+INSERT INTO t2 VALUES (1,1);
3218+INSERT INTO t2 VALUES (2,1);
3219+INSERT INTO t2 VALUES (2,2);
3220+CREATE TABLE t3 (
3221+t3_id bigint(21) NOT NULL auto_increment,
3222+_field_131 varchar(128),
3223+_field_133 tinyint(4) DEFAULT '0' NOT NULL,
3224+_field_135 datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
3225+_field_137 tinyint(4),
3226+_field_139 datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
3227+_field_140 blob,
3228+_field_142 tinyint(4) DEFAULT '0' NOT NULL,
3229+_field_145 tinyint(4) DEFAULT '0' NOT NULL,
3230+_field_148 tinyint(4) DEFAULT '0' NOT NULL,
3231+PRIMARY KEY (t3_id),
3232+KEY _field_133 (_field_133),
3233+KEY _field_135 (_field_135),
3234+KEY _field_139 (_field_139),
3235+KEY _field_142 (_field_142),
3236+KEY _field_145 (_field_145),
3237+KEY _field_148 (_field_148)
3238+);
3239+INSERT INTO t3 VALUES (1,'test job 1',0,'0000-00-00 00:00:00',0,'1999-02-25 22:43:32','test\r\njob\r\n1',0,0,0);
3240+INSERT INTO t3 VALUES (2,'test job 2',0,'0000-00-00 00:00:00',0,'1999-02-26 21:08:04','',0,0,0);
3241+CREATE TABLE t4 (
3242+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
3243+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
3244+PRIMARY KEY (seq_0_id,seq_1_id)
3245+);
3246+INSERT INTO t4 VALUES (1,1);
3247+INSERT INTO t4 VALUES (2,1);
3248+CREATE TABLE t5 (
3249+t5_id bigint(21) NOT NULL auto_increment,
3250+_field_149 tinyint(4),
3251+_field_156 varchar(128) DEFAULT '' NOT NULL,
3252+_field_157 varchar(128) DEFAULT '' NOT NULL,
3253+_field_158 varchar(128) DEFAULT '' NOT NULL,
3254+_field_159 varchar(128) DEFAULT '' NOT NULL,
3255+_field_160 varchar(128) DEFAULT '' NOT NULL,
3256+_field_161 varchar(128) DEFAULT '' NOT NULL,
3257+PRIMARY KEY (t5_id),
3258+KEY _field_156 (_field_156),
3259+KEY _field_157 (_field_157),
3260+KEY _field_158 (_field_158),
3261+KEY _field_159 (_field_159),
3262+KEY _field_160 (_field_160),
3263+KEY _field_161 (_field_161)
3264+);
3265+INSERT INTO t5 VALUES (1,0,'tomato','','','','','');
3266+INSERT INTO t5 VALUES (2,0,'cilantro','','','','','');
3267+CREATE TABLE t6 (
3268+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
3269+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
3270+PRIMARY KEY (seq_0_id,seq_1_id)
3271+);
3272+INSERT INTO t6 VALUES (1,1);
3273+INSERT INTO t6 VALUES (1,2);
3274+INSERT INTO t6 VALUES (2,2);
3275+CREATE TABLE t7 (
3276+t7_id bigint(21) NOT NULL auto_increment,
3277+_field_143 tinyint(4),
3278+_field_165 varchar(32),
3279+_field_166 smallint(6) DEFAULT '0' NOT NULL,
3280+PRIMARY KEY (t7_id),
3281+KEY _field_166 (_field_166)
3282+);
3283+INSERT INTO t7 VALUES (1,0,'High',1);
3284+INSERT INTO t7 VALUES (2,0,'Medium',2);
3285+INSERT INTO t7 VALUES (3,0,'Low',3);
3286+select replace(t3._field_140, "\r","^M"),t3_id,min(t3._field_131), min(t3._field_135), min(t3._field_139), min(t3._field_137), min(link_alias_142._field_165), min(link_alias_133._field_72), min(t3._field_145), min(link_alias_148._field_156), replace(min(t3._field_140), "\r","^M"),t3.t3_id from t3 left join t4 on t4.seq_0_id = t3.t3_id left join t7 link_alias_142 on t4.seq_1_id = link_alias_142.t7_id left join t6 on t6.seq_0_id = t3.t3_id left join t1 link_alias_133 on t6.seq_1_id = link_alias_133.t1_id left join t2 on t2.seq_0_id = t3.t3_id left join t5 link_alias_148 on t2.seq_1_id = link_alias_148.t5_id where t3.t3_id in (1) group by t3.t3_id order by link_alias_142._field_166, _field_139, link_alias_133._field_72, _field_135, link_alias_148._field_156;
3287+replace(t3._field_140, "\r","^M") t3_id min(t3._field_131) min(t3._field_135) min(t3._field_139) min(t3._field_137) min(link_alias_142._field_165) min(link_alias_133._field_72) min(t3._field_145) min(link_alias_148._field_156) replace(min(t3._field_140), "\r","^M") t3_id
3288+test^M
3289+job^M
3290+1 1 test job 1 0000-00-00 00:00:00 1999-02-25 22:43:32 0 High admin 0 tomato test^M
3291+job^M
3292+1 1
3293+drop table t1,t2,t3,t4,t5,t6,t7;
3294+create table t1 (a blob);
3295+insert into t1 values ("empty"),("");
3296+select a,reverse(a) from t1;
3297+a reverse(a)
3298+empty ytpme
3299+
3300+drop table t1;
3301+create table t1 (id integer auto_increment unique,imagem LONGBLOB not null default '');
3302+Warnings:
3303+Warning 1101 BLOB/TEXT column 'imagem' can't have a default value
3304+insert into t1 (id) values (1);
3305+select
3306+charset(load_file('../../std_data/words.dat')),
3307+collation(load_file('../../std_data/words.dat')),
3308+coercibility(load_file('../../std_data/words.dat'));
3309+charset(load_file('../../std_data/words.dat')) collation(load_file('../../std_data/words.dat')) coercibility(load_file('../../std_data/words.dat'))
3310+binary binary 4
3311+explain extended select
3312+charset(load_file('MYSQLTEST_VARDIR/std_data/words.dat')),
3313+collation(load_file('MYSQLTEST_VARDIR/std_data/words.dat')),
3314+coercibility(load_file('MYSQLTEST_VARDIR/std_data/words.dat'));
3315+id select_type table type possible_keys key key_len ref rows filtered Extra
3316+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
3317+Warnings:
3318+Note 1003 select charset(load_file('MYSQLTEST_VARDIR/std_data/words.dat')) AS `charset(load_file('MYSQLTEST_VARDIR/std_data/words.dat'))`,collation(load_file('MYSQLTEST_VARDIR/std_data/words.dat')) AS `collation(load_file('MYSQLTEST_VARDIR/std_data/words.dat'))`,coercibility(load_file('MYSQLTEST_VARDIR/std_data/words.dat')) AS `coercibility(load_file('MYSQLTEST_VARDIR/std_data/words.dat'))`
3319+update t1 set imagem=load_file('MYSQLTEST_VARDIR/std_data/words.dat') where id=1;
3320+select if(imagem is null, "ERROR", "OK"),length(imagem) from t1 where id = 1;
3321+if(imagem is null, "ERROR", "OK") length(imagem)
3322+OK 581
3323+drop table t1;
3324+create table t1 select load_file('MYSQLTEST_VARDIR/std_data/words.dat') l;
3325+show full fields from t1;
3326+Field Type Collation Null Key Default Extra Privileges Comment
3327+l longblob NULL YES NULL #
3328+drop table t1;
3329+create table t1 (id integer primary key auto_increment, txt text not null);
3330+insert into t1 (txt) values ('Chevy ');
3331+select * from t1 where txt='Chevy';
3332+id txt
3333+1 Chevy
3334+select * from t1 where txt='Chevy ';
3335+id txt
3336+1 Chevy
3337+select * from t1 where txt='Chevy ' or txt='Chevy';
3338+id txt
3339+1 Chevy
3340+select * from t1 where txt='Chevy' or txt='Chevy ';
3341+id txt
3342+1 Chevy
3343+select * from t1 where id='1' or id='2';
3344+id txt
3345+1 Chevy
3346+insert into t1 (txt) values('Ford');
3347+select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford';
3348+id txt
3349+1 Chevy
3350+2 Ford
3351+select * from t1 where txt='Chevy' or txt='Chevy ';
3352+id txt
3353+1 Chevy
3354+select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy';
3355+id txt
3356+1 Chevy
3357+select * from t1 where txt in ('Chevy ','Chevy');
3358+id txt
3359+1 Chevy
3360+select * from t1 where txt in ('Chevy');
3361+id txt
3362+1 Chevy
3363+select * from t1 where txt between 'Chevy' and 'Chevy';
3364+id txt
3365+1 Chevy
3366+select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy ';
3367+id txt
3368+1 Chevy
3369+select * from t1 where txt between 'Chevy' and 'Chevy ';
3370+id txt
3371+1 Chevy
3372+select * from t1 where txt < 'Chevy ';
3373+id txt
3374+select * from t1 where txt <= 'Chevy';
3375+id txt
3376+1 Chevy
3377+select * from t1 where txt > 'Chevy';
3378+id txt
3379+2 Ford
3380+select * from t1 where txt >= 'Chevy';
3381+id txt
3382+1 Chevy
3383+2 Ford
3384+drop table t1;
3385+create table t1 (id integer primary key auto_increment, txt text);
3386+insert into t1 (txt) values ('Chevy'), ('Chevy '), (NULL);
3387+select * from t1 where txt='Chevy' or txt is NULL;
3388+id txt
3389+1 Chevy
3390+2 Chevy
3391+3 NULL
3392+explain select * from t1 where txt='Chevy' or txt is NULL;
3393+id select_type table type possible_keys key key_len ref rows Extra
3394+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
3395+select * from t1 where txt='Chevy ';
3396+id txt
3397+1 Chevy
3398+2 Chevy
3399+select * from t1 where txt='Chevy ' or txt='Chevy';
3400+id txt
3401+1 Chevy
3402+2 Chevy
3403+select * from t1 where txt='Chevy' or txt='Chevy ';
3404+id txt
3405+1 Chevy
3406+2 Chevy
3407+select * from t1 where id='1' or id='2';
3408+id txt
3409+1 Chevy
3410+2 Chevy
3411+insert into t1 (txt) values('Ford');
3412+select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford';
3413+id txt
3414+1 Chevy
3415+2 Chevy
3416+4 Ford
3417+select * from t1 where txt='Chevy' or txt='Chevy ';
3418+id txt
3419+1 Chevy
3420+2 Chevy
3421+select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy';
3422+id txt
3423+1 Chevy
3424+2 Chevy
3425+select * from t1 where txt in ('Chevy ','Chevy');
3426+id txt
3427+1 Chevy
3428+2 Chevy
3429+select * from t1 where txt in ('Chevy');
3430+id txt
3431+1 Chevy
3432+2 Chevy
3433+select * from t1 where txt between 'Chevy' and 'Chevy';
3434+id txt
3435+1 Chevy
3436+2 Chevy
3437+select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy ';
3438+id txt
3439+1 Chevy
3440+2 Chevy
3441+select * from t1 where txt between 'Chevy' and 'Chevy ';
3442+id txt
3443+1 Chevy
3444+2 Chevy
3445+select * from t1 where txt < 'Chevy ';
3446+id txt
3447+select * from t1 where txt < 'Chevy ' or txt is NULL;
3448+id txt
3449+3 NULL
3450+select * from t1 where txt <= 'Chevy';
3451+id txt
3452+1 Chevy
3453+2 Chevy
3454+select * from t1 where txt > 'Chevy';
3455+id txt
3456+4 Ford
3457+select * from t1 where txt >= 'Chevy';
3458+id txt
3459+1 Chevy
3460+2 Chevy
3461+4 Ford
3462+alter table t1 modify column txt blob;
3463+explain select * from t1 where txt='Chevy' or txt is NULL;
3464+id select_type table type possible_keys key key_len ref rows Extra
3465+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where
3466+select * from t1 where txt='Chevy' or txt is NULL;
3467+id txt
3468+1 Chevy
3469+3 NULL
3470+explain select * from t1 where txt='Chevy' or txt is NULL order by txt;
3471+id select_type table type possible_keys key key_len ref rows Extra
3472+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where; Using filesort
3473+select * from t1 where txt='Chevy' or txt is NULL order by txt;
3474+id txt
3475+3 NULL
3476+1 Chevy
3477+drop table t1;
3478+CREATE TABLE t1 ( i int(11) NOT NULL default '0', c text NOT NULL, d varchar(1) NOT NULL DEFAULT ' ', PRIMARY KEY (i));
3479+INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,'');
3480+select max(i) from t1 where c = '';
3481+max(i)
3482+4
3483+drop table t1;
3484+CREATE table t1 (a blob);
3485+insert into t1 values ('b'),('a\0'),('a'),('a '),('aa'),(NULL);
3486+select hex(a) from t1 order by a;
3487+hex(a)
3488+NULL
3489+61
3490+6100
3491+6120
3492+6161
3493+62
3494+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
3495+b
3496+NULL
3497+6100
3498+610000
3499+612000
3500+616100
3501+6200
3502+alter table t1 modify a varbinary(5);
3503+select hex(a) from t1 order by a;
3504+hex(a)
3505+NULL
3506+61
3507+6100
3508+6120
3509+6161
3510+62
3511+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
3512+b
3513+NULL
3514+6100
3515+610000
3516+612000
3517+616100
3518+6200
3519+alter table t1 modify a char(5);
3520+select hex(a) from t1 order by a;
3521+hex(a)
3522+NULL
3523+6100
3524+61
3525+61
3526+6161
3527+62
3528+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
3529+b
3530+NULL
3531+610000
3532+6100
3533+6100
3534+616100
3535+6200
3536+alter table t1 modify a binary(5);
3537+select hex(a) from t1 order by a;
3538+hex(a)
3539+NULL
3540+6100000000
3541+6100000000
3542+6100000000
3543+6161000000
3544+6200000000
3545+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
3546+b
3547+NULL
3548+610000000000
3549+610000000000
3550+610000000000
3551+616100000000
3552+620000000000
3553+drop table t1;
3554+create table t1 (a text default '');
3555+Warnings:
3556+Warning 1101 BLOB/TEXT column 'a' can't have a default value
3557+show create table t1;
3558+Table Create Table
3559+t1 CREATE TABLE `t1` (
3560+ `a` text
3561+) ENGINE=MEMORY DEFAULT CHARSET=latin1
3562+insert into t1 values (default);
3563+select * from t1;
3564+a
3565+NULL
3566+drop table t1;
3567+set @@sql_mode='TRADITIONAL';
3568+create table t1 (a text default '');
3569+ERROR 42000: BLOB/TEXT column 'a' can't have a default value
3570+set @@sql_mode='';
3571+CREATE TABLE t (c TEXT CHARSET ASCII);
3572+INSERT INTO t (c) VALUES (REPEAT('1',65537));
3573+Warnings:
3574+Warning 1265 Data truncated for column 'c' at row 1
3575+INSERT INTO t (c) VALUES (REPEAT('2',65536));
3576+Warnings:
3577+Warning 1265 Data truncated for column 'c' at row 1
3578+INSERT INTO t (c) VALUES (REPEAT('3',65535));
3579+SELECT LENGTH(c), CHAR_LENGTH(c) FROM t;
3580+LENGTH(c) CHAR_LENGTH(c)
3581+65535 65535
3582+65535 65535
3583+65535 65535
3584+DROP TABLE t;
3585+drop table if exists b15776;
3586+create table b15776 (data blob(2147483647));
3587+drop table b15776;
3588+create table b15776 (data blob(-1));
3589+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1))' at line 1
3590+create table b15776 (data blob(2147483648));
3591+drop table b15776;
3592+create table b15776 (data blob(4294967294));
3593+drop table b15776;
3594+create table b15776 (data blob(4294967295));
3595+drop table b15776;
3596+create table b15776 (data blob(4294967296));
3597+ERROR 42000: Display width out of range for column 'data' (max = 4294967295)
3598+CREATE TABLE b15776 (a blob(2147483647), b blob(2147483648), c blob(4294967295), a1 text(2147483647), b1 text(2147483648), c1 text(4294967295) );
3599+show columns from b15776;
3600+Field Type Null Key Default Extra
3601+a longblob YES NULL
3602+b longblob YES NULL
3603+c longblob YES NULL
3604+a1 longtext YES NULL
3605+b1 longtext YES NULL
3606+c1 longtext YES NULL
3607+drop table b15776;
3608+CREATE TABLE b15776 (a blob(4294967296));
3609+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3610+CREATE TABLE b15776 (a text(4294967296));
3611+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3612+CREATE TABLE b15776 (a blob(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3613+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3614+CREATE TABLE b15776 (a text(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3615+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3616+CREATE TABLE b15776 (a int(0));
3617+INSERT INTO b15776 values (NULL), (1), (42), (654);
3618+SELECT * from b15776 ORDER BY a;
3619+a
3620+NULL
3621+1
3622+42
3623+654
3624+DROP TABLE b15776;
3625+CREATE TABLE b15776 (a int(-1));
3626+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1))' at line 1
3627+CREATE TABLE b15776 (a int(255));
3628+DROP TABLE b15776;
3629+CREATE TABLE b15776 (a int(256));
3630+ERROR 42000: Display width out of range for column 'a' (max = 255)
3631+CREATE TABLE b15776 (data blob(-1));
3632+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1))' at line 1
3633+CREATE TABLE b15776 (a char(2147483647));
3634+ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead
3635+CREATE TABLE b15776 (a char(2147483648));
3636+ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead
3637+CREATE TABLE b15776 (a char(4294967295));
3638+ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead
3639+CREATE TABLE b15776 (a char(4294967296));
3640+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3641+CREATE TABLE b15776 (a year(4294967295));
3642+INSERT INTO b15776 VALUES (42);
3643+SELECT * FROM b15776;
3644+a
3645+2042
3646+DROP TABLE b15776;
3647+CREATE TABLE b15776 (a year(4294967296));
3648+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3649+CREATE TABLE b15776 (a year(0));
3650+DROP TABLE b15776;
3651+CREATE TABLE b15776 (a year(-2));
3652+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-2))' at line 1
3653+CREATE TABLE b15776 (a int(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3654+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3655+CREATE TABLE b15776 (a char(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3656+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3657+CREATE TABLE b15776 (a year(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3658+ERROR 42000: Display width out of range for column 'a' (max = 4294967295)
3659+CREATE TABLE b15776 select cast(null as char(4294967295));
3660+show columns from b15776;
3661+Field Type Null Key Default Extra
3662+cast(null as char(4294967295)) char(0) YES NULL
3663+drop table b15776;
3664+CREATE TABLE b15776 select cast(null as nchar(4294967295));
3665+show columns from b15776;
3666+Field Type Null Key Default Extra
3667+cast(null as nchar(4294967295)) char(0) YES NULL
3668+drop table b15776;
3669+CREATE TABLE b15776 select cast(null as binary(4294967295));
3670+show columns from b15776;
3671+Field Type Null Key Default Extra
3672+cast(null as binary(4294967295)) binary(0) YES NULL
3673+drop table b15776;
3674+explain select cast(1 as char(4294967295));
3675+id select_type table type possible_keys key key_len ref rows Extra
3676+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
3677+explain select cast(1 as nchar(4294967295));
3678+id select_type table type possible_keys key key_len ref rows Extra
3679+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
3680+explain select cast(1 as binary(4294967295));
3681+id select_type table type possible_keys key key_len ref rows Extra
3682+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
3683+explain select cast(1 as char(4294967296));
3684+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3685+explain select cast(1 as nchar(4294967296));
3686+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3687+explain select cast(1 as binary(4294967296));
3688+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3689+explain select cast(1 as decimal(-1));
3690+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1))' at line 1
3691+explain select cast(1 as decimal(64, 30));
3692+id select_type table type possible_keys key key_len ref rows Extra
3693+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
3694+explain select cast(1 as decimal(64, 999999999999999999999999999999));
3695+Got one of the listed errors
3696+explain select cast(1 as decimal(4294967296));
3697+Got one of the listed errors
3698+explain select cast(1 as decimal(999999999999999999999999999999999999));
3699+Got one of the listed errors
3700+explain select convert(1, char(4294967295));
3701+id select_type table type possible_keys key key_len ref rows Extra
3702+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
3703+explain select convert(1, char(4294967296));
3704+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3705+explain select convert(1, char(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3706+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3707+explain select convert(1, nchar(4294967295));
3708+id select_type table type possible_keys key key_len ref rows Extra
3709+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
3710+explain select convert(1, nchar(4294967296));
3711+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3712+explain select convert(1, nchar(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3713+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3714+explain select convert(1, binary(4294967295));
3715+id select_type table type possible_keys key key_len ref rows Extra
3716+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
3717+explain select convert(1, binary(4294967296));
3718+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3719+explain select convert(1, binary(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
3720+ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295)
3721+End of 5.0 tests
3722+CREATE TABLE t1(id INT NOT NULL);
3723+CREATE TABLE t2(id INT NOT NULL, c TEXT NOT NULL);
3724+INSERT INTO t1 VALUES (1);
3725+INSERT INTO t2 VALUES (1, '');
3726+UPDATE t2 SET c = REPEAT('1', 70000);
3727+Warnings:
3728+Warning 1265 Data truncated for column 'c' at row 1
3729+SELECT LENGTH(c) FROM t2;
3730+LENGTH(c)
3731+65535
3732+UPDATE t1 LEFT JOIN t2 USING(id) SET t2.c = REPEAT('1', 70000) WHERE t1.id = 1;
3733+Warnings:
3734+Warning 1265 Data truncated for column 'c' at row 1
3735+SELECT LENGTH(c) FROM t2;
3736+LENGTH(c)
3737+65535
3738+DROP TABLE t1, t2;
3739+# Bug #52160: crash and inconsistent results when grouping
3740+# by a function and column
3741+CREATE FUNCTION f1() RETURNS TINYBLOB RETURN 1;
3742+CREATE TABLE t1(a CHAR(1));
3743+INSERT INTO t1 VALUES ('0'), ('0');
3744+SELECT COUNT(*) FROM t1 GROUP BY f1(), a;
3745+COUNT(*)
3746+2
3747+DROP FUNCTION f1;
3748+DROP TABLE t1;
3749+SET default_storage_engine=@old_default_storage_engine;
3750+SET @old_max_heap_table_size = @@global.max_heap_table_size;
3751+SET @old_max_allowed_packet = @@global.max_allowed_packet;
3752+SET GLOBAL max_heap_table_size = 18 * 1024 * 1024;
3753+SET GLOBAL max_allowed_packet = 24 * 1024 * 1024;
3754+drop table if exists t1;
3755+CREATE TABLE t1 (data LONGBLOB) ENGINE=memory;
3756+INSERT INTO t1 (data) VALUES (NULL);
3757+UPDATE t1 set data=repeat('a',18*1024*1024);
3758+select length(data) from t1;
3759+length(data)
3760+18874368
3761+delete from t1 where left(data,1)='a';
3762+truncate table t1;
3763+INSERT INTO t1 (data) VALUES (repeat('a',1*1024*1024));
3764+INSERT INTO t1 (data) VALUES (repeat('b',16*1024*1024-1024));
3765+delete from t1 where left(data,1)='b';
3766+UPDATE t1 set data=repeat('c',17*1024*1024);
3767+delete from t1 where left(data,1)='c';
3768+INSERT INTO t1 set data=repeat('a',18*1024*1024);
3769+select length(data) from t1;
3770+length(data)
3771+18874368
3772+alter table t1 modify data blob;
3773+select length(data) from t1;
3774+length(data)
3775+0
3776+drop table t1;
3777+CREATE TABLE t1 (data BLOB) ENGINE=myisam;
3778+INSERT INTO t1 (data) VALUES (NULL);
3779+UPDATE t1 set data=repeat('a',18*1024*1024);
3780+Warnings:
3781+Warning 1265 Data truncated for column 'data' at row 1
3782+select length(data) from t1;
3783+length(data)
3784+65535
3785+drop table t1;
3786+SET GLOBAL max_allowed_packet = @old_max_allowed_packet;
3787+SET GLOBAL max_heap_table_size = @old_max_heap_table_size;
3788--- /dev/null
3789+++ b/mysql-test/r/percona_heap_bug783366.result
3790@@ -0,0 +1,14 @@
3791+drop table if exists t1;
3792+CREATE TABLE t1 (
3793+f1 VARCHAR ( 128 ) ,
3794+f2 VARCHAR ( 32 ),
3795+PRIMARY KEY ( f2 ( 2 ) , f1 )
3796+)
3797+ENGINE=HEAP KEY_BLOCK_SIZE = 512;
3798+INSERT IGNORE INTO t1 VALUES ( 'te' , 'm') , ( NULL , 'think' );
3799+Warnings:
3800+Warning 1048 Column 'f1' cannot be null
3801+INSERT IGNORE INTO t1 VALUES ( 'te' , 'm') , ( NULL , 'think' );
3802+Warnings:
3803+Warning 1048 Column 'f1' cannot be null
3804+DROP TABLE t1;
3805--- /dev/null
3806+++ b/mysql-test/r/percona_heap_bug783451.result
3807@@ -0,0 +1,132 @@
3808+DROP TABLE IF EXISTS local_1_1;
3809+CREATE TABLE IF NOT EXISTS local_1_1 ( f1 VARCHAR ( 32 ) NOT NULL , f2 VARCHAR ( 128 ) NOT NULL DEFAULT 'cboepfaobilcchabvglgjdbynog' , f3 VARCHAR ( 32 ) NOT NULL , f4 VARBINARY ( 32 ) NOT NULL , f5 VARBINARY ( 1024 ) DEFAULT 'ycboepfao' , KEY ( f1 /* ( 2 ) */ , f2 /* ( 2 ) */ ) ) ENGINE=HEAP KEY_BLOCK_SIZE = 512;
3810+INSERT IGNORE INTO local_1_1 VALUES ( REPEAT( 'ervydbimvmbqmsowdbsa' , 1 ) , 'v' , NULL , NULL , REPEAT( 'mervydbimvmbqms' , 5 ) ) , ( 'p' , 6 , 'n' , REPEAT( 'imervydbimvmbqmsowdbs' , 4 ) , 'do' ) , ( NULL , NULL , REPEAT( 'himervydbimvmbqmsowdbsaybudvwaamvhempuublmia' , 6 ) , REPEAT('X', POW(2, 20) * 2) , REPEAT('X', POW(2, 20) * 2) ) , ( REPEAT('X', POW(2, 20) * 2) , REPEAT( 'Y' , 763 ) , NULL , REPEAT('X', POW(2, 20) * 2) , NULL ) , ( REPEAT('X', POW(2, 20) * 2) , 'time' , 'how' , 2 , REPEAT( 'Y' , 107 ) ) , ( REPEAT( 'hyshimervydbimvmbqmsowdbsaybud' , 5 ) , 2 , 8 , NULL , REPEAT('X', POW(2, 20) * 2) ) , ( 'come' , NULL , 'i' , NULL , REPEAT('X', POW(2, 20) * 2) );
3811+Warnings:
3812+Warning 1048 Column 'f3' cannot be null
3813+Warning 1048 Column 'f4' cannot be null
3814+Warning 1265 Data truncated for column 'f4' at row 2
3815+Warning 1048 Column 'f1' cannot be null
3816+Warning 1048 Column 'f2' cannot be null
3817+Warning 1265 Data truncated for column 'f3' at row 3
3818+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3819+Warning 1048 Column 'f4' cannot be null
3820+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3821+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3822+Warning 1048 Column 'f1' cannot be null
3823+Warning 1265 Data truncated for column 'f2' at row 4
3824+Warning 1048 Column 'f3' cannot be null
3825+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3826+Warning 1048 Column 'f4' cannot be null
3827+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3828+Warning 1048 Column 'f1' cannot be null
3829+Warning 1265 Data truncated for column 'f1' at row 6
3830+Warning 1048 Column 'f4' cannot be null
3831+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3832+Warning 1048 Column 'f2' cannot be null
3833+Warning 1048 Column 'f4' cannot be null
3834+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3835+INSERT IGNORE INTO local_1_1 VALUES ( 'ok' , NULL , REPEAT( 'Y' , 651 ) , 2 , 5 ) , ( REPEAT( 'zylcdzkfrqpihyshimervydbimvmbqmsowdbsaybu' , 3 ) , REPEAT( 'Y' , 282 ) , REPEAT( 'X' , 0 ) , REPEAT( 'Y' , 369 ) , 'g' ) , ( 'think' , REPEAT('X', POW(2, 20) * 2), NULL , NULL , REPEAT('X', POW(2, 20) * 2) ) , ( REPEAT( 'Y' , 468 ) , REPEAT( 'dfvbrzylcd' , 6 ) , REPEAT( 'Y' , 264 ) , NULL , 'c' ) , ( NULL , NULL , REPEAT( 'srdfvbrzylcdzkfrqpihyshimervydbimvmbqms' , 0 ) , REPEAT( 'Y' , 244 ) , 7 ) , ( REPEAT( 'Y' , 0 ) , 'how' , 'going' , 'q' , NULL );
3836+Warnings:
3837+Warning 1048 Column 'f2' cannot be null
3838+Warning 1265 Data truncated for column 'f3' at row 1
3839+Warning 1265 Data truncated for column 'f1' at row 2
3840+Warning 1265 Data truncated for column 'f2' at row 2
3841+Warning 1265 Data truncated for column 'f4' at row 2
3842+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3843+Warning 1048 Column 'f2' cannot be null
3844+Warning 1048 Column 'f3' cannot be null
3845+Warning 1048 Column 'f4' cannot be null
3846+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3847+Warning 1265 Data truncated for column 'f1' at row 4
3848+Warning 1265 Data truncated for column 'f3' at row 4
3849+Warning 1048 Column 'f4' cannot be null
3850+Warning 1048 Column 'f1' cannot be null
3851+Warning 1048 Column 'f2' cannot be null
3852+Warning 1265 Data truncated for column 'f4' at row 5
3853+INSERT IGNORE INTO local_1_1 VALUES ( REPEAT('X', POW(2, 20) * 2) , NULL , NULL , NULL , REPEAT('X', POW(2, 20) * 2) ) , ( REPEAT('X', POW(2, 20) * 2) , NULL , REPEAT('X', POW(2, 20) * 2) , 'this' , 'e' ) , ( NULL , 'think' , NULL , 'were' , NULL ) , ( 9 , 'l' , 'c' , 3 , REPEAT( 'geysrdfvbrzylcdzkfrqpihyshimervydbi' , 5 ) ) , ( NULL , NULL , NULL , 'h' , 'w' );
3854+Warnings:
3855+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3856+Warning 1048 Column 'f1' cannot be null
3857+Warning 1048 Column 'f2' cannot be null
3858+Warning 1048 Column 'f3' cannot be null
3859+Warning 1048 Column 'f4' cannot be null
3860+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3861+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3862+Warning 1048 Column 'f1' cannot be null
3863+Warning 1048 Column 'f2' cannot be null
3864+Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated
3865+Warning 1048 Column 'f3' cannot be null
3866+Warning 1048 Column 'f1' cannot be null
3867+Warning 1048 Column 'f3' cannot be null
3868+Warning 1048 Column 'f1' cannot be null
3869+Warning 1048 Column 'f2' cannot be null
3870+Warning 1048 Column 'f3' cannot be null
3871+INSERT IGNORE INTO local_1_1 SELECT * FROM local_1_1;
3872+INSERT IGNORE INTO local_1_1 SELECT * FROM local_1_1;
3873+UPDATE local_1_1 SET f5 = REPEAT ('X', 215566);
3874+Warnings:
3875+Warning 1265 Data truncated for column 'f5' at row 1
3876+Warning 1265 Data truncated for column 'f5' at row 2
3877+Warning 1265 Data truncated for column 'f5' at row 3
3878+Warning 1265 Data truncated for column 'f5' at row 4
3879+Warning 1265 Data truncated for column 'f5' at row 5
3880+Warning 1265 Data truncated for column 'f5' at row 6
3881+Warning 1265 Data truncated for column 'f5' at row 7
3882+Warning 1265 Data truncated for column 'f5' at row 8
3883+Warning 1265 Data truncated for column 'f5' at row 9
3884+Warning 1265 Data truncated for column 'f5' at row 10
3885+Warning 1265 Data truncated for column 'f5' at row 11
3886+Warning 1265 Data truncated for column 'f5' at row 12
3887+Warning 1265 Data truncated for column 'f5' at row 13
3888+Warning 1265 Data truncated for column 'f5' at row 14
3889+Warning 1265 Data truncated for column 'f5' at row 15
3890+Warning 1265 Data truncated for column 'f5' at row 16
3891+Warning 1265 Data truncated for column 'f5' at row 17
3892+Warning 1265 Data truncated for column 'f5' at row 18
3893+Warning 1265 Data truncated for column 'f5' at row 19
3894+Warning 1265 Data truncated for column 'f5' at row 20
3895+Warning 1265 Data truncated for column 'f5' at row 21
3896+Warning 1265 Data truncated for column 'f5' at row 22
3897+Warning 1265 Data truncated for column 'f5' at row 23
3898+Warning 1265 Data truncated for column 'f5' at row 24
3899+Warning 1265 Data truncated for column 'f5' at row 25
3900+Warning 1265 Data truncated for column 'f5' at row 26
3901+Warning 1265 Data truncated for column 'f5' at row 27
3902+Warning 1265 Data truncated for column 'f5' at row 28
3903+Warning 1265 Data truncated for column 'f5' at row 29
3904+Warning 1265 Data truncated for column 'f5' at row 30
3905+Warning 1265 Data truncated for column 'f5' at row 31
3906+Warning 1265 Data truncated for column 'f5' at row 32
3907+Warning 1265 Data truncated for column 'f5' at row 33
3908+Warning 1265 Data truncated for column 'f5' at row 34
3909+Warning 1265 Data truncated for column 'f5' at row 35
3910+Warning 1265 Data truncated for column 'f5' at row 36
3911+Warning 1265 Data truncated for column 'f5' at row 37
3912+Warning 1265 Data truncated for column 'f5' at row 38
3913+Warning 1265 Data truncated for column 'f5' at row 39
3914+Warning 1265 Data truncated for column 'f5' at row 40
3915+Warning 1265 Data truncated for column 'f5' at row 41
3916+Warning 1265 Data truncated for column 'f5' at row 42
3917+Warning 1265 Data truncated for column 'f5' at row 43
3918+Warning 1265 Data truncated for column 'f5' at row 44
3919+Warning 1265 Data truncated for column 'f5' at row 45
3920+Warning 1265 Data truncated for column 'f5' at row 46
3921+Warning 1265 Data truncated for column 'f5' at row 47
3922+Warning 1265 Data truncated for column 'f5' at row 48
3923+Warning 1265 Data truncated for column 'f5' at row 49
3924+Warning 1265 Data truncated for column 'f5' at row 50
3925+Warning 1265 Data truncated for column 'f5' at row 51
3926+Warning 1265 Data truncated for column 'f5' at row 52
3927+Warning 1265 Data truncated for column 'f5' at row 53
3928+Warning 1265 Data truncated for column 'f5' at row 54
3929+Warning 1265 Data truncated for column 'f5' at row 55
3930+Warning 1265 Data truncated for column 'f5' at row 56
3931+Warning 1265 Data truncated for column 'f5' at row 57
3932+Warning 1265 Data truncated for column 'f5' at row 58
3933+Warning 1265 Data truncated for column 'f5' at row 59
3934+Warning 1265 Data truncated for column 'f5' at row 60
3935+Warning 1265 Data truncated for column 'f5' at row 61
3936+Warning 1265 Data truncated for column 'f5' at row 62
3937+Warning 1265 Data truncated for column 'f5' at row 63
3938+Warning 1265 Data truncated for column 'f5' at row 64
3939+DROP TABLE local_1_1;
3940--- /dev/null
3941+++ b/mysql-test/r/percona_heap_bug784464.result
3942@@ -0,0 +1,58 @@
3943+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
3944+PRIMARY KEY (f1)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3945+SHOW TABLE STATUS LIKE 't1';
3946+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3947+t1 MEMORY 10 Fixed 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC
3948+DROP TABLE t1;
3949+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
3950+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=33 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3951+ERROR 42000: Incorrect usage/placement of 'key_block_size'
3952+SHOW TABLE STATUS LIKE 't1';
3953+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3954+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
3955+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=34 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3956+SHOW TABLE STATUS LIKE 't1';
3957+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3958+t1 MEMORY 10 Dynamic 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=34
3959+DROP TABLE t1;
3960+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
3961+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=123 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3962+SHOW TABLE STATUS LIKE 't1';
3963+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3964+t1 MEMORY 10 Dynamic 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=123
3965+DROP TABLE t1;
3966+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
3967+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=1000 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3968+SHOW TABLE STATUS LIKE 't1';
3969+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3970+t1 MEMORY 10 Fixed 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=1000
3971+DROP TABLE t1;
3972+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
3973+PRIMARY KEY (f1)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3974+SHOW TABLE STATUS LIKE 't1';
3975+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3976+t1 MEMORY 10 Fixed 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC
3977+DROP TABLE t1;
3978+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
3979+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=33 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3980+ERROR 42000: Incorrect usage/placement of 'key_block_size'
3981+SHOW TABLE STATUS LIKE 't1';
3982+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3983+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
3984+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=34 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3985+SHOW TABLE STATUS LIKE 't1';
3986+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3987+t1 MEMORY 10 Dynamic 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=34
3988+DROP TABLE t1;
3989+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
3990+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=121 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3991+SHOW TABLE STATUS LIKE 't1';
3992+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3993+t1 MEMORY 10 Dynamic 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=121
3994+DROP TABLE t1;
3995+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
3996+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=1000 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
3997+SHOW TABLE STATUS LIKE 't1';
3998+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3999+t1 MEMORY 10 Fixed 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=1000
4000+DROP TABLE t1;
4001--- /dev/null
4002+++ b/mysql-test/r/percona_heap_bug784464_32bit.result
4003@@ -0,0 +1,12 @@
4004+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
4005+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=124 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4006+SHOW TABLE STATUS LIKE 't1';
4007+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4008+t1 MEMORY 10 Dynamic 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=124
4009+DROP TABLE t1;
4010+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
4011+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=122 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4012+SHOW TABLE STATUS LIKE 't1';
4013+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4014+t1 MEMORY 10 Dynamic 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=122
4015+DROP TABLE t1;
4016--- /dev/null
4017+++ b/mysql-test/r/percona_heap_bug784464_64bit.result
4018@@ -0,0 +1,12 @@
4019+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
4020+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=124 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4021+SHOW TABLE STATUS LIKE 't1';
4022+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4023+t1 MEMORY 10 Fixed 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=124
4024+DROP TABLE t1;
4025+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
4026+PRIMARY KEY (f1)) KEY_BLOCK_SIZE=122 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4027+SHOW TABLE STATUS LIKE 't1';
4028+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4029+t1 MEMORY 10 Fixed 0 X 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC KEY_BLOCK_SIZE=122
4030+DROP TABLE t1;
4031--- /dev/null
4032+++ b/mysql-test/r/percona_heap_bug784468.result
4033@@ -0,0 +1,15 @@
4034+CREATE TABLE t1 ( f1 VARCHAR(30)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4035+SHOW TABLE STATUS LIKE 't1';
4036+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4037+t1 MEMORY 10 Fixed 0 32 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC
4038+DROP TABLE t1;
4039+CREATE TABLE t1 ( f1 VARCHAR(31)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4040+SHOW TABLE STATUS LIKE 't1';
4041+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4042+t1 MEMORY 10 Fixed 0 33 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC
4043+DROP TABLE t1;
4044+CREATE TABLE t1 ( f1 VARCHAR(32)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4045+SHOW TABLE STATUS LIKE 't1';
4046+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4047+t1 MEMORY 10 Fixed 0 34 0 X 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL row_format=DYNAMIC
4048+DROP TABLE t1;
4049--- /dev/null
4050+++ b/mysql-test/r/percona_heap_bug788544.result
4051@@ -0,0 +1,9 @@
4052+CREATE TABLE t1 (f2 VARCHAR (32), f4 LONGBLOB, f5 TEXT) ENGINE=HEAP;
4053+INSERT INTO t1 VALUES ('a', NULL, NULL),
4054+('b' , REPEAT('a' , 593338), REPEAT('a', 800));
4055+UPDATE t1 SET f2 = 'c' WHERE f4 = 'd';
4056+SELECT LENGTH(f2), LENGTH(f4), LENGTH(f5) FROM t1;
4057+LENGTH(f2) LENGTH(f4) LENGTH(f5)
4058+1 NULL NULL
4059+1 593338 800
4060+DROP TABLE t1;
4061--- /dev/null
4062+++ b/mysql-test/r/percona_heap_bug788576.result
4063@@ -0,0 +1,19 @@
4064+CREATE TABLE t1 (f1 VARCHAR (32), f2 VARCHAR (128), f3 VARBINARY (128),
4065+f4 VARBINARY (512), f5 VARBINARY (1024),
4066+KEY (f2(1))) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
4067+INSERT IGNORE INTO t1 VALUES (2, NULL, 6, REPEAT('glugcgqk', 5), 'look'),
4068+(REPEAT( 'kglugcgqkin', 6), 'if', 'was', NULL, NULL),
4069+(NULL, NULL, NULL, NULL, 7);
4070+Warnings:
4071+Warning 1265 Data truncated for column 'f1' at row 2
4072+SELECT * FROM t1;
4073+f1 f2 f3 f4 f5
4074+2 NULL 6 glugcgqkglugcgqkglugcgqkglugcgqkglugcgqk look
4075+kglugcgqkinkglugcgqkinkglugcgqki if was NULL NULL
4076+NULL NULL NULL NULL 7
4077+DELETE FROM t1 WHERE f5 <=> NULL;
4078+SELECT * FROM t1;
4079+f1 f2 f3 f4 f5
4080+2 NULL 6 glugcgqkglugcgqkglugcgqkglugcgqkglugcgqk look
4081+NULL NULL NULL NULL 7
4082+DROP TABLE t1;
4083--- /dev/null
4084+++ b/mysql-test/r/percona_heap_bug788722.result
4085@@ -0,0 +1,18 @@
4086+CREATE TABLE IF NOT EXISTS local_1_1 (f1 VARCHAR (32) NOT NULL,
4087+f2 VARCHAR (128) NOT NULL,
4088+f3 BLOB NOT NULL,
4089+f4 TEXT,
4090+f5 BLOB (1024),
4091+PRIMARY KEY (f1),
4092+KEY (f1 , f2)
4093+) ENGINE=HEAP ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE = 2048;
4094+INSERT IGNORE INTO local_1_1 VALUES
4095+(REPEAT('egqeqfxwaejpqixuvvtentruyqadxiybjdfqjspfbyjdjczrrwjnagkzsoagatqookhsgtrvvbxacppljfzaseidqggxvuirm' , 5), NULL, NULL, NULL, REPEAT('hegqeqfxwaejpqixuvvtentruyqadxiy', 1)),
4096+('you', NULL, 0, REPEAT("X", 2048) , 0);
4097+Warnings:
4098+Warning 1265 Data truncated for column 'f1' at row 1
4099+Warning 1048 Column 'f2' cannot be null
4100+Warning 1048 Column 'f3' cannot be null
4101+Warning 1048 Column 'f2' cannot be null
4102+INSERT IGNORE INTO local_1_1 SELECT * FROM local_1_1;
4103+DROP TABLE local_1_1;
4104--- /dev/null
4105+++ b/mysql-test/r/percona_heap_bug789131.result
4106@@ -0,0 +1,7 @@
4107+CREATE TABLE t1 (f1 VARCHAR (128), f2 VARCHAR (128), f3 VARBINARY (512),
4108+f4 TEXT (65525), f5 VARCHAR (128), KEY (f1(1))) ENGINE=HEAP;
4109+INSERT IGNORE INTO t1 VALUES
4110+( 'o' , "" , NULL , "" , 0 ) ,
4111+(NULL, "" , "" , "" , 'f' ) ;
4112+INSERT IGNORE INTO t1 SELECT * FROM t1;
4113+DROP TABLE t1;
4114--- /dev/null
4115+++ b/mysql-test/r/percona_heap_var.result
4116@@ -0,0 +1,194 @@
4117+drop table if exists t1;
4118+set @@session.max_heap_table_size=16*1024*1024;
4119+create table t1 (a int not null, b varchar(400), c int, primary key (a), key (c)) engine=heap comment="testing heaps" key_block_size=128;
4120+ERROR 42000: Incorrect usage/placement of 'key_block_size'
4121+create table t1 (a int not null, b int, c varchar(400), primary key (a), key (b)) engine=heap comment="testing heaps" key_block_size=4;
4122+ERROR 42000: Incorrect usage/placement of 'key_block_size'
4123+create table t1 (a int not null, b int, c varchar(400), d varchar(400), primary key (a), key (b)) engine=heap comment="testing heaps" key_block_size=24;
4124+show table status like "t1";
4125+Name t1
4126+Engine MEMORY
4127+Version 10
4128+Row_format Dynamic
4129+Rows 0
4130+Avg_row_length X
4131+Data_length X
4132+Max_data_length X
4133+Index_length X
4134+Data_free X
4135+Auto_increment X
4136+Create_time X
4137+Update_time X
4138+Check_time X
4139+Collation latin1_swedish_ci
4140+Checksum NULL
4141+Create_options KEY_BLOCK_SIZE=24
4142+Comment testing heaps
4143+insert into t1 values (1,1,'012',NULL), (2,2,'0123456789',NULL), (3,3,'012345678901234567890123456789',NULL), (4,4,NULL,'0123456789012345678901234567890123456789012345678901234567890123456789');
4144+select * from t1;
4145+a b c d
4146+1 1 012 NULL
4147+2 2 0123456789 NULL
4148+3 3 012345678901234567890123456789 NULL
4149+4 4 NULL 0123456789012345678901234567890123456789012345678901234567890123456789
4150+delete from t1 where a = 3;
4151+select * from t1;
4152+a b c d
4153+1 1 012 NULL
4154+2 2 0123456789 NULL
4155+4 4 NULL 0123456789012345678901234567890123456789012345678901234567890123456789
4156+insert into t1 values (5,5,NULL,'0123'), (6,6,NULL,'0123');
4157+select * from t1;
4158+a b c d
4159+1 1 012 NULL
4160+2 2 0123456789 NULL
4161+6 6 NULL 0123
4162+5 5 NULL 0123
4163+4 4 NULL 0123456789012345678901234567890123456789012345678901234567890123456789
4164+update t1 set c = '012345678901234567890123456789' where a = 2;
4165+select * from t1;
4166+a b c d
4167+1 1 012 NULL
4168+2 2 012345678901234567890123456789 NULL
4169+6 6 NULL 0123
4170+5 5 NULL 0123
4171+4 4 NULL 0123456789012345678901234567890123456789012345678901234567890123456789
4172+update t1 set c = '0123456789' where a = 2;
4173+select * from t1;
4174+a b c d
4175+1 1 012 NULL
4176+2 2 0123456789 NULL
4177+6 6 NULL 0123
4178+5 5 NULL 0123
4179+4 4 NULL 0123456789012345678901234567890123456789012345678901234567890123456789
4180+insert into t1 values (7,7,'0123',NULL), (8,8,'0123',NULL);
4181+select * from t1;
4182+a b c d
4183+1 1 012 NULL
4184+2 2 0123456789 NULL
4185+6 6 NULL 0123
4186+5 5 NULL 0123
4187+4 4 NULL 0123456789012345678901234567890123456789012345678901234567890123456789
4188+7 7 0123 NULL
4189+8 8 0123 NULL
4190+show table status like "t1";
4191+Name t1
4192+Engine MEMORY
4193+Version 10
4194+Row_format Dynamic
4195+Rows 7
4196+Avg_row_length X
4197+Data_length X
4198+Max_data_length X
4199+Index_length X
4200+Data_free X
4201+Auto_increment X
4202+Create_time X
4203+Update_time X
4204+Check_time X
4205+Collation latin1_swedish_ci
4206+Checksum NULL
4207+Create_options KEY_BLOCK_SIZE=24
4208+Comment testing heaps
4209+alter table t1 key_block_size = 0;
4210+show table status like "t1";
4211+Name t1
4212+Engine MEMORY
4213+Version 10
4214+Row_format Dynamic
4215+Rows 7
4216+Avg_row_length X
4217+Data_length X
4218+Max_data_length X
4219+Index_length X
4220+Data_free X
4221+Auto_increment X
4222+Create_time X
4223+Update_time X
4224+Check_time X
4225+Collation latin1_swedish_ci
4226+Checksum NULL
4227+Create_options
4228+Comment testing heaps
4229+alter table t1 row_format = dynamic;
4230+show table status like "t1";
4231+Name t1
4232+Engine MEMORY
4233+Version 10
4234+Row_format Dynamic
4235+Rows 7
4236+Avg_row_length X
4237+Data_length X
4238+Max_data_length X
4239+Index_length X
4240+Data_free X
4241+Auto_increment X
4242+Create_time X
4243+Update_time X
4244+Check_time X
4245+Collation latin1_swedish_ci
4246+Checksum NULL
4247+Create_options row_format=DYNAMIC KEY_BLOCK_SIZE=X
4248+Comment testing heaps
4249+alter table t1 key_block_size = 128, max_rows = 10001;
4250+show table status like "t1";
4251+Name t1
4252+Engine MEMORY
4253+Version 10
4254+Row_format Dynamic
4255+Rows 7
4256+Avg_row_length X
4257+Data_length X
4258+Max_data_length X
4259+Index_length X
4260+Data_free X
4261+Auto_increment X
4262+Create_time X
4263+Update_time X
4264+Check_time X
4265+Collation latin1_swedish_ci
4266+Checksum NULL
4267+Create_options max_rows=10001 row_format=DYNAMIC KEY_BLOCK_SIZE=128
4268+Comment testing heaps
4269+select * from t1;
4270+a b c d
4271+1 1 012 NULL
4272+2 2 0123456789 NULL
4273+6 6 NULL 0123
4274+5 5 NULL 0123
4275+4 4 NULL 0123456789012345678901234567890123456789012345678901234567890123456789
4276+7 7 0123 NULL
4277+8 8 0123 NULL
4278+delete from t1;
4279+select * from t1;
4280+a b c d
4281+call mtr.add_suppression("The table 't1' is full");
4282+select count(*) from t1;
4283+count(*)
4284+10001
4285+insert into t1 values (100000,100000,NULL,'0123'), (100000,100000,NULL,'0123');
4286+ERROR HY000: The table 't1' is full
4287+show table status like "t1";
4288+Name t1
4289+Engine MEMORY
4290+Version 10
4291+Row_format Dynamic
4292+Rows 10001
4293+Avg_row_length X
4294+Data_length X
4295+Max_data_length X
4296+Index_length X
4297+Data_free X
4298+Auto_increment X
4299+Create_time X
4300+Update_time X
4301+Check_time X
4302+Collation latin1_swedish_ci
4303+Checksum NULL
4304+Create_options max_rows=10001 row_format=DYNAMIC KEY_BLOCK_SIZE=128
4305+Comment testing heaps
4306+select count(*) from t1;
4307+count(*)
4308+10001
4309+set @@session.max_heap_table_size=default;
4310+drop table t1;
4311--- /dev/null
4312+++ b/mysql-test/t/percona_heap_blob.test
4313@@ -0,0 +1,642 @@
4314+########################################################################
4315+# Test blobs with the HEAP/MEMORY storage engine
4316+########################################################################
4317+
4318+########################################################################
4319+# Modified tests from type_blob.test
4320+########################################################################
4321+
4322+SET @old_default_storage_engine=@@default_storage_engine;
4323+SET default_storage_engine=MEMORY;
4324+
4325+#
4326+# Basic cleanup
4327+#
4328+--disable_warnings
4329+drop table if exists t1,t2,t3,t4,t5,t6,t7;
4330+--enable_warnings
4331+
4332+
4333+#
4334+# Check syntax for creating BLOB/TEXT
4335+#
4336+
4337+CREATE TABLE t1 (a blob, b text, c blob(250), d text(70000), e text(70000000));
4338+show columns from t1;
4339+# PS doesn't give errors on prepare yet
4340+CREATE TABLE t2 (a char(255), b varbinary(70000), c varchar(70000000));
4341+CREATE TABLE t4 (c varchar(65530) character set utf8 not null);
4342+show columns from t2;
4343+create table t3 (a long, b long byte);
4344+show create TABLE t3;
4345+show create TABLE t4;
4346+drop table t1,t2,t3,t4;
4347+
4348+#
4349+# Check errors with blob
4350+#
4351+
4352+--error 1074
4353+CREATE TABLE t1 (a char(257) default "hello");
4354+--error 1074
4355+CREATE TABLE t2 (a char(256));
4356+--error 1074
4357+CREATE TABLE t1 (a varchar(70000) default "hello");
4358+--error 1101
4359+CREATE TABLE t2 (a blob default "hello");
4360+
4361+# Safety to be able to continue with other tests if above fails
4362+--disable_warnings
4363+drop table if exists t1,t2;
4364+--enable_warnings
4365+
4366+#
4367+# test of full join with blob
4368+#
4369+
4370+create table t1 (nr int(5) not null auto_increment,b blob,str char(10), primary key (nr));
4371+insert into t1 values (null,"a","A");
4372+insert into t1 values (null,"bbb","BBB");
4373+insert into t1 values (null,"ccc","CCC");
4374+select last_insert_id();
4375+select * from t1,t1 as t2;
4376+
4377+drop table t1;
4378+
4379+#
4380+# Test of changing TEXT column
4381+#
4382+
4383+create table t1 (a text);
4384+insert into t1 values ('where');
4385+update t1 set a='Where';
4386+select * from t1;
4387+drop table t1;
4388+
4389+#
4390+# test of blob, text, char and varbinary
4391+#
4392+create table t1 (t text,c char(10),b blob, d varbinary(10));
4393+insert into t1 values (NULL,NULL,NULL,NULL);
4394+insert into t1 values ("","","","");
4395+insert into t1 values ("hello","hello","hello","hello");
4396+insert into t1 values ("HELLO","HELLO","HELLO","HELLO");
4397+insert into t1 values ("HELLO MY","HELLO MY","HELLO MY","HELLO MY");
4398+insert into t1 values ("a","a","a","a");
4399+insert into t1 values (1,1,1,1);
4400+insert into t1 values (NULL,NULL,NULL,NULL);
4401+update t1 set c="",b=null where c="1";
4402+
4403+lock tables t1 READ;
4404+# We mask out the Privileges column because it differs for embedded server
4405+--replace_column 8 #
4406+show full fields from t1;
4407+lock tables t1 WRITE;
4408+--replace_column 8 #
4409+show full fields from t1;
4410+unlock tables;
4411+
4412+select t from t1 where t like "hello";
4413+select c from t1 where c like "hello";
4414+select b from t1 where b like "hello";
4415+select d from t1 where d like "hello";
4416+select c from t1 having c like "hello";
4417+select d from t1 having d like "hello";
4418+select t from t1 where t like "%HELLO%";
4419+select c from t1 where c like "%HELLO%";
4420+select b from t1 where b like "%HELLO%";
4421+select d from t1 where d like "%HELLO%";
4422+select c from t1 having c like "%HELLO%";
4423+select d from t1 having d like "%HELLO%";
4424+select d from t1 having d like "%HE%LLO%";
4425+select t from t1 order by t;
4426+select c from t1 order by c;
4427+select b from t1 order by b;
4428+select d from t1 order by d;
4429+select distinct t from t1;
4430+select distinct b from t1;
4431+select distinct t from t1 order by t;
4432+select distinct b from t1 order by b;
4433+select t from t1 group by t;
4434+select b from t1 group by b;
4435+set option sql_big_tables=1;
4436+select distinct t from t1;
4437+select distinct b from t1;
4438+select distinct t from t1 order by t;
4439+select distinct b from t1 order by b;
4440+select distinct c from t1;
4441+select distinct d from t1;
4442+select distinct c from t1 order by c;
4443+select distinct d from t1 order by d;
4444+select c from t1 group by c;
4445+select d from t1 group by d;
4446+set option sql_big_tables=0;
4447+select distinct * from t1;
4448+select t,count(*) from t1 group by t;
4449+select b,count(*) from t1 group by b;
4450+select c,count(*) from t1 group by c;
4451+select d,count(*) from t1 group by d;
4452+drop table t1;
4453+
4454+
4455+#
4456+# Test of join with blobs and min
4457+#
4458+
4459+CREATE TABLE t1 (
4460+ t1_id bigint(21) NOT NULL auto_increment,
4461+ _field_72 varchar(128) DEFAULT '' NOT NULL,
4462+ _field_95 varchar(32),
4463+ _field_115 tinyint(4) DEFAULT '0' NOT NULL,
4464+ _field_122 tinyint(4) DEFAULT '0' NOT NULL,
4465+ _field_126 tinyint(4),
4466+ _field_134 tinyint(4),
4467+ PRIMARY KEY (t1_id),
4468+ UNIQUE _field_72 (_field_72),
4469+ KEY _field_115 (_field_115),
4470+ KEY _field_122 (_field_122)
4471+);
4472+
4473+
4474+INSERT INTO t1 VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',0,1,NULL,NULL);
4475+INSERT INTO t1 VALUES (2,'hroberts','7415275a8c95952901e42b13a6b78566',0,1,NULL,NULL);
4476+INSERT INTO t1 VALUES (3,'guest','d41d8cd98f00b204e9800998ecf8427e',1,0,NULL,NULL);
4477+
4478+
4479+CREATE TABLE t2 (
4480+ seq_0_id bigint(21) DEFAULT '0' NOT NULL,
4481+ seq_1_id bigint(21) DEFAULT '0' NOT NULL,
4482+ PRIMARY KEY (seq_0_id,seq_1_id)
4483+);
4484+
4485+
4486+INSERT INTO t2 VALUES (1,1);
4487+INSERT INTO t2 VALUES (2,1);
4488+INSERT INTO t2 VALUES (2,2);
4489+
4490+CREATE TABLE t3 (
4491+ t3_id bigint(21) NOT NULL auto_increment,
4492+ _field_131 varchar(128),
4493+ _field_133 tinyint(4) DEFAULT '0' NOT NULL,
4494+ _field_135 datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
4495+ _field_137 tinyint(4),
4496+ _field_139 datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
4497+ _field_140 blob,
4498+ _field_142 tinyint(4) DEFAULT '0' NOT NULL,
4499+ _field_145 tinyint(4) DEFAULT '0' NOT NULL,
4500+ _field_148 tinyint(4) DEFAULT '0' NOT NULL,
4501+ PRIMARY KEY (t3_id),
4502+ KEY _field_133 (_field_133),
4503+ KEY _field_135 (_field_135),
4504+ KEY _field_139 (_field_139),
4505+ KEY _field_142 (_field_142),
4506+ KEY _field_145 (_field_145),
4507+ KEY _field_148 (_field_148)
4508+);
4509+
4510+
4511+INSERT INTO t3 VALUES (1,'test job 1',0,'0000-00-00 00:00:00',0,'1999-02-25 22:43:32','test\r\njob\r\n1',0,0,0);
4512+INSERT INTO t3 VALUES (2,'test job 2',0,'0000-00-00 00:00:00',0,'1999-02-26 21:08:04','',0,0,0);
4513+
4514+
4515+CREATE TABLE t4 (
4516+ seq_0_id bigint(21) DEFAULT '0' NOT NULL,
4517+ seq_1_id bigint(21) DEFAULT '0' NOT NULL,
4518+ PRIMARY KEY (seq_0_id,seq_1_id)
4519+);
4520+
4521+
4522+INSERT INTO t4 VALUES (1,1);
4523+INSERT INTO t4 VALUES (2,1);
4524+
4525+CREATE TABLE t5 (
4526+ t5_id bigint(21) NOT NULL auto_increment,
4527+ _field_149 tinyint(4),
4528+ _field_156 varchar(128) DEFAULT '' NOT NULL,
4529+ _field_157 varchar(128) DEFAULT '' NOT NULL,
4530+ _field_158 varchar(128) DEFAULT '' NOT NULL,
4531+ _field_159 varchar(128) DEFAULT '' NOT NULL,
4532+ _field_160 varchar(128) DEFAULT '' NOT NULL,
4533+ _field_161 varchar(128) DEFAULT '' NOT NULL,
4534+ PRIMARY KEY (t5_id),
4535+ KEY _field_156 (_field_156),
4536+ KEY _field_157 (_field_157),
4537+ KEY _field_158 (_field_158),
4538+ KEY _field_159 (_field_159),
4539+ KEY _field_160 (_field_160),
4540+ KEY _field_161 (_field_161)
4541+);
4542+
4543+
4544+INSERT INTO t5 VALUES (1,0,'tomato','','','','','');
4545+INSERT INTO t5 VALUES (2,0,'cilantro','','','','','');
4546+
4547+CREATE TABLE t6 (
4548+ seq_0_id bigint(21) DEFAULT '0' NOT NULL,
4549+ seq_1_id bigint(21) DEFAULT '0' NOT NULL,
4550+ PRIMARY KEY (seq_0_id,seq_1_id)
4551+);
4552+
4553+INSERT INTO t6 VALUES (1,1);
4554+INSERT INTO t6 VALUES (1,2);
4555+INSERT INTO t6 VALUES (2,2);
4556+
4557+CREATE TABLE t7 (
4558+ t7_id bigint(21) NOT NULL auto_increment,
4559+ _field_143 tinyint(4),
4560+ _field_165 varchar(32),
4561+ _field_166 smallint(6) DEFAULT '0' NOT NULL,
4562+ PRIMARY KEY (t7_id),
4563+ KEY _field_166 (_field_166)
4564+);
4565+
4566+
4567+INSERT INTO t7 VALUES (1,0,'High',1);
4568+INSERT INTO t7 VALUES (2,0,'Medium',2);
4569+INSERT INTO t7 VALUES (3,0,'Low',3);
4570+
4571+select replace(t3._field_140, "\r","^M"),t3_id,min(t3._field_131), min(t3._field_135), min(t3._field_139), min(t3._field_137), min(link_alias_142._field_165), min(link_alias_133._field_72), min(t3._field_145), min(link_alias_148._field_156), replace(min(t3._field_140), "\r","^M"),t3.t3_id from t3 left join t4 on t4.seq_0_id = t3.t3_id left join t7 link_alias_142 on t4.seq_1_id = link_alias_142.t7_id left join t6 on t6.seq_0_id = t3.t3_id left join t1 link_alias_133 on t6.seq_1_id = link_alias_133.t1_id left join t2 on t2.seq_0_id = t3.t3_id left join t5 link_alias_148 on t2.seq_1_id = link_alias_148.t5_id where t3.t3_id in (1) group by t3.t3_id order by link_alias_142._field_166, _field_139, link_alias_133._field_72, _field_135, link_alias_148._field_156;
4572+
4573+drop table t1,t2,t3,t4,t5,t6,t7;
4574+
4575+#
4576+# Test of reverse with empty blob
4577+#
4578+
4579+create table t1 (a blob);
4580+insert into t1 values ("empty"),("");
4581+select a,reverse(a) from t1;
4582+drop table t1;
4583+
4584+#
4585+# Bug when blob is updated
4586+#
4587+
4588+create table t1 (id integer auto_increment unique,imagem LONGBLOB not null default '');
4589+insert into t1 (id) values (1);
4590+# We have to clean up the path in the results for safe comparison
4591+eval select
4592+ charset(load_file('../../std_data/words.dat')),
4593+ collation(load_file('../../std_data/words.dat')),
4594+ coercibility(load_file('../../std_data/words.dat'));
4595+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
4596+eval explain extended select
4597+ charset(load_file('$MYSQLTEST_VARDIR/std_data/words.dat')),
4598+ collation(load_file('$MYSQLTEST_VARDIR/std_data/words.dat')),
4599+ coercibility(load_file('$MYSQLTEST_VARDIR/std_data/words.dat'));
4600+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
4601+eval update t1 set imagem=load_file('$MYSQLTEST_VARDIR/std_data/words.dat') where id=1;
4602+select if(imagem is null, "ERROR", "OK"),length(imagem) from t1 where id = 1;
4603+drop table t1;
4604+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
4605+eval create table t1 select load_file('$MYSQLTEST_VARDIR/std_data/words.dat') l;
4606+# We mask out the Privileges column because it differs for embedded server
4607+--replace_column 8 #
4608+show full fields from t1;
4609+drop table t1;
4610+
4611+#
4612+# Test blob's with end space (Bug #1651)
4613+# This is a bit changed since we now have true varchar
4614+#
4615+
4616+create table t1 (id integer primary key auto_increment, txt text not null);
4617+insert into t1 (txt) values ('Chevy ');
4618+select * from t1 where txt='Chevy';
4619+select * from t1 where txt='Chevy ';
4620+select * from t1 where txt='Chevy ' or txt='Chevy';
4621+select * from t1 where txt='Chevy' or txt='Chevy ';
4622+select * from t1 where id='1' or id='2';
4623+insert into t1 (txt) values('Ford');
4624+select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford';
4625+select * from t1 where txt='Chevy' or txt='Chevy ';
4626+select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy';
4627+select * from t1 where txt in ('Chevy ','Chevy');
4628+select * from t1 where txt in ('Chevy');
4629+select * from t1 where txt between 'Chevy' and 'Chevy';
4630+select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy ';
4631+select * from t1 where txt between 'Chevy' and 'Chevy ';
4632+select * from t1 where txt < 'Chevy ';
4633+select * from t1 where txt <= 'Chevy';
4634+select * from t1 where txt > 'Chevy';
4635+select * from t1 where txt >= 'Chevy';
4636+drop table t1;
4637+
4638+create table t1 (id integer primary key auto_increment, txt text);
4639+insert into t1 (txt) values ('Chevy'), ('Chevy '), (NULL);
4640+select * from t1 where txt='Chevy' or txt is NULL;
4641+explain select * from t1 where txt='Chevy' or txt is NULL;
4642+select * from t1 where txt='Chevy ';
4643+select * from t1 where txt='Chevy ' or txt='Chevy';
4644+select * from t1 where txt='Chevy' or txt='Chevy ';
4645+select * from t1 where id='1' or id='2';
4646+insert into t1 (txt) values('Ford');
4647+select * from t1 where txt='Chevy' or txt='Chevy ' or txt='Ford';
4648+select * from t1 where txt='Chevy' or txt='Chevy ';
4649+select * from t1 where txt='Chevy' or txt='Chevy ' or txt=' Chevy';
4650+select * from t1 where txt in ('Chevy ','Chevy');
4651+select * from t1 where txt in ('Chevy');
4652+select * from t1 where txt between 'Chevy' and 'Chevy';
4653+select * from t1 where txt between 'Chevy' and 'Chevy' or txt='Chevy ';
4654+select * from t1 where txt between 'Chevy' and 'Chevy ';
4655+select * from t1 where txt < 'Chevy ';
4656+select * from t1 where txt < 'Chevy ' or txt is NULL;
4657+select * from t1 where txt <= 'Chevy';
4658+select * from t1 where txt > 'Chevy';
4659+select * from t1 where txt >= 'Chevy';
4660+alter table t1 modify column txt blob;
4661+explain select * from t1 where txt='Chevy' or txt is NULL;
4662+select * from t1 where txt='Chevy' or txt is NULL;
4663+explain select * from t1 where txt='Chevy' or txt is NULL order by txt;
4664+select * from t1 where txt='Chevy' or txt is NULL order by txt;
4665+drop table t1;
4666+
4667+CREATE TABLE t1 ( i int(11) NOT NULL default '0', c text NOT NULL, d varchar(1) NOT NULL DEFAULT ' ', PRIMARY KEY (i));
4668+INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,'');
4669+select max(i) from t1 where c = '';
4670+drop table t1;
4671+
4672+# End of 4.1 tests
4673+
4674+#
4675+# Test that blob's and varbinary are sorted according to length
4676+#
4677+
4678+CREATE table t1 (a blob);
4679+insert into t1 values ('b'),('a\0'),('a'),('a '),('aa'),(NULL);
4680+select hex(a) from t1 order by a;
4681+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
4682+alter table t1 modify a varbinary(5);
4683+select hex(a) from t1 order by a;
4684+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
4685+alter table t1 modify a char(5);
4686+select hex(a) from t1 order by a;
4687+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
4688+alter table t1 modify a binary(5);
4689+select hex(a) from t1 order by a;
4690+select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0');
4691+drop table t1;
4692+
4693+#
4694+# Bug #19489: Inconsistent support for DEFAULT in TEXT columns
4695+#
4696+create table t1 (a text default '');
4697+show create table t1;
4698+insert into t1 values (default);
4699+select * from t1;
4700+drop table t1;
4701+set @@sql_mode='TRADITIONAL';
4702+--error ER_BLOB_CANT_HAVE_DEFAULT
4703+create table t1 (a text default '');
4704+set @@sql_mode='';
4705+
4706+#
4707+# Bug #32282: TEXT silently truncates when value is exactly 65536 bytes
4708+#
4709+
4710+CREATE TABLE t (c TEXT CHARSET ASCII);
4711+INSERT INTO t (c) VALUES (REPEAT('1',65537));
4712+INSERT INTO t (c) VALUES (REPEAT('2',65536));
4713+INSERT INTO t (c) VALUES (REPEAT('3',65535));
4714+SELECT LENGTH(c), CHAR_LENGTH(c) FROM t;
4715+DROP TABLE t;
4716+# Bug#15776: 32-bit signed int used for length of blob
4717+# """LONGBLOB: A BLOB column with a maximum length of 4,294,967,295 or 4GB."""
4718+#
4719+# Conditions should be in this order:
4720+# A size is not in the allowed bounds.
4721+# If the type is char-ish AND size is within the max blob size:
4722+# raise ER_TOO_BIG_FIELDLENGTH (suggest using BLOB)
4723+# If size is too small:
4724+# raise ER_PARSE_ERROR
4725+# raise ER_TOO_BIG_DISPLAYWIDTH
4726+
4727+# BLOB and TEXT types
4728+--disable_warnings
4729+drop table if exists b15776;
4730+--enable_warnings
4731+create table b15776 (data blob(2147483647));
4732+drop table b15776;
4733+--error ER_PARSE_ERROR
4734+create table b15776 (data blob(-1));
4735+create table b15776 (data blob(2147483648));
4736+drop table b15776;
4737+create table b15776 (data blob(4294967294));
4738+drop table b15776;
4739+create table b15776 (data blob(4294967295));
4740+drop table b15776;
4741+--error ER_TOO_BIG_DISPLAYWIDTH
4742+create table b15776 (data blob(4294967296));
4743+
4744+CREATE TABLE b15776 (a blob(2147483647), b blob(2147483648), c blob(4294967295), a1 text(2147483647), b1 text(2147483648), c1 text(4294967295) );
4745+show columns from b15776;
4746+drop table b15776;
4747+
4748+--error ER_TOO_BIG_DISPLAYWIDTH
4749+CREATE TABLE b15776 (a blob(4294967296));
4750+--error ER_TOO_BIG_DISPLAYWIDTH
4751+CREATE TABLE b15776 (a text(4294967296));
4752+--error ER_TOO_BIG_DISPLAYWIDTH
4753+CREATE TABLE b15776 (a blob(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4754+--error ER_TOO_BIG_DISPLAYWIDTH
4755+CREATE TABLE b15776 (a text(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4756+
4757+# Int types
4758+# "Another extension is supported by MySQL for optionally specifying the
4759+# display width of integer data types in parentheses following the base keyword
4760+# for the type (for example, INT(4)). This optional display width is used to
4761+# display integer values having a width less than the width specified for the
4762+# column by left-padding them with spaces." § Numeric Types
4763+CREATE TABLE b15776 (a int(0)); # 0 is special case, means default size
4764+INSERT INTO b15776 values (NULL), (1), (42), (654);
4765+SELECT * from b15776 ORDER BY a;
4766+DROP TABLE b15776;
4767+--error ER_PARSE_ERROR
4768+CREATE TABLE b15776 (a int(-1));
4769+CREATE TABLE b15776 (a int(255));
4770+DROP TABLE b15776;
4771+--error ER_TOO_BIG_DISPLAYWIDTH
4772+CREATE TABLE b15776 (a int(256));
4773+--error ER_PARSE_ERROR
4774+CREATE TABLE b15776 (data blob(-1));
4775+
4776+# Char types
4777+# Recommend BLOB
4778+--error ER_TOO_BIG_FIELDLENGTH
4779+CREATE TABLE b15776 (a char(2147483647));
4780+--error ER_TOO_BIG_FIELDLENGTH
4781+CREATE TABLE b15776 (a char(2147483648));
4782+--error ER_TOO_BIG_FIELDLENGTH
4783+CREATE TABLE b15776 (a char(4294967295));
4784+# Even BLOB won't hold
4785+--error ER_TOO_BIG_DISPLAYWIDTH
4786+CREATE TABLE b15776 (a char(4294967296));
4787+
4788+
4789+# Other numeric-ish types
4790+## For year, widths not "2" or "4" are silently rewritten to "4". But
4791+## When we complain about it, we say that the max is 255. We may be
4792+## talking about different things. It's confusing.
4793+CREATE TABLE b15776 (a year(4294967295));
4794+INSERT INTO b15776 VALUES (42);
4795+SELECT * FROM b15776;
4796+DROP TABLE b15776;
4797+--error ER_TOO_BIG_DISPLAYWIDTH
4798+CREATE TABLE b15776 (a year(4294967296));
4799+CREATE TABLE b15776 (a year(0)); # 0 is special case, means default size
4800+DROP TABLE b15776;
4801+--error ER_PARSE_ERROR
4802+CREATE TABLE b15776 (a year(-2));
4803+
4804+
4805+# We've already tested the case, but this should visually show that
4806+# widths that are too large to be interpreted cause DISPLAYWIDTH errors.
4807+--error ER_TOO_BIG_DISPLAYWIDTH
4808+CREATE TABLE b15776 (a int(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4809+--error ER_TOO_BIG_DISPLAYWIDTH
4810+CREATE TABLE b15776 (a char(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4811+--error ER_TOO_BIG_DISPLAYWIDTH
4812+CREATE TABLE b15776 (a year(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4813+
4814+## Do not select, too much memory needed.
4815+CREATE TABLE b15776 select cast(null as char(4294967295));
4816+show columns from b15776;
4817+drop table b15776;
4818+CREATE TABLE b15776 select cast(null as nchar(4294967295));
4819+show columns from b15776;
4820+drop table b15776;
4821+CREATE TABLE b15776 select cast(null as binary(4294967295));
4822+show columns from b15776;
4823+drop table b15776;
4824+
4825+explain select cast(1 as char(4294967295));
4826+explain select cast(1 as nchar(4294967295));
4827+explain select cast(1 as binary(4294967295));
4828+
4829+--error ER_TOO_BIG_DISPLAYWIDTH
4830+explain select cast(1 as char(4294967296));
4831+--error ER_TOO_BIG_DISPLAYWIDTH
4832+explain select cast(1 as nchar(4294967296));
4833+--error ER_TOO_BIG_DISPLAYWIDTH
4834+explain select cast(1 as binary(4294967296));
4835+
4836+--error ER_PARSE_ERROR
4837+explain select cast(1 as decimal(-1));
4838+explain select cast(1 as decimal(64, 30));
4839+# It's not as important which errors are raised for these, since the
4840+# limit is nowhere near 2**32. We may fix these eventually to take
4841+# 4294967295 and still reject it because it's greater than 64 or 30,
4842+# but that's not a high priority and the parser needn't worry about
4843+# such a weird case.
4844+--error ER_TOO_BIG_SCALE,ER_PARSE_ERROR
4845+explain select cast(1 as decimal(64, 999999999999999999999999999999));
4846+--error ER_TOO_BIG_PRECISION,ER_PARSE_ERROR
4847+explain select cast(1 as decimal(4294967296));
4848+--error ER_TOO_BIG_PRECISION,ER_PARSE_ERROR
4849+explain select cast(1 as decimal(999999999999999999999999999999999999));
4850+
4851+explain select convert(1, char(4294967295));
4852+--error ER_TOO_BIG_DISPLAYWIDTH
4853+explain select convert(1, char(4294967296));
4854+--error ER_TOO_BIG_DISPLAYWIDTH
4855+explain select convert(1, char(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4856+explain select convert(1, nchar(4294967295));
4857+--error ER_TOO_BIG_DISPLAYWIDTH
4858+explain select convert(1, nchar(4294967296));
4859+--error ER_TOO_BIG_DISPLAYWIDTH
4860+explain select convert(1, nchar(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4861+explain select convert(1, binary(4294967295));
4862+--error ER_TOO_BIG_DISPLAYWIDTH
4863+explain select convert(1, binary(4294967296));
4864+--error ER_TOO_BIG_DISPLAYWIDTH
4865+explain select convert(1, binary(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999));
4866+
4867+--echo End of 5.0 tests
4868+
4869+#
4870+# Bug #33969: Updating a text field via a left join
4871+#
4872+
4873+CREATE TABLE t1(id INT NOT NULL);
4874+CREATE TABLE t2(id INT NOT NULL, c TEXT NOT NULL);
4875+
4876+INSERT INTO t1 VALUES (1);
4877+INSERT INTO t2 VALUES (1, '');
4878+
4879+UPDATE t2 SET c = REPEAT('1', 70000);
4880+SELECT LENGTH(c) FROM t2;
4881+
4882+UPDATE t1 LEFT JOIN t2 USING(id) SET t2.c = REPEAT('1', 70000) WHERE t1.id = 1;
4883+SELECT LENGTH(c) FROM t2;
4884+
4885+DROP TABLE t1, t2;
4886+
4887+--echo # Bug #52160: crash and inconsistent results when grouping
4888+--echo # by a function and column
4889+
4890+CREATE FUNCTION f1() RETURNS TINYBLOB RETURN 1;
4891+
4892+CREATE TABLE t1(a CHAR(1));
4893+INSERT INTO t1 VALUES ('0'), ('0');
4894+
4895+SELECT COUNT(*) FROM t1 GROUP BY f1(), a;
4896+
4897+DROP FUNCTION f1;
4898+DROP TABLE t1;
4899+
4900+
4901+
4902+SET default_storage_engine=@old_default_storage_engine;
4903+
4904+
4905+########################################################################
4906+# Modified test from myisam-blob.test
4907+########################################################################
4908+
4909+SET @old_max_heap_table_size = @@global.max_heap_table_size;
4910+SET @old_max_allowed_packet = @@global.max_allowed_packet;
4911+SET GLOBAL max_heap_table_size = 18 * 1024 * 1024;
4912+SET GLOBAL max_allowed_packet = 24 * 1024 * 1024;
4913+
4914+connect(con1, localhost, root,,);
4915+connection con1;
4916+
4917+--disable_warnings
4918+drop table if exists t1;
4919+--enable_warnings
4920+
4921+# Bug #2159 (Problem with update of blob to > 16M)
4922+
4923+CREATE TABLE t1 (data LONGBLOB) ENGINE=memory;
4924+INSERT INTO t1 (data) VALUES (NULL);
4925+UPDATE t1 set data=repeat('a',18*1024*1024);
4926+select length(data) from t1;
4927+delete from t1 where left(data,1)='a';
4928+truncate table t1;
4929+INSERT INTO t1 (data) VALUES (repeat('a',1*1024*1024));
4930+INSERT INTO t1 (data) VALUES (repeat('b',16*1024*1024-1024));
4931+delete from t1 where left(data,1)='b';
4932+
4933+# now we have two blocks in the table, first is a 1M record and second is
4934+# a 16M delete block.
4935+
4936+UPDATE t1 set data=repeat('c',17*1024*1024);
4937+delete from t1 where left(data,1)='c';
4938+
4939+INSERT INTO t1 set data=repeat('a',18*1024*1024);
4940+select length(data) from t1;
4941+alter table t1 modify data blob;
4942+select length(data) from t1;
4943+drop table t1;
4944+
4945+CREATE TABLE t1 (data BLOB) ENGINE=myisam;
4946+INSERT INTO t1 (data) VALUES (NULL);
4947+UPDATE t1 set data=repeat('a',18*1024*1024);
4948+select length(data) from t1;
4949+drop table t1;
4950+
4951+disconnect con1;
4952+connection default;
4953+
4954+SET GLOBAL max_allowed_packet = @old_max_allowed_packet;
4955+SET GLOBAL max_heap_table_size = @old_max_heap_table_size;
4956--- /dev/null
4957+++ b/mysql-test/t/percona_heap_bug783366.test
4958@@ -0,0 +1,19 @@
4959+#
4960+# Test for bug lp:783366
4961+#
4962+
4963+--disable_warnings
4964+drop table if exists t1;
4965+--enable_warnings
4966+
4967+CREATE TABLE t1 (
4968+ f1 VARCHAR ( 128 ) ,
4969+ f2 VARCHAR ( 32 ),
4970+ PRIMARY KEY ( f2 ( 2 ) , f1 )
4971+)
4972+ENGINE=HEAP KEY_BLOCK_SIZE = 512;
4973+INSERT IGNORE INTO t1 VALUES ( 'te' , 'm') , ( NULL , 'think' );
4974+INSERT IGNORE INTO t1 VALUES ( 'te' , 'm') , ( NULL , 'think' );
4975+
4976+DROP TABLE t1;
4977+
4978--- /dev/null
4979+++ b/mysql-test/t/percona_heap_bug783451.test
4980@@ -0,0 +1,16 @@
4981+# Testcase for the bug https://bugs.launchpad.net/percona-projects-qa/+bug/783451
4982+# With dynamic row format in HEAP and the UPDATE statement that significantly
4983+# increases the data size, the table scan in-progress desyncs its table position state.
4984+# Run with Valgrind if it does not crash for you.
4985+--disable_warnings
4986+DROP TABLE IF EXISTS local_1_1;
4987+--enable_warnings
4988+CREATE TABLE IF NOT EXISTS local_1_1 ( f1 VARCHAR ( 32 ) NOT NULL , f2 VARCHAR ( 128 ) NOT NULL DEFAULT 'cboepfaobilcchabvglgjdbynog' , f3 VARCHAR ( 32 ) NOT NULL , f4 VARBINARY ( 32 ) NOT NULL , f5 VARBINARY ( 1024 ) DEFAULT 'ycboepfao' , KEY ( f1 /* ( 2 ) */ , f2 /* ( 2 ) */ ) ) ENGINE=HEAP KEY_BLOCK_SIZE = 512;
4989+INSERT IGNORE INTO local_1_1 VALUES ( REPEAT( 'ervydbimvmbqmsowdbsa' , 1 ) , 'v' , NULL , NULL , REPEAT( 'mervydbimvmbqms' , 5 ) ) , ( 'p' , 6 , 'n' , REPEAT( 'imervydbimvmbqmsowdbs' , 4 ) , 'do' ) , ( NULL , NULL , REPEAT( 'himervydbimvmbqmsowdbsaybudvwaamvhempuublmia' , 6 ) , REPEAT('X', POW(2, 20) * 2) , REPEAT('X', POW(2, 20) * 2) ) , ( REPEAT('X', POW(2, 20) * 2) , REPEAT( 'Y' , 763 ) , NULL , REPEAT('X', POW(2, 20) * 2) , NULL ) , ( REPEAT('X', POW(2, 20) * 2) , 'time' , 'how' , 2 , REPEAT( 'Y' , 107 ) ) , ( REPEAT( 'hyshimervydbimvmbqmsowdbsaybud' , 5 ) , 2 , 8 , NULL , REPEAT('X', POW(2, 20) * 2) ) , ( 'come' , NULL , 'i' , NULL , REPEAT('X', POW(2, 20) * 2) );
4990+INSERT IGNORE INTO local_1_1 VALUES ( 'ok' , NULL , REPEAT( 'Y' , 651 ) , 2 , 5 ) , ( REPEAT( 'zylcdzkfrqpihyshimervydbimvmbqmsowdbsaybu' , 3 ) , REPEAT( 'Y' , 282 ) , REPEAT( 'X' , 0 ) , REPEAT( 'Y' , 369 ) , 'g' ) , ( 'think' , REPEAT('X', POW(2, 20) * 2), NULL , NULL , REPEAT('X', POW(2, 20) * 2) ) , ( REPEAT( 'Y' , 468 ) , REPEAT( 'dfvbrzylcd' , 6 ) , REPEAT( 'Y' , 264 ) , NULL , 'c' ) , ( NULL , NULL , REPEAT( 'srdfvbrzylcdzkfrqpihyshimervydbimvmbqms' , 0 ) , REPEAT( 'Y' , 244 ) , 7 ) , ( REPEAT( 'Y' , 0 ) , 'how' , 'going' , 'q' , NULL );
4991+INSERT IGNORE INTO local_1_1 VALUES ( REPEAT('X', POW(2, 20) * 2) , NULL , NULL , NULL , REPEAT('X', POW(2, 20) * 2) ) , ( REPEAT('X', POW(2, 20) * 2) , NULL , REPEAT('X', POW(2, 20) * 2) , 'this' , 'e' ) , ( NULL , 'think' , NULL , 'were' , NULL ) , ( 9 , 'l' , 'c' , 3 , REPEAT( 'geysrdfvbrzylcdzkfrqpihyshimervydbi' , 5 ) ) , ( NULL , NULL , NULL , 'h' , 'w' );
4992+--enable_warnings
4993+INSERT IGNORE INTO local_1_1 SELECT * FROM local_1_1;
4994+INSERT IGNORE INTO local_1_1 SELECT * FROM local_1_1;
4995+UPDATE local_1_1 SET f5 = REPEAT ('X', 215566);
4996+DROP TABLE local_1_1;
4997--- /dev/null
4998+++ b/mysql-test/t/percona_heap_bug784464.test
4999@@ -0,0 +1,64 @@
5000+#
5001+# Bug #784464: Silent conversion from Dynamic to Fixed row_format for certain
5002+# values of key_block_size.
5003+# Also see percona_heap_bug784464_32bit and percona_heap_bug784464_64bit tests.
5004+#
5005+
5006+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
5007+ PRIMARY KEY (f1)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5008+--replace_column 6 X 8 X
5009+SHOW TABLE STATUS LIKE 't1';
5010+DROP TABLE t1;
5011+
5012+--error ER_CANT_USE_OPTION_HERE
5013+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
5014+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=33 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5015+SHOW TABLE STATUS LIKE 't1';
5016+
5017+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
5018+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=34 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5019+--replace_column 6 X 8 X
5020+SHOW TABLE STATUS LIKE 't1';
5021+DROP TABLE t1;
5022+
5023+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
5024+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=123 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5025+--replace_column 6 X 8 X
5026+SHOW TABLE STATUS LIKE 't1';
5027+DROP TABLE t1;
5028+
5029+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
5030+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=1000 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5031+--replace_column 6 X 8 X
5032+SHOW TABLE STATUS LIKE 't1';
5033+DROP TABLE t1;
5034+
5035+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
5036+ PRIMARY KEY (f1)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5037+--replace_column 6 X 8 X
5038+SHOW TABLE STATUS LIKE 't1';
5039+DROP TABLE t1;
5040+
5041+--error ER_CANT_USE_OPTION_HERE
5042+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
5043+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=33 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5044+SHOW TABLE STATUS LIKE 't1';
5045+
5046+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
5047+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=34 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5048+--replace_column 6 X 8 X
5049+SHOW TABLE STATUS LIKE 't1';
5050+DROP TABLE t1;
5051+
5052+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
5053+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=121 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5054+--replace_column 6 X 8 X
5055+SHOW TABLE STATUS LIKE 't1';
5056+DROP TABLE t1;
5057+
5058+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
5059+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=1000 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5060+--replace_column 6 X 8 X
5061+SHOW TABLE STATUS LIKE 't1';
5062+DROP TABLE t1;
5063+
5064--- /dev/null
5065+++ b/mysql-test/t/percona_heap_bug784464_32bit.test
5066@@ -0,0 +1,15 @@
5067+# 32-bit platform specific parts of tests for LP bug #784464
5068+
5069+--source include/have_32bit.inc
5070+
5071+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
5072+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=124 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5073+--replace_column 6 X 8 X
5074+SHOW TABLE STATUS LIKE 't1';
5075+DROP TABLE t1;
5076+
5077+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
5078+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=122 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5079+--replace_column 6 X 8 X
5080+SHOW TABLE STATUS LIKE 't1';
5081+DROP TABLE t1;
5082--- /dev/null
5083+++ b/mysql-test/t/percona_heap_bug784464_64bit.test
5084@@ -0,0 +1,15 @@
5085+# 64-bit platform specific parts of tests for LP bug #784464
5086+
5087+--source include/have_64bit.inc
5088+
5089+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(32), f3 VARCHAR(32), f4 VARCHAR(32),
5090+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=124 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5091+--replace_column 6 X 8 X
5092+SHOW TABLE STATUS LIKE 't1';
5093+DROP TABLE t1;
5094+
5095+CREATE TABLE t1 (f1 VARCHAR(32), f2 VARCHAR(96),
5096+ PRIMARY KEY (f1)) KEY_BLOCK_SIZE=122 ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5097+--replace_column 6 X 8 X
5098+SHOW TABLE STATUS LIKE 't1';
5099+DROP TABLE t1;
5100--- /dev/null
5101+++ b/mysql-test/t/percona_heap_bug784468.test
5102@@ -0,0 +1,19 @@
5103+#
5104+# Bug #784468: Tables with VARCHAR(<31) are created as row_format = Fixed
5105+#
5106+
5107+CREATE TABLE t1 ( f1 VARCHAR(30)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5108+--replace_column 8 X
5109+SHOW TABLE STATUS LIKE 't1';
5110+DROP TABLE t1;
5111+
5112+CREATE TABLE t1 ( f1 VARCHAR(31)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5113+--replace_column 8 X
5114+SHOW TABLE STATUS LIKE 't1';
5115+DROP TABLE t1;
5116+
5117+CREATE TABLE t1 ( f1 VARCHAR(32)) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5118+--replace_column 8 X
5119+SHOW TABLE STATUS LIKE 't1';
5120+DROP TABLE t1;
5121+
5122--- /dev/null
5123+++ b/mysql-test/t/percona_heap_bug788544.test
5124@@ -0,0 +1,15 @@
5125+#
5126+# Bug #788544: Valgrind warnings/crash in mysql-55-eb-blobs in
5127+# hp_extract_record / hp_process_field_data_to_chunkset
5128+#
5129+
5130+CREATE TABLE t1 (f2 VARCHAR (32), f4 LONGBLOB, f5 TEXT) ENGINE=HEAP;
5131+
5132+INSERT INTO t1 VALUES ('a', NULL, NULL),
5133+ ('b' , REPEAT('a' , 593338), REPEAT('a', 800));
5134+
5135+UPDATE t1 SET f2 = 'c' WHERE f4 = 'd';
5136+
5137+SELECT LENGTH(f2), LENGTH(f4), LENGTH(f5) FROM t1;
5138+
5139+DROP TABLE t1;
5140--- /dev/null
5141+++ b/mysql-test/t/percona_heap_bug788576.test
5142@@ -0,0 +1,19 @@
5143+#
5144+# Bug #788576: Second crash in hp_movelink with mysql-55-eb
5145+#
5146+
5147+CREATE TABLE t1 (f1 VARCHAR (32), f2 VARCHAR (128), f3 VARBINARY (128),
5148+ f4 VARBINARY (512), f5 VARBINARY (1024),
5149+ KEY (f2(1))) ENGINE=HEAP ROW_FORMAT=DYNAMIC;
5150+
5151+INSERT IGNORE INTO t1 VALUES (2, NULL, 6, REPEAT('glugcgqk', 5), 'look'),
5152+ (REPEAT( 'kglugcgqkin', 6), 'if', 'was', NULL, NULL),
5153+ (NULL, NULL, NULL, NULL, 7);
5154+
5155+SELECT * FROM t1;
5156+
5157+DELETE FROM t1 WHERE f5 <=> NULL;
5158+
5159+SELECT * FROM t1;
5160+
5161+DROP TABLE t1;
5162--- /dev/null
5163+++ b/mysql-test/t/percona_heap_bug788722.test
5164@@ -0,0 +1,20 @@
5165+#
5166+# Bug #788722: Second valgrind warning around hp_extract_record in mysql-55-eb-blobs
5167+#
5168+
5169+CREATE TABLE IF NOT EXISTS local_1_1 (f1 VARCHAR (32) NOT NULL,
5170+ f2 VARCHAR (128) NOT NULL,
5171+ f3 BLOB NOT NULL,
5172+ f4 TEXT,
5173+ f5 BLOB (1024),
5174+ PRIMARY KEY (f1),
5175+ KEY (f1 , f2)
5176+) ENGINE=HEAP ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE = 2048;
5177+
5178+INSERT IGNORE INTO local_1_1 VALUES
5179+ (REPEAT('egqeqfxwaejpqixuvvtentruyqadxiybjdfqjspfbyjdjczrrwjnagkzsoagatqookhsgtrvvbxacppljfzaseidqggxvuirm' , 5), NULL, NULL, NULL, REPEAT('hegqeqfxwaejpqixuvvtentruyqadxiy', 1)),
5180+ ('you', NULL, 0, REPEAT("X", 2048) , 0);
5181+
5182+INSERT IGNORE INTO local_1_1 SELECT * FROM local_1_1;
5183+
5184+DROP TABLE local_1_1;
5185--- /dev/null
5186+++ b/mysql-test/t/percona_heap_bug789131.test
5187@@ -0,0 +1,14 @@
5188+#
5189+# Bug #789131: Valgrind warning in MyISAM in mysql-55-eb-blobs
5190+#
5191+
5192+CREATE TABLE t1 (f1 VARCHAR (128), f2 VARCHAR (128), f3 VARBINARY (512),
5193+ f4 TEXT (65525), f5 VARCHAR (128), KEY (f1(1))) ENGINE=HEAP;
5194+
5195+INSERT IGNORE INTO t1 VALUES
5196+ ( 'o' , "" , NULL , "" , 0 ) ,
5197+ (NULL, "" , "" , "" , 'f' ) ;
5198+
5199+INSERT IGNORE INTO t1 SELECT * FROM t1;
5200+
5201+DROP TABLE t1;
5202\ No newline at end of file
5203--- /dev/null
5204+++ b/mysql-test/t/percona_heap_var.test
5205@@ -0,0 +1,85 @@
5206+#
5207+# Test heap tables with variable-sized records.
5208+#
5209+
5210+--disable_warnings
5211+drop table if exists t1;
5212+--enable_warnings
5213+
5214+set @@session.max_heap_table_size=16*1024*1024;
5215+
5216+--error 1234
5217+create table t1 (a int not null, b varchar(400), c int, primary key (a), key (c)) engine=heap comment="testing heaps" key_block_size=128;
5218+
5219+--error 1234
5220+create table t1 (a int not null, b int, c varchar(400), primary key (a), key (b)) engine=heap comment="testing heaps" key_block_size=4;
5221+
5222+create table t1 (a int not null, b int, c varchar(400), d varchar(400), primary key (a), key (b)) engine=heap comment="testing heaps" key_block_size=24;
5223+
5224+--replace_column 6 X 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
5225+--query_vertical show table status like "t1"
5226+
5227+insert into t1 values (1,1,'012',NULL), (2,2,'0123456789',NULL), (3,3,'012345678901234567890123456789',NULL), (4,4,NULL,'0123456789012345678901234567890123456789012345678901234567890123456789');
5228+select * from t1;
5229+
5230+delete from t1 where a = 3;
5231+select * from t1;
5232+
5233+insert into t1 values (5,5,NULL,'0123'), (6,6,NULL,'0123');
5234+select * from t1;
5235+
5236+update t1 set c = '012345678901234567890123456789' where a = 2;
5237+select * from t1;
5238+
5239+update t1 set c = '0123456789' where a = 2;
5240+select * from t1;
5241+
5242+insert into t1 values (7,7,'0123',NULL), (8,8,'0123',NULL);
5243+select * from t1;
5244+
5245+--replace_column 6 X 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
5246+--query_vertical show table status like "t1"
5247+alter table t1 key_block_size = 0;
5248+--replace_column 6 X 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
5249+--query_vertical show table status like "t1"
5250+alter table t1 row_format = dynamic;
5251+--replace_column 6 X 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
5252+--replace_regex /KEY_BLOCK_SIZE=[[:digit:]]+/KEY_BLOCK_SIZE=X/
5253+--query_vertical show table status like "t1"
5254+alter table t1 key_block_size = 128, max_rows = 10001;
5255+--replace_column 6 X 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
5256+--query_vertical show table status like "t1"
5257+
5258+select * from t1;
5259+
5260+delete from t1;
5261+select * from t1;
5262+
5263+let $1=10001;
5264+
5265+call mtr.add_suppression("The table 't1' is full");
5266+
5267+disable_query_log;
5268+
5269+while ($1)
5270+{
5271+
5272+ eval insert into t1 values ($1,$1,$1,$1);
5273+
5274+ dec $1;
5275+
5276+}
5277+enable_query_log;
5278+
5279+select count(*) from t1;
5280+
5281+--error 1114
5282+insert into t1 values (100000,100000,NULL,'0123'), (100000,100000,NULL,'0123');
5283+
5284+--replace_column 6 X 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
5285+--query_vertical show table status like "t1"
5286+select count(*) from t1;
5287+
5288+set @@session.max_heap_table_size=default;
5289+
5290+drop table t1;
This page took 5.159086 seconds and 4 git commands to generate.