1 /*
2    Copyright (c) 2000, 2011, Oracle and/or its affiliates
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
16 
17 
18 #ifdef USE_PRAGMA_IMPLEMENTATION
19 #pragma implementation				// gcc: Class implementation
20 #endif
21 
22 #define MYSQL_SERVER 1
23 #include "heapdef.h"
24 #include "sql_priv.h"
25 #include "sql_plugin.h"
26 #include "ha_heap.h"
27 #include "sql_base.h"                    // enum_tdc_remove_table_type
28 
29 static handler *heap_create_handler(handlerton *, TABLE_SHARE *, MEM_ROOT *);
30 static int heap_prepare_hp_create_info(TABLE *, bool, HP_CREATE_INFO *);
31 
32 
heap_panic(handlerton * hton,ha_panic_function flag)33 int heap_panic(handlerton *hton, ha_panic_function flag)
34 {
35   return hp_panic(flag);
36 }
37 
38 
heap_init(void * p)39 int heap_init(void *p)
40 {
41   handlerton *heap_hton;
42 
43 #ifdef HAVE_PSI_INTERFACE
44   init_heap_psi_keys();
45 #endif
46 
47   heap_hton= (handlerton *)p;
48   heap_hton->state=      SHOW_OPTION_YES;
49   heap_hton->db_type=    DB_TYPE_HEAP;
50   heap_hton->create=     heap_create_handler;
51   heap_hton->panic=      heap_panic;
52   heap_hton->flags=      HTON_CAN_RECREATE;
53 
54   return 0;
55 }
56 
heap_create_handler(handlerton * hton,TABLE_SHARE * table,MEM_ROOT * mem_root)57 static handler *heap_create_handler(handlerton *hton,
58                                     TABLE_SHARE *table,
59                                     MEM_ROOT *mem_root)
60 {
61   return new (mem_root) ha_heap(hton, table);
62 }
63 
64 
65 /*****************************************************************************
66 ** HEAP tables
67 *****************************************************************************/
68 
ha_heap(handlerton * hton,TABLE_SHARE * table_arg)69 ha_heap::ha_heap(handlerton *hton, TABLE_SHARE *table_arg)
70   :handler(hton, table_arg), file(0), records_changed(0), key_stat_version(0),
71   internal_table(0)
72 {}
73 
74 /*
75   Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
76   rec_per_key) after 1/HEAP_STATS_UPDATE_THRESHOLD fraction of table records
77   have been inserted/updated/deleted. delete_all_rows() and table flush cause
78   immediate update.
79 
80   NOTE
81    hash index statistics must be updated when number of table records changes
82    from 0 to non-zero value and vice versa. Otherwise records_in_range may
83    erroneously return 0 and 'range' may miss records.
84 */
85 #define HEAP_STATS_UPDATE_THRESHOLD 10
86 
open(const char * name,int mode,uint test_if_locked)87 int ha_heap::open(const char *name, int mode, uint test_if_locked)
88 {
89   internal_table= MY_TEST(test_if_locked & HA_OPEN_INTERNAL_TABLE);
90   if (internal_table || (!(file= heap_open(name, mode)) && my_errno == ENOENT))
91   {
92     HP_CREATE_INFO create_info;
93     my_bool created_new_share;
94     int rc;
95     file= 0;
96     if (heap_prepare_hp_create_info(table, internal_table, &create_info))
97       goto end;
98     create_info.pin_share= TRUE;
99 
100     rc= heap_create(name, &create_info, &internal_share, &created_new_share);
101     my_free(create_info.keydef);
102     if (rc)
103       goto end;
104 
105     implicit_emptied= MY_TEST(created_new_share);
106     if (internal_table)
107       file= heap_open_from_share(internal_share, mode);
108     else
109       file= heap_open_from_share_and_register(internal_share, mode);
110 
111     if (!file)
112     {
113       heap_release_share(internal_share, internal_table);
114       goto end;
115     }
116   }
117 
118   ref_length= sizeof(HEAP_PTR);
119   /* Initialize variables for the opened table */
120   set_keys_for_scanning();
121   /*
122     We cannot run update_key_stats() here because we do not have a
123     lock on the table. The 'records' count might just be changed
124     temporarily at this moment and we might get wrong statistics (Bug
125     #10178). Instead we request for update. This will be done in
126     ha_heap::info(), which is always called before key statistics are
127     used.
128     */
129   key_stat_version= file->s->key_stat_version-1;
130 end:
131   return (file ? 0 : 1);
132 }
133 
close(void)134 int ha_heap::close(void)
135 {
136   return internal_table ? hp_close(file) : heap_close(file);
137 }
138 
139 
140 /*
141   Create a copy of this table
142 
143   DESCRIPTION
144     Do same as default implementation but use file->s->name instead of
145     table->s->path. This is needed by Windows where the clone() call sees
146     '/'-delimited path in table->s->path, while ha_heap::open() was called
147     with '\'-delimited path.
148 */
149 
clone(const char * name,MEM_ROOT * mem_root)150 handler *ha_heap::clone(const char *name, MEM_ROOT *mem_root)
151 {
152   handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
153   if (new_handler && !new_handler->ha_open(table, file->s->name, table->db_stat,
154                                            HA_OPEN_IGNORE_IF_LOCKED))
155     return new_handler;
156   return NULL;  /* purecov: inspected */
157 }
158 
159 
160 /*
161   Compute which keys to use for scanning
162 
163   SYNOPSIS
164     set_keys_for_scanning()
165     no parameter
166 
167   DESCRIPTION
168     Set the bitmap btree_keys, which is used when the upper layers ask
169     which keys to use for scanning. For each btree index the
170     corresponding bit is set.
171 
172   RETURN
173     void
174 */
175 
set_keys_for_scanning(void)176 void ha_heap::set_keys_for_scanning(void)
177 {
178   btree_keys.clear_all();
179   for (uint i= 0 ; i < table->s->keys ; i++)
180   {
181     if (table->key_info[i].algorithm == HA_KEY_ALG_BTREE)
182       btree_keys.set_bit(i);
183   }
184 }
185 
186 
can_continue_handler_scan()187 int ha_heap::can_continue_handler_scan()
188 {
189   int error= 0;
190   if ((file->key_version != file->s->key_version && inited == INDEX) ||
191       (file->file_version != file->s->file_version && inited == RND))
192   {
193     /* Data changed, not safe to do index or rnd scan */
194     error= HA_ERR_RECORD_CHANGED;
195   }
196   return error;
197 }
198 
199 
update_key_stats()200 void ha_heap::update_key_stats()
201 {
202   for (uint i= 0; i < table->s->keys; i++)
203   {
204     KEY *key=table->key_info+i;
205     if (!key->rec_per_key)
206       continue;
207     if (key->algorithm != HA_KEY_ALG_BTREE)
208     {
209       if (key->flags & HA_NOSAME)
210         key->rec_per_key[key->user_defined_key_parts-1]= 1;
211       else
212       {
213         ha_rows hash_buckets= file->s->keydef[i].hash_buckets;
214         ulong no_records= hash_buckets ? (ulong)(file->s->records/hash_buckets) : 2;
215         if (no_records < 2)
216           no_records= 2;
217         key->rec_per_key[key->user_defined_key_parts-1]= no_records;
218       }
219     }
220   }
221   records_changed= 0;
222   /* At the end of update_key_stats() we can proudly claim they are OK. */
223   key_stat_version= file->s->key_stat_version;
224 }
225 
226 
write_row(uchar * buf)227 int ha_heap::write_row(uchar * buf)
228 {
229   int res;
230   if (table->next_number_field && buf == table->record[0])
231   {
232     if ((res= update_auto_increment()))
233       return res;
234   }
235   res= heap_write(file,buf);
236   if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
237                file->s->records))
238   {
239     /*
240        We can perform this safely since only one writer at the time is
241        allowed on the table.
242     */
243     records_changed= 0;
244     file->s->key_stat_version++;
245   }
246   return res;
247 }
248 
update_row(const uchar * old_data,const uchar * new_data)249 int ha_heap::update_row(const uchar * old_data, const uchar * new_data)
250 {
251   int res;
252   res= heap_update(file,old_data,new_data);
253   if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
254               file->s->records)
255   {
256     /*
257        We can perform this safely since only one writer at the time is
258        allowed on the table.
259     */
260     records_changed= 0;
261     file->s->key_stat_version++;
262   }
263   return res;
264 }
265 
delete_row(const uchar * buf)266 int ha_heap::delete_row(const uchar * buf)
267 {
268   int res;
269   res= heap_delete(file,buf);
270   if (!res && table->s->tmp_table == NO_TMP_TABLE &&
271       ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
272   {
273     /*
274        We can perform this safely since only one writer at the time is
275        allowed on the table.
276     */
277     records_changed= 0;
278     file->s->key_stat_version++;
279   }
280   return res;
281 }
282 
index_read_map(uchar * buf,const uchar * key,key_part_map keypart_map,enum ha_rkey_function find_flag)283 int ha_heap::index_read_map(uchar *buf, const uchar *key,
284                             key_part_map keypart_map,
285                             enum ha_rkey_function find_flag)
286 {
287   DBUG_ASSERT(inited==INDEX);
288   int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
289   return error;
290 }
291 
index_read_last_map(uchar * buf,const uchar * key,key_part_map keypart_map)292 int ha_heap::index_read_last_map(uchar *buf, const uchar *key,
293                                  key_part_map keypart_map)
294 {
295   DBUG_ASSERT(inited==INDEX);
296   int error= heap_rkey(file, buf, active_index, key, keypart_map,
297 		       HA_READ_PREFIX_LAST);
298   return error;
299 }
300 
index_read_idx_map(uchar * buf,uint index,const uchar * key,key_part_map keypart_map,enum ha_rkey_function find_flag)301 int ha_heap::index_read_idx_map(uchar *buf, uint index, const uchar *key,
302                                 key_part_map keypart_map,
303                                 enum ha_rkey_function find_flag)
304 {
305   int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
306   return error;
307 }
308 
index_next(uchar * buf)309 int ha_heap::index_next(uchar * buf)
310 {
311   DBUG_ASSERT(inited==INDEX);
312   int error=heap_rnext(file,buf);
313   return error;
314 }
315 
index_prev(uchar * buf)316 int ha_heap::index_prev(uchar * buf)
317 {
318   DBUG_ASSERT(inited==INDEX);
319   int error=heap_rprev(file,buf);
320   return error;
321 }
322 
index_first(uchar * buf)323 int ha_heap::index_first(uchar * buf)
324 {
325   DBUG_ASSERT(inited==INDEX);
326   int error=heap_rfirst(file, buf, active_index);
327   return error;
328 }
329 
index_last(uchar * buf)330 int ha_heap::index_last(uchar * buf)
331 {
332   DBUG_ASSERT(inited==INDEX);
333   int error=heap_rlast(file, buf, active_index);
334   return error;
335 }
336 
rnd_init(bool scan)337 int ha_heap::rnd_init(bool scan)
338 {
339   return scan ? heap_scan_init(file) : 0;
340 }
341 
rnd_next(uchar * buf)342 int ha_heap::rnd_next(uchar *buf)
343 {
344   int error=heap_scan(file, buf);
345   return error;
346 }
347 
rnd_pos(uchar * buf,uchar * pos)348 int ha_heap::rnd_pos(uchar * buf, uchar *pos)
349 {
350   int error;
351   HEAP_PTR heap_position;
352   memcpy(&heap_position, pos, sizeof(HEAP_PTR));
353   error=heap_rrnd(file, buf, heap_position);
354   return error;
355 }
356 
position(const uchar * record)357 void ha_heap::position(const uchar *record)
358 {
359   *(HEAP_PTR*) ref= heap_position(file);	// Ref is aligned
360 }
361 
info(uint flag)362 int ha_heap::info(uint flag)
363 {
364   HEAPINFO hp_info;
365 
366   (void) heap_info(file,&hp_info,flag);
367 
368   errkey=                     hp_info.errkey;
369   stats.records=              hp_info.records;
370   stats.deleted=              hp_info.deleted;
371   stats.mean_rec_length=      hp_info.reclength;
372   stats.data_file_length=     hp_info.data_length;
373   stats.index_file_length=    hp_info.index_length;
374   stats.max_data_file_length= hp_info.max_records * hp_info.reclength;
375   stats.delete_length=        hp_info.deleted * hp_info.reclength;
376   stats.create_time=          (ulong) hp_info.create_time;
377   if (flag & HA_STATUS_AUTO)
378     stats.auto_increment_value= hp_info.auto_increment;
379   /*
380     If info() is called for the first time after open(), we will still
381     have to update the key statistics. Hoping that a table lock is now
382     in place.
383   */
384   if (key_stat_version != file->s->key_stat_version)
385     update_key_stats();
386   return 0;
387 }
388 
389 
extra(enum ha_extra_function operation)390 int ha_heap::extra(enum ha_extra_function operation)
391 {
392   return heap_extra(file,operation);
393 }
394 
395 
reset()396 int ha_heap::reset()
397 {
398   return heap_reset(file);
399 }
400 
401 
delete_all_rows()402 int ha_heap::delete_all_rows()
403 {
404   heap_clear(file);
405   if (table->s->tmp_table == NO_TMP_TABLE)
406   {
407     /*
408        We can perform this safely since only one writer at the time is
409        allowed on the table.
410     */
411     file->s->key_stat_version++;
412   }
413   return 0;
414 }
415 
416 
reset_auto_increment(ulonglong value)417 int ha_heap::reset_auto_increment(ulonglong value)
418 {
419   file->s->auto_increment= value;
420   return 0;
421 }
422 
423 
external_lock(THD * thd,int lock_type)424 int ha_heap::external_lock(THD *thd, int lock_type)
425 {
426 #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
427   if (lock_type == F_UNLCK && file->s->changed && heap_check_heap(file, 0))
428     return HA_ERR_CRASHED;
429 #endif
430   return 0;					// No external locking
431 }
432 
433 
434 /*
435   Disable indexes.
436 
437   SYNOPSIS
438     disable_indexes()
439     mode        mode of operation:
440                 HA_KEY_SWITCH_NONUNIQ      disable all non-unique keys
441                 HA_KEY_SWITCH_ALL          disable all keys
442                 HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
443                 HA_KEY_SWITCH_ALL_SAVE     dis. all keys and make persistent
444 
445   DESCRIPTION
446     Disable indexes and clear keys to use for scanning.
447 
448   IMPLEMENTATION
449     HA_KEY_SWITCH_NONUNIQ       is not implemented.
450     HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
451     HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.
452 
453   RETURN
454     0  ok
455     HA_ERR_WRONG_COMMAND  mode not implemented.
456 */
457 
disable_indexes(uint mode)458 int ha_heap::disable_indexes(uint mode)
459 {
460   int error;
461 
462   if (mode == HA_KEY_SWITCH_ALL)
463   {
464     if (!(error= heap_disable_indexes(file)))
465       set_keys_for_scanning();
466   }
467   else
468   {
469     /* mode not implemented */
470     error= HA_ERR_WRONG_COMMAND;
471   }
472   return error;
473 }
474 
475 
476 /*
477   Enable indexes.
478 
479   SYNOPSIS
480     enable_indexes()
481     mode        mode of operation:
482                 HA_KEY_SWITCH_NONUNIQ      enable all non-unique keys
483                 HA_KEY_SWITCH_ALL          enable all keys
484                 HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
485                 HA_KEY_SWITCH_ALL_SAVE     en. all keys and make persistent
486 
487   DESCRIPTION
488     Enable indexes and set keys to use for scanning.
489     The indexes might have been disabled by disable_index() before.
490     The function works only if both data and indexes are empty,
491     since the heap storage engine cannot repair the indexes.
492     To be sure, call handler::delete_all_rows() before.
493 
494   IMPLEMENTATION
495     HA_KEY_SWITCH_NONUNIQ       is not implemented.
496     HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
497     HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.
498 
499   RETURN
500     0  ok
501     HA_ERR_CRASHED  data or index is non-empty. Delete all rows and retry.
502     HA_ERR_WRONG_COMMAND  mode not implemented.
503 */
504 
enable_indexes(uint mode)505 int ha_heap::enable_indexes(uint mode)
506 {
507   int error;
508 
509   if (mode == HA_KEY_SWITCH_ALL)
510   {
511     if (!(error= heap_enable_indexes(file)))
512       set_keys_for_scanning();
513   }
514   else
515   {
516     /* mode not implemented */
517     error= HA_ERR_WRONG_COMMAND;
518   }
519   return error;
520 }
521 
522 
523 /*
524   Test if indexes are disabled.
525 
526   SYNOPSIS
527     indexes_are_disabled()
528     no parameters
529 
530   RETURN
531     0  indexes are not disabled
532     1  all indexes are disabled
533    [2  non-unique indexes are disabled - NOT YET IMPLEMENTED]
534 */
535 
indexes_are_disabled(void)536 int ha_heap::indexes_are_disabled(void)
537 {
538   return heap_indexes_are_disabled(file);
539 }
540 
store_lock(THD * thd,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)541 THR_LOCK_DATA **ha_heap::store_lock(THD *thd,
542 				    THR_LOCK_DATA **to,
543 				    enum thr_lock_type lock_type)
544 {
545   if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
546     file->lock.type=lock_type;
547   *to++= &file->lock;
548   return to;
549 }
550 
551 /*
552   We have to ignore ENOENT entries as the HEAP table is created on open and
553   not when doing a CREATE on the table.
554 */
555 
delete_table(const char * name)556 int ha_heap::delete_table(const char *name)
557 {
558   int error= heap_delete_table(name);
559   return error == ENOENT ? 0 : error;
560 }
561 
562 
drop_table(const char * name)563 void ha_heap::drop_table(const char *name)
564 {
565   file->s->delete_on_close= 1;
566   ha_close();
567 }
568 
569 
rename_table(const char * from,const char * to)570 int ha_heap::rename_table(const char * from, const char * to)
571 {
572   return heap_rename(from,to);
573 }
574 
575 
records_in_range(uint inx,key_range * min_key,key_range * max_key)576 ha_rows ha_heap::records_in_range(uint inx, key_range *min_key,
577                                   key_range *max_key)
578 {
579   KEY *key=table->key_info+inx;
580   if (key->algorithm == HA_KEY_ALG_BTREE)
581     return hp_rb_records_in_range(file, inx, min_key, max_key);
582 
583   if (!min_key || !max_key ||
584       min_key->length != max_key->length ||
585       min_key->length != key->key_length ||
586       min_key->flag != HA_READ_KEY_EXACT ||
587       max_key->flag != HA_READ_AFTER_KEY)
588     return HA_POS_ERROR;			// Can only use exact keys
589 
590   if (stats.records <= 1)
591     return stats.records;
592 
593   /* Assert that info() did run. We need current statistics here. */
594   DBUG_ASSERT(key_stat_version == file->s->key_stat_version);
595   return key->rec_per_key[key->user_defined_key_parts-1];
596 }
597 
598 
heap_prepare_hp_create_info(TABLE * table_arg,bool internal_table,HP_CREATE_INFO * hp_create_info)599 static int heap_prepare_hp_create_info(TABLE *table_arg, bool internal_table,
600                                        HP_CREATE_INFO *hp_create_info)
601 {
602   TABLE_SHARE *share= table_arg->s;
603   uint key, parts, mem_per_row= 0, keys= share->keys;
604   uint auto_key= 0, auto_key_type= 0;
605   ha_rows max_rows;
606   HP_KEYDEF *keydef;
607   HA_KEYSEG *seg;
608   bool found_real_auto_increment= 0;
609 
610   bzero(hp_create_info, sizeof(*hp_create_info));
611 
612   for (key= parts= 0; key < keys; key++)
613     parts+= table_arg->key_info[key].user_defined_key_parts;
614 
615   if (!my_multi_malloc(MYF(MY_WME | MY_THREAD_SPECIFIC),
616                        &keydef, keys * sizeof(HP_KEYDEF),
617                        &seg, parts * sizeof(HA_KEYSEG),
618                        NULL))
619     return my_errno;
620   for (key= 0; key < keys; key++)
621   {
622     KEY *pos= table_arg->key_info+key;
623     KEY_PART_INFO *key_part=     pos->key_part;
624     KEY_PART_INFO *key_part_end= key_part + pos->user_defined_key_parts;
625 
626     keydef[key].keysegs=   (uint) pos->user_defined_key_parts;
627     keydef[key].flag=      (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
628     keydef[key].seg=       seg;
629 
630     switch (pos->algorithm) {
631     case HA_KEY_ALG_UNDEF:
632     case HA_KEY_ALG_HASH:
633       keydef[key].algorithm= HA_KEY_ALG_HASH;
634       mem_per_row+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
635       break;
636     case HA_KEY_ALG_BTREE:
637       keydef[key].algorithm= HA_KEY_ALG_BTREE;
638       mem_per_row+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*);
639       break;
640     default:
641       DBUG_ASSERT(0); // cannot happen
642     }
643 
644     for (; key_part != key_part_end; key_part++, seg++)
645     {
646       Field *field= key_part->field;
647 
648       if (pos->algorithm == HA_KEY_ALG_BTREE)
649 	seg->type= field->key_type();
650       else
651       {
652         if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
653             seg->type != HA_KEYTYPE_VARTEXT1 &&
654             seg->type != HA_KEYTYPE_VARTEXT2 &&
655             seg->type != HA_KEYTYPE_VARBINARY1 &&
656             seg->type != HA_KEYTYPE_VARBINARY2 &&
657             seg->type != HA_KEYTYPE_BIT)
658           seg->type= HA_KEYTYPE_BINARY;
659       }
660       seg->start=   (uint) key_part->offset;
661       seg->length=  (uint) key_part->length;
662       seg->flag=    key_part->key_part_flag;
663 
664       if (field->flags & (ENUM_FLAG | SET_FLAG))
665         seg->charset= &my_charset_bin;
666       else
667         seg->charset= field->charset_for_protocol();
668       if (field->null_ptr)
669       {
670 	seg->null_bit= field->null_bit;
671 	seg->null_pos= (uint) (field->null_ptr - (uchar*) table_arg->record[0]);
672       }
673       else
674       {
675 	seg->null_bit= 0;
676 	seg->null_pos= 0;
677       }
678       if (field->flags & AUTO_INCREMENT_FLAG &&
679           table_arg->found_next_number_field &&
680           key == share->next_number_index)
681       {
682         /*
683           Store key number and type for found auto_increment key
684           We have to store type as seg->type can differ from it
685         */
686         auto_key= key+ 1;
687 	auto_key_type= field->key_type();
688       }
689       if (seg->type == HA_KEYTYPE_BIT)
690       {
691         seg->bit_length= ((Field_bit *) field)->bit_len;
692         seg->bit_start= ((Field_bit *) field)->bit_ofs;
693         seg->bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
694                                           (uchar*) table_arg->record[0]);
695       }
696       else
697       {
698         seg->bit_length= seg->bit_start= 0;
699         seg->bit_pos= 0;
700       }
701     }
702   }
703   mem_per_row+= MY_ALIGN(MY_MAX(share->reclength, sizeof(char*)) + 1, sizeof(char*));
704   if (table_arg->found_next_number_field)
705   {
706     keydef[share->next_number_index].flag|= HA_AUTO_KEY;
707     found_real_auto_increment= share->next_number_key_offset == 0;
708   }
709   hp_create_info->auto_key= auto_key;
710   hp_create_info->auto_key_type= auto_key_type;
711   hp_create_info->max_table_size=current_thd->variables.max_heap_table_size;
712   hp_create_info->with_auto_increment= found_real_auto_increment;
713   hp_create_info->internal_table= internal_table;
714 
715   max_rows= (ha_rows) (hp_create_info->max_table_size / mem_per_row);
716   if (share->max_rows && share->max_rows < max_rows)
717     max_rows= share->max_rows;
718 
719   hp_create_info->max_records= (ulong) MY_MIN(max_rows, ULONG_MAX);
720   hp_create_info->min_records= (ulong) MY_MIN(share->min_rows, ULONG_MAX);
721   hp_create_info->keys= share->keys;
722   hp_create_info->reclength= share->reclength;
723   hp_create_info->keydef= keydef;
724   return 0;
725 }
726 
727 
create(const char * name,TABLE * table_arg,HA_CREATE_INFO * create_info)728 int ha_heap::create(const char *name, TABLE *table_arg,
729 		    HA_CREATE_INFO *create_info)
730 {
731   int error;
732   my_bool created;
733   HP_CREATE_INFO hp_create_info;
734 
735   error= heap_prepare_hp_create_info(table_arg, internal_table,
736                                      &hp_create_info);
737   if (error)
738     return error;
739   hp_create_info.auto_increment= (create_info->auto_increment_value ?
740 				  create_info->auto_increment_value - 1 : 0);
741   error= heap_create(name, &hp_create_info, &internal_share, &created);
742   my_free(hp_create_info.keydef);
743   DBUG_ASSERT(file == 0);
744   return (error);
745 }
746 
747 
update_create_info(HA_CREATE_INFO * create_info)748 void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
749 {
750   table->file->info(HA_STATUS_AUTO);
751   if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
752     create_info->auto_increment_value= stats.auto_increment_value;
753 }
754 
get_auto_increment(ulonglong offset,ulonglong increment,ulonglong nb_desired_values,ulonglong * first_value,ulonglong * nb_reserved_values)755 void ha_heap::get_auto_increment(ulonglong offset, ulonglong increment,
756                                  ulonglong nb_desired_values,
757                                  ulonglong *first_value,
758                                  ulonglong *nb_reserved_values)
759 {
760   ha_heap::info(HA_STATUS_AUTO);
761   *first_value= stats.auto_increment_value;
762   /* such table has only table-level locking so reserves up to +inf */
763   *nb_reserved_values= ULONGLONG_MAX;
764 }
765 
766 
check_if_incompatible_data(HA_CREATE_INFO * info,uint table_changes)767 bool ha_heap::check_if_incompatible_data(HA_CREATE_INFO *info,
768 					 uint table_changes)
769 {
770   /* Check that auto_increment value was not changed */
771   if ((info->used_fields & HA_CREATE_USED_AUTO &&
772        info->auto_increment_value != 0) ||
773       table_changes == IS_EQUAL_NO ||
774       table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
775     return COMPATIBLE_DATA_NO;
776   return COMPATIBLE_DATA_YES;
777 }
778 
779 
780 /**
781   Find record by unique index (used in temporary tables with the index)
782 
783   @param record          (IN|OUT) the record to find
784   @param unique_idx      (IN) number of index (for this engine)
785 
786   @note It is like hp_search but uses function for raw where hp_search
787         uses functions for index.
788 
789   @retval  0 OK
790   @retval  1 Not found
791   @retval -1 Error
792 */
793 
find_unique_row(uchar * record,uint unique_idx)794 int ha_heap::find_unique_row(uchar *record, uint unique_idx)
795 {
796   DBUG_ENTER("ha_heap::find_unique_row");
797   HP_SHARE *share= file->s;
798   DBUG_ASSERT(inited==NONE);
799   HP_KEYDEF *keyinfo= share->keydef + unique_idx;
800   DBUG_ASSERT(keyinfo->algorithm == HA_KEY_ALG_HASH);
801   DBUG_ASSERT(keyinfo->flag & HA_NOSAME);
802   if (!share->records)
803     DBUG_RETURN(1); // not found
804   HASH_INFO *pos= hp_find_hash(&keyinfo->block,
805                                hp_mask(hp_rec_hashnr(keyinfo, record),
806                                        share->blength, share->records));
807   do
808   {
809     if (!hp_rec_key_cmp(keyinfo, pos->ptr_to_rec, record))
810     {
811       file->current_hash_ptr= pos;
812       file->current_ptr= pos->ptr_to_rec;
813       file->update = HA_STATE_AKTIV;
814       /*
815         We compare it only by record in the index, so better to read all
816         records.
817       */
818       memcpy(record, file->current_ptr, (size_t) share->reclength);
819 
820       DBUG_RETURN(0); // found and position set
821     }
822   }
823   while ((pos= pos->next_key));
824   DBUG_RETURN(1); // not found
825 }
826 
827 struct st_mysql_storage_engine heap_storage_engine=
828 { MYSQL_HANDLERTON_INTERFACE_VERSION };
829 
mysql_declare_plugin(heap)830 mysql_declare_plugin(heap)
831 {
832   MYSQL_STORAGE_ENGINE_PLUGIN,
833   &heap_storage_engine,
834   "MEMORY",
835   "MySQL AB",
836   "Hash based, stored in memory, useful for temporary tables",
837   PLUGIN_LICENSE_GPL,
838   heap_init,
839   NULL,
840   0x0100, /* 1.0 */
841   NULL,                       /* status variables                */
842   NULL,                       /* system variables                */
843   NULL,                       /* config options                  */
844   0,                          /* flags                           */
845 }
846 mysql_declare_plugin_end;
maria_declare_plugin(heap)847 maria_declare_plugin(heap)
848 {
849   MYSQL_STORAGE_ENGINE_PLUGIN,
850   &heap_storage_engine,
851   "MEMORY",
852   "MySQL AB",
853   "Hash based, stored in memory, useful for temporary tables",
854   PLUGIN_LICENSE_GPL,
855   heap_init,
856   NULL,
857   0x0100, /* 1.0 */
858   NULL,                       /* status variables                */
859   NULL,                       /* system variables                */
860   "1.0",                      /* string version */
861   MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
862 }
863 maria_declare_plugin_end;
864