Drizzled Public API Documentation

cursor.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00026 #include <config.h>
00027 #include <fcntl.h>
00028 #include <drizzled/error.h>
00029 #include <drizzled/field/epoch.h>
00030 #include <drizzled/gettext.h>
00031 #include <drizzled/internal/my_sys.h>
00032 #include <drizzled/item/empty_string.h>
00033 #include <drizzled/item/int.h>
00034 #include <drizzled/lock.h>
00035 #include <drizzled/message/table.h>
00036 #include <drizzled/optimizer/cost_vector.h>
00037 #include <drizzled/plugin/client.h>
00038 #include <drizzled/plugin/event_observer.h>
00039 #include <drizzled/plugin/storage_engine.h>
00040 #include <drizzled/probes.h>
00041 #include <drizzled/session.h>
00042 #include <drizzled/sql_base.h>
00043 #include <drizzled/sql_parse.h>
00044 #include <drizzled/transaction_services.h>
00045 #include <drizzled/key.h>
00046 #include <drizzled/sql_lex.h>
00047 #include <drizzled/resource_context.h>
00048 #include <drizzled/statistics_variables.h>
00049 #include <drizzled/system_variables.h>
00050 
00051 using namespace std;
00052 
00053 namespace drizzled {
00054 
00055 /****************************************************************************
00056 ** General Cursor functions
00057 ****************************************************************************/
00058 Cursor::Cursor(plugin::StorageEngine &engine_arg,
00059                Table &arg)
00060   : table(arg),
00061     engine(engine_arg),
00062     estimation_rows_to_insert(0),
00063     ref(0),
00064     key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
00065     ref_length(sizeof(internal::my_off_t)),
00066     inited(NONE),
00067     locked(false),
00068     next_insert_id(0), insert_id_for_cur_row(0)
00069 { }
00070 
00071 Cursor::~Cursor()
00072 {
00073   assert(not locked);
00074   /* TODO: assert(inited == NONE); */
00075 }
00076 
00077 
00078 /*
00079  * @note this only used in
00080  * optimizer::QuickRangeSelect::init_ror_merged_scan(bool reuse_handler) as
00081  * of the writing of this comment. -Brian
00082  */
00083 Cursor *Cursor::clone(memory::Root *mem_root)
00084 {
00085   Cursor *new_handler= getTable()->getMutableShare()->db_type()->getCursor(*getTable());
00086   /*
00087     Allocate Cursor->ref here because otherwise ha_open will allocate it
00088     on this->table->mem_root and we will not be able to reclaim that memory
00089     when the clone Cursor object is destroyed.
00090   */
00091   new_handler->ref= mem_root->alloc(ALIGN_SIZE(ref_length)*2);
00092   identifier::Table identifier(getTable()->getShare()->getSchemaName(), getTable()->getShare()->getTableName(), getTable()->getShare()->getType());
00093   return new_handler->ha_open(identifier, getTable()->getDBStat(), HA_OPEN_IGNORE_IF_LOCKED) ? NULL : new_handler;
00094 }
00095 
00096 /*
00097   DESCRIPTION
00098     given a buffer with a key value, and a map of keyparts
00099     that are present in this value, returns the length of the value
00100 */
00101 uint32_t Cursor::calculate_key_len(uint32_t key_position, key_part_map keypart_map_arg)
00102 {
00103   /* works only with key prefixes */
00104   assert(((keypart_map_arg + 1) & keypart_map_arg) == 0);
00105 
00106   const KeyPartInfo *key_part_found= getTable()->getShare()->getKeyInfo(key_position).key_part;
00107   const KeyPartInfo *end_key_part_found= key_part_found + getTable()->getShare()->getKeyInfo(key_position).key_parts;
00108   uint32_t length= 0;
00109 
00110   while (key_part_found < end_key_part_found && keypart_map_arg)
00111   {
00112     length+= key_part_found->store_length;
00113     keypart_map_arg >>= 1;
00114     key_part_found++;
00115   }
00116   return length;
00117 }
00118 
00119 int Cursor::startIndexScan(uint32_t idx, bool sorted)
00120 {
00121   int result;
00122   assert(inited == NONE);
00123   if (!(result= doStartIndexScan(idx, sorted)))
00124     inited=INDEX;
00125   end_range= NULL;
00126   return result;
00127 }
00128 
00129 int Cursor::endIndexScan()
00130 {
00131   assert(inited==INDEX);
00132   inited=NONE;
00133   end_range= NULL;
00134   return(doEndIndexScan());
00135 }
00136 
00137 int Cursor::startTableScan(bool scan)
00138 {
00139   int result;
00140   assert(inited==NONE || (inited==RND && scan));
00141   inited= (result= doStartTableScan(scan)) ? NONE: RND;
00142 
00143   return result;
00144 }
00145 
00146 int Cursor::endTableScan()
00147 {
00148   assert(inited==RND);
00149   inited=NONE;
00150   return(doEndTableScan());
00151 }
00152 
00153 int Cursor::ha_index_or_rnd_end()
00154 {
00155   return inited == INDEX ? endIndexScan() : inited == RND ? endTableScan() : 0;
00156 }
00157 
00158 void Cursor::ha_start_bulk_insert(ha_rows rows)
00159 {
00160   estimation_rows_to_insert= rows;
00161   start_bulk_insert(rows);
00162 }
00163 
00164 int Cursor::ha_end_bulk_insert()
00165 {
00166   estimation_rows_to_insert= 0;
00167   return end_bulk_insert();
00168 }
00169 
00170 const key_map *Cursor::keys_to_use_for_scanning()
00171 {
00172   return &key_map_empty;
00173 }
00174 
00175 bool Cursor::has_transactions()
00176 {
00177   return (getTable()->getShare()->db_type()->check_flag(HTON_BIT_DOES_TRANSACTIONS));
00178 }
00179 
00180 void Cursor::ha_statistic_increment(uint64_t system_status_var::*offset) const
00181 {
00182   (getTable()->in_use->status_var.*offset)++;
00183 }
00184 
00185 void **Cursor::ha_data(Session *session) const
00186 {
00187   return session->getEngineData(getEngine());
00188 }
00189 
00190 bool Cursor::is_fatal_error(int error, uint32_t flags)
00191 {
00192   if (!error ||
00193       ((flags & HA_CHECK_DUP_KEY) &&
00194        (error == HA_ERR_FOUND_DUPP_KEY ||
00195         error == HA_ERR_FOUND_DUPP_UNIQUE)))
00196     return false;
00197   return true;
00198 }
00199 
00200 
00201 ha_rows Cursor::records() { return stats.records; }
00202 uint64_t Cursor::tableSize() { return stats.index_file_length + stats.data_file_length; }
00203 uint64_t Cursor::rowSize() { return getTable()->getRecordLength() + getTable()->sizeFields(); }
00204 
00205 int Cursor::doOpen(const identifier::Table &identifier, int mode, uint32_t test_if_locked)
00206 {
00207   return open(identifier.getPath().c_str(), mode, test_if_locked);
00208 }
00209 
00216 int Cursor::ha_open(const identifier::Table &identifier,
00217                     int mode,
00218                     int test_if_locked)
00219 {
00220   int error;
00221 
00222   if ((error= doOpen(identifier, mode, test_if_locked)))
00223   {
00224     if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
00225         (getTable()->db_stat & HA_TRY_READ_ONLY))
00226     {
00227       getTable()->db_stat|=HA_READ_ONLY;
00228       error= doOpen(identifier, O_RDONLY,test_if_locked);
00229     }
00230   }
00231   if (error)
00232   {
00233     errno= error;                            /* Safeguard */
00234   }
00235   else
00236   {
00237     if (getTable()->getShare()->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
00238       getTable()->db_stat|=HA_READ_ONLY;
00239     (void) extra(HA_EXTRA_NO_READCHECK);  // Not needed in SQL
00240 
00241     /* ref is already allocated for us if we're called from Cursor::clone() */
00242     if (!ref)
00243       ref= getTable()->alloc(ALIGN_SIZE(ref_length)*2);
00244     dup_ref=ref+ALIGN_SIZE(ref_length);
00245   }
00246   return error;
00247 }
00248 
00255 int Cursor::read_first_row(unsigned char * buf, uint32_t primary_key)
00256 {
00257   int error;
00258 
00259   ha_statistic_increment(&system_status_var::ha_read_first_count);
00260 
00261   /*
00262     If there is very few deleted rows in the table, find the first row by
00263     scanning the table.
00264     @todo remove the test for HA_READ_ORDER
00265   */
00266   if (stats.deleted < 10 || primary_key >= MAX_KEY ||
00267       !(getTable()->index_flags(primary_key) & HA_READ_ORDER))
00268   {
00269     error= startTableScan(1);
00270     if (error == 0)
00271     {
00272       while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
00273       (void) endTableScan();
00274     }
00275   }
00276   else
00277   {
00278     /* Find the first row through the primary key */
00279     error= startIndexScan(primary_key, 0);
00280     if (error == 0)
00281     {
00282       error=index_first(buf);
00283       (void) endIndexScan();
00284     }
00285   }
00286   return error;
00287 }
00288 
00300 inline uint64_t
00301 compute_next_insert_id(uint64_t nr, drizzle_system_variables *variables)
00302 {
00303   if (variables->auto_increment_increment == 1)
00304     return (nr+1); // optimization of the formula below
00305   nr= (((nr+ variables->auto_increment_increment -
00306          variables->auto_increment_offset)) /
00307        (uint64_t) variables->auto_increment_increment);
00308   return (nr* (uint64_t) variables->auto_increment_increment +
00309           variables->auto_increment_offset);
00310 }
00311 
00312 
00313 void Cursor::adjust_next_insert_id_after_explicit_value(uint64_t nr)
00314 {
00315   /*
00316     If we have set Session::next_insert_id previously and plan to insert an
00317     explicitely-specified value larger than this, we need to increase
00318     Session::next_insert_id to be greater than the explicit value.
00319   */
00320   if ((next_insert_id > 0) && (nr >= next_insert_id))
00321     set_next_insert_id(compute_next_insert_id(nr, &getTable()->in_use->variables));
00322 }
00323 
00324 
00340 inline uint64_t
00341 prev_insert_id(uint64_t nr, drizzle_system_variables *variables)
00342 {
00343   if (unlikely(nr < variables->auto_increment_offset))
00344   {
00345     /*
00346       There's nothing good we can do here. That is a pathological case, where
00347       the offset is larger than the column's max possible value, i.e. not even
00348       the first sequence value may be inserted. User will receive warning.
00349     */
00350     return nr;
00351   }
00352   if (variables->auto_increment_increment == 1)
00353     return nr; // optimization of the formula below
00354   nr= (((nr - variables->auto_increment_offset)) /
00355        (uint64_t) variables->auto_increment_increment);
00356   return (nr * (uint64_t) variables->auto_increment_increment +
00357           variables->auto_increment_offset);
00358 }
00359 
00360 
00430 #define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here
00431 #define AUTO_INC_DEFAULT_NB_MAX_BITS 16
00432 #define AUTO_INC_DEFAULT_NB_MAX ((1 << AUTO_INC_DEFAULT_NB_MAX_BITS) - 1)
00433 
00434 int Cursor::update_auto_increment()
00435 {
00436   uint64_t nr, nb_reserved_values;
00437   bool append= false;
00438   Session *session= getTable()->in_use;
00439   drizzle_system_variables *variables= &session->variables;
00440 
00441   /*
00442     next_insert_id is a "cursor" into the reserved interval, it may go greater
00443     than the interval, but not smaller.
00444   */
00445   assert(next_insert_id >= auto_inc_interval_for_cur_row.minimum());
00446 
00447   /* We check if auto_increment_field_not_null is false
00448      for an auto increment column, not a magic value like NULL is.
00449      same as sql_mode=NO_AUTO_VALUE_ON_ZERO */
00450 
00451   if ((nr= getTable()->next_number_field->val_int()) != 0
00452       || getTable()->auto_increment_field_not_null)
00453   {
00454     /*
00455       Update next_insert_id if we had already generated a value in this
00456       statement (case of INSERT VALUES(null),(3763),(null):
00457       the last NULL needs to insert 3764, not the value of the first NULL plus
00458       1).
00459     */
00460     adjust_next_insert_id_after_explicit_value(nr);
00461     insert_id_for_cur_row= 0; // didn't generate anything
00462 
00463     return 0;
00464   }
00465 
00466   if ((nr= next_insert_id) >= auto_inc_interval_for_cur_row.maximum())
00467   {
00468     {
00469       /*
00470         Cursor::estimation_rows_to_insert was set by
00471         Cursor::ha_start_bulk_insert(); if 0 it means "unknown".
00472       */
00473       uint32_t nb_already_reserved_intervals= 0;
00474       uint64_t nb_desired_values;
00475       /*
00476         If an estimation was given to the engine:
00477         - use it.
00478         - if we already reserved numbers, it means the estimation was
00479         not accurate, then we'll reserve 2*AUTO_INC_DEFAULT_NB_ROWS the 2nd
00480         time, twice that the 3rd time etc.
00481         If no estimation was given, use those increasing defaults from the
00482         start, starting from AUTO_INC_DEFAULT_NB_ROWS.
00483         Don't go beyond a max to not reserve "way too much" (because
00484         reservation means potentially losing unused values).
00485       */
00486       if (nb_already_reserved_intervals == 0 &&
00487           (estimation_rows_to_insert > 0))
00488         nb_desired_values= estimation_rows_to_insert;
00489       else /* go with the increasing defaults */
00490       {
00491         /* avoid overflow in formula, with this if() */
00492         if (nb_already_reserved_intervals <= AUTO_INC_DEFAULT_NB_MAX_BITS)
00493         {
00494           nb_desired_values= AUTO_INC_DEFAULT_NB_ROWS *
00495             (1 << nb_already_reserved_intervals);
00496           set_if_smaller(nb_desired_values, (uint64_t)AUTO_INC_DEFAULT_NB_MAX);
00497         }
00498         else
00499           nb_desired_values= AUTO_INC_DEFAULT_NB_MAX;
00500       }
00501       /* This call ignores all its parameters but nr, currently */
00502       get_auto_increment(variables->auto_increment_offset,
00503                          variables->auto_increment_increment,
00504                          nb_desired_values, &nr,
00505                          &nb_reserved_values);
00506       if (nr == ~(uint64_t) 0)
00507         return HA_ERR_AUTOINC_READ_FAILED;  // Mark failure
00508 
00509       /*
00510         That rounding below should not be needed when all engines actually
00511         respect offset and increment in get_auto_increment(). But they don't
00512         so we still do it. Wonder if for the not-first-in-index we should do
00513         it. Hope that this rounding didn't push us out of the interval; even
00514         if it did we cannot do anything about it (calling the engine again
00515         will not help as we inserted no row).
00516       */
00517       nr= compute_next_insert_id(nr-1, variables);
00518     }
00519 
00520     if (getTable()->getShare()->next_number_keypart == 0)
00521     {
00522       /* We must defer the appending until "nr" has been possibly truncated */
00523       append= true;
00524     }
00525   }
00526 
00527   if (unlikely(getTable()->next_number_field->store((int64_t) nr, true)))
00528   {
00529     /*
00530       first test if the query was aborted due to strict mode constraints
00531     */
00532     if (session->getKilled() == Session::KILL_BAD_DATA)
00533       return HA_ERR_AUTOINC_ERANGE;
00534 
00535     /*
00536       field refused this value (overflow) and truncated it, use the result of
00537       the truncation (which is going to be inserted); however we try to
00538       decrease it to honour auto_increment_* variables.
00539       That will shift the left bound of the reserved interval, we don't
00540       bother shifting the right bound (anyway any other value from this
00541       interval will cause a duplicate key).
00542     */
00543     nr= prev_insert_id(getTable()->next_number_field->val_int(), variables);
00544     if (unlikely(getTable()->next_number_field->store((int64_t) nr, true)))
00545       nr= getTable()->next_number_field->val_int();
00546   }
00547   if (append)
00548     auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values, variables->auto_increment_increment);
00549 
00550   /*
00551     Record this autogenerated value. If the caller then
00552     succeeds to insert this value, it will call
00553     record_first_successful_insert_id_in_cur_stmt()
00554     which will set first_successful_insert_id_in_cur_stmt if it's not
00555     already set.
00556   */
00557   insert_id_for_cur_row= nr;
00558   /*
00559     Set next insert id to point to next auto-increment value to be able to
00560     handle multi-row statements.
00561   */
00562   set_next_insert_id(compute_next_insert_id(nr, variables));
00563 
00564   return 0;
00565 }
00566 
00567 
00584 void Cursor::ha_release_auto_increment()
00585 {
00586   release_auto_increment();
00587   insert_id_for_cur_row= 0;
00588   auto_inc_interval_for_cur_row.replace(0, 0, 0);
00589   next_insert_id= 0;
00590 }
00591 
00592 void Cursor::drop_table()
00593 {
00594   close();
00595 }
00596 
00597 int Cursor::ha_check(Session*)
00598 {
00599   return HA_ADMIN_OK;
00600 }
00601 
00607 inline
00608 void
00609 Cursor::setTransactionReadWrite()
00610 {
00611   /*
00612    * If the cursor has not context for execution then there should be no
00613    * possible resource to gain (and if there is... then there is a bug such
00614    * that in_use should have been set.
00615  */
00616   if (not getTable()->in_use)
00617     return;
00618 
00619   /*
00620     When a storage engine method is called, the transaction must
00621     have been started, unless it's a DDL call, for which the
00622     storage engine starts the transaction internally, and commits
00623     it internally, without registering in the ha_list.
00624     Unfortunately here we can't know know for sure if the engine
00625     has registered the transaction or not, so we must check.
00626   */
00627   ResourceContext& resource_context= getTable()->in_use->getResourceContext(*getEngine());
00628   if (resource_context.isStarted())
00629     resource_context.markModifiedData();
00630 }
00631 
00632 
00643 int
00644 Cursor::ha_delete_all_rows()
00645 {
00646   setTransactionReadWrite();
00647 
00648   int result= delete_all_rows();
00649 
00650   if (result == 0)
00651   {
00658     Session& session= *getTable()->in_use;
00659     TransactionServices::truncateTable(session, *getTable());
00660   }
00661 
00662   return result;
00663 }
00664 
00665 
00672 int
00673 Cursor::ha_reset_auto_increment(uint64_t value)
00674 {
00675   setTransactionReadWrite();
00676 
00677   return reset_auto_increment(value);
00678 }
00679 
00680 
00687 int
00688 Cursor::ha_analyze(Session* session)
00689 {
00690   setTransactionReadWrite();
00691 
00692   return analyze(session);
00693 }
00694 
00701 int
00702 Cursor::ha_disable_indexes(uint32_t mode)
00703 {
00704   setTransactionReadWrite();
00705 
00706   return disable_indexes(mode);
00707 }
00708 
00709 
00716 int
00717 Cursor::ha_enable_indexes(uint32_t mode)
00718 {
00719   setTransactionReadWrite();
00720 
00721   return enable_indexes(mode);
00722 }
00723 
00724 
00731 int Cursor::ha_discard_or_import_tablespace(bool discard)
00732 {
00733   setTransactionReadWrite();
00734   return discard_or_import_tablespace(discard);
00735 }
00736 
00743 void Cursor::closeMarkForDelete()
00744 {
00745   setTransactionReadWrite();
00746   return drop_table();
00747 }
00748 
00749 int Cursor::index_next_same(unsigned char *buf, const unsigned char *key, uint32_t keylen)
00750 {
00751   int error= index_next(buf);
00752   if (error)
00753     return error;
00754 
00755   ptrdiff_t ptrdiff= buf - getTable()->getInsertRecord();
00756   unsigned char *save_record_0= NULL;
00757   KeyInfo *key_info= NULL;
00758   KeyPartInfo *key_part;
00759   KeyPartInfo *key_part_end= NULL;
00760 
00761   /*
00762   key_cmp_if_same() compares table->getInsertRecord() against 'key'.
00763   In parts it uses table->getInsertRecord() directly, in parts it uses
00764   field objects with their local pointers into table->getInsertRecord().
00765   If 'buf' is distinct from table->getInsertRecord(), we need to move
00766   all record references. This is table->getInsertRecord() itself and
00767   the field pointers of the fields used in this key.
00768   */
00769   if (ptrdiff)
00770   {
00771     save_record_0= getTable()->getInsertRecord();
00772     getTable()->record[0]= buf;
00773     key_info= getTable()->key_info + active_index;
00774     key_part= key_info->key_part;
00775     key_part_end= key_part + key_info->key_parts;
00776     for (; key_part < key_part_end; key_part++)
00777     {
00778       assert(key_part->field);
00779       key_part->field->move_field_offset(ptrdiff);
00780     }
00781   }
00782 
00783   if (key_cmp_if_same(getTable(), key, active_index, keylen))
00784   {
00785     getTable()->status=STATUS_NOT_FOUND;
00786     error= HA_ERR_END_OF_FILE;
00787   }
00788 
00789   /* Move back if necessary. */
00790   if (ptrdiff)
00791   {
00792     getTable()->record[0]= save_record_0;
00793     for (key_part= key_info->key_part; key_part < key_part_end; key_part++)
00794       key_part->field->move_field_offset(-ptrdiff);
00795   }
00796   return error;
00797 }
00798 
00799 
00800 /****************************************************************************
00801 ** Some general functions that isn't in the Cursor class
00802 ****************************************************************************/
00803 
00825 double Cursor::index_only_read_time(uint32_t keynr, double key_records)
00826 {
00827   uint32_t keys_per_block= (stats.block_size/2/
00828       (getTable()->key_info[keynr].key_length + ref_length) + 1);
00829   return ((double) (key_records + keys_per_block-1) /
00830           (double) keys_per_block);
00831 }
00832 
00833 
00834 /****************************************************************************
00835  * Default MRR implementation (MRR to non-MRR converter)
00836  ***************************************************************************/
00837 
00869 ha_rows
00870 Cursor::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
00871                                      void *seq_init_param,
00872                                      uint32_t ,
00873                                      uint32_t *bufsz, uint32_t *flags, optimizer::CostVector *cost)
00874 {
00875   KEY_MULTI_RANGE range;
00876   range_seq_t seq_it;
00877   ha_rows rows, total_rows= 0;
00878   uint32_t n_ranges=0;
00879 
00880   /* Default MRR implementation doesn't need buffer */
00881   *bufsz= 0;
00882 
00883   seq_it= seq->init(seq_init_param, n_ranges, *flags);
00884   while (!seq->next(seq_it, &range))
00885   {
00886     n_ranges++;
00887     key_range *min_endp, *max_endp;
00888     {
00889       min_endp= range.start_key.length? &range.start_key : NULL;
00890       max_endp= range.end_key.length? &range.end_key : NULL;
00891     }
00892     if ((range.range_flag & UNIQUE_RANGE) && !(range.range_flag & NULL_RANGE))
00893       rows= 1; /* there can be at most one row */
00894     else
00895     {
00896       if (HA_POS_ERROR == (rows= this->records_in_range(keyno, min_endp,
00897                                                         max_endp)))
00898       {
00899         /* Can't scan one range => can't do MRR scan at all */
00900         total_rows= HA_POS_ERROR;
00901         break;
00902       }
00903     }
00904     total_rows += rows;
00905   }
00906 
00907   if (total_rows != HA_POS_ERROR)
00908   {
00909     /* The following calculation is the same as in multi_range_read_info(): */
00910     *flags |= HA_MRR_USE_DEFAULT_IMPL;
00911     cost->zero();
00912     cost->setAvgIOCost(1); /* assume random seeks */
00913     if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2)
00914       cost->setIOCount(index_only_read_time(keyno, (uint32_t)total_rows));
00915     else
00916       cost->setIOCount(read_time(keyno, n_ranges, total_rows));
00917     cost->setCpuCost((double) total_rows / TIME_FOR_COMPARE + 0.01);
00918   }
00919   return total_rows;
00920 }
00921 
00922 
00957 int Cursor::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t n_rows,
00958                                    uint32_t *bufsz, uint32_t *flags, optimizer::CostVector *cost)
00959 {
00960   *bufsz= 0; /* Default implementation doesn't need a buffer */
00961 
00962   *flags |= HA_MRR_USE_DEFAULT_IMPL;
00963 
00964   cost->zero();
00965   cost->setAvgIOCost(1); /* assume random seeks */
00966 
00967   /* Produce the same cost as non-MRR code does */
00968   if (*flags & HA_MRR_INDEX_ONLY)
00969     cost->setIOCount(index_only_read_time(keyno, n_rows));
00970   else
00971     cost->setIOCount(read_time(keyno, n_ranges, n_rows));
00972   return 0;
00973 }
00974 
00975 
01017 int
01018 Cursor::multi_range_read_init(RANGE_SEQ_IF *seq_funcs, void *seq_init_param,
01019                                uint32_t n_ranges, uint32_t mode)
01020 {
01021   mrr_iter= seq_funcs->init(seq_init_param, n_ranges, mode);
01022   mrr_funcs= *seq_funcs;
01023   mrr_is_output_sorted= test(mode & HA_MRR_SORTED);
01024   mrr_have_range= false;
01025 
01026   return 0;
01027 }
01028 
01029 
01043 int Cursor::multi_range_read_next(char **range_info)
01044 {
01045   int result= 0;
01046   int range_res= 0;
01047 
01048   if (not mrr_have_range)
01049   {
01050     mrr_have_range= true;
01051     goto start;
01052   }
01053 
01054   do
01055   {
01056     /* Save a call if there can be only one row in range. */
01057     if (mrr_cur_range.range_flag != (UNIQUE_RANGE | EQ_RANGE))
01058     {
01059       result= read_range_next();
01060       /* On success or non-EOF errors jump to the end. */
01061       if (result != HA_ERR_END_OF_FILE)
01062         break;
01063     }
01064     else
01065     {
01066       if (was_semi_consistent_read())
01067         goto scan_it_again;
01068       /*
01069         We need to set this for the last range only, but checking this
01070         condition is more expensive than just setting the result code.
01071       */
01072       result= HA_ERR_END_OF_FILE;
01073     }
01074 
01075 start:
01076     /* Try the next range(s) until one matches a record. */
01077     while (!(range_res= mrr_funcs.next(mrr_iter, &mrr_cur_range)))
01078     {
01079 scan_it_again:
01080       result= read_range_first(mrr_cur_range.start_key.keypart_map ?
01081                                  &mrr_cur_range.start_key : 0,
01082                                mrr_cur_range.end_key.keypart_map ?
01083                                  &mrr_cur_range.end_key : 0,
01084                                test(mrr_cur_range.range_flag & EQ_RANGE),
01085                                mrr_is_output_sorted);
01086       if (result != HA_ERR_END_OF_FILE)
01087         break;
01088     }
01089   }
01090   while ((result == HA_ERR_END_OF_FILE) && !range_res);
01091 
01092   *range_info= mrr_cur_range.ptr;
01093   return result;
01094 }
01095 
01096 
01097 /* **************************************************************************
01098  * DS-MRR implementation ends
01099  ***************************************************************************/
01100 
01119 int Cursor::read_range_first(const key_range *start_key,
01120                              const key_range *end_key,
01121                              bool eq_range_arg,
01122                              bool )
01123 {
01124   int result;
01125 
01126   eq_range= eq_range_arg;
01127   end_range= 0;
01128   if (end_key)
01129   {
01130     end_range= &save_end_range;
01131     save_end_range= *end_key;
01132     key_compare_result_on_equal= ((end_key->flag == HA_READ_BEFORE_KEY) ? 1 :
01133           (end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0);
01134   }
01135   range_key_part= getTable()->key_info[active_index].key_part;
01136 
01137   if (!start_key)     // Read first record
01138     result= index_first(getTable()->getInsertRecord());
01139   else
01140     result= index_read_map(getTable()->getInsertRecord(),
01141                            start_key->key,
01142                            start_key->keypart_map,
01143                            start_key->flag);
01144   if (result)
01145     return((result == HA_ERR_KEY_NOT_FOUND)
01146     ? HA_ERR_END_OF_FILE
01147     : result);
01148 
01149   return (compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE);
01150 }
01151 
01152 
01166 int Cursor::read_range_next()
01167 {
01168   int result;
01169 
01170   if (eq_range)
01171   {
01172     /* We trust that index_next_same always gives a row in range */
01173     return(index_next_same(getTable()->getInsertRecord(),
01174                                 end_range->key,
01175                                 end_range->length));
01176   }
01177   result= index_next(getTable()->getInsertRecord());
01178   if (result)
01179     return result;
01180   return(compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE);
01181 }
01182 
01183 
01199 int Cursor::compare_key(key_range *range)
01200 {
01201   int cmp;
01202   if (not range)
01203     return 0;         // No max range
01204   cmp= key_cmp(range_key_part, range->key, range->length);
01205   if (!cmp)
01206     cmp= key_compare_result_on_equal;
01207   return cmp;
01208 }
01209 
01210 int Cursor::index_read_idx_map(unsigned char * buf, uint32_t index,
01211                                 const unsigned char * key,
01212                                 key_part_map keypart_map,
01213                                 enum ha_rkey_function find_flag)
01214 {
01215   int error, error1;
01216   error= doStartIndexScan(index, 0);
01217   if (!error)
01218   {
01219     error= index_read_map(buf, key, keypart_map, find_flag);
01220     error1= doEndIndexScan();
01221   }
01222   return error ?  error : error1;
01223 }
01224 
01232 static bool log_row_for_replication(Table* table,
01233                                     const unsigned char *before_record,
01234                                     const unsigned char *after_record)
01235 {
01236   Session *const session= table->in_use;
01237 
01238   if (table->getShare()->getType() || not TransactionServices::shouldConstructMessages())
01239     return false;
01240 
01241   bool result= false;
01242 
01243   switch (session->lex().sql_command)
01244   {
01245   case SQLCOM_CREATE_TABLE:
01246     /*
01247      * We are in a CREATE TABLE ... SELECT statement
01248      * and the kernel has already created the table
01249      * and put a CreateTableStatement in the active
01250      * Transaction message.  Here, we add a new InsertRecord
01251      * to a new Transaction message (because the above
01252      * CREATE TABLE will commit the transaction containing
01253      * it).
01254      */
01255     result= TransactionServices::insertRecord(*session, *table);
01256     break;
01257   case SQLCOM_REPLACE:
01258   case SQLCOM_REPLACE_SELECT:
01259     /*
01260      * This is a total hack because of the code that is
01261      * in write_record() in sql_insert.cc. During
01262      * a REPLACE statement, a call to insertRecord() is
01263      * called.  If it fails, then a call to deleteRecord()
01264      * is called, followed by a repeat of the original
01265      * call to insertRecord().  So, log_row_for_replication
01266      * could be called multiple times for a REPLACE
01267      * statement.  The below looks at the values of before_record
01268      * and after_record to determine which call to this
01269      * function is for the delete or the insert, since NULL
01270      * is passed for after_record for the delete and NULL is
01271      * passed for before_record for the insert...
01272      *
01273      * In addition, there is an optimization that allows an
01274      * engine to convert the above delete + insert into an
01275      * update, so we must also check for this case below...
01276      */
01277     if (after_record == NULL)
01278     {
01279       /*
01280        * The storage engine is passed the record in table->record[1]
01281        * as the row to delete (this is the conflicting row), so
01282        * we need to notify TransactionService to use that row.
01283        */
01284       TransactionServices::deleteRecord(*session, *table, true);
01285       /* 
01286        * We set the "current" statement message to NULL.  This triggers
01287        * the replication services component to generate a new statement
01288        * message for the inserted record which will come next.
01289        */
01290       TransactionServices::finalizeStatementMessage(*session->getStatementMessage(), *session);
01291     }
01292     else
01293     {
01294       if (before_record == NULL)
01295         result= TransactionServices::insertRecord(*session, *table);
01296       else
01297         TransactionServices::updateRecord(*session, *table, before_record, after_record);
01298     }
01299     break;
01300   case SQLCOM_INSERT:
01301   case SQLCOM_INSERT_SELECT:
01302   case SQLCOM_LOAD:
01303     /*
01304      * The else block below represents an 
01305      * INSERT ... ON DUPLICATE KEY UPDATE that
01306      * has hit a key conflict and actually done
01307      * an update.
01308      */
01309     if (before_record == NULL)
01310       result= TransactionServices::insertRecord(*session, *table);
01311     else
01312       TransactionServices::updateRecord(*session, *table, before_record, after_record);
01313     break;
01314 
01315   case SQLCOM_UPDATE:
01316     TransactionServices::updateRecord(*session, *table, before_record, after_record);
01317     break;
01318 
01319   case SQLCOM_DELETE:
01320     TransactionServices::deleteRecord(*session, *table);
01321     break;
01322   default:
01323     break;
01324   }
01325 
01326   return result;
01327 }
01328 
01329 int Cursor::ha_external_lock(Session *session, int lock_type)
01330 {
01331   /*
01332     Whether this is lock or unlock, this should be true, and is to verify that
01333     if get_auto_increment() was called (thus may have reserved intervals or
01334     taken a table lock), ha_release_auto_increment() was too.
01335   */
01336   assert(next_insert_id == 0);
01337 
01338   if (DRIZZLE_CURSOR_RDLOCK_START_ENABLED() ||
01339       DRIZZLE_CURSOR_WRLOCK_START_ENABLED() ||
01340       DRIZZLE_CURSOR_UNLOCK_START_ENABLED())
01341   {
01342     if (lock_type == F_RDLCK)
01343     {
01344       DRIZZLE_CURSOR_RDLOCK_START(getTable()->getShare()->getSchemaName(),
01345                                   getTable()->getShare()->getTableName());
01346     }
01347     else if (lock_type == F_WRLCK)
01348     {
01349       DRIZZLE_CURSOR_WRLOCK_START(getTable()->getShare()->getSchemaName(),
01350                                   getTable()->getShare()->getTableName());
01351     }
01352     else if (lock_type == F_UNLCK)
01353     {
01354       DRIZZLE_CURSOR_UNLOCK_START(getTable()->getShare()->getSchemaName(),
01355                                   getTable()->getShare()->getTableName());
01356     }
01357   }
01358 
01359   /*
01360     We cache the table flags if the locking succeeded. Otherwise, we
01361     keep them as they were when they were fetched in ha_open().
01362   */
01363 
01364   int error= external_lock(session, lock_type);
01365 
01366   if (DRIZZLE_CURSOR_RDLOCK_DONE_ENABLED() ||
01367       DRIZZLE_CURSOR_WRLOCK_DONE_ENABLED() ||
01368       DRIZZLE_CURSOR_UNLOCK_DONE_ENABLED())
01369   {
01370     if (lock_type == F_RDLCK)
01371     {
01372       DRIZZLE_CURSOR_RDLOCK_DONE(error);
01373     }
01374     else if (lock_type == F_WRLCK)
01375     {
01376       DRIZZLE_CURSOR_WRLOCK_DONE(error);
01377     }
01378     else if (lock_type == F_UNLCK)
01379     {
01380       DRIZZLE_CURSOR_UNLOCK_DONE(error);
01381     }
01382   }
01383 
01384   return error;
01385 }
01386 
01387 
01391 int Cursor::ha_reset()
01392 {
01393   /* Check that we have called all proper deallocation functions */
01394   assert(! getTable()->getShare()->all_set.none());
01395   assert(getTable()->key_read == 0);
01396   /* ensure that ha_index_end / endTableScan has been called */
01397   assert(inited == NONE);
01398   /* Free cache used by filesort */
01399   getTable()->free_io_cache();
01400   /* reset the bitmaps to point to defaults */
01401   getTable()->default_column_bitmaps();
01402   return(reset());
01403 }
01404 
01405 
01406 int Cursor::insertRecord(unsigned char *buf)
01407 {
01408   int error;
01409 
01410   /*
01411    * If we have a timestamp column, update it to the current time
01412    *
01413    * @TODO Technically, the below two lines can be take even further out of the
01414    * Cursor interface and into the fill_record() method.
01415    */
01416   if (getTable()->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
01417   {
01418     getTable()->timestamp_field->set_time();
01419   }
01420 
01421   DRIZZLE_INSERT_ROW_START(getTable()->getShare()->getSchemaName(), getTable()->getShare()->getTableName());
01422   setTransactionReadWrite();
01423   
01424   if (unlikely(plugin::EventObserver::beforeInsertRecord(*getTable(), buf)))
01425   {
01426     error= ER_EVENT_OBSERVER_PLUGIN;
01427   }
01428   else
01429   {
01430     error= doInsertRecord(buf);
01431     if (unlikely(plugin::EventObserver::afterInsertRecord(*getTable(), buf, error))) 
01432     {
01433       error= ER_EVENT_OBSERVER_PLUGIN;
01434     }
01435   }
01436 
01437   ha_statistic_increment(&system_status_var::ha_write_count);
01438 
01439   DRIZZLE_INSERT_ROW_DONE(error);
01440 
01441   if (unlikely(error))
01442   {
01443     return error;
01444   }
01445 
01446   if (unlikely(log_row_for_replication(getTable(), NULL, buf)))
01447     return HA_ERR_RBR_LOGGING_FAILED;
01448 
01449   return 0;
01450 }
01451 
01452 
01453 int Cursor::updateRecord(const unsigned char *old_data, unsigned char *new_data)
01454 {
01455   int error;
01456 
01457   /*
01458     Some storage engines require that the new record is in getInsertRecord()
01459     (and the old record is in getUpdateRecord()).
01460    */
01461   assert(new_data == getTable()->getInsertRecord());
01462 
01463   DRIZZLE_UPDATE_ROW_START(getTable()->getShare()->getSchemaName(), getTable()->getShare()->getTableName());
01464   setTransactionReadWrite();
01465   if (unlikely(plugin::EventObserver::beforeUpdateRecord(*getTable(), old_data, new_data)))
01466   {
01467     error= ER_EVENT_OBSERVER_PLUGIN;
01468   }
01469   else
01470   {
01471     if (getTable()->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
01472     {
01473       getTable()->timestamp_field->set_time();
01474     }
01475 
01476     error= doUpdateRecord(old_data, new_data);
01477     if (unlikely(plugin::EventObserver::afterUpdateRecord(*getTable(), old_data, new_data, error)))
01478     {
01479       error= ER_EVENT_OBSERVER_PLUGIN;
01480     }
01481   }
01482 
01483   ha_statistic_increment(&system_status_var::ha_update_count);
01484 
01485   DRIZZLE_UPDATE_ROW_DONE(error);
01486 
01487   if (unlikely(error))
01488   {
01489     return error;
01490   }
01491 
01492   if (unlikely(log_row_for_replication(getTable(), old_data, new_data)))
01493     return HA_ERR_RBR_LOGGING_FAILED;
01494 
01495   return 0;
01496 }
01497 TableShare *Cursor::getShare()
01498 {
01499   return getTable()->getMutableShare();
01500 }
01501 
01502 int Cursor::deleteRecord(const unsigned char *buf)
01503 {
01504   int error;
01505 
01506   DRIZZLE_DELETE_ROW_START(getTable()->getShare()->getSchemaName(), getTable()->getShare()->getTableName());
01507   setTransactionReadWrite();
01508   if (unlikely(plugin::EventObserver::beforeDeleteRecord(*getTable(), buf)))
01509   {
01510     error= ER_EVENT_OBSERVER_PLUGIN;
01511   }
01512   else
01513   {
01514     error= doDeleteRecord(buf);
01515     if (unlikely(plugin::EventObserver::afterDeleteRecord(*getTable(), buf, error)))
01516     {
01517       error= ER_EVENT_OBSERVER_PLUGIN;
01518     }
01519   }
01520 
01521   ha_statistic_increment(&system_status_var::ha_delete_count);
01522 
01523   DRIZZLE_DELETE_ROW_DONE(error);
01524 
01525   if (unlikely(error))
01526     return error;
01527 
01528   if (unlikely(log_row_for_replication(getTable(), buf, NULL)))
01529     return HA_ERR_RBR_LOGGING_FAILED;
01530 
01531   return 0;
01532 }
01533 
01534 } /* namespace drizzled */