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