Drizzled Public API Documentation

ha_heap.cc
00001 /* Copyright (C) 2000-2006 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 #include "heap_priv.h"
00017 #include <drizzled/error.h>
00018 #include <drizzled/table.h>
00019 #include <drizzled/session.h>
00020 #include <drizzled/field/varstring.h>
00021 #include <drizzled/plugin/daemon.h>
00022 #include <drizzled/plugin/storage_engine.h>
00023 #include <drizzled/util/test.h>
00024 #include <drizzled/session/table_messages.h>
00025 #include <drizzled/statistics_variables.h>
00026 #include <drizzled/system_variables.h>
00027 
00028 #include <boost/thread/mutex.hpp>
00029 
00030 #include "heap.h"
00031 #include "ha_heap.h"
00032 
00033 #include <string>
00034 
00035 using namespace drizzled;
00036 using namespace std;
00037 
00038 static const string engine_name("MEMORY");
00039 
00040 boost::mutex THR_LOCK_heap;
00041 
00042 static const char *ha_heap_exts[] = {
00043   NULL
00044 };
00045 
00046 class HeapEngine : public plugin::StorageEngine
00047 {
00048 public:
00049   explicit HeapEngine(string name_arg) :
00050     plugin::StorageEngine(name_arg,
00051                           HTON_STATS_RECORDS_IS_EXACT |
00052                           HTON_NULL_IN_KEY |
00053                           HTON_FAST_KEY_READ |
00054                           HTON_NO_BLOBS |
00055                           HTON_HAS_RECORDS |
00056                           HTON_SKIP_STORE_LOCK |
00057                           HTON_TEMPORARY_ONLY)
00058   {
00059   }
00060 
00061   virtual ~HeapEngine()
00062   {
00063     hp_panic(HA_PANIC_CLOSE);
00064   }
00065 
00066   virtual Cursor *create(Table &table)
00067   {
00068     return new ha_heap(*this, table);
00069   }
00070 
00071   const char **bas_ext() const 
00072   {
00073     return ha_heap_exts;
00074   }
00075 
00076   drizzled::message::Table::Index::IndexType default_index_type() const
00077   {
00078     return drizzled::message::Table::Index::HASH;
00079   }
00080 
00081   int doCreateTable(Session &session,
00082                     Table &table_arg,
00083                     const identifier::Table &identifier,
00084                     const message::Table &create_proto);
00085 
00086   /* For whatever reason, internal tables can be created by Cursor::open()
00087      for MEMORY.
00088      Instead of diving down a rat hole, let's just cry ourselves to sleep
00089      at night with this odd hackish workaround.
00090    */
00091   int heap_create_table(Session *session, const char *table_name,
00092                         Table *table_arg,
00093                         bool internal_table,
00094                         const message::Table &create_proto,
00095                         HP_SHARE **internal_share);
00096 
00097   int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
00098 
00099   int doDropTable(Session&, const identifier::Table &identifier);
00100 
00101   int doGetTableDefinition(Session& session,
00102                            const identifier::Table &identifier,
00103                            message::Table &table_message);
00104 
00105   uint32_t max_supported_keys()          const { return MAX_KEY; }
00106   uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
00107 
00108   uint32_t index_flags(enum  ha_key_alg ) const
00109   {
00110     return ( HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
00111   }
00112 
00113   bool doDoesTableExist(Session& session, const identifier::Table &identifier);
00114   void doGetTableIdentifiers(CachedDirectory &directory,
00115                              const identifier::Schema &schema_identifier,
00116                              identifier::table::vector &set_of_identifiers);
00117 };
00118 
00119 void HeapEngine::doGetTableIdentifiers(CachedDirectory&,
00120                                        const identifier::Schema&,
00121                                        identifier::table::vector&)
00122 {
00123 }
00124 
00125 bool HeapEngine::doDoesTableExist(Session& session, const identifier::Table &identifier)
00126 {
00127   return session.getMessageCache().doesTableMessageExist(identifier);
00128 }
00129 
00130 int HeapEngine::doGetTableDefinition(Session &session,
00131                                      const identifier::Table &identifier,
00132                                      message::Table &table_proto)
00133 {
00134   if (session.getMessageCache().getTableMessage(identifier, table_proto))
00135     return EEXIST;
00136 
00137   return ENOENT;
00138 }
00139 /*
00140   We have to ignore ENOENT entries as the MEMORY table is created on open and
00141   not when doing a CREATE on the table.
00142 */
00143 int HeapEngine::doDropTable(Session &session, const identifier::Table &identifier)
00144 {
00145   session.getMessageCache().removeTableMessage(identifier);
00146 
00147   int error= heap_delete_table(identifier.getPath().c_str());
00148 
00149   if (error == ENOENT)
00150     error= 0;
00151 
00152   return error;
00153 }
00154 
00155 static HeapEngine *heap_storage_engine= NULL;
00156 
00157 static int heap_init(module::Context &context)
00158 {
00159   heap_storage_engine= new HeapEngine(engine_name);
00160   context.add(heap_storage_engine);
00161   return 0;
00162 }
00163 
00164 
00165 /*****************************************************************************
00166 ** MEMORY tables
00167 *****************************************************************************/
00168 
00169 ha_heap::ha_heap(plugin::StorageEngine &engine_arg,
00170                  Table &table_arg)
00171   :Cursor(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
00172   internal_table(0)
00173 {}
00174 
00175 /*
00176   Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
00177   rec_per_key) after 1/MEMORY_STATS_UPDATE_THRESHOLD fraction of table records
00178   have been inserted/updated/deleted. delete_all_rows() and table flush cause
00179   immediate update.
00180 
00181   NOTE
00182    hash index statistics must be updated when number of table records changes
00183    from 0 to non-zero value and vice versa. Otherwise records_in_range may
00184    erroneously return 0 and 'range' may miss records.
00185 */
00186 #define MEMORY_STATS_UPDATE_THRESHOLD 10
00187 
00188 int ha_heap::doOpen(const drizzled::identifier::Table &identifier, int mode, uint32_t test_if_locked)
00189 {
00190   if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(identifier.getPath().c_str(), mode)) && errno == ENOENT))
00191   {
00192     internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
00193     file= 0;
00194     HP_SHARE *internal_share= NULL;
00195     message::Table create_proto;
00196 
00197     if (not heap_storage_engine->heap_create_table(getTable()->in_use,
00198                                                    identifier.getPath().c_str(),
00199                                                    getTable(),
00200                                                    internal_table,
00201                                                    create_proto,
00202                                                    &internal_share))
00203     {
00204         file= internal_table ?
00205           heap_open_from_share(internal_share, mode) :
00206           heap_open_from_share_and_register(internal_share, mode);
00207       if (!file)
00208       {
00209          /* Couldn't open table; Remove the newly created table */
00210         THR_LOCK_heap.lock();
00211         hp_free(internal_share);
00212         THR_LOCK_heap.unlock();
00213       }
00214     }
00215   }
00216   ref_length= sizeof(HEAP_PTR);
00217   if (file)
00218   {
00219     /* Initialize variables for the opened table */
00220     set_keys_for_scanning();
00221     /*
00222       We cannot run update_key_stats() here because we do not have a
00223       lock on the table. The 'records' count might just be changed
00224       temporarily at this moment and we might get wrong statistics (Bug
00225       #10178). Instead we request for update. This will be done in
00226       ha_heap::info(), which is always called before key statistics are
00227       used.
00228     */
00229     key_stat_version= file->getShare()->key_stat_version - 1;
00230   }
00231   return file ? 0 : 1;
00232 }
00233 
00234 int ha_heap::close(void)
00235 {
00236   return internal_table ? hp_close(file) : heap_close(file);
00237 }
00238 
00239 
00240 /*
00241   Create a copy of this table
00242 
00243   DESCRIPTION
00244     Do same as default implementation but use file->s->name instead of
00245     table->getShare()->path. This is needed by Windows where the clone() call sees
00246     '/'-delimited path in table->getShare()->path, while ha_peap::open() was called
00247     with '\'-delimited path.
00248 */
00249 
00250 Cursor *ha_heap::clone(memory::Root *)
00251 {
00252   Cursor *new_handler= getTable()->getMutableShare()->db_type()->getCursor(*getTable());
00253   identifier::Table identifier(getTable()->getShare()->getSchemaName(),
00254                              getTable()->getShare()->getTableName(),
00255                              getTable()->getShare()->getPath());
00256 
00257   if (new_handler && !new_handler->ha_open(identifier, getTable()->db_stat,
00258                                            HA_OPEN_IGNORE_IF_LOCKED))
00259     return new_handler;
00260   return NULL;
00261 }
00262 
00263 
00264 const char *ha_heap::index_type(uint32_t )
00265 {
00266   return ("HASH");
00267 }
00268 
00269 
00270 /*
00271   Compute which keys to use for scanning
00272 
00273   SYNOPSIS
00274     set_keys_for_scanning()
00275     no parameter
00276 
00277   DESCRIPTION
00278     Set the bitmap btree_keys, which is used when the upper layers ask
00279     which keys to use for scanning. For each btree index the
00280     corresponding bit is set.
00281 
00282   RETURN
00283     void
00284 */
00285 
00286 void ha_heap::set_keys_for_scanning(void)
00287 {
00288 }
00289 
00290 
00291 void ha_heap::update_key_stats()
00292 {
00293   for (uint32_t i= 0; i < getTable()->getShare()->sizeKeys(); i++)
00294   {
00295     KeyInfo *key= &getTable()->key_info[i];
00296 
00297     if (!key->rec_per_key)
00298       continue;
00299 
00300     {
00301       if (key->flags & HA_NOSAME)
00302         key->rec_per_key[key->key_parts-1]= 1;
00303       else
00304       {
00305         ha_rows hash_buckets= file->getShare()->keydef[i].hash_buckets;
00306         uint32_t no_records= hash_buckets ? (uint) (file->getShare()->records/hash_buckets) : 2;
00307         if (no_records < 2)
00308           no_records= 2;
00309         key->rec_per_key[key->key_parts-1]= no_records;
00310       }
00311     }
00312   }
00313   records_changed= 0;
00314   /* At the end of update_key_stats() we can proudly claim they are OK. */
00315   key_stat_version= file->getShare()->key_stat_version;
00316 }
00317 
00318 
00319 int ha_heap::doInsertRecord(unsigned char * buf)
00320 {
00321   int res;
00322   if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
00323   {
00324     if ((res= update_auto_increment()))
00325       return res;
00326   }
00327   res= heap_write(file,buf);
00328   if (!res && (++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
00329                file->getShare()->records))
00330   {
00331     /*
00332        We can perform this safely since only one writer at the time is
00333        allowed on the table.
00334     */
00335     file->getShare()->key_stat_version++;
00336   }
00337   return res;
00338 }
00339 
00340 int ha_heap::doUpdateRecord(const unsigned char * old_data, unsigned char * new_data)
00341 {
00342   int res;
00343 
00344   res= heap_update(file,old_data,new_data);
00345   if (!res && ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
00346               file->getShare()->records)
00347   {
00348     /*
00349        We can perform this safely since only one writer at the time is
00350        allowed on the table.
00351     */
00352     file->getShare()->key_stat_version++;
00353   }
00354   return res;
00355 }
00356 
00357 int ha_heap::doDeleteRecord(const unsigned char * buf)
00358 {
00359   int res;
00360 
00361   res= heap_delete(file,buf);
00362   if (!res && getTable()->getShare()->getType() == message::Table::STANDARD &&
00363       ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->getShare()->records)
00364   {
00365     /*
00366        We can perform this safely since only one writer at the time is
00367        allowed on the table.
00368     */
00369     file->getShare()->key_stat_version++;
00370   }
00371   return res;
00372 }
00373 
00374 int ha_heap::index_read_map(unsigned char *buf, const unsigned char *key,
00375                             key_part_map keypart_map,
00376                             enum ha_rkey_function find_flag)
00377 {
00378   assert(inited==INDEX);
00379   ha_statistic_increment(&system_status_var::ha_read_key_count);
00380   int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
00381   getTable()->status = error ? STATUS_NOT_FOUND : 0;
00382   return error;
00383 }
00384 
00385 int ha_heap::index_read_last_map(unsigned char *buf, const unsigned char *key,
00386                                  key_part_map keypart_map)
00387 {
00388   assert(inited==INDEX);
00389   ha_statistic_increment(&system_status_var::ha_read_key_count);
00390   int error= heap_rkey(file, buf, active_index, key, keypart_map,
00391            HA_READ_PREFIX_LAST);
00392   getTable()->status= error ? STATUS_NOT_FOUND : 0;
00393   return error;
00394 }
00395 
00396 int ha_heap::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
00397                                 key_part_map keypart_map,
00398                                 enum ha_rkey_function find_flag)
00399 {
00400   ha_statistic_increment(&system_status_var::ha_read_key_count);
00401   int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
00402   getTable()->status = error ? STATUS_NOT_FOUND : 0;
00403   return error;
00404 }
00405 
00406 int ha_heap::index_next(unsigned char * buf)
00407 {
00408   assert(inited==INDEX);
00409   ha_statistic_increment(&system_status_var::ha_read_next_count);
00410   int error=heap_rnext(file,buf);
00411   getTable()->status=error ? STATUS_NOT_FOUND: 0;
00412   return error;
00413 }
00414 
00415 int ha_heap::index_prev(unsigned char * buf)
00416 {
00417   assert(inited==INDEX);
00418   ha_statistic_increment(&system_status_var::ha_read_prev_count);
00419   int error=heap_rprev(file,buf);
00420   getTable()->status=error ? STATUS_NOT_FOUND: 0;
00421   return error;
00422 }
00423 
00424 int ha_heap::index_first(unsigned char * buf)
00425 {
00426   assert(inited==INDEX);
00427   ha_statistic_increment(&system_status_var::ha_read_first_count);
00428   int error=heap_rfirst(file, buf, active_index);
00429   getTable()->status=error ? STATUS_NOT_FOUND: 0;
00430   return error;
00431 }
00432 
00433 int ha_heap::index_last(unsigned char * buf)
00434 {
00435   assert(inited==INDEX);
00436   ha_statistic_increment(&system_status_var::ha_read_last_count);
00437   int error=heap_rlast(file, buf, active_index);
00438   getTable()->status=error ? STATUS_NOT_FOUND: 0;
00439   return error;
00440 }
00441 
00442 int ha_heap::doStartTableScan(bool scan)
00443 {
00444   return scan ? heap_scan_init(file) : 0;
00445 }
00446 
00447 int ha_heap::rnd_next(unsigned char *buf)
00448 {
00449   ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
00450   int error=heap_scan(file, buf);
00451   getTable()->status=error ? STATUS_NOT_FOUND: 0;
00452   return error;
00453 }
00454 
00455 int ha_heap::rnd_pos(unsigned char * buf, unsigned char *pos)
00456 {
00457   int error;
00458   HEAP_PTR heap_position;
00459   ha_statistic_increment(&system_status_var::ha_read_rnd_count);
00460   memcpy(&heap_position, pos, sizeof(HEAP_PTR));
00461   error=heap_rrnd(file, buf, heap_position);
00462   getTable()->status=error ? STATUS_NOT_FOUND: 0;
00463   return error;
00464 }
00465 
00466 void ha_heap::position(const unsigned char *)
00467 {
00468   *(HEAP_PTR*) ref= heap_position(file);  // Ref is aligned
00469 }
00470 
00471 int ha_heap::info(uint32_t flag)
00472 {
00473   HEAPINFO hp_info;
00474   (void) heap_info(file,&hp_info,flag);
00475 
00476   errkey=                     hp_info.errkey;
00477   stats.records=              hp_info.records;
00478   stats.deleted=              hp_info.deleted;
00479   stats.mean_rec_length=      hp_info.reclength;
00480   stats.data_file_length=     hp_info.data_length;
00481   stats.index_file_length=    hp_info.index_length;
00482   stats.max_data_file_length= hp_info.max_records * hp_info.reclength;
00483   stats.delete_length=        hp_info.deleted * hp_info.reclength;
00484   if (flag & HA_STATUS_AUTO)
00485     stats.auto_increment_value= hp_info.auto_increment;
00486   /*
00487     If info() is called for the first time after open(), we will still
00488     have to update the key statistics. Hoping that a table lock is now
00489     in place.
00490   */
00491   if (key_stat_version != file->getShare()->key_stat_version)
00492     update_key_stats();
00493   return 0;
00494 }
00495 
00496 int ha_heap::extra(enum ha_extra_function operation)
00497 {
00498   return heap_extra(file,operation);
00499 }
00500 
00501 
00502 int ha_heap::reset()
00503 {
00504   return heap_reset(file);
00505 }
00506 
00507 
00508 int ha_heap::delete_all_rows()
00509 {
00510   heap_clear(file);
00511   if (getTable()->getShare()->getType() == message::Table::STANDARD)
00512   {
00513     /*
00514        We can perform this safely since only one writer at the time is
00515        allowed on the table.
00516     */
00517     file->getShare()->key_stat_version++;
00518   }
00519   return 0;
00520 }
00521 
00522 /*
00523   Disable indexes.
00524 
00525   SYNOPSIS
00526     disable_indexes()
00527     mode        mode of operation:
00528                 HA_KEY_SWITCH_NONUNIQ      disable all non-unique keys
00529                 HA_KEY_SWITCH_ALL          disable all keys
00530                 HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
00531                 HA_KEY_SWITCH_ALL_SAVE     dis. all keys and make persistent
00532 
00533   DESCRIPTION
00534     Disable indexes and clear keys to use for scanning.
00535 
00536   IMPLEMENTATION
00537     HA_KEY_SWITCH_NONUNIQ       is not implemented.
00538     HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
00539     HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.
00540 
00541   RETURN
00542     0  ok
00543     HA_ERR_WRONG_COMMAND  mode not implemented.
00544 */
00545 
00546 int ha_heap::disable_indexes(uint32_t mode)
00547 {
00548   int error;
00549 
00550   if (mode == HA_KEY_SWITCH_ALL)
00551   {
00552     if (!(error= heap_disable_indexes(file)))
00553       set_keys_for_scanning();
00554   }
00555   else
00556   {
00557     /* mode not implemented */
00558     error= HA_ERR_WRONG_COMMAND;
00559   }
00560   return error;
00561 }
00562 
00563 
00564 /*
00565   Enable indexes.
00566 
00567   SYNOPSIS
00568     enable_indexes()
00569     mode        mode of operation:
00570                 HA_KEY_SWITCH_NONUNIQ      enable all non-unique keys
00571                 HA_KEY_SWITCH_ALL          enable all keys
00572                 HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
00573                 HA_KEY_SWITCH_ALL_SAVE     en. all keys and make persistent
00574 
00575   DESCRIPTION
00576     Enable indexes and set keys to use for scanning.
00577     The indexes might have been disabled by disable_index() before.
00578     The function works only if both data and indexes are empty,
00579     since the heap storage engine cannot repair the indexes.
00580     To be sure, call Cursor::delete_all_rows() before.
00581 
00582   IMPLEMENTATION
00583     HA_KEY_SWITCH_NONUNIQ       is not implemented.
00584     HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
00585     HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.
00586 
00587   RETURN
00588     0  ok
00589     HA_ERR_CRASHED  data or index is non-empty. Delete all rows and retry.
00590     HA_ERR_WRONG_COMMAND  mode not implemented.
00591 */
00592 
00593 int ha_heap::enable_indexes(uint32_t mode)
00594 {
00595   int error;
00596 
00597   if (mode == HA_KEY_SWITCH_ALL)
00598   {
00599     if (!(error= heap_enable_indexes(file)))
00600       set_keys_for_scanning();
00601   }
00602   else
00603   {
00604     /* mode not implemented */
00605     error= HA_ERR_WRONG_COMMAND;
00606   }
00607   return error;
00608 }
00609 
00610 
00611 /*
00612   Test if indexes are disabled.
00613 
00614   SYNOPSIS
00615     indexes_are_disabled()
00616     no parameters
00617 
00618   RETURN
00619     0  indexes are not disabled
00620     1  all indexes are disabled
00621    [2  non-unique indexes are disabled - NOT YET IMPLEMENTED]
00622 */
00623 
00624 int ha_heap::indexes_are_disabled()
00625 {
00626   return heap_indexes_are_disabled(file);
00627 }
00628 
00629 void ha_heap::drop_table()
00630 {
00631   file->getShare()->delete_on_close= 1;
00632   close();
00633 }
00634 
00635 
00636 int HeapEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
00637 {
00638   session.getMessageCache().renameTableMessage(from, to);
00639   return heap_rename(from.getPath().c_str(), to.getPath().c_str());
00640 }
00641 
00642 
00643 ha_rows ha_heap::records_in_range(uint32_t inx, key_range *min_key,
00644                                   key_range *max_key)
00645 {
00646   KeyInfo *key= &getTable()->key_info[inx];
00647 
00648   if (!min_key || !max_key ||
00649       min_key->length != max_key->length ||
00650       min_key->length != key->key_length ||
00651       min_key->flag != HA_READ_KEY_EXACT ||
00652       max_key->flag != HA_READ_AFTER_KEY)
00653     return HA_POS_ERROR;      // Can only use exact keys
00654 
00655   if (stats.records <= 1)
00656     return stats.records;
00657 
00658   /* Assert that info() did run. We need current statistics here. */
00659   assert(key_stat_version == file->getShare()->key_stat_version);
00660   return key->rec_per_key[key->key_parts-1];
00661 }
00662 
00663 int HeapEngine::doCreateTable(Session &session,
00664                               Table &table_arg,
00665                               const identifier::Table &identifier,
00666                               const message::Table& create_proto)
00667 {
00668   int error;
00669   HP_SHARE *internal_share;
00670   const char *table_name= identifier.getPath().c_str();
00671 
00672   error= heap_create_table(&session, table_name, &table_arg,
00673                            false, 
00674                            create_proto,
00675                            &internal_share);
00676 
00677   if (error == 0)
00678   {
00679     session.getMessageCache().storeTableMessage(identifier, create_proto);
00680   }
00681 
00682   return error;
00683 }
00684 
00685 
00686 int HeapEngine::heap_create_table(Session *session, const char *table_name,
00687                                   Table *table_arg,
00688                                   bool internal_table, 
00689                                   const message::Table &create_proto,
00690                                   HP_SHARE **internal_share)
00691 {
00692   uint32_t key, parts, mem_per_row_keys= 0;
00693   uint32_t keys= table_arg->getShare()->sizeKeys();
00694   uint32_t auto_key= 0, auto_key_type= 0;
00695   uint32_t max_key_fieldnr = 0, key_part_size = 0, next_field_pos = 0;
00696   uint32_t column_count= table_arg->getShare()->sizeFields();
00697   std::vector<HP_KEYDEF> keydef;
00698   int error;
00699   bool found_real_auto_increment= 0;
00700 
00701   /* 
00702    * We cannot create tables with more rows than UINT32_MAX.  This is a
00703    * limitation of the HEAP engine.  Here, since TableShare::getMaxRows()
00704    * can return a number more than that, we trap it here instead of casting
00705    * to a truncated integer.
00706    */
00707   uint64_t num_rows= table_arg->getShare()->getMaxRows();
00708   if (num_rows > UINT32_MAX)
00709     return -1;
00710 
00711   for (key= parts= 0; key < keys; key++)
00712     parts+= table_arg->key_info[key].key_parts;
00713 
00714   keydef.resize(keys);
00715   std::vector<HA_KEYSEG> seg_buffer;
00716   seg_buffer.resize(parts);
00717   HA_KEYSEG *seg= &seg_buffer[0];
00718 
00719   for (key= 0; key < keys; key++)
00720   {
00721     KeyInfo *pos= &table_arg->key_info[key];
00722     KeyPartInfo *key_part=     pos->key_part;
00723     KeyPartInfo *key_part_end= key_part + pos->key_parts;
00724 
00725     keydef[key].keysegs=   (uint) pos->key_parts;
00726     keydef[key].flag=      (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
00727     keydef[key].seg=       seg;
00728 
00729     mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
00730 
00731     for (; key_part != key_part_end; key_part++, seg++)
00732     {
00733       Field *field= key_part->field;
00734 
00735       {
00736         if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
00737             seg->type != HA_KEYTYPE_VARTEXT1 &&
00738             seg->type != HA_KEYTYPE_VARTEXT2 &&
00739             seg->type != HA_KEYTYPE_VARBINARY1 &&
00740             seg->type != HA_KEYTYPE_VARBINARY2)
00741           seg->type= HA_KEYTYPE_BINARY;
00742       }
00743       seg->start=   (uint) key_part->offset;
00744       seg->length=  (uint) key_part->length;
00745       seg->flag=    key_part->key_part_flag;
00746 
00747       next_field_pos= seg->start + seg->length;
00748       if (field->type() == DRIZZLE_TYPE_VARCHAR)
00749       {
00750         next_field_pos+= (uint8_t)(((Field_varstring*)field)->pack_length_no_ptr());
00751       }
00752 
00753       if (next_field_pos > key_part_size) {
00754         key_part_size= next_field_pos;
00755       }
00756 
00757       if (field->flags & ENUM_FLAG)
00758         seg->charset= &my_charset_bin;
00759       else
00760         seg->charset= field->charset();
00761       if (field->null_ptr)
00762       {
00763   seg->null_bit= field->null_bit;
00764   seg->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->getInsertRecord());
00765       }
00766       else
00767       {
00768   seg->null_bit= 0;
00769   seg->null_pos= 0;
00770       }
00771       if (field->flags & AUTO_INCREMENT_FLAG &&
00772           table_arg->found_next_number_field &&
00773           key == table_arg->getShare()->next_number_index)
00774       {
00775         /*
00776           Store key number and type for found auto_increment key
00777           We have to store type as seg->type can differ from it
00778         */
00779         auto_key= key+ 1;
00780   auto_key_type= field->key_type();
00781       }
00782       if ((uint)field->position() + 1 > max_key_fieldnr)
00783       {
00784         /* Do not use seg->fieldnr as it's not reliable in case of temp tables */
00785         max_key_fieldnr= field->position() + 1;
00786       }
00787     }
00788   }
00789 
00790   if (key_part_size < table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3))
00791   {
00792     /* Make sure to include null fields regardless of the presense of keys */
00793     key_part_size = table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3);
00794   }
00795 
00796 
00797 
00798   if (table_arg->found_next_number_field)
00799   {
00800     keydef[table_arg->getShare()->next_number_index].flag|= HA_AUTO_KEY;
00801     found_real_auto_increment= table_arg->getShare()->next_number_key_offset == 0;
00802   }
00803   HP_CREATE_INFO hp_create_info;
00804   hp_create_info.auto_key= auto_key;
00805   hp_create_info.auto_key_type= auto_key_type;
00806   hp_create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
00807           create_proto.options().auto_increment_value() - 1 : 0);
00808   hp_create_info.max_table_size=session->variables.max_heap_table_size;
00809   hp_create_info.with_auto_increment= found_real_auto_increment;
00810   hp_create_info.internal_table= internal_table;
00811   hp_create_info.max_chunk_size= table_arg->getShare()->block_size;
00812 
00813   error= heap_create(table_name,
00814                      keys, &keydef[0],
00815                      column_count,
00816                      key_part_size,
00817                      table_arg->getShare()->getRecordLength(), mem_per_row_keys,
00818                      static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
00819                      0, // Factor out MIN
00820                      &hp_create_info, internal_share);
00821 
00822   return (error);
00823 }
00824 
00825 
00826 void ha_heap::get_auto_increment(uint64_t, uint64_t, uint64_t,
00827                                  uint64_t *first_value,
00828                                  uint64_t *nb_reserved_values)
00829 {
00830   ha_heap::info(HA_STATUS_AUTO);
00831   *first_value= stats.auto_increment_value;
00832   /* such table has only table-level locking so reserves up to +inf */
00833   *nb_reserved_values= UINT64_MAX;
00834 }
00835 
00836 
00837 int ha_heap::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
00838 {
00839   return memcmp(ref1, ref2, sizeof(HEAP_PTR));
00840 }
00841 
00842 
00843 DRIZZLE_DECLARE_PLUGIN
00844 {
00845   DRIZZLE_VERSION_ID,
00846   "MEMORY",
00847   "1.0",
00848   "MySQL AB",
00849   "Hash based, stored in memory, useful for temporary tables",
00850   PLUGIN_LICENSE_GPL,
00851   heap_init,
00852   NULL,                       /* depends */
00853   NULL                        /* config options                  */
00854 }
00855 DRIZZLE_DECLARE_PLUGIN_END;