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