Drizzled Public API Documentation

ha_heap.cc
1 /* Copyright (C) 2000-2006 MySQL AB
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "heap_priv.h"
17 #include <drizzled/error.h>
18 #include <drizzled/table.h>
19 #include <drizzled/session.h>
20 #include <drizzled/field/varstring.h>
21 #include <drizzled/plugin/daemon.h>
22 #include <drizzled/plugin/storage_engine.h>
23 #include <drizzled/util/test.h>
24 #include <drizzled/session/table_messages.h>
25 #include <drizzled/statistics_variables.h>
26 #include <drizzled/system_variables.h>
27 
28 #include <boost/thread/mutex.hpp>
29 
30 #include "heap.h"
31 #include "ha_heap.h"
32 
33 #include <string>
34 
35 using namespace drizzled;
36 using namespace std;
37 
38 static const string engine_name("MEMORY");
39 
40 boost::mutex THR_LOCK_heap;
41 
42 static const char *ha_heap_exts[] = {
43  NULL
44 };
45 
46 class HeapEngine : public plugin::StorageEngine
47 {
48 public:
49  explicit HeapEngine(string name_arg) :
50  plugin::StorageEngine(name_arg,
51  HTON_STATS_RECORDS_IS_EXACT |
52  HTON_NULL_IN_KEY |
53  HTON_FAST_KEY_READ |
54  HTON_NO_BLOBS |
55  HTON_HAS_RECORDS |
56  HTON_SKIP_STORE_LOCK |
57  HTON_TEMPORARY_ONLY)
58  {
59  }
60 
61  virtual ~HeapEngine()
62  {
63  hp_panic(HA_PANIC_CLOSE);
64  }
65 
66  virtual Cursor *create(Table &table)
67  {
68  return new ha_heap(*this, table);
69  }
70 
71  const char **bas_ext() const
72  {
73  return ha_heap_exts;
74  }
75 
76  drizzled::message::Table::Index::IndexType default_index_type() const
77  {
78  return drizzled::message::Table::Index::HASH;
79  }
80 
81  int doCreateTable(Session &session,
82  Table &table_arg,
83  const identifier::Table &identifier,
84  const message::Table &create_proto);
85 
86  /* For whatever reason, internal tables can be created by Cursor::open()
87  for MEMORY.
88  Instead of diving down a rat hole, let's just cry ourselves to sleep
89  at night with this odd hackish workaround.
90  */
91  int heap_create_table(Session *session, const char *table_name,
92  Table *table_arg,
93  bool internal_table,
94  const message::Table &create_proto,
95  HP_SHARE **internal_share);
96 
97  int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
98 
99  int doDropTable(Session&, const identifier::Table &identifier);
100 
101  int doGetTableDefinition(Session& session,
102  const identifier::Table &identifier,
103  message::Table &table_message);
104 
105  uint32_t max_supported_keys() const { return MAX_KEY; }
106  uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
107 
108  uint32_t index_flags(enum ha_key_alg ) const
109  {
110  return ( HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
111  }
112 
113  bool doDoesTableExist(Session& session, const identifier::Table &identifier);
114  void doGetTableIdentifiers(CachedDirectory &directory,
115  const identifier::Schema &schema_identifier,
116  identifier::table::vector &set_of_identifiers);
117 };
118 
119 void HeapEngine::doGetTableIdentifiers(CachedDirectory&,
120  const identifier::Schema&,
121  identifier::table::vector&)
122 {
123 }
124 
125 bool HeapEngine::doDoesTableExist(Session& session, const identifier::Table &identifier)
126 {
127  return session.getMessageCache().doesTableMessageExist(identifier);
128 }
129 
130 int HeapEngine::doGetTableDefinition(Session &session,
131  const identifier::Table &identifier,
132  message::Table &table_proto)
133 {
134  if (session.getMessageCache().getTableMessage(identifier, table_proto))
135  return EEXIST;
136 
137  return ENOENT;
138 }
139 /*
140  We have to ignore ENOENT entries as the MEMORY table is created on open and
141  not when doing a CREATE on the table.
142 */
143 int HeapEngine::doDropTable(Session &session, const identifier::Table &identifier)
144 {
145  session.getMessageCache().removeTableMessage(identifier);
146 
147  int error= heap_delete_table(identifier.getPath().c_str());
148 
149  if (error == ENOENT)
150  error= 0;
151 
152  return error;
153 }
154 
155 static HeapEngine *heap_storage_engine= NULL;
156 
157 static int heap_init(module::Context &context)
158 {
159  heap_storage_engine= new HeapEngine(engine_name);
160  context.add(heap_storage_engine);
161  return 0;
162 }
163 
164 
165 /*****************************************************************************
166 ** MEMORY tables
167 *****************************************************************************/
168 
169 ha_heap::ha_heap(plugin::StorageEngine &engine_arg,
170  Table &table_arg)
171  :Cursor(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
172  internal_table(0)
173 {}
174 
175 /*
176  Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
177  rec_per_key) after 1/MEMORY_STATS_UPDATE_THRESHOLD fraction of table records
178  have been inserted/updated/deleted. delete_all_rows() and table flush cause
179  immediate update.
180 
181  NOTE
182  hash index statistics must be updated when number of table records changes
183  from 0 to non-zero value and vice versa. Otherwise records_in_range may
184  erroneously return 0 and 'range' may miss records.
185 */
186 #define MEMORY_STATS_UPDATE_THRESHOLD 10
187 
188 int ha_heap::doOpen(const drizzled::identifier::Table &identifier, int mode, uint32_t test_if_locked)
189 {
190  if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(identifier.getPath().c_str(), mode)) && errno == ENOENT))
191  {
192  internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
193  file= 0;
194  HP_SHARE *internal_share= NULL;
195  message::Table create_proto;
196 
197  if (not heap_storage_engine->heap_create_table(getTable()->in_use,
198  identifier.getPath().c_str(),
199  getTable(),
200  internal_table,
201  create_proto,
202  &internal_share))
203  {
204  file= internal_table ?
205  heap_open_from_share(internal_share, mode) :
206  heap_open_from_share_and_register(internal_share, mode);
207  if (!file)
208  {
209  /* Couldn't open table; Remove the newly created table */
210  THR_LOCK_heap.lock();
211  hp_free(internal_share);
212  THR_LOCK_heap.unlock();
213  }
214  }
215  }
216  ref_length= sizeof(HEAP_PTR);
217  if (file)
218  {
219  /* Initialize variables for the opened table */
220  set_keys_for_scanning();
221  /*
222  We cannot run update_key_stats() here because we do not have a
223  lock on the table. The 'records' count might just be changed
224  temporarily at this moment and we might get wrong statistics (Bug
225  #10178). Instead we request for update. This will be done in
226  ha_heap::info(), which is always called before key statistics are
227  used.
228  */
229  key_stat_version= file->getShare()->key_stat_version - 1;
230  }
231  return file ? 0 : 1;
232 }
233 
234 int ha_heap::close(void)
235 {
236  return internal_table ? hp_close(file) : heap_close(file);
237 }
238 
239 
240 /*
241  Create a copy of this table
242 
243  DESCRIPTION
244  Do same as default implementation but use file->s->name instead of
245  table->getShare()->path. This is needed by Windows where the clone() call sees
246  '/'-delimited path in table->getShare()->path, while ha_peap::open() was called
247  with '\'-delimited path.
248 */
249 
250 Cursor *ha_heap::clone(memory::Root *)
251 {
252  Cursor *new_handler= getTable()->getMutableShare()->db_type()->getCursor(*getTable());
253  identifier::Table identifier(getTable()->getShare()->getSchemaName(),
254  getTable()->getShare()->getTableName(),
255  getTable()->getShare()->getPath());
256 
257  if (new_handler && !new_handler->ha_open(identifier, getTable()->db_stat,
258  HA_OPEN_IGNORE_IF_LOCKED))
259  return new_handler;
260  return NULL;
261 }
262 
263 
264 const char *ha_heap::index_type(uint32_t )
265 {
266  return ("HASH");
267 }
268 
269 
270 /*
271  Compute which keys to use for scanning
272 
273  SYNOPSIS
274  set_keys_for_scanning()
275  no parameter
276 
277  DESCRIPTION
278  Set the bitmap btree_keys, which is used when the upper layers ask
279  which keys to use for scanning. For each btree index the
280  corresponding bit is set.
281 
282  RETURN
283  void
284 */
285 
286 void ha_heap::set_keys_for_scanning(void)
287 {
288 }
289 
290 
291 void ha_heap::update_key_stats()
292 {
293  for (uint32_t i= 0; i < getTable()->getShare()->sizeKeys(); i++)
294  {
295  KeyInfo *key= &getTable()->key_info[i];
296 
297  if (!key->rec_per_key)
298  continue;
299 
300  {
301  if (key->flags & HA_NOSAME)
302  key->rec_per_key[key->key_parts-1]= 1;
303  else
304  {
305  ha_rows hash_buckets= file->getShare()->keydef[i].hash_buckets;
306  uint32_t no_records= hash_buckets ? (uint) (file->getShare()->records/hash_buckets) : 2;
307  if (no_records < 2)
308  no_records= 2;
309  key->rec_per_key[key->key_parts-1]= no_records;
310  }
311  }
312  }
313  records_changed= 0;
314  /* At the end of update_key_stats() we can proudly claim they are OK. */
315  key_stat_version= file->getShare()->key_stat_version;
316 }
317 
318 
319 int ha_heap::doInsertRecord(unsigned char * buf)
320 {
321  int res;
322  if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
323  {
324  if ((res= update_auto_increment()))
325  return res;
326  }
327  res= heap_write(file,buf);
328  if (!res && (++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
329  file->getShare()->records))
330  {
331  /*
332  We can perform this safely since only one writer at the time is
333  allowed on the table.
334  */
335  file->getShare()->key_stat_version++;
336  }
337  return res;
338 }
339 
340 int ha_heap::doUpdateRecord(const unsigned char * old_data, unsigned char * new_data)
341 {
342  int res;
343 
344  res= heap_update(file,old_data,new_data);
345  if (!res && ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
346  file->getShare()->records)
347  {
348  /*
349  We can perform this safely since only one writer at the time is
350  allowed on the table.
351  */
352  file->getShare()->key_stat_version++;
353  }
354  return res;
355 }
356 
357 int ha_heap::doDeleteRecord(const unsigned char * buf)
358 {
359  int res;
360 
361  res= heap_delete(file,buf);
362  if (!res && getTable()->getShare()->getType() == message::Table::STANDARD &&
363  ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->getShare()->records)
364  {
365  /*
366  We can perform this safely since only one writer at the time is
367  allowed on the table.
368  */
369  file->getShare()->key_stat_version++;
370  }
371  return res;
372 }
373 
374 int ha_heap::index_read_map(unsigned char *buf, const unsigned char *key,
375  key_part_map keypart_map,
376  enum ha_rkey_function find_flag)
377 {
378  assert(inited==INDEX);
379  ha_statistic_increment(&system_status_var::ha_read_key_count);
380  int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
381  getTable()->status = error ? STATUS_NOT_FOUND : 0;
382  return error;
383 }
384 
385 int ha_heap::index_read_last_map(unsigned char *buf, const unsigned char *key,
386  key_part_map keypart_map)
387 {
388  assert(inited==INDEX);
389  ha_statistic_increment(&system_status_var::ha_read_key_count);
390  int error= heap_rkey(file, buf, active_index, key, keypart_map,
391  HA_READ_PREFIX_LAST);
392  getTable()->status= error ? STATUS_NOT_FOUND : 0;
393  return error;
394 }
395 
396 int ha_heap::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
397  key_part_map keypart_map,
398  enum ha_rkey_function find_flag)
399 {
400  ha_statistic_increment(&system_status_var::ha_read_key_count);
401  int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
402  getTable()->status = error ? STATUS_NOT_FOUND : 0;
403  return error;
404 }
405 
406 int ha_heap::index_next(unsigned char * buf)
407 {
408  assert(inited==INDEX);
409  ha_statistic_increment(&system_status_var::ha_read_next_count);
410  int error=heap_rnext(file,buf);
411  getTable()->status=error ? STATUS_NOT_FOUND: 0;
412  return error;
413 }
414 
415 int ha_heap::index_prev(unsigned char * buf)
416 {
417  assert(inited==INDEX);
418  ha_statistic_increment(&system_status_var::ha_read_prev_count);
419  int error=heap_rprev(file,buf);
420  getTable()->status=error ? STATUS_NOT_FOUND: 0;
421  return error;
422 }
423 
424 int ha_heap::index_first(unsigned char * buf)
425 {
426  assert(inited==INDEX);
427  ha_statistic_increment(&system_status_var::ha_read_first_count);
428  int error=heap_rfirst(file, buf, active_index);
429  getTable()->status=error ? STATUS_NOT_FOUND: 0;
430  return error;
431 }
432 
433 int ha_heap::index_last(unsigned char * buf)
434 {
435  assert(inited==INDEX);
436  ha_statistic_increment(&system_status_var::ha_read_last_count);
437  int error=heap_rlast(file, buf, active_index);
438  getTable()->status=error ? STATUS_NOT_FOUND: 0;
439  return error;
440 }
441 
443 {
444  return scan ? heap_scan_init(file) : 0;
445 }
446 
447 int ha_heap::rnd_next(unsigned char *buf)
448 {
449  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
450  int error=heap_scan(file, buf);
451  getTable()->status=error ? STATUS_NOT_FOUND: 0;
452  return error;
453 }
454 
455 int ha_heap::rnd_pos(unsigned char * buf, unsigned char *pos)
456 {
457  int error;
458  HEAP_PTR heap_position;
459  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
460  memcpy(&heap_position, pos, sizeof(HEAP_PTR));
461  error=heap_rrnd(file, buf, heap_position);
462  getTable()->status=error ? STATUS_NOT_FOUND: 0;
463  return error;
464 }
465 
466 void ha_heap::position(const unsigned char *)
467 {
468  *(HEAP_PTR*) ref= heap_position(file); // Ref is aligned
469 }
470 
471 int ha_heap::info(uint32_t flag)
472 {
473  HEAPINFO hp_info;
474  (void) heap_info(file,&hp_info,flag);
475 
476  errkey= hp_info.errkey;
477  stats.records= hp_info.records;
478  stats.deleted= hp_info.deleted;
479  stats.mean_rec_length= hp_info.reclength;
480  stats.data_file_length= hp_info.data_length;
481  stats.index_file_length= hp_info.index_length;
482  stats.max_data_file_length= hp_info.max_records * hp_info.reclength;
483  stats.delete_length= hp_info.deleted * hp_info.reclength;
484  if (flag & HA_STATUS_AUTO)
485  stats.auto_increment_value= hp_info.auto_increment;
486  /*
487  If info() is called for the first time after open(), we will still
488  have to update the key statistics. Hoping that a table lock is now
489  in place.
490  */
491  if (key_stat_version != file->getShare()->key_stat_version)
492  update_key_stats();
493  return 0;
494 }
495 
496 int ha_heap::extra(enum ha_extra_function operation)
497 {
498  return heap_extra(file,operation);
499 }
500 
501 
503 {
504  return heap_reset(file);
505 }
506 
507 
509 {
510  heap_clear(file);
511  if (getTable()->getShare()->getType() == message::Table::STANDARD)
512  {
513  /*
514  We can perform this safely since only one writer at the time is
515  allowed on the table.
516  */
517  file->getShare()->key_stat_version++;
518  }
519  return 0;
520 }
521 
522 /*
523  Disable indexes.
524 
525  SYNOPSIS
526  disable_indexes()
527  mode mode of operation:
528  HA_KEY_SWITCH_NONUNIQ disable all non-unique keys
529  HA_KEY_SWITCH_ALL disable all keys
530  HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
531  HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent
532 
533  DESCRIPTION
534  Disable indexes and clear keys to use for scanning.
535 
536  IMPLEMENTATION
537  HA_KEY_SWITCH_NONUNIQ is not implemented.
538  HA_KEY_SWITCH_NONUNIQ_SAVE is not implemented with HEAP.
539  HA_KEY_SWITCH_ALL_SAVE is not implemented with HEAP.
540 
541  RETURN
542  0 ok
543  HA_ERR_WRONG_COMMAND mode not implemented.
544 */
545 
546 int ha_heap::disable_indexes(uint32_t mode)
547 {
548  int error;
549 
550  if (mode == HA_KEY_SWITCH_ALL)
551  {
552  if (!(error= heap_disable_indexes(file)))
553  set_keys_for_scanning();
554  }
555  else
556  {
557  /* mode not implemented */
558  error= HA_ERR_WRONG_COMMAND;
559  }
560  return error;
561 }
562 
563 
564 /*
565  Enable indexes.
566 
567  SYNOPSIS
568  enable_indexes()
569  mode mode of operation:
570  HA_KEY_SWITCH_NONUNIQ enable all non-unique keys
571  HA_KEY_SWITCH_ALL enable all keys
572  HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
573  HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent
574 
575  DESCRIPTION
576  Enable indexes and set keys to use for scanning.
577  The indexes might have been disabled by disable_index() before.
578  The function works only if both data and indexes are empty,
579  since the heap storage engine cannot repair the indexes.
580  To be sure, call Cursor::delete_all_rows() before.
581 
582  IMPLEMENTATION
583  HA_KEY_SWITCH_NONUNIQ is not implemented.
584  HA_KEY_SWITCH_NONUNIQ_SAVE is not implemented with HEAP.
585  HA_KEY_SWITCH_ALL_SAVE is not implemented with HEAP.
586 
587  RETURN
588  0 ok
589  HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry.
590  HA_ERR_WRONG_COMMAND mode not implemented.
591 */
592 
593 int ha_heap::enable_indexes(uint32_t mode)
594 {
595  int error;
596 
597  if (mode == HA_KEY_SWITCH_ALL)
598  {
599  if (!(error= heap_enable_indexes(file)))
600  set_keys_for_scanning();
601  }
602  else
603  {
604  /* mode not implemented */
605  error= HA_ERR_WRONG_COMMAND;
606  }
607  return error;
608 }
609 
610 
611 /*
612  Test if indexes are disabled.
613 
614  SYNOPSIS
615  indexes_are_disabled()
616  no parameters
617 
618  RETURN
619  0 indexes are not disabled
620  1 all indexes are disabled
621  [2 non-unique indexes are disabled - NOT YET IMPLEMENTED]
622 */
623 
624 int ha_heap::indexes_are_disabled()
625 {
626  return heap_indexes_are_disabled(file);
627 }
628 
629 void ha_heap::drop_table()
630 {
631  file->getShare()->delete_on_close= 1;
632  close();
633 }
634 
635 
636 int HeapEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
637 {
638  session.getMessageCache().renameTableMessage(from, to);
639  return heap_rename(from.getPath().c_str(), to.getPath().c_str());
640 }
641 
642 
643 ha_rows ha_heap::records_in_range(uint32_t inx, key_range *min_key,
644  key_range *max_key)
645 {
646  KeyInfo *key= &getTable()->key_info[inx];
647 
648  if (!min_key || !max_key ||
649  min_key->length != max_key->length ||
650  min_key->length != key->key_length ||
651  min_key->flag != HA_READ_KEY_EXACT ||
652  max_key->flag != HA_READ_AFTER_KEY)
653  return HA_POS_ERROR; // Can only use exact keys
654 
655  if (stats.records <= 1)
656  return stats.records;
657 
658  /* Assert that info() did run. We need current statistics here. */
659  assert(key_stat_version == file->getShare()->key_stat_version);
660  return key->rec_per_key[key->key_parts-1];
661 }
662 
663 int HeapEngine::doCreateTable(Session &session,
664  Table &table_arg,
665  const identifier::Table &identifier,
666  const message::Table& create_proto)
667 {
668  int error;
669  HP_SHARE *internal_share;
670  const char *table_name= identifier.getPath().c_str();
671 
672  error= heap_create_table(&session, table_name, &table_arg,
673  false,
674  create_proto,
675  &internal_share);
676 
677  if (error == 0)
678  {
679  session.getMessageCache().storeTableMessage(identifier, create_proto);
680  }
681 
682  return error;
683 }
684 
685 
686 int HeapEngine::heap_create_table(Session *session, const char *table_name,
687  Table *table_arg,
688  bool internal_table,
689  const message::Table &create_proto,
690  HP_SHARE **internal_share)
691 {
692  uint32_t key, parts, mem_per_row_keys= 0;
693  uint32_t keys= table_arg->getShare()->sizeKeys();
694  uint32_t auto_key= 0, auto_key_type= 0;
695  uint32_t max_key_fieldnr = 0, key_part_size = 0, next_field_pos = 0;
696  uint32_t column_count= table_arg->getShare()->sizeFields();
697  std::vector<HP_KEYDEF> keydef;
698  int error;
699  bool found_real_auto_increment= 0;
700 
701  /*
702  * We cannot create tables with more rows than UINT32_MAX. This is a
703  * limitation of the HEAP engine. Here, since TableShare::getMaxRows()
704  * can return a number more than that, we trap it here instead of casting
705  * to a truncated integer.
706  */
707  uint64_t num_rows= table_arg->getShare()->getMaxRows();
708  if (num_rows > UINT32_MAX)
709  return -1;
710 
711  for (key= parts= 0; key < keys; key++)
712  parts+= table_arg->key_info[key].key_parts;
713 
714  keydef.resize(keys);
715  std::vector<HA_KEYSEG> seg_buffer;
716  seg_buffer.resize(parts);
717  HA_KEYSEG *seg= &seg_buffer[0];
718 
719  for (key= 0; key < keys; key++)
720  {
721  KeyInfo *pos= &table_arg->key_info[key];
722  KeyPartInfo *key_part= pos->key_part;
723  KeyPartInfo *key_part_end= key_part + pos->key_parts;
724 
725  keydef[key].keysegs= (uint) pos->key_parts;
726  keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
727  keydef[key].seg= seg;
728 
729  mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
730 
731  for (; key_part != key_part_end; key_part++, seg++)
732  {
733  Field *field= key_part->field;
734 
735  {
736  if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
737  seg->type != HA_KEYTYPE_VARTEXT1 &&
738  seg->type != HA_KEYTYPE_VARTEXT2 &&
739  seg->type != HA_KEYTYPE_VARBINARY1 &&
740  seg->type != HA_KEYTYPE_VARBINARY2)
741  seg->type= HA_KEYTYPE_BINARY;
742  }
743  seg->start= (uint) key_part->offset;
744  seg->length= (uint) key_part->length;
745  seg->flag= key_part->key_part_flag;
746 
747  next_field_pos= seg->start + seg->length;
748  if (field->type() == DRIZZLE_TYPE_VARCHAR)
749  {
750  next_field_pos+= (uint8_t)(((Field_varstring*)field)->pack_length_no_ptr());
751  }
752 
753  if (next_field_pos > key_part_size) {
754  key_part_size= next_field_pos;
755  }
756 
757  if (field->flags & ENUM_FLAG)
758  seg->charset= &my_charset_bin;
759  else
760  seg->charset= field->charset();
761  if (field->null_ptr)
762  {
763  seg->null_bit= field->null_bit;
764  seg->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->getInsertRecord());
765  }
766  else
767  {
768  seg->null_bit= 0;
769  seg->null_pos= 0;
770  }
771  if (field->flags & AUTO_INCREMENT_FLAG &&
772  table_arg->found_next_number_field &&
773  key == table_arg->getShare()->next_number_index)
774  {
775  /*
776  Store key number and type for found auto_increment key
777  We have to store type as seg->type can differ from it
778  */
779  auto_key= key+ 1;
780  auto_key_type= field->key_type();
781  }
782  if ((uint)field->position() + 1 > max_key_fieldnr)
783  {
784  /* Do not use seg->fieldnr as it's not reliable in case of temp tables */
785  max_key_fieldnr= field->position() + 1;
786  }
787  }
788  }
789 
790  if (key_part_size < table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3))
791  {
792  /* Make sure to include null fields regardless of the presense of keys */
793  key_part_size = table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3);
794  }
795 
796 
797 
798  if (table_arg->found_next_number_field)
799  {
800  keydef[table_arg->getShare()->next_number_index].flag|= HA_AUTO_KEY;
801  found_real_auto_increment= table_arg->getShare()->next_number_key_offset == 0;
802  }
803  HP_CREATE_INFO hp_create_info;
804  hp_create_info.auto_key= auto_key;
805  hp_create_info.auto_key_type= auto_key_type;
806  hp_create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
807  create_proto.options().auto_increment_value() - 1 : 0);
808  hp_create_info.max_table_size=session->variables.max_heap_table_size;
809  hp_create_info.with_auto_increment= found_real_auto_increment;
810  hp_create_info.internal_table= internal_table;
811  hp_create_info.max_chunk_size= table_arg->getShare()->block_size;
812 
813  error= heap_create(table_name,
814  keys, &keydef[0],
815  column_count,
816  key_part_size,
817  table_arg->getShare()->getRecordLength(), mem_per_row_keys,
818  static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
819  0, // Factor out MIN
820  &hp_create_info, internal_share);
821 
822  return (error);
823 }
824 
825 
826 void ha_heap::get_auto_increment(uint64_t, uint64_t, uint64_t,
827  uint64_t *first_value,
828  uint64_t *nb_reserved_values)
829 {
830  ha_heap::info(HA_STATUS_AUTO);
831  *first_value= stats.auto_increment_value;
832  /* such table has only table-level locking so reserves up to +inf */
833  *nb_reserved_values= UINT64_MAX;
834 }
835 
836 
837 int ha_heap::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
838 {
839  return memcmp(ref1, ref2, sizeof(HEAP_PTR));
840 }
841 
842 
843 DRIZZLE_DECLARE_PLUGIN
844 {
845  DRIZZLE_VERSION_ID,
846  "memory",
847  "1.0",
848  "MySQL AB",
849  N_("MEMORY storage engine"),
850  PLUGIN_LICENSE_GPL,
851  heap_init,
852  NULL,
853  NULL
854 }
855 DRIZZLE_DECLARE_PLUGIN_END;