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