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