Drizzled Public API Documentation

ha_innodb.cc
Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003 Copyright (C) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved.
00004 Copyright (C) 2008, 2009 Google Inc.
00005 Copyright (C) 2009, Percona Inc.
00006 Copyright (C) 2011, Stewart Smith
00007 
00008 Portions of this file contain modifications contributed and copyrighted by
00009 Google, Inc. Those modifications are gratefully acknowledged and are described
00010 briefly in the InnoDB documentation. The contributions by Google are
00011 incorporated with their permission, and subject to the conditions contained in
00012 the file COPYING.Google.
00013 
00014 Portions of this file contain modifications contributed and copyrighted
00015 by Percona Inc.. Those modifications are
00016 gratefully acknowledged and are described briefly in the InnoDB
00017 documentation. The contributions by Percona Inc. are incorporated with
00018 their permission, and subject to the conditions contained in the file
00019 COPYING.Percona.
00020 
00021 This program is free software; you can redistribute it and/or modify it under
00022 the terms of the GNU General Public License as published by the Free Software
00023 Foundation; version 2 of the License.
00024 
00025 This program is distributed in the hope that it will be useful, but WITHOUT
00026 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00027 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00028 
00029 You should have received a copy of the GNU General Public License along with
00030 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00031 St, Fifth Floor, Boston, MA 02110-1301 USA
00032 
00033 *****************************************************************************/
00034 
00035 /* TODO list for the InnoDB Cursor in 5.0:
00036   - fix savepoint functions to use savepoint storage area
00037   - Find out what kind of problems the OS X case-insensitivity causes to
00038     table and database names; should we 'normalize' the names like we do
00039     in Windows?
00040 */
00041 
00042 #include <config.h>
00043 
00044 #include <limits.h>
00045 #include <fcntl.h>
00046 
00047 #include <drizzled/error.h>
00048 #include <drizzled/errmsg_print.h>
00049 #include <drizzled/internal/m_string.h>
00050 #include <drizzled/internal/my_sys.h>
00051 #include <drizzled/plugin.h>
00052 #include <drizzled/show.h>
00053 #include <drizzled/data_home.h>
00054 #include <drizzled/catalog/local.h>
00055 #include <drizzled/error.h>
00056 #include <drizzled/field.h>
00057 #include <drizzled/charset.h>
00058 #include <drizzled/session.h>
00059 #include <drizzled/current_session.h>
00060 #include <drizzled/table.h>
00061 #include <drizzled/field/blob.h>
00062 #include <drizzled/field/varstring.h>
00063 #include <drizzled/plugin/xa_storage_engine.h>
00064 #include <drizzled/plugin/daemon.h>
00065 #include <drizzled/memory/multi_malloc.h>
00066 #include <drizzled/pthread_globals.h>
00067 #include <drizzled/named_savepoint.h>
00068 #include <drizzled/session/table_messages.h>
00069 #include <drizzled/transaction_services.h>
00070 #include <drizzled/message/statement_transform.h>
00071 #include <drizzled/cached_directory.h>
00072 #include <drizzled/statistics_variables.h>
00073 #include <drizzled/system_variables.h>
00074 #include <drizzled/session/times.h>
00075 #include <drizzled/session/transactions.h>
00076 #include <drizzled/typelib.h>
00077 
00078 #include <boost/algorithm/string.hpp>
00079 #include <boost/program_options.hpp>
00080 #include <boost/scoped_array.hpp>
00081 #include <boost/filesystem.hpp>
00082 #include <drizzled/module/option_map.h>
00083 #include <iostream>
00084 
00085 namespace po= boost::program_options;
00086 namespace fs=boost::filesystem;
00087 using namespace std;
00088 
00091 /* Include necessary InnoDB headers */
00092 #include "univ.i"
00093 #include "buf0lru.h"
00094 #include "btr0sea.h"
00095 #include "os0file.h"
00096 #include "os0thread.h"
00097 #include "srv0start.h"
00098 #include "srv0srv.h"
00099 #include "trx0roll.h"
00100 #include "trx0trx.h"
00101 #include "trx0sys.h"
00102 #include "mtr0mtr.h"
00103 #include "row0ins.h"
00104 #include "row0mysql.h"
00105 #include "row0sel.h"
00106 #include "row0upd.h"
00107 #include "log0log.h"
00108 #include "lock0lock.h"
00109 #include "dict0crea.h"
00110 #include "create_replication.h"
00111 #include "btr0cur.h"
00112 #include "btr0btr.h"
00113 #include "fsp0fsp.h"
00114 #include "sync0sync.h"
00115 #include "fil0fil.h"
00116 #include "trx0xa.h"
00117 #include "row0merge.h"
00118 #include "thr0loc.h"
00119 #include "dict0boot.h"
00120 #include "ha_prototypes.h"
00121 #include "ut0mem.h"
00122 #include "ibuf0ibuf.h"
00123 
00124 #include "ha_innodb.h"
00125 #include "data_dictionary.h"
00126 #include "replication_dictionary.h"
00127 #include "internal_dictionary.h"
00128 #include "handler0vars.h"
00129 
00130 #include <iostream>
00131 #include <sstream>
00132 #include <string>
00133 
00134 #include <plugin/innobase/handler/status_function.h>
00135 #include <plugin/innobase/handler/replication_log.h>
00136 
00137 #include <google/protobuf/io/zero_copy_stream.h>
00138 #include <google/protobuf/io/zero_copy_stream_impl.h>
00139 #include <google/protobuf/io/coded_stream.h>
00140 #include <google/protobuf/text_format.h>
00141 
00142 #include <boost/thread/mutex.hpp>
00143 
00144 using namespace std;
00145 using namespace drizzled;
00146 
00148 static boost::mutex innobase_share_mutex;
00149 
00151 static ulong commit_threads = 0;
00152 static boost::condition_variable commit_cond;
00153 static boost::mutex commit_cond_m;
00154 static bool innodb_inited = 0;
00155 
00156 #define INSIDE_HA_INNOBASE_CC
00157 
00158 /* In the Windows plugin, the return value of current_session is
00159 undefined.  Map it to NULL. */
00160 #if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
00161 # undef current_session
00162 # define current_session NULL
00163 # define EQ_CURRENT_SESSION(session) TRUE
00164 #else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
00165 # define EQ_CURRENT_SESSION(session) ((session) == current_session)
00166 #endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
00167 
00168 static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
00169 
00170 typedef constrained_check<uint32_t, UINT32_MAX, 10> open_files_constraint;
00171 static open_files_constraint innobase_open_files;
00172 typedef constrained_check<uint32_t, 10, 1> mirrored_log_groups_constraint;
00173 static mirrored_log_groups_constraint innobase_mirrored_log_groups;
00174 typedef constrained_check<uint32_t, 100, 2> log_files_in_group_constraint;
00175 static log_files_in_group_constraint innobase_log_files_in_group;
00176 typedef constrained_check<uint32_t, 6, 0> force_recovery_constraint;
00177 force_recovery_constraint innobase_force_recovery;
00178 typedef constrained_check<size_t, SIZE_MAX, 256*1024, 1024> log_buffer_constraint;
00179 static log_buffer_constraint innobase_log_buffer_size;
00180 typedef constrained_check<size_t, SIZE_MAX, 512*1024, 1024> additional_mem_pool_constraint;
00181 static additional_mem_pool_constraint innobase_additional_mem_pool_size;
00182 typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
00183 static autoextend_constraint innodb_auto_extend_increment;
00184 typedef constrained_check<size_t, SIZE_MAX, 33554432, 1048576> buffer_pool_constraint;
00185 static buffer_pool_constraint innobase_buffer_pool_size;
00186 typedef constrained_check<uint32_t, MAX_BUFFER_POOLS, 1> buffer_pool_instances_constraint;
00187 static buffer_pool_instances_constraint innobase_buffer_pool_instances;
00188 typedef constrained_check<uint32_t,
00189         (1 << UNIV_PAGE_SIZE_SHIFT_MAX),
00190         (1 << 12)> page_size_constraint;
00191 static page_size_constraint innobase_page_size;
00192 typedef constrained_check<uint32_t,
00193         (1 << UNIV_PAGE_SIZE_SHIFT_MAX),
00194         (1 << 9)> log_block_size_constraint;
00195 static log_block_size_constraint innobase_log_block_size;
00196 typedef constrained_check<uint32_t, UINT32_MAX, 100> io_capacity_constraint;
00197 static io_capacity_constraint innodb_io_capacity;
00198 typedef constrained_check<uint32_t, 5000, 1> purge_batch_constraint;
00199 static purge_batch_constraint innodb_purge_batch_size;
00200 typedef constrained_check<uint32_t, 1, 0> purge_threads_constraint;
00201 static purge_threads_constraint innodb_n_purge_threads;
00202 typedef constrained_check<uint32_t, 2, 0> trinary_constraint;
00203 static trinary_constraint innodb_flush_log_at_trx_commit;
00204 typedef constrained_check<unsigned int, 99, 0> max_dirty_pages_constraint;
00205 static max_dirty_pages_constraint innodb_max_dirty_pages_pct;
00206 static uint64_constraint innodb_max_purge_lag;
00207 static uint64_nonzero_constraint innodb_stats_sample_pages;
00208 typedef constrained_check<uint32_t, 64, 1> io_threads_constraint;
00209 static io_threads_constraint innobase_read_io_threads;
00210 static io_threads_constraint innobase_write_io_threads;
00211 
00212 typedef constrained_check<uint32_t, 1000, 0> concurrency_constraint;
00213 static concurrency_constraint innobase_commit_concurrency;
00214 static concurrency_constraint innobase_thread_concurrency;
00215 static uint32_nonzero_constraint innodb_concurrency_tickets;
00216 
00217 typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
00218 static log_file_constraint innobase_log_file_size;
00219 
00220 static uint64_constraint innodb_replication_delay;
00221 
00222 static uint32_constraint buffer_pool_restore_at_startup;
00223 
00226 typedef constrained_check<uint32_t, 95, 5> old_blocks_constraint;
00227 static old_blocks_constraint innobase_old_blocks_pct;
00228 
00229 static uint32_constraint innodb_sync_spin_loops;
00230 static uint32_constraint innodb_spin_wait_delay;
00231 static uint32_constraint innodb_thread_sleep_delay;
00232 
00233 typedef constrained_check<uint32_t, 64, 0> read_ahead_threshold_constraint;
00234 static read_ahead_threshold_constraint innodb_read_ahead_threshold;
00235 
00236 static uint64_constraint ibuf_max_size;
00237 
00238 typedef constrained_check<uint32_t, 1, 0> binary_constraint;
00239 static binary_constraint ibuf_active_contract;
00240 
00241 typedef constrained_check<uint32_t, 999999999, 100> ibuf_accel_rate_constraint;
00242 static ibuf_accel_rate_constraint ibuf_accel_rate;
00243 static uint32_constraint checkpoint_age_target;
00244 static binary_constraint flush_neighbor_pages;
00245 
00246 /* The default values for the following char* start-up parameters
00247 are determined in innobase_init below: */
00248 
00249 std::string innobase_data_home_dir;
00250 std::string innobase_data_file_path;
00251 std::string innobase_log_group_home_dir;
00252 static string innobase_file_format_name;
00253 static string innobase_change_buffering;
00254 
00255 static string read_ahead;
00256 static string adaptive_flushing_method;
00257 
00258 /* The highest file format being used in the database. The value can be
00259 set by user, however, it will be adjusted to the newer file format if
00260 a table of such format is created/opened. */
00261 static string innobase_file_format_max;
00262 
00263 /* Below we have boolean-valued start-up parameters, and their default
00264 values */
00265 
00266 static trinary_constraint innobase_fast_shutdown;
00267 
00268 /* "innobase_file_format_check" decides whether we would continue
00269 booting the server if the file format stamped on the system
00270 table space exceeds the maximum file format supported
00271 by the server. Can be set during server startup at command
00272 line or configure file, and a read only variable after
00273 server startup */
00274 
00275 /* If a new file format is introduced, the file format
00276 name needs to be updated accordingly. Please refer to
00277 file_format_name_map[] defined in trx0sys.c for the next
00278 file format name. */
00279 
00280 static my_bool  innobase_file_format_check = TRUE;
00281 static my_bool  innobase_use_doublewrite    = TRUE;
00282 static my_bool  innobase_use_checksums      = TRUE;
00283 static my_bool  innobase_rollback_on_timeout    = FALSE;
00284 static my_bool  innobase_create_status_file   = FALSE;
00285 static bool innobase_use_replication_log;
00286 static bool support_xa;
00287 static bool strict_mode;
00288 typedef constrained_check<uint32_t, 1024*1024*1024, 1> lock_wait_constraint;
00289 static lock_wait_constraint lock_wait_timeout;
00290 
00291 static char*  internal_innobase_data_file_path  = NULL;
00292 
00293 /* The following counter is used to convey information to InnoDB
00294 about server activity: in selects it is not sensible to call
00295 srv_active_wake_master_thread after each fetch or search, we only do
00296 it every INNOBASE_WAKE_INTERVAL'th step. */
00297 
00298 #define INNOBASE_WAKE_INTERVAL  32
00299 static ulong  innobase_active_counter = 0;
00300 
00301 static hash_table_t*  innobase_open_tables;
00302 
00303 #ifdef __NETWARE__  /* some special cleanup for NetWare */
00304 bool nw_panic = FALSE;
00305 #endif
00306 
00308 static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
00309   "none",   /* IBUF_USE_NONE */
00310   "inserts",  /* IBUF_USE_INSERT */
00311   "deletes",  /* IBUF_USE_DELETE_MARK */
00312   "changes",  /* IBUF_USE_INSERT_DELETE_MARK */
00313   "purges", /* IBUF_USE_DELETE */
00314   "all"   /* IBUF_USE_ALL */
00315 };
00316 
00318 static const char* read_ahead_names[] = {
00319   "none",       /* 0 */
00320   "random",
00321   "linear",
00322   "both",       /* 3 */
00323   /* For compatibility with the older Percona patch */
00324   "0",          /* 4 ("none" + 4) */
00325   "1",
00326   "2",
00327   "3",          /* 7 ("both" + 4) */
00328   NULL
00329 };
00330 
00331 static TYPELIB read_ahead_typelib = {
00332   array_elements(read_ahead_names) - 1, "read_ahead_typelib",
00333   read_ahead_names, NULL
00334 };
00335 
00337 static const char* adaptive_flushing_method_names[] = {
00338     "native",           /* 0 */
00339     "estimate",         /* 1 */
00340     "keep_average",     /* 2 */
00341     /* For compatibility with the older Percona patch */
00342     "0",                /* 3 ("native" + 3) */
00343     "1",                /* 4 ("estimate" + 3) */
00344     "2",                /* 5 ("keep_average" + 3) */
00345     NULL
00346 };
00347 
00348 static TYPELIB adaptive_flushing_method_typelib = {
00349   array_elements(adaptive_flushing_method_names) - 1,
00350   "adaptive_flushing_method_typelib",
00351   adaptive_flushing_method_names, NULL
00352 };
00353 
00354 /* "GEN_CLUST_INDEX" is the name reserved for Innodb default
00355 system primary index. */
00356 static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX";
00357 
00358 /********************************************************************
00359 Gives the file extension of an InnoDB single-table tablespace. */
00360 static const char* ha_innobase_exts[] = {
00361   ".ibd",
00362   NULL
00363 };
00364 
00365 #define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
00366 
00367 static INNOBASE_SHARE *get_share(const char *table_name);
00368 static void free_share(INNOBASE_SHARE *share);
00369 
00370 class InnobaseEngine : public plugin::XaStorageEngine
00371 {
00372 public:
00373   explicit InnobaseEngine(string name_arg) :
00374     plugin::XaStorageEngine(name_arg,
00375                             HTON_NULL_IN_KEY |
00376                             HTON_CAN_INDEX_BLOBS |
00377                             HTON_PRIMARY_KEY_IN_READ_INDEX |
00378                             HTON_PARTIAL_COLUMN_READ |
00379                             HTON_TABLE_SCAN_ON_INDEX |
00380                             HTON_HAS_FOREIGN_KEYS |
00381                             HTON_HAS_DOES_TRANSACTIONS)
00382   {
00383     table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
00384     addAlias("INNOBASE");
00385   }
00386 
00387   virtual ~InnobaseEngine()
00388   {
00389     if (innodb_inited) {
00390       srv_fast_shutdown = (ulint) innobase_fast_shutdown;
00391       innodb_inited = 0;
00392       hash_table_free(innobase_open_tables);
00393       innobase_open_tables = NULL;
00394       if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
00395         // Throw here?
00396       }
00397       srv_free_paths_and_sizes();
00398       free(internal_innobase_data_file_path);
00399     }
00400     
00401     /* These get strdup'd from vm variables */
00402 
00403   }
00404 
00405 private:
00406   virtual int doStartTransaction(Session *session, start_transaction_option_t options);
00407   virtual void doStartStatement(Session *session);
00408   virtual void doEndStatement(Session *session);
00409 public:
00410   virtual
00411   int
00412   close_connection(
00413 /*======================*/
00414       /* out: 0 or error number */
00415   Session*  session); /* in: handle to the MySQL thread of the user
00416       whose resources should be free'd */
00417 
00418   virtual int doSetSavepoint(Session* session,
00419                                  drizzled::NamedSavepoint &savepoint);
00420   virtual int doRollbackToSavepoint(Session* session,
00421                                      drizzled::NamedSavepoint &savepoint);
00422   virtual int doReleaseSavepoint(Session* session,
00423                                      drizzled::NamedSavepoint &savepoint);
00424   virtual int doXaCommit(Session* session, bool all)
00425   {
00426     return doCommit(session, all); /* XA commit just does a SQL COMMIT */
00427   }
00428   virtual int doXaRollback(Session *session, bool all)
00429   {
00430     return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
00431   }
00432   virtual uint64_t doGetCurrentTransactionId(Session *session);
00433   virtual uint64_t doGetNewTransactionId(Session *session);
00434   virtual int doCommit(Session* session, bool all);
00435   virtual int doRollback(Session* session, bool all);
00436 
00437   /***********************************************************************
00438   This function is used to prepare X/Open XA distributed transaction   */
00439   virtual
00440   int
00441   doXaPrepare(
00442   /*================*/
00443         /* out: 0 or error number */
00444     Session*  session,  /* in: handle to the MySQL thread of the user
00445         whose XA transaction should be prepared */
00446     bool  all); /* in: TRUE - commit transaction
00447         FALSE - the current SQL statement ended */
00448   /***********************************************************************
00449   This function is used to recover X/Open XA distributed transactions   */
00450   virtual
00451   int
00452   doXaRecover(
00453   /*================*/
00454           /* out: number of prepared transactions
00455           stored in xid_list */
00456     ::drizzled::XID*  xid_list, /* in/out: prepared transactions */
00457     size_t len);    /* in: number of slots in xid_list */
00458   /***********************************************************************
00459   This function is used to commit one X/Open XA distributed transaction
00460   which is in the prepared state */
00461   virtual
00462   int
00463   doXaCommitXid(
00464   /*===================*/
00465         /* out: 0 or error number */
00466     ::drizzled::XID*  xid); /* in: X/Open XA transaction identification */
00467   /***********************************************************************
00468   This function is used to rollback one X/Open XA distributed transaction
00469   which is in the prepared state */
00470   virtual
00471   int
00472   doXaRollbackXid(
00473   /*=====================*/
00474         /* out: 0 or error number */
00475     ::drizzled::XID *xid);  /* in: X/Open XA transaction identification */
00476 
00477   virtual Cursor *create(Table &table)
00478   {
00479     return new ha_innobase(*this, table);
00480   }
00481 
00482   /*********************************************************************
00483   Removes all tables in the named database inside InnoDB. */
00484   bool
00485   doDropSchema(
00486   /*===================*/
00487         /* out: error number */
00488     const identifier::Schema  &identifier); /* in: database path; inside InnoDB the name
00489         of the last directory in the path is used as
00490         the database name: for example, in 'mysql/data/test'
00491         the database name is 'test' */
00492 
00493   /********************************************************************
00494   Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
00495   the logs, and the name of this function should be innobase_checkpoint. */
00496   virtual
00497   bool
00498   flush_logs();
00499   /*================*/
00500           /* out: TRUE if error */
00501   
00502   /****************************************************************************
00503   Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
00504   Monitor to the client. */
00505   virtual
00506   bool
00507   show_status(
00508   /*===============*/
00509     Session*  session,  /* in: the MySQL query thread of the caller */
00510     stat_print_fn *stat_print,
00511   enum ha_stat_type stat_type);
00512 
00513   virtual
00514   int
00515   doReleaseTemporaryLatches(
00516   /*===============================*/
00517         /* out: 0 */
00518   Session*    session); /* in: MySQL thread */
00519 
00520 
00521   const char** bas_ext() const {
00522   return(ha_innobase_exts);
00523   }
00524 
00525   UNIV_INTERN int doCreateTable(Session &session,
00526                                 Table &form,
00527                                 const identifier::Table &identifier,
00528                                 const message::Table&);
00529   UNIV_INTERN int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
00530   UNIV_INTERN int doDropTable(Session &session, const identifier::Table &identifier);
00531 
00532   UNIV_INTERN virtual bool get_error_message(int error, String *buf) const;
00533 
00534   UNIV_INTERN uint32_t max_supported_keys() const;
00535   UNIV_INTERN uint32_t max_supported_key_length() const;
00536   UNIV_INTERN uint32_t max_supported_key_part_length() const;
00537 
00538 
00539   UNIV_INTERN uint32_t index_flags(enum  ha_key_alg) const
00540   {
00541     return (HA_READ_NEXT |
00542             HA_READ_PREV |
00543             HA_READ_ORDER |
00544             HA_READ_RANGE |
00545             HA_KEYREAD_ONLY);
00546   }
00547 
00548   int doGetTableDefinition(drizzled::Session& session,
00549                            const identifier::Table &identifier,
00550                            drizzled::message::Table &table_proto);
00551 
00552   bool doDoesTableExist(drizzled::Session& session, const identifier::Table &identifier);
00553 
00554   void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
00555                              const drizzled::identifier::Schema &schema_identifier,
00556                              drizzled::identifier::table::vector &set_of_identifiers);
00557   bool validateCreateTableOption(const std::string &key, const std::string &state);
00558   void dropTemporarySchema();
00559 
00560 };
00561 
00562 
00563 bool InnobaseEngine::validateCreateTableOption(const std::string &key, const std::string &state)
00564 {
00565   if (boost::iequals(key, "ROW_FORMAT"))
00566   {
00567     if (boost::iequals(state, "COMPRESSED"))
00568       return true;
00569 
00570     if (boost::iequals(state, "COMPACT"))
00571       return true;
00572 
00573     if (boost::iequals(state, "DYNAMIC"))
00574       return true;
00575 
00576     if (boost::iequals(state, "REDUNDANT"))
00577       return true;
00578   }
00579 
00580   return false;
00581 }
00582 
00583 void InnobaseEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
00584                                            const drizzled::identifier::Schema &schema_identifier,
00585                                            drizzled::identifier::table::vector &set_of_identifiers)
00586 {
00587   CachedDirectory::Entries entries= directory.getEntries();
00588 
00589   std::string search_string(schema_identifier.getSchemaName());
00590 
00591   boost::algorithm::to_lower(search_string);
00592 
00593   if (search_string.compare("data_dictionary") == 0)
00594   {
00595     set_of_identifiers.push_back(identifier::Table(schema_identifier.getSchemaName(), "SYS_REPLICATION_LOG"));
00596   }
00597 
00598   for (CachedDirectory::Entries::iterator entry_iter= entries.begin(); 
00599        entry_iter != entries.end(); ++entry_iter)
00600   {
00601     CachedDirectory::Entry *entry= *entry_iter;
00602     const string *filename= &entry->filename;
00603 
00604     assert(filename->size());
00605 
00606     const char *ext= strchr(filename->c_str(), '.');
00607 
00608     if (ext == NULL || system_charset_info->strcasecmp(ext, DEFAULT_FILE_EXTENSION) ||
00609         (filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
00610     { }
00611     else
00612     {
00613       std::string path;
00614       path+= directory.getPath();
00615       path+= FN_LIBCHAR;
00616       path+= entry->filename;
00617 
00618       message::Table definition;
00619       if (StorageEngine::readTableFile(path, definition))
00620       {
00621         /* 
00622            Using schema_identifier here to stop unused warning, could use
00623            definition.schema() instead
00624         */
00625         identifier::Table identifier(schema_identifier.getSchemaName(), definition.name());
00626         set_of_identifiers.push_back(identifier);
00627       }
00628     }
00629   }
00630 }
00631 
00632 bool InnobaseEngine::doDoesTableExist(Session &session, const identifier::Table &identifier)
00633 {
00634   string proto_path(identifier.getPath());
00635   proto_path.append(DEFAULT_FILE_EXTENSION);
00636 
00637   if (session.getMessageCache().doesTableMessageExist(identifier))
00638     return true;
00639 
00640   std::string search_string(identifier.getPath());
00641   boost::algorithm::to_lower(search_string);
00642 
00643   if (search_string.compare("data_dictionary/sys_replication_log") == 0)
00644     return true;
00645 
00646   if (access(proto_path.c_str(), F_OK))
00647   {
00648     return false;
00649   }
00650 
00651   return true;
00652 }
00653 
00654 int InnobaseEngine::doGetTableDefinition(Session &session,
00655                                          const identifier::Table &identifier,
00656                                          message::Table &table_proto)
00657 {
00658   string proto_path(identifier.getPath());
00659   proto_path.append(DEFAULT_FILE_EXTENSION);
00660 
00661   // First we check the temporary tables.
00662   if (session.getMessageCache().getTableMessage(identifier, table_proto))
00663     return EEXIST;
00664 
00665   if (read_replication_log_table_message(identifier.getTableName().c_str(), &table_proto) == 0)
00666     return EEXIST;
00667 
00668   if (access(proto_path.c_str(), F_OK))
00669   {
00670     return errno;
00671   }
00672 
00673   if (StorageEngine::readTableFile(proto_path, table_proto))
00674     return EEXIST;
00675 
00676   return ENOENT;
00677 }
00678 
00679 
00680 /************************************************************/
00683 static
00684 uint
00685 innobase_file_format_name_lookup(
00686 /*=============================*/
00687   const char* format_name);   
00689 /************************************************************/
00693 static
00694 int
00695 innobase_file_format_validate_and_set(
00696 /*================================*/
00697   const char* format_max);    
00699 static const char innobase_engine_name[]= "InnoDB";
00700 
00701 
00702 /*****************************************************************/
00704 static
00705 void
00706 innobase_commit_low(
00707 /*================*/
00708   trx_t*  trx); 
00710 static drizzle_show_var innodb_status_variables[]= {
00711   {"buffer_pool_pages_data",
00712   (char*) &export_vars.innodb_buffer_pool_pages_data,   SHOW_LONG},
00713   {"buffer_pool_pages_dirty",
00714   (char*) &export_vars.innodb_buffer_pool_pages_dirty,    SHOW_LONG},
00715   {"buffer_pool_pages_flushed",
00716   (char*) &export_vars.innodb_buffer_pool_pages_flushed,  SHOW_LONG},
00717   {"buffer_pool_pages_free",
00718   (char*) &export_vars.innodb_buffer_pool_pages_free,   SHOW_LONG},
00719 #ifdef UNIV_DEBUG
00720   {"buffer_pool_pages_latched",
00721   (char*) &export_vars.innodb_buffer_pool_pages_latched,  SHOW_LONG},
00722 #endif /* UNIV_DEBUG */
00723   {"buffer_pool_pages_misc",
00724   (char*) &export_vars.innodb_buffer_pool_pages_misc,   SHOW_LONG},
00725   {"buffer_pool_pages_total",
00726   (char*) &export_vars.innodb_buffer_pool_pages_total,    SHOW_LONG},
00727   {"buffer_pool_read_ahead",
00728   (char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG},
00729   {"buffer_pool_read_ahead_evicted",
00730   (char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG},
00731   {"buffer_pool_read_requests",
00732   (char*) &export_vars.innodb_buffer_pool_read_requests,  SHOW_LONG},
00733   {"buffer_pool_reads",
00734   (char*) &export_vars.innodb_buffer_pool_reads,    SHOW_LONG},
00735   {"buffer_pool_wait_free",
00736   (char*) &export_vars.innodb_buffer_pool_wait_free,    SHOW_LONG},
00737   {"buffer_pool_write_requests",
00738   (char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
00739   {"data_fsyncs",
00740   (char*) &export_vars.innodb_data_fsyncs,      SHOW_LONG},
00741   {"data_pending_fsyncs",
00742   (char*) &export_vars.innodb_data_pending_fsyncs,    SHOW_LONG},
00743   {"data_pending_reads",
00744   (char*) &export_vars.innodb_data_pending_reads,   SHOW_LONG},
00745   {"data_pending_writes",
00746   (char*) &export_vars.innodb_data_pending_writes,    SHOW_LONG},
00747   {"data_read",
00748   (char*) &export_vars.innodb_data_read,      SHOW_LONG},
00749   {"data_reads",
00750   (char*) &export_vars.innodb_data_reads,     SHOW_LONG},
00751   {"data_writes",
00752   (char*) &export_vars.innodb_data_writes,      SHOW_LONG},
00753   {"data_written",
00754   (char*) &export_vars.innodb_data_written,     SHOW_LONG},
00755   {"dblwr_pages_written",
00756   (char*) &export_vars.innodb_dblwr_pages_written,    SHOW_LONG},
00757   {"dblwr_writes",
00758   (char*) &export_vars.innodb_dblwr_writes,     SHOW_LONG},
00759   {"have_atomic_builtins",
00760   (char*) &export_vars.innodb_have_atomic_builtins,   SHOW_BOOL},
00761   {"log_waits",
00762   (char*) &export_vars.innodb_log_waits,      SHOW_LONG},
00763   {"log_write_requests",
00764   (char*) &export_vars.innodb_log_write_requests,   SHOW_LONG},
00765   {"log_writes",
00766   (char*) &export_vars.innodb_log_writes,     SHOW_LONG},
00767   {"os_log_fsyncs",
00768   (char*) &export_vars.innodb_os_log_fsyncs,      SHOW_LONG},
00769   {"os_log_pending_fsyncs",
00770   (char*) &export_vars.innodb_os_log_pending_fsyncs,    SHOW_LONG},
00771   {"os_log_pending_writes",
00772   (char*) &export_vars.innodb_os_log_pending_writes,    SHOW_LONG},
00773   {"os_log_written",
00774   (char*) &export_vars.innodb_os_log_written,     SHOW_LONG},
00775   {"page_size",
00776   (char*) &export_vars.innodb_page_size,      SHOW_LONG},
00777   {"pages_created",
00778   (char*) &export_vars.innodb_pages_created,      SHOW_LONG},
00779   {"pages_read",
00780   (char*) &export_vars.innodb_pages_read,     SHOW_LONG},
00781   {"pages_written",
00782   (char*) &export_vars.innodb_pages_written,      SHOW_LONG},
00783   {"row_lock_current_waits",
00784   (char*) &export_vars.innodb_row_lock_current_waits,   SHOW_LONG},
00785   {"row_lock_time",
00786   (char*) &export_vars.innodb_row_lock_time,      SHOW_LONGLONG},
00787   {"row_lock_time_avg",
00788   (char*) &export_vars.innodb_row_lock_time_avg,    SHOW_LONG},
00789   {"row_lock_time_max",
00790   (char*) &export_vars.innodb_row_lock_time_max,    SHOW_LONG},
00791   {"row_lock_waits",
00792   (char*) &export_vars.innodb_row_lock_waits,     SHOW_LONG},
00793   {"rows_deleted",
00794   (char*) &export_vars.innodb_rows_deleted,     SHOW_LONG},
00795   {"rows_inserted",
00796   (char*) &export_vars.innodb_rows_inserted,      SHOW_LONG},
00797   {"rows_read",
00798   (char*) &export_vars.innodb_rows_read,      SHOW_LONG},
00799   {"rows_updated",
00800   (char*) &export_vars.innodb_rows_updated,     SHOW_LONG},
00801   {NULL, NULL, SHOW_LONG}
00802 };
00803 
00804 InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
00805   plugin::TableFunction::Generator(fields)
00806 { 
00807   srv_export_innodb_status();
00808   status_var_ptr= innodb_status_variables;
00809 }
00810 
00811 bool InnodbStatusTool::Generator::populate()
00812 {
00813   if (status_var_ptr->name)
00814   {
00815     std::ostringstream oss;
00816     string return_value;
00817     const char *value= status_var_ptr->value;
00818 
00819     /* VARIABLE_NAME */
00820     push(status_var_ptr->name);
00821 
00822     switch (status_var_ptr->type)
00823     {
00824     case SHOW_LONG:
00825       oss << *(int64_t*) value;
00826       return_value= oss.str();
00827       break;
00828     case SHOW_LONGLONG:
00829       oss << *(int64_t*) value;
00830       return_value= oss.str();
00831       break;
00832     case SHOW_BOOL:
00833       return_value= *(bool*) value ? "ON" : "OFF";
00834       break;
00835     default:
00836       assert(0);
00837     }
00838 
00839     /* VARIABLE_VALUE */
00840     if (return_value.length())
00841       push(return_value);
00842     else 
00843       push(" ");
00844 
00845     status_var_ptr++;
00846 
00847     return true;
00848   }
00849   return false;
00850 }
00851 
00852 /* General functions */
00853 
00854 /******************************************************************/
00864 UNIV_INTERN
00865 ibool
00866 thd_is_replication_slave_thread(
00867 /*============================*/
00868   drizzled::Session* ) 
00869 {
00870   return false;
00871 }
00872 
00873 /******************************************************************/
00876 static inline
00877 void
00878 innodb_srv_conc_enter_innodb(
00879 /*=========================*/
00880   trx_t*  trx)  
00881 {
00882   if (UNIV_LIKELY(!srv_thread_concurrency)) {
00883 
00884     return;
00885   }
00886 
00887   srv_conc_enter_innodb(trx);
00888 }
00889 
00890 /******************************************************************/
00893 static inline
00894 void
00895 innodb_srv_conc_exit_innodb(
00896 /*========================*/
00897   trx_t*  trx)  
00898 {
00899   if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
00900 
00901     return;
00902   }
00903 
00904   srv_conc_exit_innodb(trx);
00905 }
00906 
00907 /******************************************************************/
00912 static inline
00913 void
00914 innobase_release_stat_resources(
00915 /*============================*/
00916   trx_t*  trx)  
00917 {
00918   if (trx->has_search_latch) {
00919     trx_search_latch_release_if_reserved(trx);
00920   }
00921 
00922   if (trx->declared_to_be_inside_innodb) {
00923     /* Release our possible ticket in the FIFO */
00924 
00925     srv_conc_force_exit_innodb(trx);
00926   }
00927 }
00928 
00929 /******************************************************************/
00938 UNIV_INTERN
00939 ibool
00940 thd_has_edited_nontrans_tables(
00941 /*===========================*/
00942   drizzled::Session *session)  
00943 {
00944   return((ibool)session->transaction.all.hasModifiedNonTransData());
00945 }
00946 
00947 /******************************************************************/
00950 UNIV_INTERN
00951 ibool
00952 thd_is_select(
00953 /*==========*/
00954   const drizzled::Session *session)  
00955 {
00956   return(session->getSqlCommand() == SQLCOM_SELECT);
00957 }
00958 
00959 /******************************************************************/
00963 UNIV_INTERN
00964 ibool
00965 thd_supports_xa(
00966 /*============*/
00967   drizzled::Session* )  
00969 {
00970   /* TODO: Add support here for per-session value */
00971   return(support_xa);
00972 }
00973 
00974 /******************************************************************/
00977 UNIV_INTERN
00978 ulong
00979 thd_lock_wait_timeout(
00980 /*==================*/
00981   drizzled::Session*)  
00983 {
00984   /* TODO: Add support here for per-session value */
00985   /* According to <drizzle/plugin.h>, passing session == NULL
00986   returns the global value of the session variable. */
00987   return((ulong)lock_wait_timeout.get());
00988 }
00989 
00990 /******************************************************************/
00992 UNIV_INTERN
00993 void
00994 thd_set_lock_wait_time(
00995 /*===================*/
00996   drizzled::Session*  in_session, 
00997   ulint value)  
00998 {
00999   if (in_session)
01000     in_session->times.utime_after_lock+= value;
01001 }
01002 
01003 /********************************************************************/
01006 static inline
01007 trx_t*&
01008 session_to_trx(
01009 /*=======*/
01010   Session*  session)  
01011 {
01012   return *(trx_t**) session->getEngineData(innodb_engine_ptr);
01013 }
01014 
01015 
01016 plugin::ReplicationReturnCode ReplicationLog::apply(Session &session,
01017                                                     const message::Transaction &message)
01018 {
01019   char *data= new char[message.ByteSize()];
01020 
01021   message.SerializeToArray(data, message.ByteSize());
01022 
01023   trx_t *trx= session_to_trx(&session);
01024 
01025   uint64_t trx_id= message.transaction_context().transaction_id();
01026   uint32_t seg_id= message.segment_id();
01027   uint64_t end_timestamp= message.transaction_context().end_timestamp();
01028   bool is_end_segment= message.end_segment();
01029   trx->log_commit_id= TRUE;
01030 
01031   string server_uuid= session.getServerUUID();
01032   string originating_server_uuid= session.getOriginatingServerUUID();
01033   uint64_t originating_commit_id= session.getOriginatingCommitID();
01034   bool use_originating_server_uuid= session.isOriginatingServerUUIDSet();
01035 
01036   ulint error= insert_replication_message(data, message.ByteSize(), trx, trx_id,
01037                end_timestamp, is_end_segment, seg_id, server_uuid.c_str(),
01038                use_originating_server_uuid, originating_server_uuid.c_str(),
01039                originating_commit_id);
01040 
01041   (void)error;
01042 
01043   delete[] data;
01044 
01045   return plugin::SUCCESS;
01046 }
01047 
01048 /********************************************************************/
01053 int
01054 InnobaseEngine::doReleaseTemporaryLatches(
01055 /*===============================*/
01056   Session*    session)  
01057 {
01058   trx_t*  trx;
01059 
01060   assert(this == innodb_engine_ptr);
01061 
01062   if (!innodb_inited) {
01063 
01064     return(0);
01065   }
01066 
01067   trx = session_to_trx(session);
01068 
01069   if (trx) {
01070     innobase_release_stat_resources(trx);
01071   }
01072   return(0);
01073 }
01074 
01075 /********************************************************************/
01080 static inline
01081 void
01082 innobase_active_small(void)
01083 /*=======================*/
01084 {
01085   innobase_active_counter++;
01086 
01087   if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
01088     srv_active_wake_master_thread();
01089   }
01090 }
01091 
01092 /********************************************************************/
01097 UNIV_INTERN
01098 int
01099 convert_error_code_to_mysql(
01100 /*========================*/
01101   int   error,  
01102   ulint   flags,  
01103   Session*  session)
01104 {
01105   switch (error) {
01106   case DB_SUCCESS:
01107     return(0);
01108 
01109   case DB_INTERRUPTED:
01110     my_error(ER_QUERY_INTERRUPTED, MYF(0));
01111     /* fall through */
01112 
01113   case DB_FOREIGN_EXCEED_MAX_CASCADE:
01114     push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
01115                         HA_ERR_ROW_IS_REFERENCED,
01116                         "InnoDB: Cannot delete/update "
01117                         "rows with cascading foreign key "
01118                         "constraints that exceed max "
01119                         "depth of %d. Please "
01120                         "drop extra constraints and try "
01121                         "again", DICT_FK_MAX_RECURSIVE_LOAD);
01122     /* fall through */
01123 
01124   case DB_ERROR:
01125   default:
01126     return(-1); /* unspecified error */
01127 
01128   case DB_DUPLICATE_KEY:
01129     /* Be cautious with returning this error, since
01130        mysql could re-enter the storage layer to get
01131        duplicated key info, the operation requires a
01132        valid table handle and/or transaction information,
01133        which might not always be available in the error
01134        handling stage. */
01135     return(HA_ERR_FOUND_DUPP_KEY);
01136 
01137   case DB_FOREIGN_DUPLICATE_KEY:
01138     return(HA_ERR_FOREIGN_DUPLICATE_KEY);
01139 
01140   case DB_MISSING_HISTORY:
01141     return(HA_ERR_TABLE_DEF_CHANGED);
01142 
01143   case DB_RECORD_NOT_FOUND:
01144     return(HA_ERR_NO_ACTIVE_RECORD);
01145 
01146   case DB_DEADLOCK:
01147     /* Since we rolled back the whole transaction, we must
01148     tell it also to MySQL so that MySQL knows to empty the
01149     cached binlog for this transaction */
01150 
01151     session->markTransactionForRollback(TRUE);
01152 
01153     return(HA_ERR_LOCK_DEADLOCK);
01154 
01155   case DB_LOCK_WAIT_TIMEOUT:
01156     /* Starting from 5.0.13, we let MySQL just roll back the
01157     latest SQL statement in a lock wait timeout. Previously, we
01158     rolled back the whole transaction. */
01159 
01160     session->markTransactionForRollback((bool)row_rollback_on_timeout);
01161 
01162     return(HA_ERR_LOCK_WAIT_TIMEOUT);
01163 
01164   case DB_NO_REFERENCED_ROW:
01165     return(HA_ERR_NO_REFERENCED_ROW);
01166 
01167   case DB_ROW_IS_REFERENCED:
01168     return(HA_ERR_ROW_IS_REFERENCED);
01169 
01170   case DB_CANNOT_ADD_CONSTRAINT:
01171   case DB_CHILD_NO_INDEX:
01172   case DB_PARENT_NO_INDEX:
01173     return(HA_ERR_CANNOT_ADD_FOREIGN);
01174 
01175   case DB_CANNOT_DROP_CONSTRAINT:
01176 
01177     return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
01178             misleading, a new MySQL error
01179             code should be introduced */
01180 
01181   case DB_COL_APPEARS_TWICE_IN_INDEX:
01182   case DB_CORRUPTION:
01183     return(HA_ERR_CRASHED);
01184 
01185   case DB_OUT_OF_FILE_SPACE:
01186     return(HA_ERR_RECORD_FILE_FULL);
01187 
01188   case DB_TABLE_IS_BEING_USED:
01189     return(HA_ERR_WRONG_COMMAND);
01190 
01191   case DB_TABLE_NOT_FOUND:
01192     return(HA_ERR_NO_SUCH_TABLE);
01193 
01194   case DB_TOO_BIG_RECORD:
01195     my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
01196              page_get_free_space_of_empty(flags & DICT_TF_COMPACT) / 2);
01197     return(HA_ERR_TO_BIG_ROW);
01198 
01199   case DB_NO_SAVEPOINT:
01200     return(HA_ERR_NO_SAVEPOINT);
01201 
01202   case DB_LOCK_TABLE_FULL:
01203     /* Since we rolled back the whole transaction, we must
01204     tell it also to MySQL so that MySQL knows to empty the
01205     cached binlog for this transaction */
01206 
01207     session->markTransactionForRollback(TRUE);
01208 
01209     return(HA_ERR_LOCK_TABLE_FULL);
01210 
01211   case DB_PRIMARY_KEY_IS_NULL:
01212     return(ER_PRIMARY_CANT_HAVE_NULL);
01213 
01214   case DB_TOO_MANY_CONCURRENT_TRXS:
01215 
01216     /* Once MySQL add the appropriate code to errmsg.txt then
01217     we can get rid of this #ifdef. NOTE: The code checked by
01218     the #ifdef is the suggested name for the error condition
01219     and the actual error code name could very well be different.
01220     This will require some monitoring, ie. the status
01221     of this request on our part.*/
01222 
01223     /* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only
01224        available in 5.1.38 and later, but the plugin should still
01225        work with previous versions of MySQL.
01226        In Drizzle we seem to not have this yet.
01227     */
01228 #ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS
01229     return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
01230 #else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
01231     return(HA_ERR_RECORD_FILE_FULL);
01232 #endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
01233   case DB_UNSUPPORTED:
01234     return(HA_ERR_UNSUPPORTED);
01235   }
01236 }
01237 
01238 
01239 /*************************************************************/
01241 UNIV_INTERN
01242 void
01243 innobase_mysql_print_thd(
01244 /*=====================*/
01245   FILE* f,    
01246   drizzled::Session *in_session,  
01247   uint  )   
01249 {
01250   drizzled::identifier::user::ptr user_identifier(in_session->user());
01251 
01252   fprintf(f,
01253           "Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
01254           static_cast<uint64_t>(in_session->getSessionId()),
01255           static_cast<uint64_t>(in_session->getQueryId()),
01256           getServerHostname().c_str(),
01257           user_identifier->address().c_str(),
01258           user_identifier->username().c_str()
01259   );
01260   fprintf(f, "\n%s", in_session->getQueryString()->c_str());
01261   putc('\n', f);
01262 }
01263 
01264 /******************************************************************/
01266 UNIV_INTERN
01267 void
01268 innobase_get_cset_width(
01269 /*====================*/
01270   ulint cset,   
01271   ulint*  mbminlen, 
01272   ulint*  mbmaxlen) 
01273 {
01274   charset_info_st* cs;
01275   ut_ad(cset < 256);
01276   ut_ad(mbminlen);
01277   ut_ad(mbmaxlen);
01278 
01279   cs = all_charsets[cset];
01280   if (cs) {
01281     *mbminlen = cs->mbminlen;
01282     *mbmaxlen = cs->mbmaxlen;
01283     ut_ad(*mbminlen < DATA_MBMAX);
01284     ut_ad(*mbmaxlen < DATA_MBMAX);
01285   } else {
01286     ut_a(cset == 0);
01287     *mbminlen = *mbmaxlen = 0;
01288   }
01289 }
01290 
01291 /******************************************************************/
01293 UNIV_INTERN
01294 void
01295 innobase_convert_from_table_id(
01296 /*===========================*/
01297   const void*,      
01298   char*     to, 
01299   const char*   from, 
01300   ulint     len)  
01301 {
01302   strncpy(to, from, len);
01303 }
01304 
01305 /******************************************************************/
01307 UNIV_INTERN
01308 void
01309 innobase_convert_from_id(
01310 /*=====================*/
01311   const void*,      
01312   char*     to, 
01313   const char*   from, 
01314   ulint     len)  
01315 {
01316   strncpy(to, from, len);
01317 }
01318 
01319 /******************************************************************/
01322 UNIV_INTERN
01323 int
01324 innobase_strcasecmp(
01325 /*================*/
01326   const char* a,  
01327   const char* b)  
01328 {
01329   return(system_charset_info->strcasecmp(a, b));
01330 }
01331 
01332 /******************************************************************/
01334 UNIV_INTERN
01335 void
01336 innobase_casedn_str(
01337 /*================*/
01338   char* a)  
01339 {
01340   system_charset_info->casedn_str(a);
01341 }
01342 
01343 UNIV_INTERN
01344 bool
01345 innobase_isspace(
01346   const void* cs,
01347   char char_to_test)
01348 {
01349   return static_cast<const charset_info_st*>(cs)->isspace(char_to_test);
01350 }
01351 
01352 #if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
01353 /*******************************************************************/
01356 void __cdecl
01357 _dosmaperr(
01358   unsigned long); 
01360 /*********************************************************************/
01363 UNIV_INTERN
01364 int
01365 innobase_mysql_tmpfile(void)
01366 /*========================*/
01367 {
01368   int fd;       /* handle of opened file */
01369   HANDLE  osfh;       /* OS handle of opened file */
01370   char* tmpdir;       /* point to the directory
01371             where to create file */
01372   TCHAR path_buf[MAX_PATH - 14];  /* buffer for tmp file path.
01373             The length cannot be longer
01374             than MAX_PATH - 14, or
01375             GetTempFileName will fail. */
01376   char  filename[MAX_PATH];   /* name of the tmpfile */
01377   DWORD fileaccess = GENERIC_READ /* OS file access */
01378            | GENERIC_WRITE
01379            | DELETE;
01380   DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
01381           | FILE_SHARE_WRITE
01382           | FILE_SHARE_DELETE;
01383   DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
01384   DWORD fileattrib =      /* OS file attribute flags */
01385            FILE_ATTRIBUTE_NORMAL
01386            | FILE_FLAG_DELETE_ON_CLOSE
01387            | FILE_ATTRIBUTE_TEMPORARY
01388            | FILE_FLAG_SEQUENTIAL_SCAN;
01389 
01390   tmpdir = my_tmpdir(&mysql_tmpdir_list);
01391 
01392   /* The tmpdir parameter can not be NULL for GetTempFileName. */
01393   if (!tmpdir) {
01394     uint  ret;
01395 
01396     /* Use GetTempPath to determine path for temporary files. */
01397     ret = GetTempPath(sizeof(path_buf), path_buf);
01398     if (ret > sizeof(path_buf) || (ret == 0)) {
01399 
01400       _dosmaperr(GetLastError()); /* map error */
01401       return(-1);
01402     }
01403 
01404     tmpdir = path_buf;
01405   }
01406 
01407   /* Use GetTempFileName to generate a unique filename. */
01408   if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
01409 
01410     _dosmaperr(GetLastError()); /* map error */
01411     return(-1);
01412   }
01413 
01414   /* Open/Create the file. */
01415   osfh = CreateFile(filename, fileaccess, fileshare, NULL,
01416         filecreate, fileattrib, NULL);
01417   if (osfh == INVALID_HANDLE_VALUE) {
01418 
01419     /* open/create file failed! */
01420     _dosmaperr(GetLastError()); /* map error */
01421     return(-1);
01422   }
01423 
01424   do {
01425     /* Associates a CRT file descriptor with the OS file handle. */
01426     fd = _open_osfhandle((intptr_t) osfh, 0);
01427   } while (fd == -1 && errno == EINTR);
01428 
01429   if (fd == -1) {
01430     /* Open failed, close the file handle. */
01431 
01432     _dosmaperr(GetLastError()); /* map error */
01433     CloseHandle(osfh);    /* no need to check if
01434             CloseHandle fails */
01435   }
01436 
01437   return(fd);
01438 }
01439 #else
01440 /*********************************************************************/
01443 UNIV_INTERN
01444 int
01445 innobase_mysql_tmpfile(void)
01446 /*========================*/
01447 {
01448   int fd2 = -1;
01449   int fd = ::drizzled::tmpfile("ib");
01450   if (fd >= 0) {
01451     /* Copy the file descriptor, so that the additional resources
01452     allocated by create_temp_file() can be freed by invoking
01453     internal::my_close().
01454 
01455     Because the file descriptor returned by this function
01456     will be passed to fdopen(), it will be closed by invoking
01457     fclose(), which in turn will invoke close() instead of
01458     internal::my_close(). */
01459     fd2 = dup(fd);
01460     if (fd2 < 0) {
01461       errno=errno;
01462       my_error(EE_OUT_OF_FILERESOURCES,
01463          MYF(ME_BELL+ME_WAITTANG),
01464          "ib*", errno);
01465     }
01466     internal::my_close(fd, MYF(MY_WME));
01467   }
01468   return(fd2);
01469 }
01470 #endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
01471 
01472 
01473 /*******************************************************************/
01482 UNIV_INTERN
01483 ulint
01484 innobase_raw_format(
01485 /*================*/
01486   const char* data,   
01487   ulint   data_len, 
01489   ulint   ,   
01490   char*   buf,    
01491   ulint   buf_size) 
01493 {
01494   return(ut_str_sql_format(data, data_len, buf, buf_size));
01495 }
01496 
01497 /*********************************************************************/
01514 static
01515 uint64_t
01516 innobase_next_autoinc(
01517 /*==================*/
01518   uint64_t  current,  
01519   uint64_t  increment,  
01520   uint64_t  offset,   
01521   uint64_t  max_value)  
01522 {
01523   uint64_t  next_value;
01524 
01525   /* Should never be 0. */
01526   ut_a(increment > 0);
01527 
01528   /* According to MySQL documentation, if the offset is greater than
01529   the increment then the offset is ignored. */
01530   if (offset > increment) {
01531     offset = 0;
01532   }
01533 
01534   if (max_value <= current) {
01535     next_value = max_value;
01536   } else if (offset <= 1) {
01537     /* Offset 0 and 1 are the same, because there must be at
01538     least one node in the system. */
01539     if (max_value - current <= increment) {
01540       next_value = max_value;
01541     } else {
01542       next_value = current + increment;
01543     }
01544   } else if (max_value > current) {
01545     if (current > offset) {
01546       next_value = ((current - offset) / increment) + 1;
01547     } else {
01548       next_value = ((offset - current) / increment) + 1;
01549     }
01550 
01551     ut_a(increment > 0);
01552     ut_a(next_value > 0);
01553 
01554     /* Check for multiplication overflow. */
01555     if (increment > (max_value / next_value)) {
01556 
01557       next_value = max_value;
01558     } else {
01559       next_value *= increment;
01560 
01561       ut_a(max_value >= next_value);
01562 
01563       /* Check for overflow. */
01564       if (max_value - next_value <= offset) {
01565         next_value = max_value;
01566       } else {
01567         next_value += offset;
01568       }
01569     }
01570   } else {
01571     next_value = max_value;
01572   }
01573 
01574   ut_a(next_value <= max_value);
01575 
01576   return(next_value);
01577 }
01578 
01579 /*********************************************************************/
01581 static
01582 void
01583 innobase_trx_init(
01584 /*==============*/
01585   Session*  session,  
01586   trx_t*  trx)  
01587 {
01588   assert(session == trx->mysql_thd);
01589 
01590   trx->check_foreigns = !session_test_options(
01591     session, OPTION_NO_FOREIGN_KEY_CHECKS);
01592 
01593   trx->check_unique_secondary = !session_test_options(
01594     session, OPTION_RELAXED_UNIQUE_CHECKS);
01595 
01596   return;
01597 }
01598 
01599 /*********************************************************************/
01602 UNIV_INTERN
01603 trx_t*
01604 innobase_trx_allocate(
01605 /*==================*/
01606   Session*  session)  
01607 {
01608   trx_t*  trx;
01609 
01610   assert(session != NULL);
01611   assert(EQ_CURRENT_SESSION(session));
01612 
01613   trx = trx_allocate_for_mysql();
01614 
01615   trx->mysql_thd = session;
01616 
01617   innobase_trx_init(session, trx);
01618 
01619   return(trx);
01620 }
01621 
01622 /*********************************************************************/
01627 static
01628 trx_t*
01629 check_trx_exists(
01630 /*=============*/
01631   Session*  session)  
01632 {
01633   trx_t*& trx = session_to_trx(session);
01634 
01635   ut_ad(EQ_CURRENT_SESSION(session));
01636 
01637   if (trx == NULL) {
01638     trx = innobase_trx_allocate(session);
01639   } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
01640     mem_analyze_corruption(trx);
01641     ut_error;
01642   }
01643 
01644   innobase_trx_init(session, trx);
01645 
01646   return(trx);
01647 }
01648 
01649 
01650 /*********************************************************************/
01652 UNIV_INTERN
01653 ha_innobase::ha_innobase(plugin::StorageEngine &engine_arg,
01654                          Table &table_arg)
01655   :Cursor(engine_arg, table_arg),
01656   primary_key(0), /* needs initialization because index_flags() may be called 
01657                      before this is set to the real value. It's ok to have any 
01658                      value here because it doesn't matter if we return the
01659                      HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
01660   start_of_scan(0),
01661   num_write_row(0)
01662 {}
01663 
01664 /*********************************************************************/
01666 UNIV_INTERN
01667 ha_innobase::~ha_innobase()
01668 {
01669 }
01670 
01671 /*********************************************************************/
01675 UNIV_INTERN inline
01676 void
01677 ha_innobase::update_session(
01678 /*====================*/
01679   Session*  session)  
01680 {
01681   trx_t*    trx;
01682 
01683   assert(session);
01684   trx = check_trx_exists(session);
01685 
01686   if (prebuilt->trx != trx) {
01687 
01688     row_update_prebuilt_trx(prebuilt, trx);
01689   }
01690 
01691   user_session = session;
01692 }
01693 
01694 /*****************************************************************/
01698 static
01699 char*
01700 innobase_convert_identifier(
01701 /*========================*/
01702   char*   buf,  
01703   ulint   buflen, 
01704   const char* id, 
01705   ulint   idlen,  
01706   drizzled::Session *session,
01707   ibool   file_id)
01709 {
01710   char nz[NAME_LEN + 1];
01711   const size_t nz2_size= NAME_LEN + 1 + srv_mysql50_table_name_prefix.size();
01712   boost::scoped_array<char> nz2(new char[nz2_size]);
01713 
01714   const char* s = id;
01715   int   q;
01716 
01717   if (file_id) {
01718     /* Decode the table name.  The filename_to_tablename()
01719     function expects a NUL-terminated string.  The input and
01720     output strings buffers must not be shared. */
01721 
01722     if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
01723       idlen = (sizeof nz) - 1;
01724     }
01725 
01726     memcpy(nz, id, idlen);
01727     nz[idlen] = 0;
01728 
01729     s = nz2.get();
01730     idlen = identifier::Table::filename_to_tablename(nz, nz2.get(), nz2_size);
01731   }
01732 
01733   /* See if the identifier needs to be quoted. */
01734   if (UNIV_UNLIKELY(!session)) {
01735     q = '"';
01736   } else {
01737     q = get_quote_char_for_identifier();
01738   }
01739 
01740   if (q == EOF) {
01741     if (UNIV_UNLIKELY(idlen > buflen)) {
01742       idlen = buflen;
01743     }
01744     memcpy(buf, s, idlen);
01745     return(buf + idlen);
01746   }
01747 
01748   /* Quote the identifier. */
01749   if (buflen < 2) {
01750     return(buf);
01751   }
01752 
01753   *buf++ = q;
01754   buflen--;
01755 
01756   for (; idlen; idlen--) {
01757     int c = *s++;
01758     if (UNIV_UNLIKELY(c == q)) {
01759       if (UNIV_UNLIKELY(buflen < 3)) {
01760         break;
01761       }
01762 
01763       *buf++ = c;
01764       *buf++ = c;
01765       buflen -= 2;
01766     } else {
01767       if (UNIV_UNLIKELY(buflen < 2)) {
01768         break;
01769       }
01770 
01771       *buf++ = c;
01772       buflen--;
01773     }
01774   }
01775 
01776   *buf++ = q;
01777   return(buf);
01778 }
01779 
01780 /*****************************************************************/
01784 UNIV_INTERN
01785 char*
01786 innobase_convert_name(
01787 /*==================*/
01788   char*   buf,  
01789   ulint   buflen, 
01790   const char* id, 
01791   ulint   idlen,  
01792   drizzled::Session *session,
01793   ibool   table_id)
01795 {
01796   char*   s = buf;
01797   const char* bufend  = buf + buflen;
01798 
01799   if (table_id) {
01800     const char* slash = (const char*) memchr(id, '/', idlen);
01801     if (!slash) {
01802 
01803       goto no_db_name;
01804     }
01805 
01806     /* Print the database name and table name separately. */
01807     s = innobase_convert_identifier(s, bufend - s, id, slash - id,
01808             session, TRUE);
01809     if (UNIV_LIKELY(s < bufend)) {
01810       *s++ = '.';
01811       s = innobase_convert_identifier(s, bufend - s,
01812               slash + 1, idlen
01813               - (slash - id) - 1,
01814               session, TRUE);
01815     }
01816   } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
01817     /* Temporary index name (smart ALTER TABLE) */
01818     const char temp_index_suffix[]= "--temporary--";
01819 
01820     s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
01821             session, FALSE);
01822     if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
01823       memcpy(s, temp_index_suffix,
01824              sizeof temp_index_suffix - 1);
01825       s += sizeof temp_index_suffix - 1;
01826     }
01827   } else {
01828 no_db_name:
01829     s = innobase_convert_identifier(buf, buflen, id, idlen,
01830             session, table_id);
01831   }
01832 
01833   return(s);
01834 
01835 }
01836 
01837 /**********************************************************************/
01840 UNIV_INTERN
01841 ibool
01842 trx_is_interrupted(
01843 /*===============*/
01844   trx_t*  trx)  
01845 {
01846   return(trx && trx->mysql_thd && trx->mysql_thd->getKilled());
01847 }
01848 
01849 /**********************************************************************/
01852 UNIV_INTERN
01853 ibool
01854 trx_is_strict(
01855 /*==========*/
01856   trx_t*  trx)  
01857 {
01858   return(trx && trx->mysql_thd
01859          && true);
01860 }
01861 
01862 /**************************************************************/
01865 static
01866 void
01867 reset_template(
01868 /*===========*/
01869   row_prebuilt_t* prebuilt) 
01870 {
01871   prebuilt->keep_other_fields_on_keyread = 0;
01872   prebuilt->read_just_key = 0;
01873 }
01874 
01875 template<class T>
01876 void align_value(T& value, size_t align_val= 1024)
01877 {
01878   value= value - (value % align_val);
01879 }
01880 
01881 static void auto_extend_update(Session *, sql_var_t)
01882 {
01883   srv_auto_extend_increment= innodb_auto_extend_increment.get();
01884 }
01885 
01886 static void io_capacity_update(Session *, sql_var_t)
01887 {
01888   srv_io_capacity= innodb_io_capacity.get();
01889 }
01890 
01891 static void purge_batch_update(Session *, sql_var_t)
01892 {
01893   srv_purge_batch_size= innodb_purge_batch_size.get();
01894 }
01895 
01896 static void purge_threads_update(Session *, sql_var_t)
01897 {
01898   srv_n_purge_threads= innodb_n_purge_threads.get();
01899 }
01900 
01901 static void innodb_adaptive_hash_index_update(Session *, sql_var_t)
01902 {
01903   if (btr_search_enabled)
01904   {
01905     btr_search_enable();
01906   } else {
01907     btr_search_disable();
01908   }
01909 }
01910 
01911 static void innodb_old_blocks_pct_update(Session *, sql_var_t)
01912 {
01913   innobase_old_blocks_pct= buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(), TRUE);
01914 }
01915 
01916 static void innodb_thread_concurrency_update(Session *, sql_var_t)
01917 {
01918   srv_thread_concurrency= innobase_thread_concurrency.get();
01919 }
01920 
01921 static void innodb_sync_spin_loops_update(Session *, sql_var_t)
01922 {
01923   srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
01924 }
01925 
01926 static void innodb_spin_wait_delay_update(Session *, sql_var_t)
01927 {
01928   srv_spin_wait_delay= innodb_spin_wait_delay.get();
01929 }
01930 
01931 static void innodb_thread_sleep_delay_update(Session *, sql_var_t)
01932 {
01933   srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
01934 }
01935 
01936 static void innodb_read_ahead_threshold_update(Session *, sql_var_t)
01937 {
01938   srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
01939 }
01940 
01941 static void auto_lru_dump_update(Session *, sql_var_t)
01942 {
01943   srv_auto_lru_dump= buffer_pool_restore_at_startup.get();
01944 }
01945 
01946 static void ibuf_active_contract_update(Session *, sql_var_t)
01947 {
01948   srv_ibuf_active_contract= ibuf_active_contract.get();
01949 }
01950 
01951 static void ibuf_accel_rate_update(Session *, sql_var_t)
01952 {
01953   srv_ibuf_accel_rate= ibuf_accel_rate.get();
01954 }
01955 
01956 static void checkpoint_age_target_update(Session *, sql_var_t)
01957 {
01958   srv_checkpoint_age_target= checkpoint_age_target.get();
01959 }
01960 
01961 static void flush_neighbor_pages_update(Session *, sql_var_t)
01962 {
01963   srv_flush_neighbor_pages= flush_neighbor_pages.get();
01964 }
01965 
01966 static int innodb_commit_concurrency_validate(Session *session, set_var *var)
01967 {
01968    uint64_t new_value= var->getInteger();
01969 
01970    if ((innobase_commit_concurrency.get() == 0 && new_value != 0) ||
01971        (innobase_commit_concurrency.get() != 0 && new_value == 0))
01972    {
01973      push_warning_printf(session,
01974                          DRIZZLE_ERROR::WARN_LEVEL_WARN,
01975                          ER_WRONG_ARGUMENTS,
01976                          _("Once InnoDB is running, innodb_commit_concurrency "
01977                            "must not change between zero and nonzero."));
01978      return 1;
01979    }
01980    return 0;
01981 }
01982 
01983 /*************************************************************/
01987 static
01988 int
01989 innodb_file_format_name_validate(
01990 /*=============================*/
01991   Session*      , 
01992   set_var *var)
01993 {
01994   const char *file_format_input = var->value->str_value.ptr();
01995   if (file_format_input == NULL)
01996     return 1;
01997 
01998   if (file_format_input != NULL) {
01999     uint  format_id;
02000 
02001     format_id = innobase_file_format_name_lookup(
02002       file_format_input);
02003 
02004     if (format_id <= DICT_TF_FORMAT_MAX) {
02005       innobase_file_format_name =
02006         trx_sys_file_format_id_to_name(format_id);
02007 
02008       return(0);
02009     }
02010   }
02011 
02012   return(1);
02013 }
02014 
02015 /*************************************************************/
02019 static
02020 int
02021 innodb_change_buffering_validate(
02022 /*=============================*/
02023   Session*      , 
02024   set_var *var)
02025 {
02026   const char *change_buffering_input = var->value->str_value.ptr();
02027 
02028   if (change_buffering_input == NULL)
02029     return 1;
02030 
02031   ulint use;
02032 
02033   for (use = 0;
02034        use < UT_ARR_SIZE(innobase_change_buffering_values);
02035        ++use) {
02036     if (!innobase_strcasecmp(change_buffering_input,
02037                              innobase_change_buffering_values[use]))
02038     {
02039       ibuf_use= static_cast<ibuf_use_t>(use); 
02040       return 0;
02041     }
02042   }
02043 
02044   return 1;
02045 }
02046 
02047 
02048 /*************************************************************/
02052 static
02053 int
02054 innodb_file_format_max_validate(
02055 /*==============================*/
02056   Session*   session, 
02057   set_var *var)
02058 {
02059   const char *file_format_input = var->value->str_value.ptr();
02060   if (file_format_input == NULL)
02061     return 1;
02062 
02063   if (file_format_input != NULL) {
02064     int format_id = innobase_file_format_validate_and_set(file_format_input);
02065 
02066     if (format_id > DICT_TF_FORMAT_MAX) {
02067       /* DEFAULT is "on", which is invalid at runtime. */
02068       return 1;
02069     }
02070 
02071     if (format_id >= 0) {
02072       innobase_file_format_max.assign(
02073                              trx_sys_file_format_id_to_name((uint)format_id));
02074 
02075       /* Update the max format id in the system tablespace. */
02076       const char *name_buff;
02077 
02078       if (trx_sys_file_format_max_set(format_id, &name_buff))
02079       {
02080         errmsg_printf(error::WARN,
02081                       " [Info] InnoDB: the file format in the system "
02082                       "tablespace is now set to %s.\n", name_buff);
02083         innobase_file_format_max= name_buff;
02084       }
02085       return(0);
02086 
02087     } else {
02088       push_warning_printf(session,
02089                           DRIZZLE_ERROR::WARN_LEVEL_WARN,
02090                           ER_WRONG_ARGUMENTS,
02091                           "InnoDB: invalid innodb_file_format_max "
02092                           "value; can be any format up to %s "
02093                           "or equivalent id of %d",
02094                           trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX),
02095                           DICT_TF_FORMAT_MAX);
02096     }
02097   }
02098 
02099   return(1);
02100 }
02101 
02102 /*********************************************************************/
02106 static
02107 int
02108 read_ahead_validate(
02109 /*================*/
02110   Session*,             
02111   set_var*    var)
02112 {
02113   const char *read_ahead_input = var->value->str_value.ptr();
02114   int res = read_ahead_typelib.find_type(read_ahead_input, TYPELIB::e_none); // e_none is wrong
02115 
02116   if (res > 0) {
02117     srv_read_ahead = res - 1;
02118     return 0;
02119   }
02120 
02121   return 1;
02122 }
02123 
02124 /*********************************************************************/
02128 static
02129 int
02130 adaptive_flushing_method_validate(
02131 /*==============================*/
02132   Session*,             
02133   set_var*    var)
02134 {
02135   const char *adaptive_flushing_method_input = var->value->str_value.ptr();
02136   int res = adaptive_flushing_method_typelib.find_type(adaptive_flushing_method_input, TYPELIB::e_none); // e_none is wrong
02137 
02138   if (res > 0) {
02139     srv_adaptive_flushing_method = res - 1;
02140     return 0;
02141   }
02142   return 1;
02143 }
02144 
02145 
02146 /*********************************************************************/
02149 static
02150 int
02151 innobase_init(
02152 /*==========*/
02153   module::Context &context) 
02154 {
02155   int   err;
02156   bool    ret;
02157   uint    format_id;
02158   InnobaseEngine *actuall_engine_ptr;
02159   const module::option_map &vm= context.getOptions();
02160 
02161   srv_auto_extend_increment= innodb_auto_extend_increment.get();
02162   srv_io_capacity= innodb_io_capacity.get();
02163   srv_purge_batch_size= innodb_purge_batch_size.get();
02164   srv_n_purge_threads= innodb_n_purge_threads.get();
02165   srv_flush_log_at_trx_commit= innodb_flush_log_at_trx_commit.get();
02166   srv_max_buf_pool_modified_pct= innodb_max_dirty_pages_pct.get();
02167   srv_max_purge_lag= innodb_max_purge_lag.get();
02168   srv_stats_sample_pages= innodb_stats_sample_pages.get();
02169   srv_n_free_tickets_to_enter= innodb_concurrency_tickets.get();
02170   srv_replication_delay= innodb_replication_delay.get();
02171   srv_thread_concurrency= innobase_thread_concurrency.get();
02172   srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
02173   srv_spin_wait_delay= innodb_spin_wait_delay.get();
02174   srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
02175   srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
02176   srv_auto_lru_dump= buffer_pool_restore_at_startup.get();
02177   srv_ibuf_max_size= ibuf_max_size.get();
02178   srv_ibuf_active_contract= ibuf_active_contract.get();
02179   srv_ibuf_accel_rate= ibuf_accel_rate.get();
02180   srv_checkpoint_age_target= checkpoint_age_target.get();
02181   srv_flush_neighbor_pages= flush_neighbor_pages.get();
02182 
02183   srv_read_ahead = read_ahead_typelib.find_type_or_exit(vm["read-ahead"].as<string>().c_str(),
02184                                                         "read_ahead_typelib") + 1;
02185 
02186   srv_adaptive_flushing_method = adaptive_flushing_method_typelib.find_type_or_exit(vm["adaptive-flushing-method"].as<string>().c_str(),
02187                                                                                     "adaptive_flushing_method_typelib") + 1;
02188 
02189   /* Inverted Booleans */
02190 
02191   innobase_use_checksums= not vm.count("disable-checksums");
02192   innobase_use_doublewrite= not vm.count("disable-doublewrite");
02193   srv_adaptive_flushing= not vm.count("disable-adaptive-flushing");
02194   srv_use_sys_malloc= not vm.count("use-internal-malloc");
02195   srv_use_native_aio= not vm.count("disable-native-aio");
02196   support_xa= not vm.count("disable-xa");
02197   btr_search_enabled= not vm.count("disable-adaptive-hash-index");
02198 
02199   /* Hafta do this here because we need to late-bind the default value */
02200   innobase_data_home_dir= vm.count("data-home-dir") ? vm["data-home-dir"].as<string>() : getDataHome().file_string();
02201 
02202   if (vm.count("data-file-path"))
02203   {
02204     innobase_data_file_path= vm["data-file-path"].as<string>();
02205   }
02206 
02207 
02208   innodb_engine_ptr= actuall_engine_ptr= new InnobaseEngine(innobase_engine_name);
02209 
02210   ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
02211 
02212 #ifdef UNIV_DEBUG
02213   static const char test_filename[] = "-@";
02214   const size_t test_tablename_size= sizeof test_filename
02215     + srv_mysql50_table_name_prefix.size();
02216   boost::scoped_array test_tablename(new char[test_tablename_size]);
02217   if ((test_tablename_size) - 1
02218       != filename_to_tablename(test_filename, test_tablename.get(),
02219                                test_tablename_size)
02220       || strncmp(test_tablename.get(),
02221                  srv_mysql50_table_name_prefix.c_str(),
02222                  srv_mysql50_table_name_prefix.size())
02223       || strcmp(test_tablename.get()
02224                 + srv_mysql50_table_name_prefix.size(),
02225                 test_filename)) {
02226     errmsg_printf(error::ERROR, "tablename encoding has been changed");
02227     goto error;
02228   }
02229 #endif /* UNIV_DEBUG */
02230 
02231   srv_page_size = 0;
02232   srv_page_size_shift = 0;
02233 
02234   uint32_t page_size = innobase_page_size.get();
02235   uint32_t log_block_size = innobase_log_block_size.get();
02236 
02237   if (innobase_page_size != (1 << 14)) {
02238     uint n_shift;
02239 
02240     errmsg_printf(error::WARN,
02241       "InnoDB: Warning: innodb_page_size has been changed from default value 16384. (###EXPERIMENTAL### operation)\n");
02242     for (n_shift = 12; n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX; n_shift++) {
02243       if (innobase_page_size == (1UL << n_shift)) {
02244   srv_page_size_shift = n_shift;
02245   srv_page_size = (1 << srv_page_size_shift);
02246   errmsg_printf(error::WARN,
02247           "InnoDB: The universal page size of the database is set to %lu.\n",
02248           srv_page_size);
02249   break;
02250       }
02251     }
02252   } else {
02253     srv_page_size_shift = 14;
02254     srv_page_size = (1 << srv_page_size_shift);
02255   }
02256 
02257   if (!srv_page_size_shift) {
02258     errmsg_printf(error::ERROR,
02259       "InnoDB: Error: %"PRIu32" is not a valid value for innodb_page_size.\n"
02260       "InnoDB: Error: Valid values are 4096, 8192, and 16384 (default=16384).\n",
02261       page_size);
02262     goto error;
02263   }
02264 
02265   srv_log_block_size = 0;
02266   if (log_block_size != (1 << 9)) { 
02267     uint  n_shift;
02268 
02269     errmsg_printf(error::WARN,
02270       "InnoDB: Warning: innodb_log_block_size has been changed from default value 512. (###EXPERIMENTAL### operation)\n");
02271     for (n_shift = 9; n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX; n_shift++) {
02272       if (log_block_size == (1UL << n_shift)) {
02273   srv_log_block_size = (1 << n_shift);
02274   errmsg_printf(error::WARN, "InnoDB: The log block size is set to %"PRIu32".\n",
02275           srv_log_block_size);
02276   break;
02277       }
02278     }
02279   } else {
02280     srv_log_block_size = 512;
02281   }
02282 
02283   if (!srv_log_block_size) {
02284     errmsg_printf(error::ERROR,
02285       "InnoDB: Error: %"PRIu32" is not a valid value for innodb_log_block_size.\n"
02286       "InnoDB: Error: A valid value for innodb_log_block_size is\n"
02287       "InnoDB: Error: a power of 2 from 512 to 16384.\n",
02288       log_block_size);
02289     goto error;
02290   }
02291 
02292   os_innodb_umask = (ulint)internal::my_umask;
02293 
02294 
02295   /* Set InnoDB initialization parameters according to the values
02296     read from MySQL .cnf file */
02297 
02298   /*--------------- Data files -------------------------*/
02299 
02300   /* The default dir for data files is the datadir of MySQL */
02301 
02302   srv_data_home = (char *)innobase_data_home_dir.c_str();
02303 
02304   /* Set default InnoDB data file size to 10 MB and let it be
02305     auto-extending. Thus users can use InnoDB in >= 4.0 without having
02306     to specify any startup options. */
02307 
02308   if (innobase_data_file_path.empty()) 
02309   {
02310     innobase_data_file_path= std::string("ibdata1:10M:autoextend");
02311   }
02312 
02313   /* Since InnoDB edits the argument in the next call, we make another
02314     copy of it: */
02315 
02316   internal_innobase_data_file_path = strdup(innobase_data_file_path.c_str());
02317 
02318   ret = (bool) srv_parse_data_file_paths_and_sizes(
02319                                                    internal_innobase_data_file_path);
02320   if (ret == FALSE) {
02321     errmsg_printf(error::ERROR, "InnoDB: syntax error in innodb_data_file_path");
02322 
02323 mem_free_and_error:
02324     srv_free_paths_and_sizes();
02325     free(internal_innobase_data_file_path);
02326     goto error;
02327   }
02328 
02329   /* -------------- Log files ---------------------------*/
02330 
02331   /* The default dir for log files is the datadir of MySQL */
02332 
02333   if (vm.count("log-group-home-dir"))
02334   {
02335     innobase_log_group_home_dir= vm["log-group-home-dir"].as<string>();
02336   }
02337   else
02338   {
02339     innobase_log_group_home_dir= getDataHome().file_string();
02340   }
02341 
02342   ret = (bool)
02343     srv_parse_log_group_home_dirs((char *)innobase_log_group_home_dir.c_str());
02344 
02345   if (ret == FALSE || innobase_mirrored_log_groups.get() != 1) {
02346     errmsg_printf(error::ERROR, _("syntax error in innodb_log_group_home_dir, or a "
02347                                   "wrong number of mirrored log groups"));
02348 
02349     goto mem_free_and_error;
02350   }
02351 
02352 
02353   /* Validate the file format by animal name */
02354   if (vm.count("file-format"))
02355   {
02356     format_id = innobase_file_format_name_lookup(
02357                                                  vm["file-format"].as<string>().c_str());
02358 
02359     if (format_id > DICT_TF_FORMAT_MAX) {
02360 
02361       errmsg_printf(error::ERROR, "InnoDB: wrong innodb_file_format.");
02362 
02363       goto mem_free_and_error;
02364     }
02365   } else {
02366     /* Set it to the default file format id.*/
02367     format_id = 0;
02368   }
02369 
02370   srv_file_format = format_id;
02371 
02372   innobase_file_format_name =
02373     trx_sys_file_format_id_to_name(format_id);
02374 
02375   /* Check innobase_file_format_check variable */
02376   if (!innobase_file_format_check)
02377   {
02378     /* Set the value to disable checking. */
02379     srv_max_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
02380   } else {
02381     /* Set the value to the lowest supported format. */
02382     srv_max_file_format_at_startup = DICT_TF_FORMAT_MIN;
02383   }
02384 
02385   /* Did the user specify a format name that we support?
02386      As a side effect it will update the variable
02387      srv_max_file_format_at_startup */
02388   if (innobase_file_format_validate_and_set(innobase_file_format_max.c_str()) < 0)
02389   {
02390     errmsg_printf(error::ERROR, _("InnoDB: invalid innodb_file_format_max value: "
02391                                   "should be any value up to %s or its equivalent numeric id"),
02392                   trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
02393     goto mem_free_and_error;
02394   }
02395 
02396   if (vm.count("change-buffering"))
02397   {
02398     ulint use;
02399 
02400     for (use = 0;
02401          use < UT_ARR_SIZE(innobase_change_buffering_values);
02402          use++) {
02403       if (!innobase_strcasecmp(
02404                                innobase_change_buffering.c_str(),
02405                                innobase_change_buffering_values[use])) {
02406         ibuf_use = static_cast<ibuf_use_t>(use);
02407         goto innobase_change_buffering_inited_ok;
02408       }
02409     }
02410 
02411     errmsg_printf(error::ERROR, "InnoDB: invalid value innodb_change_buffering=%s",
02412                   vm["change-buffering"].as<string>().c_str());
02413     goto mem_free_and_error;
02414   }
02415 
02416 innobase_change_buffering_inited_ok:
02417   ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
02418   innobase_change_buffering = innobase_change_buffering_values[ibuf_use];
02419 
02420   /* --------------------------------------------------*/
02421 
02422   if (vm.count("flush-method") != 0)
02423   {
02424     srv_file_flush_method_str = (char *)vm["flush-method"].as<string>().c_str();
02425   }
02426 
02427   srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
02428   srv_n_log_files = (ulint) innobase_log_files_in_group;
02429   srv_log_file_size = (ulint) innobase_log_file_size;
02430 
02431   srv_log_buffer_size = (ulint) innobase_log_buffer_size;
02432 
02433   srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
02434   srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances;
02435 
02436   srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
02437 
02438   srv_n_read_io_threads = (ulint) innobase_read_io_threads;
02439   srv_n_write_io_threads = (ulint) innobase_write_io_threads;
02440 
02441   srv_read_ahead &= 3;
02442   srv_adaptive_flushing_method %= 3;
02443 
02444   srv_force_recovery = (ulint) innobase_force_recovery;
02445 
02446   srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
02447   srv_use_checksums = (ibool) innobase_use_checksums;
02448 
02449 #ifdef HAVE_LARGE_PAGES
02450   if ((os_use_large_pages = (ibool) my_use_large_pages))
02451     os_large_page_size = (ulint) opt_large_page_size;
02452 #endif
02453 
02454   row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
02455 
02456   srv_locks_unsafe_for_binlog = (ibool) TRUE;
02457 
02458   srv_max_n_open_files = (ulint) innobase_open_files;
02459   srv_innodb_status = (ibool) innobase_create_status_file;
02460 
02461   srv_print_verbose_log = true;
02462 
02463   /* Store the default charset-collation number of this MySQL
02464     installation */
02465 
02466   data_mysql_default_charset_coll = (ulint)default_charset_info->number;
02467 
02468   /* Since we in this module access directly the fields of a trx
02469     struct, and due to different headers and flags it might happen that
02470     mutex_t has a different size in this module and in InnoDB
02471     modules, we check at run time that the size is the same in
02472     these compilation modules. */
02473 
02474   err = innobase_start_or_create_for_mysql();
02475 
02476   if (err != DB_SUCCESS)
02477   {
02478     goto mem_free_and_error;
02479   }
02480 
02481   err = dict_create_sys_replication_log();
02482 
02483   if (err != DB_SUCCESS) {
02484     goto mem_free_and_error;
02485   }
02486 
02487 
02488   innobase_old_blocks_pct = buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(),
02489                                                      TRUE);
02490 
02491   innobase_open_tables = hash_create(200);
02492   innodb_inited= 1;
02493 
02494   actuall_engine_ptr->dropTemporarySchema();
02495 
02496   context.add(new InnodbStatusTool);
02497   context.add(innodb_engine_ptr);
02498   context.add(new CmpTool(false));
02499   context.add(new CmpTool(true));
02500   context.add(new CmpmemTool(false));
02501   context.add(new CmpmemTool(true));
02502   context.add(new InnodbTrxTool("INNODB_TRX"));
02503   context.add(new InnodbTrxTool("INNODB_LOCKS"));
02504   context.add(new InnodbTrxTool("INNODB_LOCK_WAITS"));
02505   context.add(new InnodbSysTablesTool());
02506   context.add(new InnodbSysTableStatsTool());
02507   context.add(new InnodbSysIndexesTool());
02508   context.add(new InnodbSysColumnsTool());
02509   context.add(new InnodbSysFieldsTool());
02510   context.add(new InnodbSysForeignTool());
02511   context.add(new InnodbSysForeignColsTool());
02512   context.add(new InnodbInternalTables());
02513   context.add(new InnodbReplicationTable());
02514 
02515   if (innobase_use_replication_log)
02516   {
02517     ReplicationLog *replication_logger= new ReplicationLog();
02518     context.add(replication_logger);
02519     ReplicationLog::setup(replication_logger);
02520   }
02521 
02522   context.registerVariable(new sys_var_const_string_val("data-home-dir", innobase_data_home_dir));
02523   context.registerVariable(new sys_var_const_string_val("flush-method", 
02524                                                         vm.count("flush-method") ?  vm["flush-method"].as<string>() : ""));
02525   context.registerVariable(new sys_var_const_string_val("log-group-home-dir", innobase_log_group_home_dir));
02526   context.registerVariable(new sys_var_const_string_val("data-file-path", innobase_data_file_path));
02527   context.registerVariable(new sys_var_const_string_val("version", vm["version"].as<string>()));
02528 
02529 
02530   context.registerVariable(new sys_var_bool_ptr_readonly("replication_log", &innobase_use_replication_log));
02531   context.registerVariable(new sys_var_bool_ptr_readonly("checksums", &innobase_use_checksums));
02532   context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite", &innobase_use_doublewrite));
02533   context.registerVariable(new sys_var_bool_ptr("file-per-table", &srv_file_per_table));
02534   context.registerVariable(new sys_var_bool_ptr_readonly("file-format-check", &innobase_file_format_check));
02535   context.registerVariable(new sys_var_bool_ptr("adaptive-flushing", &srv_adaptive_flushing));
02536   context.registerVariable(new sys_var_bool_ptr("status-file", &innobase_create_status_file));
02537   context.registerVariable(new sys_var_bool_ptr_readonly("use-sys-malloc", &srv_use_sys_malloc));
02538   context.registerVariable(new sys_var_bool_ptr_readonly("use-native-aio", &srv_use_native_aio));
02539 
02540   context.registerVariable(new sys_var_bool_ptr("support-xa", &support_xa));
02541   context.registerVariable(new sys_var_bool_ptr("strict_mode", &strict_mode));
02542   context.registerVariable(new sys_var_constrained_value<uint32_t>("lock_wait_timeout", lock_wait_timeout));
02543 
02544   context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
02545   context.registerVariable(new sys_var_constrained_value<uint32_t>("autoextend_increment",
02546                                                                    innodb_auto_extend_increment,
02547                                                                    auto_extend_update));
02548   context.registerVariable(new sys_var_constrained_value<uint32_t>("io_capacity",
02549                                                                    innodb_io_capacity,
02550                                                                    io_capacity_update));
02551   context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_batch_size",
02552                                                                    innodb_purge_batch_size,
02553                                                                    purge_batch_update));
02554   context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_threads",
02555                                                                    innodb_n_purge_threads,
02556                                                                    purge_threads_update));
02557   context.registerVariable(new sys_var_constrained_value<uint32_t>("fast_shutdown", innobase_fast_shutdown));
02558   context.registerVariable(new sys_var_std_string("file_format",
02559                                                   innobase_file_format_name,
02560                                                   innodb_file_format_name_validate));
02561   context.registerVariable(new sys_var_std_string("change_buffering",
02562                                                   innobase_change_buffering,
02563                                                   innodb_change_buffering_validate));
02564   context.registerVariable(new sys_var_std_string("file_format_max",
02565                                                   innobase_file_format_max,
02566                                                   innodb_file_format_max_validate));
02567   context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
02568   context.registerVariable(new sys_var_constrained_value_readonly<int64_t>("log_file_size", innobase_log_file_size));
02569   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("page_size", innobase_page_size));
02570   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("log_block_size", innobase_log_block_size));
02571   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("flush_log_at_trx_commit",
02572                                                   innodb_flush_log_at_trx_commit));
02573   context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("max_dirty_pages_pct",
02574                                                   innodb_max_dirty_pages_pct));
02575   context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", innodb_max_purge_lag));
02576   context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("stats_sample_pages", innodb_stats_sample_pages));
02577   context.registerVariable(new sys_var_bool_ptr("adaptive_hash_index", &btr_search_enabled, innodb_adaptive_hash_index_update));
02578 
02579   context.registerVariable(new sys_var_constrained_value<uint32_t>("commit_concurrency",
02580                                                                    innobase_commit_concurrency,
02581                                                                    innodb_commit_concurrency_validate));
02582   context.registerVariable(new sys_var_constrained_value<uint32_t>("concurrency_tickets",
02583                                                                    innodb_concurrency_tickets));
02584   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_io_threads", innobase_read_io_threads));
02585   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_io_threads", innobase_write_io_threads));
02586   context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("replication_delay", innodb_replication_delay));
02587   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("force_recovery", innobase_force_recovery));
02588   context.registerVariable(new sys_var_constrained_value_readonly<size_t>("log_buffer_size", innobase_log_buffer_size));
02589   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("log_files_in_group", innobase_log_files_in_group));
02590   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("mirrored_log_groups", innobase_mirrored_log_groups));
02591   context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("open_files", innobase_open_files));
02592   context.registerVariable(new sys_var_constrained_value<uint32_t>("old_blocks_pct",
02593                                                                    innobase_old_blocks_pct,
02594                                                                    innodb_old_blocks_pct_update));
02595   context.registerVariable(new sys_var_uint32_t_ptr("old_blocks_time", &buf_LRU_old_threshold_ms));
02596   context.registerVariable(new sys_var_constrained_value<uint32_t>("sync_spin_loops", innodb_sync_spin_loops, innodb_sync_spin_loops_update));
02597   context.registerVariable(new sys_var_constrained_value<uint32_t>("spin_wait_delay", innodb_spin_wait_delay, innodb_spin_wait_delay_update));
02598   context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_sleep_delay", innodb_thread_sleep_delay, innodb_thread_sleep_delay_update));
02599   context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_concurrency",
02600                                                                    innobase_thread_concurrency,
02601                                                                    innodb_thread_concurrency_update));
02602   context.registerVariable(new sys_var_constrained_value<uint32_t>("read_ahead_threshold",
02603                                                                    innodb_read_ahead_threshold,
02604                                                                    innodb_read_ahead_threshold_update));
02605   context.registerVariable(new sys_var_constrained_value<uint32_t>("auto_lru_dump",
02606                                                                    buffer_pool_restore_at_startup,
02607                                                                    auto_lru_dump_update));
02608   context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("ibuf_max_size",
02609                                                                             ibuf_max_size));
02610   context.registerVariable(new sys_var_constrained_value<uint32_t>("ibuf_active_contract",
02611                                                                    ibuf_active_contract,
02612                                                                    ibuf_active_contract_update));
02613   context.registerVariable(new sys_var_constrained_value<uint32_t>("ibuf_accel_rate",
02614                                                                    ibuf_accel_rate,
02615                                                                    ibuf_accel_rate_update));
02616   context.registerVariable(new sys_var_constrained_value<uint32_t>("checkpoint_age_target",
02617                                                                    checkpoint_age_target,
02618                                                                    checkpoint_age_target_update));
02619   context.registerVariable(new sys_var_constrained_value<uint32_t>("flush_neighbor_pages",
02620                                                                    flush_neighbor_pages,
02621                                                                    flush_neighbor_pages_update));
02622   context.registerVariable(new sys_var_std_string("read_ahead",
02623                                                   read_ahead,
02624                                                   read_ahead_validate));
02625   context.registerVariable(new sys_var_std_string("adaptive_flushing_method",
02626                                                   adaptive_flushing_method,
02627                                                   adaptive_flushing_method_validate));
02628   /* Get the current high water mark format. */
02629   innobase_file_format_max = trx_sys_file_format_max_get();
02630   btr_search_fully_disabled = (!btr_search_enabled);
02631 
02632   return(FALSE);
02633 
02634 error:
02635   return(TRUE);
02636 }
02637 
02638 
02639 /****************************************************************/
02643 bool
02644 InnobaseEngine::flush_logs()
02645 /*=====================*/
02646 {
02647   bool  result = 0;
02648 
02649   assert(this == innodb_engine_ptr);
02650 
02651   log_buffer_flush_to_disk();
02652 
02653   return(result);
02654 }
02655 
02656 /*****************************************************************/
02658 static
02659 void
02660 innobase_commit_low(
02661 /*================*/
02662   trx_t*  trx)  
02663 {
02664   if (trx->conc_state == TRX_NOT_STARTED) {
02665 
02666     return;
02667   }
02668 
02669   trx_commit_for_mysql(trx);
02670 }
02671 
02672 /*****************************************************************/
02678 int
02679 InnobaseEngine::doStartTransaction(
02680 /*====================================*/
02681   Session*  session,  
02683   start_transaction_option_t options)
02684 {
02685   assert(this == innodb_engine_ptr);
02686 
02687   /* Create a new trx struct for session, if it does not yet have one */
02688   trx_t *trx = check_trx_exists(session);
02689 
02690   /* This is just to play safe: release a possible FIFO ticket and
02691   search latch. Since we will reserve the kernel mutex, we have to
02692   release the search system latch first to obey the latching order. */
02693   innobase_release_stat_resources(trx);
02694 
02695   /* If the transaction is not started yet, start it */
02696   trx_start_if_not_started(trx);
02697 
02698   /* Assign a read view if the transaction does not have it yet */
02699   if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
02700     trx_assign_read_view(trx);
02701 
02702   return 0;
02703 }
02704 
02705 /*****************************************************************/
02709 int
02710 InnobaseEngine::doCommit(
02711 /*============*/
02712   Session*  session,  
02714   bool  all)  
02716 {
02717   trx_t*    trx;
02718 
02719   assert(this == innodb_engine_ptr);
02720 
02721   trx = check_trx_exists(session);
02722 
02723   /* Since we will reserve the kernel mutex, we have to release
02724   the search system latch first to obey the latching order. */
02725 
02726   if (trx->has_search_latch) {
02727     trx_search_latch_release_if_reserved(trx);
02728   }
02729 
02730   if (all)
02731   {
02732     /* We were instructed to commit the whole transaction, or
02733     this is an SQL statement end and autocommit is on */
02734 
02735     /* We need current binlog position for ibbackup to work.
02736     Note, the position is current because of
02737     prepare_commit_mutex */
02738     const uint32_t commit_concurrency= innobase_commit_concurrency.get();
02739     if (commit_concurrency)
02740     {
02741       do 
02742       {
02743         boost::mutex::scoped_lock scopedLock(commit_cond_m);
02744         commit_threads++;
02745 
02746         if (commit_threads <= commit_concurrency) 
02747           break;
02748 
02749         commit_threads--;
02750         commit_cond.wait(scopedLock);
02751       } while (1);
02752     }
02753 
02754     trx->mysql_log_file_name = NULL;
02755     trx->mysql_log_offset = 0;
02756 
02757     /* Don't do write + flush right now. For group commit
02758     to work we want to do the flush after releasing the
02759     prepare_commit_mutex. */
02760     trx->flush_log_later = TRUE;
02761     innobase_commit_low(trx);
02762     trx->flush_log_later = FALSE;
02763 
02764     if (commit_concurrency)
02765     {
02766       boost::mutex::scoped_lock scopedLock(commit_cond_m);
02767       commit_threads--;
02768       commit_cond.notify_one();
02769     }
02770 
02771     /* Now do a write + flush of logs. */
02772     trx_commit_complete_for_mysql(trx);
02773 
02774   } else {
02775     /* We just mark the SQL statement ended and do not do a
02776     transaction commit */
02777 
02778     /* If we had reserved the auto-inc lock for some
02779     table in this SQL statement we release it now */
02780 
02781     row_unlock_table_autoinc_for_mysql(trx);
02782 
02783     /* Store the current undo_no of the transaction so that we
02784     know where to roll back if we have to roll back the next
02785     SQL statement */
02786 
02787     trx_mark_sql_stat_end(trx);
02788 
02789     if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
02790     {
02791       if (trx->conc_state != TRX_NOT_STARTED)
02792       {
02793         commit(session, TRUE);
02794       }
02795     }
02796   }
02797 
02798   trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
02799 
02800   if (trx->declared_to_be_inside_innodb) {
02801     /* Release our possible ticket in the FIFO */
02802 
02803     srv_conc_force_exit_innodb(trx);
02804   }
02805 
02806   /* Tell the InnoDB server that there might be work for utility
02807   threads: */
02808   srv_active_wake_master_thread();
02809 
02810   if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
02811       trx->global_read_view)
02812   {
02813     /* At low transaction isolation levels we let
02814        each consistent read set its own snapshot */
02815     read_view_close_for_mysql(trx);
02816   }
02817 
02818   return(0);
02819 }
02820 
02821 /*****************************************************************/
02824 int
02825 InnobaseEngine::doRollback(
02826 /*==============*/
02827   Session*  session,
02829   bool  all)  
02831 {
02832   int error = 0;
02833   trx_t*  trx;
02834 
02835   assert(this == innodb_engine_ptr);
02836 
02837   trx = check_trx_exists(session);
02838 
02839   /* Release a possible FIFO ticket and search latch. Since we will
02840   reserve the kernel mutex, we have to release the search system latch
02841   first to obey the latching order. */
02842 
02843   innobase_release_stat_resources(trx);
02844 
02845   trx->n_autoinc_rows = 0;
02846 
02847   /* If we had reserved the auto-inc lock for some table (if
02848   we come here to roll back the latest SQL statement) we
02849   release it now before a possibly lengthy rollback */
02850 
02851   row_unlock_table_autoinc_for_mysql(trx);
02852 
02853   if (all)
02854   {
02855     error = trx_rollback_for_mysql(trx);
02856   } else {
02857     error = trx_rollback_last_sql_stat_for_mysql(trx);
02858   }
02859 
02860   if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
02861       trx->global_read_view)
02862   {
02863     /* At low transaction isolation levels we let
02864        each consistent read set its own snapshot */
02865     read_view_close_for_mysql(trx);
02866   }
02867 
02868   return(convert_error_code_to_mysql(error, 0, NULL));
02869 }
02870 
02871 /*****************************************************************/
02874 static
02875 int
02876 innobase_rollback_trx(
02877 /*==================*/
02878   trx_t*  trx)  
02879 {
02880   int error = 0;
02881 
02882   /* Release a possible FIFO ticket and search latch. Since we will
02883   reserve the kernel mutex, we have to release the search system latch
02884   first to obey the latching order. */
02885 
02886   innobase_release_stat_resources(trx);
02887 
02888   /* If we had reserved the auto-inc lock for some table (if
02889   we come here to roll back the latest SQL statement) we
02890   release it now before a possibly lengthy rollback */
02891 
02892   row_unlock_table_autoinc_for_mysql(trx);
02893 
02894   error = trx_rollback_for_mysql(trx);
02895 
02896   return(convert_error_code_to_mysql(error, 0, NULL));
02897 }
02898 
02899 /*****************************************************************/
02903 int
02904 InnobaseEngine::doRollbackToSavepoint(
02905 /*===========================*/
02906   Session*  session,    
02908   drizzled::NamedSavepoint &named_savepoint)  
02909 {
02910   ib_int64_t  mysql_binlog_cache_pos;
02911   int   error = 0;
02912   trx_t*    trx;
02913 
02914   assert(this == innodb_engine_ptr);
02915 
02916   trx = check_trx_exists(session);
02917 
02918   /* Release a possible FIFO ticket and search latch. Since we will
02919   reserve the kernel mutex, we have to release the search system latch
02920   first to obey the latching order. */
02921 
02922   innobase_release_stat_resources(trx);
02923 
02924   error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
02925                                                         &mysql_binlog_cache_pos);
02926   return(convert_error_code_to_mysql(error, 0, NULL));
02927 }
02928 
02929 /*****************************************************************/
02933 int
02934 InnobaseEngine::doReleaseSavepoint(
02935 /*=======================*/
02936   Session*  session,    
02938   drizzled::NamedSavepoint &named_savepoint)  
02939 {
02940   int   error = 0;
02941   trx_t*    trx;
02942 
02943   assert(this == innodb_engine_ptr);
02944 
02945   trx = check_trx_exists(session);
02946 
02947   error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
02948 
02949   return(convert_error_code_to_mysql(error, 0, NULL));
02950 }
02951 
02952 /*****************************************************************/
02955 int
02956 InnobaseEngine::doSetSavepoint(
02957 /*===============*/
02958   Session*  session,
02959   drizzled::NamedSavepoint &named_savepoint)  
02960 {
02961   int error = 0;
02962   trx_t*  trx;
02963 
02964   assert(this == innodb_engine_ptr);
02965 
02966   /*
02967     In the autocommit mode there is no sense to set a savepoint
02968     (unless we are in sub-statement), so SQL layer ensures that
02969     this method is never called in such situation.
02970   */
02971 
02972   trx = check_trx_exists(session);
02973 
02974   /* Release a possible FIFO ticket and search latch. Since we will
02975   reserve the kernel mutex, we have to release the search system latch
02976   first to obey the latching order. */
02977 
02978   innobase_release_stat_resources(trx);
02979 
02980   /* cannot happen outside of transaction */
02981   assert(trx->conc_state != TRX_NOT_STARTED);
02982 
02983   error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
02984 
02985   return(convert_error_code_to_mysql(error, 0, NULL));
02986 }
02987 
02988 /*****************************************************************/
02991 int
02992 InnobaseEngine::close_connection(
02993 /*======================*/
02994   Session*  session)
02996 {
02997   trx_t*  trx;
02998 
02999   assert(this == innodb_engine_ptr);
03000   trx = session_to_trx(session);
03001 
03002   ut_a(trx);
03003 
03004   assert(session->getKilled() != Session::NOT_KILLED ||
03005          trx->conc_state == TRX_NOT_STARTED);
03006 
03007   /* Warn if rolling back some things... */
03008   if (session->getKilled() != Session::NOT_KILLED &&
03009       trx->conc_state != TRX_NOT_STARTED &&
03010       trx->undo_no > 0 &&
03011       global_system_variables.log_warnings)
03012   {
03013       errmsg_printf(error::WARN,
03014       "Drizzle is closing a connection during a KILL operation\n"
03015       "that has an active InnoDB transaction.  %llu row modifications will "
03016       "roll back.\n",
03017       (ullint) trx->undo_no);
03018   }
03019 
03020   innobase_rollback_trx(trx);
03021 
03022   thr_local_free(trx->mysql_thread_id);
03023   trx_free_for_mysql(trx);
03024 
03025   return(0);
03026 }
03027 
03028 
03029 /*************************************************************************/
03033 /****************************************************************/
03035 UNIV_INTERN
03036 const char*
03037 ha_innobase::index_type(
03038 /*====================*/
03039   uint)
03041 {
03042   return("BTREE");
03043 }
03044 
03045 /****************************************************************/
03048 UNIV_INTERN
03049 uint
03050 InnobaseEngine::max_supported_keys() const
03051 /*===================================*/
03052 {
03053   return(MAX_KEY);
03054 }
03055 
03056 /****************************************************************/
03059 UNIV_INTERN
03060 uint32_t
03061 InnobaseEngine::max_supported_key_length() const
03062 /*=========================================*/
03063 {
03064   /* An InnoDB page must store >= 2 keys; a secondary key record
03065   must also contain the primary key value: max key length is
03066   therefore set to slightly less than 1 / 4 of page size which
03067   is 16 kB; but currently MySQL does not work with keys whose
03068   size is > MAX_KEY_LENGTH */
03069   return(3500);
03070 }
03071 
03072 /****************************************************************/
03075 UNIV_INTERN
03076 const key_map*
03077 ha_innobase::keys_to_use_for_scanning()
03078 {
03079   return(&key_map_full);
03080 }
03081 
03082 
03083 /****************************************************************/
03086 UNIV_INTERN
03087 bool
03088 ha_innobase::primary_key_is_clustered()
03089 {
03090   return(true);
03091 }
03092 
03093 /********************************************************************/
03096 static
03097 uint64_t
03098 innobase_get_int_col_max_value(
03099 /*===========================*/
03100   const Field*  field)  
03101 {
03102   uint64_t  max_value = 0;
03103 
03104   switch(field->key_type()) {
03105   /* TINY */
03106   case HA_KEYTYPE_BINARY:
03107     max_value = 0xFFULL;
03108     break;
03109   /* LONG */
03110   case HA_KEYTYPE_ULONG_INT:
03111     max_value = 0xFFFFFFFFULL;
03112     break;
03113   case HA_KEYTYPE_LONG_INT:
03114     max_value = 0x7FFFFFFFULL;
03115     break;
03116   /* BIG */
03117   case HA_KEYTYPE_ULONGLONG:
03118     max_value = 0xFFFFFFFFFFFFFFFFULL;
03119     break;
03120   case HA_KEYTYPE_LONGLONG:
03121     max_value = 0x7FFFFFFFFFFFFFFFULL;
03122     break;
03123   case HA_KEYTYPE_DOUBLE:
03124     /* We use the maximum as per IEEE754-2008 standard, 2^53 */
03125     max_value = 0x20000000000000ULL;
03126     break;
03127   default:
03128     ut_error;
03129   }
03130 
03131   return(max_value);
03132 }
03133 
03134 /*******************************************************************/
03138 static
03139 ibool
03140 innobase_match_index_columns(
03141 /*=========================*/
03142   const KeyInfo*    key_info, 
03144   const dict_index_t* index_info) 
03146 {
03147   const KeyPartInfo*  key_part;
03148   const KeyPartInfo*  key_end;
03149   const dict_field_t* innodb_idx_fld;
03150   const dict_field_t* innodb_idx_fld_end;
03151 
03152   /* Check whether user defined index column count matches */
03153   if (key_info->key_parts != index_info->n_user_defined_cols) {
03154     return(FALSE);
03155   }
03156 
03157   key_part = key_info->key_part;
03158   key_end = key_part + key_info->key_parts;
03159   innodb_idx_fld = index_info->fields;
03160   innodb_idx_fld_end = index_info->fields + index_info->n_fields;
03161 
03162   /* Check each index column's datatype. We do not check
03163   column name because there exists case that index
03164   column name got modified in mysql but such change does not
03165   propagate to InnoDB.
03166   One hidden assumption here is that the index column sequences
03167   are matched up between those in mysql and Innodb. */
03168   for (; key_part != key_end; ++key_part) {
03169     ulint col_type;
03170     ibool is_unsigned;
03171     ulint mtype = innodb_idx_fld->col->mtype;
03172 
03173     /* Need to translate to InnoDB column type before
03174     comparison. */
03175     col_type = get_innobase_type_from_mysql_type(&is_unsigned,
03176                    key_part->field);
03177 
03178     /* Ignore Innodb specific system columns. */
03179     while (mtype == DATA_SYS) {
03180       innodb_idx_fld++;
03181 
03182       if (innodb_idx_fld >= innodb_idx_fld_end) {
03183         return(FALSE);
03184       }
03185     }
03186 
03187     if (col_type != mtype) {
03188       /* Column Type mismatches */
03189       return(FALSE);
03190     }
03191 
03192     innodb_idx_fld++;
03193   }
03194 
03195   return(TRUE);
03196 }
03197 
03198 /*******************************************************************/
03209 static
03210 ibool
03211 innobase_build_index_translation(
03212 /*=============================*/
03213   const Table*    table,    
03215   dict_table_t*   ib_table, 
03217   INNOBASE_SHARE*   share)    
03220 {
03221   ulint   mysql_num_index;
03222   ulint   ib_num_index;
03223   dict_index_t**  index_mapping;
03224   ibool   ret = TRUE;
03225 
03226         mutex_enter(&dict_sys->mutex);
03227 
03228   mysql_num_index = table->getShare()->keys;
03229   ib_num_index = UT_LIST_GET_LEN(ib_table->indexes);
03230 
03231   index_mapping = share->idx_trans_tbl.index_mapping;
03232 
03233   /* If there exists inconsistency between MySQL and InnoDB dictionary
03234   (metadata) information, the number of index defined in MySQL
03235   could exceed that in InnoDB, do not build index translation
03236   table in such case */
03237   if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) {
03238     ret = FALSE;
03239     goto func_exit;
03240   }
03241 
03242   /* If index entry count is non-zero, nothing has
03243   changed since last update, directly return TRUE */
03244   if (share->idx_trans_tbl.index_count) {
03245     /* Index entry count should still match mysql_num_index */
03246     ut_a(share->idx_trans_tbl.index_count == mysql_num_index);
03247     goto func_exit;
03248   }
03249 
03250   /* The number of index increased, rebuild the mapping table */
03251   if (mysql_num_index > share->idx_trans_tbl.array_size) {
03252     index_mapping = (dict_index_t**) realloc(index_mapping,
03253               mysql_num_index *
03254                                                          sizeof(*index_mapping));
03255 
03256     if (!index_mapping) {
03257       /* Report an error if index_mapping continues to be
03258       NULL and mysql_num_index is a non-zero value */
03259       errmsg_printf(error::ERROR, "InnoDB: fail to allocate memory for "
03260                                       "index translation table. Number of Index:%lu, array size:%lu",
03261           mysql_num_index,
03262           share->idx_trans_tbl.array_size);
03263       ret = FALSE;
03264       goto func_exit;
03265     }
03266 
03267     share->idx_trans_tbl.array_size = mysql_num_index;
03268   }
03269 
03270   /* For each index in the mysql key_info array, fetch its
03271   corresponding InnoDB index pointer into index_mapping
03272   array. */
03273   for (ulint count = 0; count < mysql_num_index; count++) {
03274 
03275     /* Fetch index pointers into index_mapping according to mysql
03276     index sequence */
03277     index_mapping[count] = dict_table_get_index_on_name(
03278       ib_table, table->key_info[count].name);
03279 
03280     if (!index_mapping[count]) {
03281       errmsg_printf(error::ERROR, "Cannot find index %s in InnoDB index dictionary.",
03282                                       table->key_info[count].name);
03283       ret = FALSE;
03284       goto func_exit;
03285     }
03286 
03287     /* Double check fetched index has the same
03288     column info as those in mysql key_info. */
03289     if (!innobase_match_index_columns(&table->key_info[count], index_mapping[count])) {
03290                   errmsg_printf(error::ERROR, "Found index %s whose column info does not match that of MySQL.",
03291                                 table->key_info[count].name);
03292                   ret = FALSE;
03293                   goto func_exit;
03294     }
03295   }
03296 
03297   /* Successfully built the translation table */
03298   share->idx_trans_tbl.index_count = mysql_num_index;
03299 
03300 func_exit:
03301   if (!ret) {
03302     /* Build translation table failed. */
03303     free(index_mapping);
03304 
03305     share->idx_trans_tbl.array_size = 0;
03306     share->idx_trans_tbl.index_count = 0;
03307     index_mapping = NULL;
03308   }
03309 
03310   share->idx_trans_tbl.index_mapping = index_mapping;
03311 
03312         mutex_exit(&dict_sys->mutex);
03313 
03314   return(ret);
03315 }
03316 
03317 /*******************************************************************/
03326 static
03327 dict_index_t*
03328 innobase_index_lookup(
03329 /*==================*/
03330   INNOBASE_SHARE* share,  
03332   uint    keynr)  
03334 {
03335   if (!share->idx_trans_tbl.index_mapping
03336       || keynr >= share->idx_trans_tbl.index_count) {
03337     return(NULL);
03338   }
03339 
03340   return(share->idx_trans_tbl.index_mapping[keynr]);
03341 }
03342 
03343 /********************************************************************/
03346 UNIV_INTERN
03347 void
03348 ha_innobase::innobase_initialize_autoinc()
03349 /*======================================*/
03350 {
03351   uint64_t  auto_inc;
03352   const Field*  field = getTable()->found_next_number_field;
03353 
03354   if (field != NULL) {
03355     auto_inc = innobase_get_int_col_max_value(field);
03356   } else {
03357     /* We have no idea what's been passed in to us as the
03358        autoinc column. We set it to the 0, effectively disabling
03359        updates to the table. */
03360     auto_inc = 0;
03361 
03362     ut_print_timestamp(stderr);
03363     errmsg_printf(error::ERROR, "InnoDB: Unable to determine the AUTOINC column name");
03364   }
03365 
03366   if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
03367     /* If the recovery level is set so high that writes
03368        are disabled we force the AUTOINC counter to 0
03369        value effectively disabling writes to the table.
03370        Secondly, we avoid reading the table in case the read
03371        results in failure due to a corrupted table/index.
03372 
03373        We will not return an error to the client, so that the
03374        tables can be dumped with minimal hassle.  If an error
03375        were returned in this case, the first attempt to read
03376        the table would fail and subsequent SELECTs would succeed. */
03377     auto_inc = 0;
03378   } else if (field == NULL) {
03379     /* This is a far more serious error, best to avoid
03380        opening the table and return failure. */
03381     my_error(ER_AUTOINC_READ_FAILED, MYF(0));
03382   } else {
03383     dict_index_t* index;
03384     const char* col_name;
03385     uint64_t  read_auto_inc;
03386     ulint   err;
03387 
03388     update_session(getTable()->in_use);
03389     col_name = field->field_name;
03390 
03391     ut_a(prebuilt->trx == session_to_trx(user_session));
03392 
03393     index = innobase_get_index(getTable()->getShare()->next_number_index);
03394 
03395     /* Execute SELECT MAX(col_name) FROM TABLE; */
03396     err = row_search_max_autoinc(index, col_name, &read_auto_inc);
03397 
03398     switch (err) {
03399     case DB_SUCCESS: {
03400       uint64_t col_max_value;
03401 
03402       col_max_value = innobase_get_int_col_max_value(field);
03403 
03404       /* At the this stage we do not know the increment
03405          nor the offset, so use a default increment of 1. */
03406 
03407       auto_inc = innobase_next_autoinc(read_auto_inc, 1, 1, col_max_value);
03408 
03409       break;
03410     }
03411     case DB_RECORD_NOT_FOUND:
03412       ut_print_timestamp(stderr);
03413       errmsg_printf(error::ERROR, "InnoDB: MySQL and InnoDB data dictionaries are out of sync.\n"
03414                     "InnoDB: Unable to find the AUTOINC column %s in the InnoDB table %s.\n"
03415                     "InnoDB: We set the next AUTOINC column value to 0,\n"
03416                     "InnoDB: in effect disabling the AUTOINC next value generation.\n"
03417                     "InnoDB: You can either set the next AUTOINC value explicitly using ALTER TABLE\n"
03418                     "InnoDB: or fix the data dictionary by recreating the table.\n",
03419                     col_name, index->table->name);
03420 
03421       /* This will disable the AUTOINC generation. */
03422       auto_inc = 0;
03423 
03424       /* We want the open to succeed, so that the user can
03425          take corrective action. ie. reads should succeed but
03426          updates should fail. */
03427       err = DB_SUCCESS;
03428       break;
03429     default:
03430       /* row_search_max_autoinc() should only return
03431          one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
03432       ut_error;
03433     }
03434   }
03435 
03436   dict_table_autoinc_initialize(prebuilt->table, auto_inc);
03437 }
03438 
03439 /*****************************************************************/
03443 UNIV_INTERN
03444 int
03445 ha_innobase::doOpen(const identifier::Table &identifier,
03446                     int   mode,   
03447                     uint    test_if_locked) 
03448 {
03449   dict_table_t* ib_table;
03450   Session*    session;
03451 
03452   UT_NOT_USED(mode);
03453   UT_NOT_USED(test_if_locked);
03454 
03455   session= getTable()->in_use;
03456 
03457   /* Under some cases Drizzle seems to call this function while
03458   holding btr_search_latch. This breaks the latching order as
03459   we acquire dict_sys->mutex below and leads to a deadlock. */
03460   if (session != NULL) {
03461     getTransactionalEngine()->releaseTemporaryLatches(session);
03462   }
03463 
03464   user_session = NULL;
03465 
03466   std::string search_string(identifier.getSchemaName());
03467   boost::algorithm::to_lower(search_string);
03468 
03469   if (search_string.compare("data_dictionary") == 0)
03470   {
03471     std::string table_name(identifier.getTableName());
03472     boost::algorithm::to_upper(table_name);
03473     if (!(share=get_share(table_name.c_str())))
03474     {
03475       return 1;
03476     }
03477   }
03478   else
03479   {
03480     if (!(share=get_share(identifier.getKeyPath().c_str())))
03481     {
03482       return(1);
03483     }
03484   }
03485 
03486   /* Create buffers for packing the fields of a record. Why
03487   table->stored_rec_length did not work here? Obviously, because char
03488   fields when packed actually became 1 byte longer, when we also
03489   stored the string length as the first byte. */
03490 
03491   upd_and_key_val_buff_len =
03492         getTable()->getShare()->sizeStoredRecord()
03493         + getTable()->getShare()->max_key_length
03494         + MAX_REF_PARTS * 3;
03495 
03496   upd_buff.resize(upd_and_key_val_buff_len);
03497 
03498   if (upd_buff.size() < upd_and_key_val_buff_len)
03499   {
03500     free_share(share);
03501   }
03502 
03503   key_val_buff.resize(upd_and_key_val_buff_len);
03504   if (key_val_buff.size() < upd_and_key_val_buff_len)
03505   {
03506     return(1);
03507   }
03508 
03509   /* Get pointer to a table object in InnoDB dictionary cache */
03510   if (search_string.compare("data_dictionary") == 0)
03511   {
03512     std::string table_name(identifier.getTableName());
03513     boost::algorithm::to_upper(table_name);
03514     ib_table = dict_table_get(table_name.c_str(), TRUE);
03515   }
03516   else
03517   {
03518     ib_table = dict_table_get(identifier.getKeyPath().c_str(), TRUE);
03519   }
03520   
03521   if (NULL == ib_table) {
03522     errmsg_printf(error::ERROR, "Cannot find or open table %s from\n"
03523         "the internal data dictionary of InnoDB "
03524         "though the .frm file for the\n"
03525         "table exists. Maybe you have deleted and "
03526         "recreated InnoDB data\n"
03527         "files but have forgotten to delete the "
03528         "corresponding .frm files\n"
03529         "of InnoDB tables, or you have moved .frm "
03530         "files to another database?\n"
03531         "or, the table contains indexes that this "
03532         "version of the engine\n"
03533         "doesn't support.\n"
03534         "See " REFMAN "innodb-troubleshooting.html\n"
03535         "how you can resolve the problem.\n",
03536         identifier.getKeyPath().c_str());
03537     free_share(share);
03538     upd_buff.resize(0);
03539     key_val_buff.resize(0);
03540     errno = ENOENT;
03541 
03542     return(HA_ERR_NO_SUCH_TABLE);
03543   }
03544 
03545   if (ib_table->ibd_file_missing && ! session->doing_tablespace_operation()) {
03546     errmsg_printf(error::ERROR, "MySQL is trying to open a table handle but "
03547         "the .ibd file for\ntable %s does not exist.\n"
03548         "Have you deleted the .ibd file from the "
03549         "database directory under\nthe MySQL datadir, "
03550         "or have you used DISCARD TABLESPACE?\n"
03551         "See " REFMAN "innodb-troubleshooting.html\n"
03552         "how you can resolve the problem.\n",
03553         identifier.getKeyPath().c_str());
03554     free_share(share);
03555     upd_buff.resize(0);
03556     key_val_buff.resize(0);
03557     errno = ENOENT;
03558 
03559     dict_table_decrement_handle_count(ib_table, FALSE);
03560     return(HA_ERR_NO_SUCH_TABLE);
03561   }
03562 
03563   prebuilt = row_create_prebuilt(ib_table);
03564 
03565   prebuilt->mysql_row_len = getTable()->getShare()->sizeStoredRecord();
03566   prebuilt->default_rec = getTable()->getDefaultValues();
03567   ut_ad(prebuilt->default_rec);
03568 
03569   /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
03570 
03571   primary_key = getTable()->getShare()->getPrimaryKey();
03572   key_used_on_scan = primary_key;
03573 
03574   if (!innobase_build_index_translation(getTable(), ib_table, share)) {
03575     errmsg_printf(error::ERROR, "Build InnoDB index translation table for"
03576                     " Table %s failed", identifier.getKeyPath().c_str());
03577   }
03578 
03579   /* Allocate a buffer for a 'row reference'. A row reference is
03580   a string of bytes of length ref_length which uniquely specifies
03581   a row in our table. Note that MySQL may also compare two row
03582   references for equality by doing a simple memcmp on the strings
03583   of length ref_length! */
03584 
03585   if (!row_table_got_default_clust_index(ib_table)) {
03586 
03587     prebuilt->clust_index_was_generated = FALSE;
03588 
03589     if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
03590       errmsg_printf(error::ERROR, "Table %s has a primary key in "
03591                     "InnoDB data dictionary, but not "
03592                     "in MySQL!", identifier.getTableName().c_str());
03593 
03594       /* This mismatch could cause further problems
03595          if not attended, bring this to the user's attention
03596          by printing a warning in addition to log a message
03597          in the errorlog */
03598       push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
03599                           ER_NO_SUCH_INDEX,
03600                           "InnoDB: Table %s has a "
03601                           "primary key in InnoDB data "
03602                           "dictionary, but not in "
03603                           "MySQL!", identifier.getTableName().c_str());
03604 
03605       /* If primary_key >= MAX_KEY, its (primary_key)
03606          value could be out of bound if continue to index
03607          into key_info[] array. Find InnoDB primary index,
03608          and assign its key_length to ref_length.
03609          In addition, since MySQL indexes are sorted starting
03610          with primary index, unique index etc., initialize
03611          ref_length to the first index key length in
03612          case we fail to find InnoDB cluster index.
03613 
03614          Please note, this will not resolve the primary
03615          index mismatch problem, other side effects are
03616          possible if users continue to use the table.
03617          However, we allow this table to be opened so
03618          that user can adopt necessary measures for the
03619          mismatch while still being accessible to the table
03620          date. */
03621       ref_length = getTable()->key_info[0].key_length;
03622 
03623       /* Find correspoinding cluster index
03624          key length in MySQL's key_info[] array */
03625       for (ulint i = 0; i < getTable()->getShare()->keys; i++) {
03626         dict_index_t* index;
03627         index = innobase_get_index(i);
03628         if (dict_index_is_clust(index)) {
03629           ref_length =
03630             getTable()->key_info[i].key_length;
03631         }
03632       }
03633     } else {
03634       /* MySQL allocates the buffer for ref.
03635          key_info->key_length includes space for all key
03636          columns + one byte for each column that may be
03637          NULL. ref_length must be as exact as possible to
03638          save space, because all row reference buffers are
03639          allocated based on ref_length. */
03640 
03641       ref_length = getTable()->key_info[primary_key].key_length;
03642     }
03643   } else {
03644     if (primary_key != MAX_KEY) {
03645       errmsg_printf(error::ERROR,
03646                     "Table %s has no primary key in InnoDB data "
03647                     "dictionary, but has one in MySQL! If you "
03648                     "created the table with a MySQL version < "
03649                     "3.23.54 and did not define a primary key, "
03650                     "but defined a unique key with all non-NULL "
03651                     "columns, then MySQL internally treats that "
03652                     "key as the primary key. You can fix this "
03653                     "error by dump + DROP + CREATE + reimport "
03654                     "of the table.", identifier.getTableName().c_str());
03655 
03656       /* This mismatch could cause further problems
03657          if not attended, bring this to the user attention
03658          by printing a warning in addition to log a message
03659          in the errorlog */
03660       push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
03661                           ER_NO_SUCH_INDEX,
03662                           "InnoDB: Table %s has no "
03663                           "primary key in InnoDB data "
03664                           "dictionary, but has one in "
03665                           "MySQL!", identifier.getTableName().c_str());
03666     }
03667 
03668     prebuilt->clust_index_was_generated = TRUE;
03669 
03670     ref_length = DATA_ROW_ID_LEN;
03671 
03672     /* If we automatically created the clustered index, then
03673     MySQL does not know about it, and MySQL must NOT be aware
03674     of the index used on scan, to make it avoid checking if we
03675     update the column of the index. That is why we assert below
03676     that key_used_on_scan is the undefined value MAX_KEY.
03677     The column is the row id in the automatical generation case,
03678     and it will never be updated anyway. */
03679 
03680     if (key_used_on_scan != MAX_KEY) {
03681       errmsg_printf(error::WARN, 
03682         "Table %s key_used_on_scan is %lu even "
03683         "though there is no primary key inside "
03684         "InnoDB.", identifier.getTableName().c_str(), (ulong) key_used_on_scan);
03685     }
03686   }
03687 
03688   /* Index block size in InnoDB: used by MySQL in query optimization */
03689   stats.block_size = 16 * 1024;
03690 
03691   /* Init table lock structure */
03692   lock.init(&share->lock);
03693 
03694   if (prebuilt->table) {
03695     /* We update the highest file format in the system table
03696     space, if this table has higher file format setting. */
03697 
03698     char changed_file_format_max[100];
03699     strcpy(changed_file_format_max, innobase_file_format_max.c_str());
03700     trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
03701       dict_table_get_format(prebuilt->table));
03702     innobase_file_format_max= changed_file_format_max;
03703   }
03704 
03705   /* Only if the table has an AUTOINC column. */
03706   if (prebuilt->table != NULL && getTable()->found_next_number_field != NULL) {
03707 
03708     dict_table_autoinc_lock(prebuilt->table);
03709 
03710     /* Since a table can already be "open" in InnoDB's internal
03711     data dictionary, we only init the autoinc counter once, the
03712     first time the table is loaded. We can safely reuse the
03713     autoinc value from a previous Drizzle open. */
03714     if (dict_table_autoinc_read(prebuilt->table) == 0) {
03715 
03716       innobase_initialize_autoinc();
03717     }
03718 
03719     dict_table_autoinc_unlock(prebuilt->table);
03720   }
03721 
03722   info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
03723 
03724   return(0);
03725 }
03726 
03727 UNIV_INTERN
03728 uint32_t
03729 InnobaseEngine::max_supported_key_part_length() const
03730 {
03731   return(DICT_MAX_INDEX_COL_LEN - 1);
03732 }
03733 
03734 /******************************************************************/
03737 UNIV_INTERN
03738 int
03739 ha_innobase::close(void)
03740 /*====================*/
03741 {
03742   Session*  session;
03743 
03744   session= getTable()->in_use;
03745   if (session != NULL) {
03746     getTransactionalEngine()->releaseTemporaryLatches(session);
03747   }
03748 
03749   row_prebuilt_free(prebuilt, FALSE);
03750 
03751   upd_buff.clear();
03752   key_val_buff.clear();
03753   free_share(share);
03754 
03755   /* Tell InnoDB server that there might be work for
03756   utility threads: */
03757 
03758   srv_active_wake_master_thread();
03759 
03760   return(0);
03761 }
03762 
03763 /* The following accessor functions should really be inside MySQL code! */
03764 
03765 /**************************************************************/
03768 static inline
03769 uint
03770 get_field_offset(
03771 /*=============*/
03772   Table*  table,  
03773   Field*  field)  
03774 {
03775   return((uint) (field->ptr - table->getInsertRecord()));
03776 }
03777 
03778 /**************************************************************/
03782 static inline
03783 uint
03784 field_in_record_is_null(
03785 /*====================*/
03786   Table*  table,  
03787   Field*  field,  
03788   char* record) 
03789 {
03790   int null_offset;
03791 
03792   if (!field->null_ptr) {
03793 
03794     return(0);
03795   }
03796 
03797   null_offset = (uint) ((char*) field->null_ptr
03798           - (char*) table->getInsertRecord());
03799 
03800   if (record[null_offset] & field->null_bit) {
03801 
03802     return(1);
03803   }
03804 
03805   return(0);
03806 }
03807 
03808 /**************************************************************/
03811 static inline
03812 void
03813 set_field_in_record_to_null(
03814 /*========================*/
03815   Table*  table,  
03816   Field*  field,  
03817   char* record) 
03818 {
03819   int null_offset;
03820 
03821   null_offset = (uint) ((char*) field->null_ptr
03822           - (char*) table->getInsertRecord());
03823 
03824   record[null_offset] = record[null_offset] | field->null_bit;
03825 }
03826 
03827 /*************************************************************/
03833 UNIV_INTERN int
03834 innobase_mysql_cmp(
03835 /*===============*/
03836   int   mysql_type, 
03837   uint    charset_number, 
03838   const unsigned char* a,   
03839   unsigned int  a_length, 
03841   const unsigned char* b,   /* in: data field */
03842   unsigned int  b_length);  /* in: data field length,
03843           not UNIV_SQL_NULL */
03844 
03845 int
03846 innobase_mysql_cmp(
03847 /*===============*/
03848           /* out: 1, 0, -1, if a is greater, equal, less than b, respectively */
03849   int   mysql_type, /* in: MySQL type */
03850   uint    charset_number, /* in: number of the charset */
03851   const unsigned char* a,   /* in: data field */
03852   unsigned int  a_length, /* in: data field length, not UNIV_SQL_NULL */
03853   const unsigned char* b,   /* in: data field */
03854   unsigned int  b_length) /* in: data field length, not UNIV_SQL_NULL */
03855 {
03856   const charset_info_st* charset;
03857   enum_field_types  mysql_tp;
03858   int     ret;
03859 
03860   assert(a_length != UNIV_SQL_NULL);
03861   assert(b_length != UNIV_SQL_NULL);
03862 
03863   mysql_tp = (enum_field_types) mysql_type;
03864 
03865   switch (mysql_tp) {
03866 
03867   case DRIZZLE_TYPE_BLOB:
03868   case DRIZZLE_TYPE_VARCHAR:
03869     /* Use the charset number to pick the right charset struct for
03870       the comparison. Since the MySQL function get_charset may be
03871       slow before Bar removes the mutex operation there, we first
03872       look at 2 common charsets directly. */
03873 
03874     if (charset_number == default_charset_info->number) {
03875       charset = default_charset_info;
03876     } else {
03877       charset = get_charset(charset_number);
03878 
03879       if (charset == NULL) {
03880         errmsg_printf(error::ERROR, "InnoDB needs charset %lu for doing "
03881                       "a comparison, but MySQL cannot "
03882                       "find that charset.",
03883                       (ulong) charset_number);
03884         ut_a(0);
03885       }
03886     }
03887 
03888     /* Starting from 4.1.3, we use strnncollsp() in comparisons of
03889       non-latin1_swedish_ci strings. NOTE that the collation order
03890       changes then: 'b\0\0...' is ordered BEFORE 'b  ...'. Users
03891       having indexes on such data need to rebuild their tables! */
03892 
03893     ret = charset->coll->strnncollsp(charset,
03894                                      a, a_length,
03895                                      b, b_length, 0);
03896     if (ret < 0) {
03897       return(-1);
03898     } else if (ret > 0) {
03899       return(1);
03900     } else {
03901       return(0);
03902     }
03903   default:
03904     ut_error;
03905   }
03906 
03907   return(0);
03908 }
03909 
03910 /**************************************************************/
03915 UNIV_INTERN
03916 ulint
03917 get_innobase_type_from_mysql_type(
03918 /*==============================*/
03919   ulint*    unsigned_flag,  
03924   const void* f)    
03925 {
03926   const class Field* field = reinterpret_cast<const class Field*>(f);
03927 
03928   /* The following asserts try to check that the MySQL type code fits in
03929   8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
03930   the type */
03931 
03932   assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
03933 
03934   if (field->flags & UNSIGNED_FLAG) {
03935 
03936     *unsigned_flag = DATA_UNSIGNED;
03937   } else {
03938     *unsigned_flag = 0;
03939   }
03940 
03941   if (field->real_type() == DRIZZLE_TYPE_ENUM)
03942   {
03943     /* MySQL has field->type() a string type for these, but the
03944     data is actually internally stored as an unsigned integer
03945     code! */
03946 
03947     *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
03948             flag set to zero, even though
03949             internally this is an unsigned
03950             integer type */
03951     return(DATA_INT);
03952   }
03953 
03954   switch (field->type()) {
03955     /* NOTE that we only allow string types in DATA_DRIZZLE and
03956     DATA_VARDRIZZLE */
03957   case DRIZZLE_TYPE_VARCHAR:    /* new >= 5.0.3 true VARCHAR */
03958     if (field->binary()) {
03959       return(DATA_BINARY);
03960     } else {
03961       return(DATA_VARMYSQL);
03962     }
03963   case DRIZZLE_TYPE_DECIMAL:
03964   case DRIZZLE_TYPE_MICROTIME:
03965     return(DATA_FIXBINARY);
03966   case DRIZZLE_TYPE_LONG:
03967   case DRIZZLE_TYPE_LONGLONG:
03968   case DRIZZLE_TYPE_DATETIME:
03969   case DRIZZLE_TYPE_TIME:
03970   case DRIZZLE_TYPE_DATE:
03971   case DRIZZLE_TYPE_TIMESTAMP:
03972   case DRIZZLE_TYPE_ENUM:
03973     return(DATA_INT);
03974   case DRIZZLE_TYPE_DOUBLE:
03975     return(DATA_DOUBLE);
03976   case DRIZZLE_TYPE_BLOB:
03977     return(DATA_BLOB);
03978   case DRIZZLE_TYPE_BOOLEAN:
03979   case DRIZZLE_TYPE_UUID:
03980     return(DATA_FIXBINARY);
03981   case DRIZZLE_TYPE_IPV6:
03982    return(DATA_FIXBINARY);
03983   case DRIZZLE_TYPE_NULL:
03984     ut_error;
03985   }
03986 
03987   return(0);
03988 }
03989 
03990 /*******************************************************************/
03993 static inline
03994 void
03995 innobase_write_to_2_little_endian(
03996 /*==============================*/
03997   byte* buf,  
03998   ulint val)  
03999 {
04000   ut_a(val < 256 * 256);
04001 
04002   buf[0] = (byte)(val & 0xFF);
04003   buf[1] = (byte)(val / 256);
04004 }
04005 
04006 /*******************************************************************/
04010 static inline
04011 uint
04012 innobase_read_from_2_little_endian(
04013 /*===============================*/
04014   const unsigned char*  buf)  
04015 {
04016   return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
04017 }
04018 
04019 /*******************************************************************/
04022 UNIV_INTERN
04023 uint
04024 ha_innobase::store_key_val_for_row(
04025 /*===============================*/
04026   uint    keynr,  
04027   char*   buff, 
04029   uint    buff_len,
04030   const unsigned char*  record)
04031 {
04032   KeyInfo*    key_info  = &getTable()->key_info[keynr];
04033   KeyPartInfo*  key_part  = key_info->key_part;
04034   KeyPartInfo*  end   = key_part + key_info->key_parts;
04035   char*   buff_start  = buff;
04036   enum_field_types mysql_type;
04037   Field*    field;
04038   ibool   is_null;
04039 
04040   /* The format for storing a key field in MySQL is the following:
04041 
04042   1. If the column can be NULL, then in the first byte we put 1 if the
04043   field value is NULL, 0 otherwise.
04044 
04045   2. If the column is of a BLOB type (it must be a column prefix field
04046   in this case), then we put the length of the data in the field to the
04047   next 2 bytes, in the little-endian format. If the field is SQL NULL,
04048   then these 2 bytes are set to 0. Note that the length of data in the
04049   field is <= column prefix length.
04050 
04051   3. In a column prefix field, prefix_len next bytes are reserved for
04052   data. In a normal field the max field length next bytes are reserved
04053   for data. For a VARCHAR(n) the max field length is n. If the stored
04054   value is the SQL NULL then these data bytes are set to 0.
04055 
04056   4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
04057   in the MySQL row format, the length is stored in 1 or 2 bytes,
04058   depending on the maximum allowed length. But in the MySQL key value
04059   format, the length always takes 2 bytes.
04060 
04061   We have to zero-fill the buffer so that MySQL is able to use a
04062   simple memcmp to compare two key values to determine if they are
04063   equal. MySQL does this to compare contents of two 'ref' values. */
04064 
04065   bzero(buff, buff_len);
04066 
04067   for (; key_part != end; key_part++) {
04068     is_null = FALSE;
04069 
04070     if (key_part->null_bit) {
04071       if (record[key_part->null_offset]
04072             & key_part->null_bit) {
04073         *buff = 1;
04074         is_null = TRUE;
04075       } else {
04076         *buff = 0;
04077       }
04078       buff++;
04079     }
04080 
04081     field = key_part->field;
04082     mysql_type = field->type();
04083 
04084     if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
04085             /* >= 5.0.3 true VARCHAR */
04086       ulint   lenlen;
04087       ulint   len;
04088       const byte* data;
04089       ulint   key_len;
04090       ulint   true_len;
04091       const charset_info_st* cs;
04092       int   error=0;
04093 
04094       key_len = key_part->length;
04095 
04096       if (is_null) {
04097         buff += key_len + 2;
04098 
04099         continue;
04100       }
04101       cs = field->charset();
04102 
04103       lenlen = (ulint)
04104         (((Field_varstring*)field)->pack_length_no_ptr());
04105 
04106       data = row_mysql_read_true_varchar(&len,
04107         (byte*) (record
04108         + (ulint)get_field_offset(getTable(), field)),
04109         lenlen);
04110 
04111       true_len = len;
04112 
04113       /* For multi byte character sets we need to calculate
04114       the true length of the key */
04115 
04116       if (len > 0 && cs->mbmaxlen > 1) {
04117         true_len = (ulint) cs->cset->well_formed_len(*cs, str_ref(data, len), (uint) (key_len / cs->mbmaxlen), &error);
04118       }
04119 
04120       /* In a column prefix index, we may need to truncate
04121       the stored value: */
04122 
04123       if (true_len > key_len) {
04124         true_len = key_len;
04125       }
04126 
04127       /* The length in a key value is always stored in 2
04128       bytes */
04129 
04130       row_mysql_store_true_var_len((byte*)buff, true_len, 2);
04131       buff += 2;
04132 
04133       memcpy(buff, data, true_len);
04134 
04135       /* Note that we always reserve the maximum possible
04136       length of the true VARCHAR in the key value, though
04137       only len first bytes after the 2 length bytes contain
04138       actual data. The rest of the space was reset to zero
04139       in the bzero() call above. */
04140 
04141       buff += key_len;
04142 
04143     } else if (mysql_type == DRIZZLE_TYPE_BLOB) {
04144 
04145       const charset_info_st* cs;
04146       ulint   key_len;
04147       ulint   true_len;
04148       int   error=0;
04149       ulint   blob_len;
04150       const byte* blob_data;
04151 
04152       ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
04153 
04154       key_len = key_part->length;
04155 
04156       if (is_null) {
04157         buff += key_len + 2;
04158 
04159         continue;
04160       }
04161 
04162       cs = field->charset();
04163 
04164       blob_data = row_mysql_read_blob_ref(&blob_len,
04165         (byte*) (record
04166         + (ulint)get_field_offset(getTable(), field)),
04167           (ulint) field->pack_length());
04168 
04169       true_len = blob_len;
04170 
04171       ut_a(get_field_offset(getTable(), field)
04172         == key_part->offset);
04173 
04174       /* For multi byte character sets we need to calculate
04175       the true length of the key */
04176 
04177       if (blob_len > 0 && cs->mbmaxlen > 1) {
04178         true_len = (ulint) cs->cset->well_formed_len(*cs, str_ref(blob_data, blob_len), (uint) (key_len / cs->mbmaxlen), &error);
04179       }
04180 
04181       /* All indexes on BLOB and TEXT are column prefix
04182       indexes, and we may need to truncate the data to be
04183       stored in the key value: */
04184 
04185       if (true_len > key_len) {
04186         true_len = key_len;
04187       }
04188 
04189       /* MySQL reserves 2 bytes for the length and the
04190       storage of the number is little-endian */
04191 
04192       innobase_write_to_2_little_endian(
04193           (byte*)buff, true_len);
04194       buff += 2;
04195 
04196       memcpy(buff, blob_data, true_len);
04197 
04198       /* Note that we always reserve the maximum possible
04199       length of the BLOB prefix in the key value. */
04200 
04201       buff += key_len;
04202     } else {
04203       /* Here we handle all other data types except the
04204       true VARCHAR, BLOB and TEXT. Note that the column
04205       value we store may be also in a column prefix
04206       index. */
04207 
04208       ulint     true_len;
04209       ulint     key_len;
04210       const unsigned char*    src_start;
04211       const charset_info_st* cs= field->charset();
04212 
04213       key_len = key_part->length;
04214 
04215       if (is_null) {
04216          buff += key_len;
04217 
04218          continue;
04219       }
04220 
04221       src_start = record + key_part->offset;
04222       true_len = key_len;
04223 
04224       /* Character set for the field is defined only
04225       to fields whose type is string and real field
04226       type is not enum or set. For these fields check
04227       if character set is multi byte. */
04228 
04229       memcpy(buff, src_start, true_len);
04230       buff += true_len;
04231 
04232       /* Pad the unused space with spaces. */
04233 
04234       if (true_len < key_len) {
04235         ulint pad_len = key_len - true_len;
04236         ut_a(!(pad_len % cs->mbminlen));
04237 
04238         cs->cset->fill(cs, buff, pad_len,
04239                        0x20 /* space */);
04240         buff += pad_len;
04241       }
04242     }
04243   }
04244 
04245   ut_a(buff <= buff_start + buff_len);
04246 
04247   return((uint)(buff - buff_start));
04248 }
04249 
04250 /**************************************************************/
04253 static
04254 void
04255 build_template(
04256 /*===========*/
04257   row_prebuilt_t* prebuilt, 
04258   Session*  ,   
04261   Table*    table,    
04262   uint    templ_type) 
04264 {
04265   dict_index_t* index;
04266   dict_index_t* clust_index;
04267   mysql_row_templ_t* templ;
04268   Field*    field;
04269   ulint   n_fields;
04270   ulint   n_requested_fields  = 0;
04271   ibool   fetch_all_in_key  = FALSE;
04272   ibool   fetch_primary_key_cols  = FALSE;
04273   ulint   i= 0;
04274   /* byte offset of the end of last requested column */
04275   ulint   mysql_prefix_len  = 0;
04276 
04277   if (prebuilt->select_lock_type == LOCK_X) {
04278     /* We always retrieve the whole clustered index record if we
04279     use exclusive row level locks, for example, if the read is
04280     done in an UPDATE statement. */
04281 
04282     templ_type = ROW_MYSQL_WHOLE_ROW;
04283   }
04284 
04285   if (templ_type == ROW_MYSQL_REC_FIELDS) {
04286     if (prebuilt->hint_need_to_fetch_extra_cols
04287       == ROW_RETRIEVE_ALL_COLS) {
04288 
04289       /* We know we must at least fetch all columns in the
04290       key, or all columns in the table */
04291 
04292       if (prebuilt->read_just_key) {
04293         /* MySQL has instructed us that it is enough
04294         to fetch the columns in the key; looks like
04295         MySQL can set this flag also when there is
04296         only a prefix of the column in the key: in
04297         that case we retrieve the whole column from
04298         the clustered index */
04299 
04300         fetch_all_in_key = TRUE;
04301       } else {
04302         templ_type = ROW_MYSQL_WHOLE_ROW;
04303       }
04304     } else if (prebuilt->hint_need_to_fetch_extra_cols
04305       == ROW_RETRIEVE_PRIMARY_KEY) {
04306       /* We must at least fetch all primary key cols. Note
04307          that if the clustered index was internally generated
04308          by InnoDB on the row id (no primary key was
04309          defined), then row_search_for_mysql() will always
04310          retrieve the row id to a special buffer in the
04311          prebuilt struct. */
04312 
04313       fetch_primary_key_cols = TRUE;
04314     }
04315   }
04316 
04317   clust_index = dict_table_get_first_index(prebuilt->table);
04318 
04319   if (templ_type == ROW_MYSQL_REC_FIELDS) {
04320     index = prebuilt->index;
04321   } else {
04322     index = clust_index;
04323   }
04324 
04325   if (index == clust_index) {
04326     prebuilt->need_to_access_clustered = TRUE;
04327   } else {
04328     prebuilt->need_to_access_clustered = FALSE;
04329     /* Below we check column by column if we need to access
04330     the clustered index */
04331   }
04332 
04333   n_fields = (ulint)table->getShare()->sizeFields(); /* number of columns */
04334 
04335   if (!prebuilt->mysql_template) {
04336     prebuilt->mysql_template = (mysql_row_templ_t*)
04337       mem_alloc(n_fields * sizeof(mysql_row_templ_t));
04338   }
04339 
04340   prebuilt->template_type = templ_type;
04341   prebuilt->null_bitmap_len = table->getShare()->null_bytes;
04342 
04343   prebuilt->templ_contains_blob = FALSE;
04344 
04345   /* Note that in InnoDB, i is the column number. MySQL calls columns
04346   'fields'. */
04347   for (i = 0; i < n_fields; i++)
04348   {
04349     const dict_col_t *col= &index->table->cols[i];
04350     templ = prebuilt->mysql_template + n_requested_fields;
04351     field = table->getField(i);
04352 
04353     if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
04354       /* Decide which columns we should fetch
04355       and which we can skip. */
04356       register const ibool  index_contains_field =
04357         dict_index_contains_col_or_prefix(index, i);
04358 
04359       if (!index_contains_field && prebuilt->read_just_key) {
04360         /* If this is a 'key read', we do not need
04361         columns that are not in the key */
04362 
04363         goto skip_field;
04364       }
04365 
04366       if (index_contains_field && fetch_all_in_key) {
04367         /* This field is needed in the query */
04368 
04369         goto include_field;
04370       }
04371 
04372                         if (field->isReadSet() || field->isWriteSet())
04373         /* This field is needed in the query */
04374         goto include_field;
04375 
04376                         assert(table->isReadSet(i) == field->isReadSet());
04377                         assert(table->isWriteSet(i) == field->isWriteSet());
04378 
04379       if (fetch_primary_key_cols
04380         && dict_table_col_in_clustered_key(
04381           index->table, i)) {
04382         /* This field is needed in the query */
04383 
04384         goto include_field;
04385       }
04386 
04387       /* This field is not needed in the query, skip it */
04388 
04389       goto skip_field;
04390     }
04391 include_field:
04392     n_requested_fields++;
04393 
04394     templ->col_no = i;
04395     templ->clust_rec_field_no = dict_col_get_clust_pos(col, clust_index);
04396     ut_ad(templ->clust_rec_field_no != ULINT_UNDEFINED);
04397 
04398     if (index == clust_index) {
04399       templ->rec_field_no = templ->clust_rec_field_no;
04400     } else {
04401       templ->rec_field_no = dict_index_get_nth_col_pos(
04402                 index, i);
04403       if (templ->rec_field_no == ULINT_UNDEFINED) {
04404         prebuilt->need_to_access_clustered = TRUE;
04405       }
04406     }
04407 
04408     if (field->null_ptr) {
04409       templ->mysql_null_byte_offset =
04410         (ulint) ((char*) field->null_ptr
04411           - (char*) table->getInsertRecord());
04412 
04413       templ->mysql_null_bit_mask = (ulint) field->null_bit;
04414     } else {
04415       templ->mysql_null_bit_mask = 0;
04416     }
04417 
04418     templ->mysql_col_offset = (ulint)
04419           get_field_offset(table, field);
04420 
04421     templ->mysql_col_len = (ulint) field->pack_length();
04422     if (mysql_prefix_len < templ->mysql_col_offset
04423         + templ->mysql_col_len) {
04424       mysql_prefix_len = templ->mysql_col_offset
04425         + templ->mysql_col_len;
04426     }
04427     templ->type = col->mtype;
04428     templ->mysql_type = (ulint)field->type();
04429 
04430     if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
04431       templ->mysql_length_bytes = (ulint)
04432         (((Field_varstring*)field)->pack_length_no_ptr());
04433     }
04434 
04435     templ->charset = dtype_get_charset_coll(col->prtype);
04436     templ->mbminlen = dict_col_get_mbminlen(col);
04437     templ->mbmaxlen = dict_col_get_mbmaxlen(col);
04438     templ->is_unsigned = col->prtype & DATA_UNSIGNED;
04439     if (templ->type == DATA_BLOB) {
04440       prebuilt->templ_contains_blob = TRUE;
04441     }
04442 skip_field:
04443     ;
04444   }
04445 
04446   prebuilt->n_template = n_requested_fields;
04447   prebuilt->mysql_prefix_len = mysql_prefix_len;
04448 
04449   if (index != clust_index && prebuilt->need_to_access_clustered) {
04450     /* Change rec_field_no's to correspond to the clustered index
04451     record */
04452     for (i = 0; i < n_requested_fields; i++) {
04453       templ = prebuilt->mysql_template + i;
04454 
04455       templ->rec_field_no = templ->clust_rec_field_no;
04456     }
04457   }
04458 }
04459 
04460 /********************************************************************/
04467 UNIV_INTERN
04468 ulint
04469 ha_innobase::innobase_lock_autoinc(void)
04470 /*====================================*/
04471 {
04472   ulint   error = DB_SUCCESS;
04473 
04474   dict_table_autoinc_lock(prebuilt->table);
04475 
04476   return(ulong(error));
04477 }
04478 
04479 /********************************************************************/
04482 UNIV_INTERN
04483 ulint
04484 ha_innobase::innobase_reset_autoinc(
04485 /*================================*/
04486   uint64_t  autoinc)  
04487 {
04488   dict_table_autoinc_lock(prebuilt->table);
04489   dict_table_autoinc_initialize(prebuilt->table, autoinc);
04490   dict_table_autoinc_unlock(prebuilt->table);
04491 
04492   return(ulong(DB_SUCCESS));
04493 }
04494 
04495 /********************************************************************/
04499 UNIV_INTERN
04500 ulint
04501 ha_innobase::innobase_set_max_autoinc(
04502 /*==================================*/
04503   uint64_t  auto_inc) 
04504 {
04505   dict_table_autoinc_lock(prebuilt->table);
04506   dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
04507   dict_table_autoinc_unlock(prebuilt->table);
04508 
04509   return(ulong(DB_SUCCESS));
04510 }
04511 
04512 /********************************************************************/
04516 UNIV_INTERN
04517 int
04518 ha_innobase::doInsertRecord(
04519 /*===================*/
04520   unsigned char*  record) 
04521 {
04522   ulint   error = 0;
04523         int             error_result= 0;
04524   ibool   auto_inc_used= FALSE;
04525   ulint   sql_command;
04526   trx_t*    trx = session_to_trx(user_session);
04527 
04528   if (prebuilt->trx != trx) {
04529     errmsg_printf(error::ERROR, "The transaction object for the table handle is at "
04530         "%p, but for the current thread it is at %p",
04531         (const void*) prebuilt->trx, (const void*) trx);
04532 
04533     fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
04534     ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
04535     fputs("\n"
04536       "InnoDB: Dump of 200 bytes around ha_data: ",
04537       stderr);
04538     ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
04539     putc('\n', stderr);
04540     ut_error;
04541   }
04542 
04543   sql_command = user_session->getSqlCommand();
04544 
04545   if ((sql_command == SQLCOM_ALTER_TABLE
04546        || sql_command == SQLCOM_CREATE_INDEX
04547        || sql_command == SQLCOM_DROP_INDEX)
04548       && num_write_row >= 10000) {
04549     /* ALTER TABLE is COMMITted at every 10000 copied rows.
04550     The IX table lock for the original table has to be re-issued.
04551     As this method will be called on a temporary table where the
04552     contents of the original table is being copied to, it is
04553     a bit tricky to determine the source table.  The cursor
04554     position in the source table need not be adjusted after the
04555     intermediate COMMIT, since writes by other transactions are
04556     being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
04557 
04558     dict_table_t* src_table;
04559     enum lock_mode  mode;
04560 
04561     num_write_row = 0;
04562 
04563     /* Commit the transaction.  This will release the table
04564     locks, so they have to be acquired again. */
04565 
04566     /* Altering an InnoDB table */
04567     /* Get the source table. */
04568     src_table = lock_get_src_table(
04569         prebuilt->trx, prebuilt->table, &mode);
04570     if (!src_table) {
04571 no_commit:
04572       /* Unknown situation: do not commit */
04573       /*
04574       ut_print_timestamp(stderr);
04575       fprintf(stderr,
04576         "  InnoDB: ALTER TABLE is holding lock"
04577         " on %lu tables!\n",
04578         prebuilt->trx->mysql_n_tables_locked);
04579       */
04580       ;
04581     } else if (src_table == prebuilt->table) {
04582       /* Source table is not in InnoDB format:
04583       no need to re-acquire locks on it. */
04584 
04585       /* Altering to InnoDB format */
04586       getTransactionalEngine()->commit(user_session, 1);
04587       /* We will need an IX lock on the destination table. */
04588       prebuilt->sql_stat_start = TRUE;
04589     } else {
04590       /* Ensure that there are no other table locks than
04591       LOCK_IX and LOCK_AUTO_INC on the destination table. */
04592 
04593       if (!lock_is_table_exclusive(prebuilt->table,
04594               prebuilt->trx)) {
04595         goto no_commit;
04596       }
04597 
04598       /* Commit the transaction.  This will release the table
04599       locks, so they have to be acquired again. */
04600       getTransactionalEngine()->commit(user_session, 1);
04601       /* Re-acquire the table lock on the source table. */
04602       row_lock_table_for_mysql(prebuilt, src_table, mode);
04603       /* We will need an IX lock on the destination table. */
04604       prebuilt->sql_stat_start = TRUE;
04605     }
04606   }
04607 
04608   num_write_row++;
04609 
04610   /* This is the case where the table has an auto-increment column */
04611   if (getTable()->next_number_field && record == getTable()->getInsertRecord()) {
04612 
04613     /* Reset the error code before calling
04614     innobase_get_auto_increment(). */
04615     prebuilt->autoinc_error = DB_SUCCESS;
04616 
04617     if ((error = update_auto_increment())) {
04618       /* We don't want to mask autoinc overflow errors. */
04619 
04620       /* Handle the case where the AUTOINC sub-system
04621          failed during initialization. */
04622       if (prebuilt->autoinc_error == DB_UNSUPPORTED) {
04623         error_result = ER_AUTOINC_READ_FAILED;
04624         /* Set the error message to report too. */
04625         my_error(ER_AUTOINC_READ_FAILED, MYF(0));
04626         goto func_exit;
04627       } else if (prebuilt->autoinc_error != DB_SUCCESS) {
04628         error = (int) prebuilt->autoinc_error;
04629 
04630         goto report_error;
04631       }
04632 
04633       /* MySQL errors are passed straight back. */
04634       error_result = (int) error;
04635       goto func_exit;
04636     }
04637 
04638     auto_inc_used = TRUE;
04639   }
04640 
04641   if (prebuilt->mysql_template == NULL
04642       || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
04643 
04644     /* Build the template used in converting quickly between
04645     the two database formats */
04646 
04647     build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
04648   }
04649 
04650   innodb_srv_conc_enter_innodb(prebuilt->trx);
04651 
04652   error = row_insert_for_mysql((byte*) record, prebuilt);
04653 
04654   user_session->setXaId(trx->id);
04655 
04656   /* Handle duplicate key errors */
04657   if (auto_inc_used) {
04658     ulint   err;
04659     uint64_t  auto_inc;
04660     uint64_t  col_max_value;
04661 
04662     /* Note the number of rows processed for this statement, used
04663     by get_auto_increment() to determine the number of AUTO-INC
04664     values to reserve. This is only useful for a mult-value INSERT
04665     and is a statement level counter.*/
04666     if (trx->n_autoinc_rows > 0) {
04667       --trx->n_autoinc_rows;
04668     }
04669 
04670     /* We need the upper limit of the col type to check for
04671     whether we update the table autoinc counter or not. */
04672     col_max_value = innobase_get_int_col_max_value(
04673       getTable()->next_number_field); 
04674     /* Get the value that MySQL attempted to store in the table.*/
04675     auto_inc = getTable()->next_number_field->val_int();
04676 
04677     switch (error) {
04678     case DB_DUPLICATE_KEY:
04679 
04680       /* A REPLACE command and LOAD DATA INFILE REPLACE
04681       handle a duplicate key error themselves, but we
04682       must update the autoinc counter if we are performing
04683       those statements. */
04684 
04685       switch (sql_command) {
04686       case SQLCOM_LOAD:
04687         if ((trx->duplicates
04688             & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
04689 
04690           goto set_max_autoinc;
04691         }
04692         break;
04693 
04694       case SQLCOM_REPLACE:
04695       case SQLCOM_INSERT_SELECT:
04696       case SQLCOM_REPLACE_SELECT:
04697         goto set_max_autoinc;
04698 
04699       default:
04700         break;
04701       }
04702 
04703       break;
04704 
04705     case DB_SUCCESS:
04706       /* If the actual value inserted is greater than
04707       the upper limit of the interval, then we try and
04708       update the table upper limit. Note: last_value
04709       will be 0 if get_auto_increment() was not called.*/
04710 
04711       if (auto_inc >= prebuilt->autoinc_last_value) {
04712 set_max_autoinc:
04713         /* This should filter out the negative
04714            values set explicitly by the user. */
04715         if (auto_inc <= col_max_value) {
04716           ut_a(prebuilt->autoinc_increment > 0);
04717 
04718           uint64_t  need;
04719           uint64_t  offset;
04720 
04721           offset = prebuilt->autoinc_offset;
04722           need = prebuilt->autoinc_increment;
04723 
04724           auto_inc = innobase_next_autoinc(
04725                                            auto_inc,
04726                                            need, offset, col_max_value);
04727 
04728           err = innobase_set_max_autoinc(
04729                                          auto_inc);
04730 
04731           if (err != DB_SUCCESS) {
04732             error = err;
04733           }
04734         }
04735       }
04736       break;
04737     }
04738   }
04739 
04740   innodb_srv_conc_exit_innodb(prebuilt->trx);
04741 
04742 report_error:
04743   error_result = convert_error_code_to_mysql((int) error,
04744                prebuilt->table->flags,
04745                user_session);
04746 
04747 func_exit:
04748   innobase_active_small();
04749 
04750   return(error_result);
04751 }
04752 
04753 /**********************************************************************/
04757 static
04758 int
04759 calc_row_difference(
04760 /*================*/
04761   upd_t*    uvect,    
04762   unsigned char*    old_row,  
04763   unsigned char*    new_row,  
04764   Table* table,   
04766   unsigned char*  upd_buff, 
04767   ulint   buff_len, 
04768   row_prebuilt_t* prebuilt, 
04769   Session*  )   
04770 {
04771   unsigned char*    original_upd_buff = upd_buff;
04772   enum_field_types field_mysql_type;
04773   uint    n_fields;
04774   ulint   o_len;
04775   ulint   n_len;
04776   ulint   col_pack_len;
04777   const byte* new_mysql_row_col;
04778   const byte* o_ptr;
04779   const byte* n_ptr;
04780   byte*   buf;
04781   upd_field_t*  ufield;
04782   ulint   col_type;
04783   ulint   n_changed = 0;
04784   dfield_t  dfield;
04785   dict_index_t* clust_index;
04786   uint    i= 0;
04787 
04788   n_fields = table->getShare()->sizeFields();
04789   clust_index = dict_table_get_first_index(prebuilt->table);
04790 
04791   /* We use upd_buff to convert changed fields */
04792   buf = (byte*) upd_buff;
04793 
04794   for (i = 0; i < n_fields; i++) {
04795     Field *field= table->getField(i);
04796 
04797     o_ptr = (const byte*) old_row + get_field_offset(table, field);
04798     n_ptr = (const byte*) new_row + get_field_offset(table, field);
04799 
04800     /* Use new_mysql_row_col and col_pack_len save the values */
04801 
04802     new_mysql_row_col = n_ptr;
04803     col_pack_len = field->pack_length();
04804 
04805     o_len = col_pack_len;
04806     n_len = col_pack_len;
04807 
04808     /* We use o_ptr and n_ptr to dig up the actual data for
04809     comparison. */
04810 
04811     field_mysql_type = field->type();
04812 
04813     col_type = prebuilt->table->cols[i].mtype;
04814 
04815     switch (col_type) {
04816 
04817     case DATA_BLOB:
04818       o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
04819       n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
04820 
04821       break;
04822 
04823     case DATA_VARCHAR:
04824     case DATA_BINARY:
04825     case DATA_VARMYSQL:
04826       if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
04827         /* This is a >= 5.0.3 type true VARCHAR where
04828         the real payload data length is stored in
04829         1 or 2 bytes */
04830 
04831         o_ptr = row_mysql_read_true_varchar(
04832           &o_len, o_ptr,
04833           (ulint)
04834           (((Field_varstring*)field)->pack_length_no_ptr()));
04835 
04836         n_ptr = row_mysql_read_true_varchar(
04837           &n_len, n_ptr,
04838           (ulint)
04839           (((Field_varstring*)field)->pack_length_no_ptr()));
04840       }
04841 
04842       break;
04843     default:
04844       ;
04845     }
04846 
04847     if (field->null_ptr) {
04848       if (field_in_record_is_null(table, field,
04849               (char*) old_row)) {
04850         o_len = UNIV_SQL_NULL;
04851       }
04852 
04853       if (field_in_record_is_null(table, field,
04854               (char*) new_row)) {
04855         n_len = UNIV_SQL_NULL;
04856       }
04857     }
04858 
04859     if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
04860           0 != memcmp(o_ptr, n_ptr, o_len))) {
04861       /* The field has changed */
04862 
04863       ufield = uvect->fields + n_changed;
04864 
04865       /* Let us use a dummy dfield to make the conversion
04866       from the MySQL column format to the InnoDB format */
04867 
04868       dict_col_copy_type(prebuilt->table->cols + i,
04869                  &dfield.type);
04870 
04871       if (n_len != UNIV_SQL_NULL) {
04872         buf = row_mysql_store_col_in_innobase_format(
04873           &dfield,
04874           (byte*)buf,
04875           TRUE,
04876           new_mysql_row_col,
04877           col_pack_len,
04878           dict_table_is_comp(prebuilt->table));
04879         dfield_copy_data(&ufield->new_val, &dfield);
04880       } else {
04881         dfield_set_null(&ufield->new_val);
04882       }
04883 
04884       ufield->exp = NULL;
04885       ufield->orig_len = 0;
04886       ufield->field_no = dict_col_get_clust_pos(
04887         &prebuilt->table->cols[i], clust_index);
04888       n_changed++;
04889     }
04890   }
04891 
04892   uvect->n_fields = n_changed;
04893   uvect->info_bits = 0;
04894 
04895   ut_a(buf <= (byte*)original_upd_buff + buff_len);
04896 
04897   return(0);
04898 }
04899 
04900 /**********************************************************************/
04908 UNIV_INTERN
04909 int
04910 ha_innobase::doUpdateRecord(
04911 /*====================*/
04912   const unsigned char*  old_row,
04913   unsigned char*    new_row)
04914 {
04915   upd_t*    uvect;
04916   int   error = 0;
04917   trx_t*    trx = session_to_trx(user_session);
04918 
04919   ut_a(prebuilt->trx == trx);
04920 
04921   if (prebuilt->upd_node) {
04922     uvect = prebuilt->upd_node->update;
04923   } else {
04924     uvect = row_get_prebuilt_update_vector(prebuilt);
04925   }
04926 
04927   /* Build an update vector from the modified fields in the rows
04928   (uses upd_buff of the handle) */
04929 
04930   calc_row_difference(uvect, (unsigned char*) old_row, new_row, getTable(),
04931       &upd_buff[0], (ulint)upd_and_key_val_buff_len,
04932       prebuilt, user_session);
04933 
04934   /* This is not a delete */
04935   prebuilt->upd_node->is_delete = FALSE;
04936 
04937   ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
04938 
04939   if (getTable()->found_next_number_field)
04940   {
04941     uint64_t  auto_inc;
04942     uint64_t  col_max_value;
04943 
04944     auto_inc = getTable()->found_next_number_field->val_int();
04945 
04946     /* We need the upper limit of the col type to check for
04947     whether we update the table autoinc counter or not. */
04948     col_max_value = innobase_get_int_col_max_value(
04949       getTable()->found_next_number_field);
04950 
04951     uint64_t current_autoinc;
04952     ulint autoinc_error= innobase_get_autoinc(&current_autoinc);
04953     if (autoinc_error == DB_SUCCESS
04954         && auto_inc <= col_max_value && auto_inc != 0
04955         && auto_inc >= current_autoinc)
04956     {
04957 
04958       uint64_t  need;
04959       uint64_t  offset;
04960 
04961       offset = prebuilt->autoinc_offset;
04962       need = prebuilt->autoinc_increment;
04963 
04964       auto_inc = innobase_next_autoinc(
04965         auto_inc, need, offset, col_max_value);
04966 
04967       dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
04968     }
04969 
04970     dict_table_autoinc_unlock(prebuilt->table);
04971   }
04972 
04973   innodb_srv_conc_enter_innodb(trx);
04974 
04975   error = row_update_for_mysql((byte*) old_row, prebuilt);
04976 
04977   user_session->setXaId(trx->id);
04978 
04979   /* We need to do some special AUTOINC handling for the following case:
04980 
04981   INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
04982 
04983   We need to use the AUTOINC counter that was actually used by
04984   MySQL in the UPDATE statement, which can be different from the
04985   value used in the INSERT statement.*/
04986 
04987   if (error == DB_SUCCESS
04988       && getTable()->next_number_field
04989       && new_row == getTable()->getInsertRecord()
04990       && user_session->getSqlCommand() == SQLCOM_INSERT
04991       && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
04992     == TRX_DUP_IGNORE)  {
04993 
04994     uint64_t  auto_inc;
04995     uint64_t  col_max_value;
04996 
04997     auto_inc = getTable()->next_number_field->val_int();
04998 
04999     /* We need the upper limit of the col type to check for
05000     whether we update the table autoinc counter or not. */
05001     col_max_value = innobase_get_int_col_max_value(
05002       getTable()->next_number_field);
05003 
05004     if (auto_inc <= col_max_value && auto_inc != 0) {
05005 
05006       uint64_t  need;
05007       uint64_t  offset;
05008 
05009       offset = prebuilt->autoinc_offset;
05010       need = prebuilt->autoinc_increment;
05011 
05012       auto_inc = innobase_next_autoinc(
05013         auto_inc, need, offset, col_max_value);
05014 
05015       error = innobase_set_max_autoinc(auto_inc);
05016     }
05017   }
05018 
05019   innodb_srv_conc_exit_innodb(trx);
05020 
05021   error = convert_error_code_to_mysql(error,
05022               prebuilt->table->flags,
05023                                             user_session);
05024 
05025   if (error == 0 /* success */
05026       && uvect->n_fields == 0 /* no columns were updated */) {
05027 
05028     /* This is the same as success, but instructs
05029     MySQL that the row is not really updated and it
05030     should not increase the count of updated rows.
05031     This is fix for http://bugs.mysql.com/29157 */
05032     error = HA_ERR_RECORD_IS_THE_SAME;
05033   }
05034 
05035   /* Tell InnoDB server that there might be work for
05036   utility threads: */
05037 
05038   innobase_active_small();
05039 
05040   return(error);
05041 }
05042 
05043 /**********************************************************************/
05046 UNIV_INTERN
05047 int
05048 ha_innobase::doDeleteRecord(
05049 /*====================*/
05050   const unsigned char*  record) 
05051 {
05052   int   error = 0;
05053   trx_t*    trx = session_to_trx(user_session);
05054 
05055   ut_a(prebuilt->trx == trx);
05056 
05057   if (!prebuilt->upd_node) {
05058     row_get_prebuilt_update_vector(prebuilt);
05059   }
05060 
05061   /* This is a delete */
05062 
05063   prebuilt->upd_node->is_delete = TRUE;
05064 
05065   innodb_srv_conc_enter_innodb(trx);
05066 
05067   error = row_update_for_mysql((byte*) record, prebuilt);
05068 
05069   user_session->setXaId(trx->id);
05070 
05071   innodb_srv_conc_exit_innodb(trx);
05072 
05073   error = convert_error_code_to_mysql(
05074     error, prebuilt->table->flags, user_session);
05075 
05076   /* Tell the InnoDB server that there might be work for
05077   utility threads: */
05078 
05079   innobase_active_small();
05080 
05081   return(error);
05082 }
05083 
05084 /**********************************************************************/
05088 UNIV_INTERN
05089 void
05090 ha_innobase::unlock_row(void)
05091 /*=========================*/
05092 {
05093   /* Consistent read does not take any locks, thus there is
05094   nothing to unlock. */
05095 
05096   if (prebuilt->select_lock_type == LOCK_NONE) {
05097     return;
05098   }
05099 
05100   switch (prebuilt->row_read_type) {
05101   case ROW_READ_WITH_LOCKS:
05102     if (!srv_locks_unsafe_for_binlog
05103         && prebuilt->trx->isolation_level
05104         > TRX_ISO_READ_COMMITTED) {
05105       break;
05106     }
05107     /* fall through */
05108   case ROW_READ_TRY_SEMI_CONSISTENT:
05109     row_unlock_for_mysql(prebuilt, FALSE);
05110     break;
05111   case ROW_READ_DID_SEMI_CONSISTENT:
05112     prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
05113     break;
05114   }
05115 
05116   return;
05117 }
05118 
05119 /* See Cursor.h and row0mysql.h for docs on this function. */
05120 UNIV_INTERN
05121 bool
05122 ha_innobase::was_semi_consistent_read(void)
05123 /*=======================================*/
05124 {
05125   return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
05126 }
05127 
05128 /* See Cursor.h and row0mysql.h for docs on this function. */
05129 UNIV_INTERN
05130 void
05131 ha_innobase::try_semi_consistent_read(bool yes)
05132 /*===========================================*/
05133 {
05134   ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
05135 
05136   /* Row read type is set to semi consistent read if this was
05137   requested by the MySQL and either innodb_locks_unsafe_for_binlog
05138   option is used or this session is using READ COMMITTED isolation
05139   level. */
05140 
05141   if (yes
05142       && (srv_locks_unsafe_for_binlog
05143     || prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED)) {
05144     prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
05145   } else {
05146     prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
05147   }
05148 }
05149 
05150 /******************************************************************/
05153 UNIV_INTERN
05154 int
05155 ha_innobase::doStartIndexScan(
05156 /*====================*/
05157   uint  keynr,  
05158   bool )    
05159 {
05160   return(change_active_index(keynr));
05161 }
05162 
05163 /******************************************************************/
05166 UNIV_INTERN
05167 int
05168 ha_innobase::doEndIndexScan(void)
05169 /*========================*/
05170 {
05171   int error = 0;
05172   active_index=MAX_KEY;
05173   return(error);
05174 }
05175 
05176 /*********************************************************************/
05179 static inline
05180 ulint
05181 convert_search_mode_to_innobase(
05182 /*============================*/
05183   enum ha_rkey_function find_flag)
05184 {
05185   switch (find_flag) {
05186   case HA_READ_KEY_EXACT:
05187     /* this does not require the index to be UNIQUE */
05188     return(PAGE_CUR_GE);
05189   case HA_READ_KEY_OR_NEXT:
05190     return(PAGE_CUR_GE);
05191   case HA_READ_KEY_OR_PREV:
05192     return(PAGE_CUR_LE);
05193   case HA_READ_AFTER_KEY: 
05194     return(PAGE_CUR_G);
05195   case HA_READ_BEFORE_KEY:
05196     return(PAGE_CUR_L);
05197   case HA_READ_PREFIX:
05198     return(PAGE_CUR_GE);
05199   case HA_READ_PREFIX_LAST:
05200     return(PAGE_CUR_LE);
05201   case HA_READ_PREFIX_LAST_OR_PREV:
05202     return(PAGE_CUR_LE);
05203     /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
05204     pass a complete-field prefix of a key value as the search
05205     tuple. I.e., it is not allowed that the last field would
05206     just contain n first bytes of the full field value.
05207     MySQL uses a 'padding' trick to convert LIKE 'abc%'
05208     type queries so that it can use as a search tuple
05209     a complete-field-prefix of a key value. Thus, the InnoDB
05210     search mode PAGE_CUR_LE_OR_EXTENDS is never used.
05211     TODO: when/if MySQL starts to use also partial-field
05212     prefixes, we have to deal with stripping of spaces
05213     and comparison of non-latin1 char type fields in
05214     innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
05215     work correctly. */
05216   case HA_READ_MBR_CONTAIN:
05217   case HA_READ_MBR_INTERSECT:
05218   case HA_READ_MBR_WITHIN:
05219   case HA_READ_MBR_DISJOINT:
05220   case HA_READ_MBR_EQUAL:
05221     return(PAGE_CUR_UNSUPP);
05222   /* do not use "default:" in order to produce a gcc warning:
05223   enumeration value '...' not handled in switch
05224   (if -Wswitch or -Wall is used) */
05225   }
05226 
05227   my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
05228 
05229   return(PAGE_CUR_UNSUPP);
05230 }
05231 
05232 /*
05233    BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
05234    ---------------------------------------------------
05235 The following does not cover all the details, but explains how we determine
05236 the start of a new SQL statement, and what is associated with it.
05237 
05238 For each table in the database the MySQL interpreter may have several
05239 table handle instances in use, also in a single SQL query. For each table
05240 handle instance there is an InnoDB  'prebuilt' struct which contains most
05241 of the InnoDB data associated with this table handle instance.
05242 
05243   A) if the user has not explicitly set any MySQL table level locks:
05244 
05245   1) Drizzle calls StorageEngine::doStartStatement(), indicating to
05246      InnoDB that a new SQL statement has begun.
05247 
05248   2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
05249      to set an 'intention' table level lock on the table of the Cursor instance.
05250      There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should 
05251      be set true if we are taking this table handle instance to use in a new SQL
05252      statement issued by the user.
05253 
05254   2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
05255 instructions to prebuilt->template of the table handle instance in
05256 ::index_read. The template is used to save CPU time in large joins.
05257 
05258   3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
05259 allocate a new consistent read view for the trx if it does not yet have one,
05260 or in the case of a locking read, set an InnoDB 'intention' table level
05261 lock on the table.
05262 
05263   4) We do the SELECT. MySQL may repeatedly call ::index_read for the
05264 same table handle instance, if it is a join.
05265 
05266 5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
05267 
05268  (a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter 
05269      does NOT execute autocommit for pure read transactions, though it should.
05270      That is why we must execute the COMMIT in ::doEndStatement().
05271  (b) we also release possible 'SQL statement level resources' InnoDB may
05272      have for this SQL statement.
05273 
05274   @todo
05275 
05276   Remove need for InnoDB to call autocommit for read-only trx
05277 
05278   @todo Check the below is still valid (I don't think it is...)
05279 
05280   B) If the user has explicitly set MySQL table level locks, then MySQL
05281 does NOT call ::external_lock at the start of the statement. To determine
05282 when we are at the start of a new SQL statement we at the start of
05283 ::index_read also compare the query id to the latest query id where the
05284 table handle instance was used. If it has changed, we know we are at the
05285 start of a new SQL statement. Since the query id can theoretically
05286 overwrap, we use this test only as a secondary way of determining the
05287 start of a new SQL statement. */
05288 
05289 
05290 /**********************************************************************/
05294 UNIV_INTERN
05295 int
05296 ha_innobase::index_read(
05297 /*====================*/
05298   unsigned char*    buf,  
05300   const unsigned char*  key_ptr,
05309   uint      key_len,
05310   enum ha_rkey_function find_flag)
05311 {
05312   ulint   mode;
05313   dict_index_t* index;
05314   ulint   match_mode  = 0;
05315   int   error;
05316   ulint   ret;
05317 
05318   ut_a(prebuilt->trx == session_to_trx(user_session));
05319 
05320   ha_statistic_increment(&system_status_var::ha_read_key_count);
05321 
05322   index = prebuilt->index;
05323 
05324   if (UNIV_UNLIKELY(index == NULL)) {
05325     prebuilt->index_usable = FALSE;
05326     return(HA_ERR_CRASHED);
05327   }
05328 
05329   if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
05330     return(HA_ERR_TABLE_DEF_CHANGED);
05331   }
05332 
05333   /* Note that if the index for which the search template is built is not
05334   necessarily prebuilt->index, but can also be the clustered index */
05335 
05336   if (prebuilt->sql_stat_start) {
05337     build_template(prebuilt, user_session, getTable(),
05338              ROW_MYSQL_REC_FIELDS);
05339   }
05340 
05341   if (key_ptr) {
05342     /* Convert the search key value to InnoDB format into
05343     prebuilt->search_tuple */
05344 
05345     row_sel_convert_mysql_key_to_innobase(
05346       prebuilt->search_tuple,
05347       (byte*) &key_val_buff[0],
05348       (ulint)upd_and_key_val_buff_len,
05349       index,
05350       (byte*) key_ptr,
05351       (ulint) key_len,
05352       prebuilt->trx);
05353   } else {
05354     /* We position the cursor to the last or the first entry
05355     in the index */
05356 
05357     dtuple_set_n_fields(prebuilt->search_tuple, 0);
05358   }
05359 
05360   mode = convert_search_mode_to_innobase(find_flag);
05361 
05362   match_mode = 0;
05363 
05364   if (find_flag == HA_READ_KEY_EXACT) {
05365 
05366     match_mode = ROW_SEL_EXACT;
05367 
05368   } else if (find_flag == HA_READ_PREFIX
05369        || find_flag == HA_READ_PREFIX_LAST) {
05370 
05371     match_mode = ROW_SEL_EXACT_PREFIX;
05372   }
05373 
05374   last_match_mode = (uint) match_mode;
05375 
05376   if (mode != PAGE_CUR_UNSUPP) {
05377 
05378     innodb_srv_conc_enter_innodb(prebuilt->trx);
05379 
05380     ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
05381              match_mode, 0);
05382 
05383     innodb_srv_conc_exit_innodb(prebuilt->trx);
05384   } else {
05385 
05386     ret = DB_UNSUPPORTED;
05387   }
05388 
05389   switch (ret) {
05390   case DB_SUCCESS:
05391     error = 0;
05392     getTable()->status = 0;
05393     break;
05394   case DB_RECORD_NOT_FOUND:
05395     error = HA_ERR_KEY_NOT_FOUND;
05396     getTable()->status = STATUS_NOT_FOUND;
05397     break;
05398   case DB_END_OF_INDEX:
05399     error = HA_ERR_KEY_NOT_FOUND;
05400     getTable()->status = STATUS_NOT_FOUND;
05401     break;
05402   default:
05403     error = convert_error_code_to_mysql((int) ret,
05404                 prebuilt->table->flags,
05405                 user_session);
05406     getTable()->status = STATUS_NOT_FOUND;
05407     break;
05408   }
05409 
05410   return(error);
05411 }
05412 
05413 /*******************************************************************/
05417 UNIV_INTERN
05418 int
05419 ha_innobase::index_read_last(
05420 /*=========================*/
05421   unsigned char*  buf,  
05422   const unsigned char*  key_ptr,
05424   uint    key_len)
05426 {
05427   return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
05428 }
05429 
05430 /********************************************************************/
05433 UNIV_INTERN
05434 dict_index_t*
05435 ha_innobase::innobase_get_index(
05436 /*============================*/
05437   uint    keynr)  
05440 {
05441   dict_index_t* index = 0;
05442 
05443   ha_statistic_increment(&system_status_var::ha_read_key_count);
05444 
05445   if (keynr != MAX_KEY && getTable()->getShare()->sizeKeys() > 0) 
05446   {
05447     KeyInfo *key = getTable()->key_info + keynr;
05448     index = innobase_index_lookup(share, keynr);
05449 
05450     if (index) {
05451       ut_a(ut_strcmp(index->name, key->name) == 0);
05452     } else {
05453       /* Can't find index with keynr in the translation
05454          table. Only print message if the index translation
05455          table exists */
05456       if (share->idx_trans_tbl.index_mapping) {
05457         errmsg_printf(error::ERROR,
05458                       "InnoDB could not find "
05459                       "index %s key no %u for "
05460                       "table %s through its "
05461                       "index translation table",
05462                       key ? key->name : "NULL",
05463                       keynr,
05464                       prebuilt->table->name);
05465       }
05466 
05467       index = dict_table_get_index_on_name(prebuilt->table,
05468                                            key->name);
05469     }
05470   } else {
05471     index = dict_table_get_first_index(prebuilt->table);
05472   }
05473 
05474   if (!index) {
05475     errmsg_printf(error::ERROR, 
05476       "Innodb could not find key n:o %u with name %s "
05477       "from dict cache for table %s",
05478       keynr, getTable()->getShare()->getTableMessage()->indexes(keynr).name().c_str(),
05479       prebuilt->table->name);
05480   }
05481 
05482   return(index);
05483 }
05484 
05485 /********************************************************************/
05488 UNIV_INTERN
05489 int
05490 ha_innobase::change_active_index(
05491 /*=============================*/
05492   uint  keynr)  
05495 {
05496   ut_ad(user_session == table->in_use);
05497   ut_a(prebuilt->trx == session_to_trx(user_session));
05498 
05499   active_index = keynr;
05500 
05501   prebuilt->index = innobase_get_index(keynr);
05502 
05503   if (UNIV_UNLIKELY(!prebuilt->index)) {
05504     errmsg_printf(error::WARN, "InnoDB: change_active_index(%u) failed",
05505           keynr);
05506     prebuilt->index_usable = FALSE;
05507     return(1);
05508   }
05509 
05510   prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
05511                  prebuilt->index);
05512 
05513   if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
05514     push_warning_printf(user_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
05515                         HA_ERR_TABLE_DEF_CHANGED,
05516                         "InnoDB: insufficient history for index %u",
05517                         keynr);
05518     /* The caller seems to ignore this.  Thus, we must check
05519     this again in row_search_for_mysql(). */
05520     return(2);
05521   }
05522 
05523   ut_a(prebuilt->search_tuple != 0);
05524 
05525   dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
05526 
05527   dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
05528       prebuilt->index->n_fields);
05529 
05530   /* MySQL changes the active index for a handle also during some
05531   queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
05532   and then calculates the sum. Previously we played safe and used
05533   the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
05534   copying. Starting from MySQL-4.1 we use a more efficient flag here. */
05535 
05536   build_template(prebuilt, user_session, getTable(), ROW_MYSQL_REC_FIELDS);
05537 
05538   return(0);
05539 }
05540 
05541 /**********************************************************************/
05546 UNIV_INTERN
05547 int
05548 ha_innobase::index_read_idx(
05549 /*========================*/
05550   unsigned char*  buf,    
05552   uint    keynr,    
05553   const unsigned char*  key,  
05556   uint    key_len,  
05557   enum ha_rkey_function find_flag)
05558 {
05559   if (change_active_index(keynr)) {
05560 
05561     return(1);
05562   }
05563 
05564   return(index_read(buf, key, key_len, find_flag));
05565 }
05566 
05567 /***********************************************************************/
05571 UNIV_INTERN
05572 int
05573 ha_innobase::general_fetch(
05574 /*=======================*/
05575   unsigned char*  buf,  
05577   uint  direction,  
05578   uint  match_mode) 
05580 {
05581   ulint   ret;
05582   int   error = 0;
05583 
05584   ut_a(prebuilt->trx == session_to_trx(user_session));
05585 
05586   innodb_srv_conc_enter_innodb(prebuilt->trx);
05587 
05588   ret = row_search_for_mysql(
05589     (byte*)buf, 0, prebuilt, match_mode, direction);
05590 
05591   innodb_srv_conc_exit_innodb(prebuilt->trx);
05592 
05593   switch (ret) {
05594   case DB_SUCCESS:
05595     error = 0;
05596     getTable()->status = 0;
05597     break;
05598   case DB_RECORD_NOT_FOUND:
05599     error = HA_ERR_END_OF_FILE;
05600     getTable()->status = STATUS_NOT_FOUND;
05601     break;
05602   case DB_END_OF_INDEX:
05603     error = HA_ERR_END_OF_FILE;
05604     getTable()->status = STATUS_NOT_FOUND;
05605     break;
05606   default:
05607     error = convert_error_code_to_mysql(
05608       (int) ret, prebuilt->table->flags, user_session);
05609     getTable()->status = STATUS_NOT_FOUND;
05610     break;
05611   }
05612 
05613   return(error);
05614 }
05615 
05616 /***********************************************************************/
05620 UNIV_INTERN
05621 int
05622 ha_innobase::index_next(
05623 /*====================*/
05624   unsigned char*  buf)  
05626 {
05627   ha_statistic_increment(&system_status_var::ha_read_next_count);
05628 
05629   return(general_fetch(buf, ROW_SEL_NEXT, 0));
05630 }
05631 
05632 /*******************************************************************/
05635 UNIV_INTERN
05636 int
05637 ha_innobase::index_next_same(
05638 /*=========================*/
05639   unsigned char*    buf,  
05640   const unsigned char*  , 
05641   uint    ) 
05642 {
05643   ha_statistic_increment(&system_status_var::ha_read_next_count);
05644 
05645   return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
05646 }
05647 
05648 /***********************************************************************/
05652 UNIV_INTERN
05653 int
05654 ha_innobase::index_prev(
05655 /*====================*/
05656   unsigned char*  buf)  
05657 {
05658   ha_statistic_increment(&system_status_var::ha_read_prev_count);
05659 
05660   return(general_fetch(buf, ROW_SEL_PREV, 0));
05661 }
05662 
05663 /********************************************************************/
05667 UNIV_INTERN
05668 int
05669 ha_innobase::index_first(
05670 /*=====================*/
05671   unsigned char*  buf)  
05672 {
05673   int error;
05674 
05675   ha_statistic_increment(&system_status_var::ha_read_first_count);
05676 
05677   error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
05678 
05679   /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
05680 
05681   if (error == HA_ERR_KEY_NOT_FOUND) {
05682     error = HA_ERR_END_OF_FILE;
05683   }
05684 
05685   return(error);
05686 }
05687 
05688 /********************************************************************/
05692 UNIV_INTERN
05693 int
05694 ha_innobase::index_last(
05695 /*====================*/
05696   unsigned char*  buf)  
05697 {
05698   int error;
05699 
05700   ha_statistic_increment(&system_status_var::ha_read_last_count);
05701 
05702   error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
05703 
05704   /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
05705 
05706   if (error == HA_ERR_KEY_NOT_FOUND) {
05707     error = HA_ERR_END_OF_FILE;
05708   }
05709 
05710   return(error);
05711 }
05712 
05713 /****************************************************************/
05716 UNIV_INTERN
05717 int
05718 ha_innobase::doStartTableScan(
05719 /*==================*/
05720   bool  scan) 
05721 {
05722   int err;
05723 
05724   /* Store the active index value so that we can restore the original
05725   value after a scan */
05726 
05727   if (prebuilt->clust_index_was_generated) {
05728     err = change_active_index(MAX_KEY);
05729   } else {
05730     err = change_active_index(primary_key);
05731   }
05732 
05733   /* Don't use semi-consistent read in random row reads (by position).
05734   This means we must disable semi_consistent_read if scan is false */
05735 
05736   if (!scan) {
05737     try_semi_consistent_read(0);
05738   }
05739 
05740   start_of_scan = 1;
05741 
05742   return(err);
05743 }
05744 
05745 /*****************************************************************/
05748 UNIV_INTERN
05749 int
05750 ha_innobase::doEndTableScan(void)
05751 /*======================*/
05752 {
05753   return(doEndIndexScan());
05754 }
05755 
05756 /*****************************************************************/
05760 UNIV_INTERN
05761 int
05762 ha_innobase::rnd_next(
05763 /*==================*/
05764   unsigned char*  buf)  
05766 {
05767   int error;
05768 
05769   ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
05770 
05771   if (start_of_scan) {
05772     error = index_first(buf);
05773 
05774     if (error == HA_ERR_KEY_NOT_FOUND) {
05775       error = HA_ERR_END_OF_FILE;
05776     }
05777 
05778     start_of_scan = 0;
05779   } else {
05780     error = general_fetch(buf, ROW_SEL_NEXT, 0);
05781   }
05782 
05783   return(error);
05784 }
05785 
05786 /**********************************************************************/
05789 UNIV_INTERN
05790 int
05791 ha_innobase::rnd_pos(
05792 /*=================*/
05793   unsigned char*  buf,  
05794   unsigned char*  pos)  
05798 {
05799   int   error;
05800   uint    keynr = active_index;
05801 
05802   ha_statistic_increment(&system_status_var::ha_read_rnd_count);
05803 
05804   ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
05805 
05806   if (prebuilt->clust_index_was_generated) {
05807     /* No primary key was defined for the table and we
05808     generated the clustered index from the row id: the
05809     row reference is the row id, not any key value
05810     that MySQL knows of */
05811 
05812     error = change_active_index(MAX_KEY);
05813   } else {
05814     error = change_active_index(primary_key);
05815   }
05816 
05817   if (error) {
05818     return(error);
05819   }
05820 
05821   /* Note that we assume the length of the row reference is fixed
05822   for the table, and it is == ref_length */
05823 
05824   error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
05825 
05826   if (error) {
05827   }
05828 
05829   change_active_index(keynr);
05830 
05831   return(error);
05832 }
05833 
05834 /*********************************************************************/
05842 UNIV_INTERN
05843 void
05844 ha_innobase::position(
05845 /*==================*/
05846   const unsigned char*  record) 
05847 {
05848   uint    len;
05849 
05850   ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
05851 
05852   if (prebuilt->clust_index_was_generated) {
05853     /* No primary key was defined for the table and we
05854     generated the clustered index from row id: the
05855     row reference will be the row id, not any key value
05856     that MySQL knows of */
05857 
05858     len = DATA_ROW_ID_LEN;
05859 
05860     memcpy(ref, prebuilt->row_id, len);
05861   } else {
05862     len = store_key_val_for_row(primary_key, (char*)ref,
05863                ref_length, record);
05864   }
05865 
05866   /* We assume that the 'ref' value len is always fixed for the same
05867   table. */
05868 
05869   if (len != ref_length) {
05870     errmsg_printf(error::ERROR, "Stored ref len is %lu, but table ref len is %lu",
05871         (ulong) len, (ulong) ref_length);
05872   }
05873 }
05874 
05875 
05876 /*****************************************************************/
05878 static
05879 int
05880 create_table_def(
05881 /*=============*/
05882   trx_t*    trx,    
05883   Table*    form,   
05885   const char* table_name, 
05886   const char* path_of_temp_table,
05894   ulint   flags)    
05895 {
05896   Field*    field;
05897   dict_table_t* table;
05898   ulint   n_cols;
05899   int   error;
05900   ulint   col_type;
05901   ulint   col_len;
05902   ulint   nulls_allowed;
05903   ulint   unsigned_type;
05904   ulint   binary_type;
05905   ulint   long_true_varchar;
05906   ulint   charset_no;
05907   ulint   i;
05908 
05909   n_cols = form->getShare()->sizeFields();
05910 
05911   /* We pass 0 as the space id, and determine at a lower level the space
05912   id where to store the table */
05913 
05914   table = dict_mem_table_create(table_name, 0, n_cols, flags);
05915 
05916   if (path_of_temp_table) {
05917     table->dir_path_of_temp_table =
05918       mem_heap_strdup(table->heap, path_of_temp_table);
05919   }
05920 
05921   for (i = 0; i < n_cols; i++) {
05922     field = form->getField(i);
05923 
05924     col_type = get_innobase_type_from_mysql_type(&unsigned_type,
05925                   field);
05926 
05927     if (!col_type) {
05928       push_warning_printf(
05929                           trx->mysql_thd,
05930                           DRIZZLE_ERROR::WARN_LEVEL_WARN,
05931                           ER_CANT_CREATE_TABLE,
05932                           "Error creating table '%s' with "
05933                           "column '%s'. Please check its "
05934                           "column type and try to re-create "
05935                           "the table with an appropriate "
05936                           "column type.",
05937                           table->name, (char*) field->field_name);
05938       goto err_col;
05939     }
05940 
05941     if (field->null_ptr) {
05942       nulls_allowed = 0;
05943     } else {
05944       nulls_allowed = DATA_NOT_NULL;
05945     }
05946 
05947     if (field->binary()) {
05948       binary_type = DATA_BINARY_TYPE;
05949     } else {
05950       binary_type = 0;
05951     }
05952 
05953     charset_no = 0;
05954 
05955     if (dtype_is_string_type(col_type)) {
05956 
05957       charset_no = (ulint)field->charset()->number;
05958 
05959       if (UNIV_UNLIKELY(charset_no >= 256)) {
05960         /* in data0type.h we assume that the
05961         number fits in one byte in prtype */
05962         push_warning_printf(
05963           trx->mysql_thd,
05964           DRIZZLE_ERROR::WARN_LEVEL_ERROR,
05965           ER_CANT_CREATE_TABLE,
05966           "In InnoDB, charset-collation codes"
05967           " must be below 256."
05968           " Unsupported code %lu.",
05969           (ulong) charset_no);
05970         return(ER_CANT_CREATE_TABLE);
05971       }
05972     }
05973 
05974     ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
05975              that this fits in one byte */
05976     col_len = field->pack_length();
05977 
05978     /* The MySQL pack length contains 1 or 2 bytes length field
05979     for a true VARCHAR. Let us subtract that, so that the InnoDB
05980     column length in the InnoDB data dictionary is the real
05981     maximum byte length of the actual data. */
05982 
05983     long_true_varchar = 0;
05984 
05985     if (field->type() == DRIZZLE_TYPE_VARCHAR) {
05986       col_len -= ((Field_varstring*)field)->pack_length_no_ptr();
05987 
05988       if (((Field_varstring*)field)->pack_length_no_ptr() == 2) {
05989         long_true_varchar = DATA_LONG_TRUE_VARCHAR;
05990       }
05991     }
05992 
05993     /* First check whether the column to be added has a
05994        system reserved name. */
05995     if (dict_col_name_is_reserved(field->field_name)){
05996       my_error(ER_WRONG_COLUMN_NAME, MYF(0), field->field_name);
05997 
05998   err_col:
05999       dict_mem_table_free(table);
06000       trx_commit_for_mysql(trx);
06001 
06002       error = DB_ERROR;
06003       goto error_ret;
06004     }
06005 
06006     dict_mem_table_add_col(table, table->heap,
06007       (char*) field->field_name,
06008       col_type,
06009       dtype_form_prtype(
06010         (ulint)field->type()
06011         | nulls_allowed | unsigned_type
06012         | binary_type | long_true_varchar,
06013         charset_no),
06014       col_len);
06015   }
06016 
06017   error = row_create_table_for_mysql(table, trx);
06018 
06019   if (error == DB_DUPLICATE_KEY) {
06020     char buf[100];
06021     char* buf_end = innobase_convert_identifier(
06022       buf, sizeof buf - 1, table_name, strlen(table_name),
06023       trx->mysql_thd, TRUE);
06024 
06025     *buf_end = '\0';
06026     my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf);
06027   }
06028 
06029 error_ret:
06030   error = convert_error_code_to_mysql(error, flags, NULL);
06031 
06032   return(error);
06033 }
06034 
06035 /*****************************************************************/
06037 static
06038 int
06039 create_index(
06040 /*=========*/
06041   trx_t*    trx,    
06042   Table*    form,   
06044   ulint   flags,    
06045   const char* table_name, 
06046   uint    key_num)  
06047 {
06048   Field*    field;
06049   dict_index_t* index;
06050   int   error;
06051   ulint   n_fields;
06052   KeyInfo*    key;
06053   KeyPartInfo*  key_part;
06054   ulint   ind_type;
06055   ulint   col_type;
06056   ulint   prefix_len;
06057   ulint   is_unsigned;
06058   ulint   i;
06059   ulint   j;
06060   ulint*    field_lengths;
06061 
06062   key = &form->key_info[key_num];
06063 
06064   n_fields = key->key_parts;
06065 
06066   /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */
06067   ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0);
06068 
06069   ind_type = 0;
06070 
06071   if (key_num == form->getShare()->getPrimaryKey()) {
06072     ind_type = ind_type | DICT_CLUSTERED;
06073   }
06074 
06075   if (key->flags & HA_NOSAME ) {
06076     ind_type = ind_type | DICT_UNIQUE;
06077   }
06078 
06079   /* We pass 0 as the space id, and determine at a lower level the space
06080   id where to store the table */
06081 
06082   index = dict_mem_index_create(table_name, key->name, 0,
06083               ind_type, n_fields);
06084 
06085   field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
06086 
06087   for (i = 0; i < n_fields; i++) {
06088     key_part = key->key_part + i;
06089 
06090     /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
06091     field in an index: we only store a specified number of first
06092     bytes of the column to the index field.) The flag does not
06093     seem to be properly set by MySQL. Let us fall back on testing
06094     the length of the key part versus the column. */
06095 
06096     field = NULL;
06097     for (j = 0; j < form->getShare()->sizeFields(); j++)
06098     {
06099 
06100       field = form->getField(j);
06101 
06102       if (0 == innobase_strcasecmp(
06103           field->field_name,
06104           key_part->field->field_name)) {
06105         /* Found the corresponding column */
06106 
06107         break;
06108       }
06109     }
06110 
06111     ut_a(j < form->getShare()->sizeFields());
06112 
06113     col_type = get_innobase_type_from_mysql_type(
06114           &is_unsigned, key_part->field);
06115 
06116     if (DATA_BLOB == col_type
06117       || (key_part->length < field->pack_length()
06118         && field->type() != DRIZZLE_TYPE_VARCHAR)
06119       || (field->type() == DRIZZLE_TYPE_VARCHAR
06120         && key_part->length < field->pack_length()
06121         - ((Field_varstring*)field)->pack_length_no_ptr())) {
06122 
06123       prefix_len = key_part->length;
06124 
06125       if (col_type == DATA_INT
06126         || col_type == DATA_FLOAT
06127         || col_type == DATA_DOUBLE
06128         || col_type == DATA_DECIMAL) {
06129         errmsg_printf(error::ERROR, 
06130           "MySQL is trying to create a column "
06131           "prefix index field, on an "
06132           "inappropriate data type. Table "
06133           "name %s, column name %s.",
06134           table_name,
06135           key_part->field->field_name);
06136 
06137         prefix_len = 0;
06138       }
06139     } else {
06140       prefix_len = 0;
06141     }
06142 
06143     field_lengths[i] = key_part->length;
06144 
06145     dict_mem_index_add_field(index,
06146       (char*) key_part->field->field_name, prefix_len);
06147   }
06148 
06149   /* Even though we've defined max_supported_key_part_length, we
06150   still do our own checking using field_lengths to be absolutely
06151   sure we don't create too long indexes. */
06152   error = row_create_index_for_mysql(index, trx, field_lengths);
06153 
06154   error = convert_error_code_to_mysql(error, flags, NULL);
06155 
06156   free(field_lengths);
06157 
06158   return(error);
06159 }
06160 
06161 /*****************************************************************/
06164 static
06165 int
06166 create_clustered_index_when_no_primary(
06167 /*===================================*/
06168   trx_t*    trx,    
06169   ulint   flags,    
06170   const char* table_name) 
06171 {
06172   dict_index_t* index;
06173   int   error;
06174 
06175   /* We pass 0 as the space id, and determine at a lower level the space
06176   id where to store the table */
06177 
06178   index = dict_mem_index_create(table_name,
06179                                 innobase_index_reserve_name,
06180                                 0, DICT_CLUSTERED, 0);
06181 
06182   error = row_create_index_for_mysql(index, trx, NULL);
06183 
06184   error = convert_error_code_to_mysql(error, flags, NULL);
06185 
06186   return(error);
06187 }
06188 
06189 /*****************************************************************/
06195 #if 0
06196 static
06197 ibool
06198 create_options_are_valid(
06199 /*=====================*/
06200   Session*  session,  
06201   Table&    form,   
06203         message::Table& create_proto)
06204 {
06205   ibool kbs_specified = FALSE;
06206   ibool ret   = TRUE;
06207 
06208 
06209   ut_ad(session != NULL);
06210 
06211   /* If innodb_strict_mode is not set don't do any validation. */
06212   if (!(SessionVAR(session, strict_mode))) {
06213     return(TRUE);
06214   }
06215 
06216   /* Now check for ROW_FORMAT specifier. */
06217   return(ret);
06218 }
06219 #endif
06220 
06221 /*********************************************************************
06222 Creates a new table to an InnoDB database. */
06223 UNIV_INTERN
06224 int
06225 InnobaseEngine::doCreateTable(
06226             /*================*/
06227             Session         &session, 
06228             Table&    form,   
06229             const identifier::Table &identifier,
06230             const message::Table& create_proto)
06231 {
06232   int   error;
06233   dict_table_t* innobase_table;
06234   trx_t*    parent_trx;
06235   trx_t*    trx;
06236   int   primary_key_no;
06237   uint    i;
06238   ib_int64_t  auto_inc_value;
06239   ulint   iflags;
06240   /* Cache the value of innodb_file_format, in case it is
06241     modified by another thread while the table is being created. */
06242   const ulint file_format = srv_file_format;
06243   bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
06244   const char* stmt;
06245   size_t stmt_len;
06246 
06247   std::string search_string(identifier.getSchemaName());
06248   boost::algorithm::to_lower(search_string);
06249 
06250   if (search_string.compare("data_dictionary") == 0)
06251   {
06252     return HA_WRONG_CREATE_OPTION;
06253   }
06254 
06255   if (form.getShare()->sizeFields() > 1000) {
06256     /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
06257       but we play safe here */
06258 
06259     return(HA_ERR_TO_BIG_ROW);
06260   }
06261 
06262   /* Get the transaction associated with the current session, or create one
06263     if not yet created */
06264 
06265   parent_trx = check_trx_exists(&session);
06266 
06267   /* In case MySQL calls this in the middle of a SELECT query, release
06268     possible adaptive hash latch to avoid deadlocks of threads */
06269 
06270   trx_search_latch_release_if_reserved(parent_trx);
06271 
06272   trx = innobase_trx_allocate(&session);
06273 
06274   srv_lower_case_table_names = TRUE;
06275 
06276   /* Latch the InnoDB data dictionary exclusively so that no deadlocks
06277     or lock waits can happen in it during a table create operation.
06278     Drop table etc. do this latching in row0mysql.c. */
06279 
06280   row_mysql_lock_data_dictionary(trx);
06281 
06282   /* Create the table definition in InnoDB */
06283 
06284   iflags = 0;
06285 
06286 #if 0 // Since we validate the options before this stage, we no longer need to do this.
06287   /* Validate create options if innodb_strict_mode is set. */
06288   if (! create_options_are_valid(&session, form, create_proto)) {
06289     error = ER_ILLEGAL_HA_CREATE_OPTION;
06290     goto cleanup;
06291   }
06292 #endif
06293 
06294   // We assume compact format by default
06295   iflags= DICT_TF_COMPACT;
06296 
06297   size_t num_engine_options= create_proto.engine().options_size();
06298   for (size_t x= 0; x < num_engine_options; ++x)
06299   {
06300     if (boost::iequals(create_proto.engine().options(x).name(), "ROW_FORMAT"))
06301     {
06302       if (boost::iequals(create_proto.engine().options(x).state(), "COMPRESSED"))
06303       {
06304         iflags= DICT_TF_FORMAT_ZIP;
06305       }
06306       else if (boost::iequals(create_proto.engine().options(x).state(), "COMPACT"))
06307       {
06308         iflags= DICT_TF_FORMAT_ZIP;
06309       }
06310       else if (boost::iequals(create_proto.engine().options(x).state(), "DYNAMIC"))
06311       {
06312         iflags= DICT_TF_COMPACT;
06313       }
06314       else if (boost::iequals(create_proto.engine().options(x).state(), "REDUNDANT"))
06315       {
06316         iflags= DICT_TF_COMPACT;
06317       }
06318     }
06319     else
06320     {
06321       assert(0); // This should never happen since we have already validated the options.
06322     }
06323   }
06324 
06325   if (iflags == DICT_TF_FORMAT_ZIP)
06326   {
06327     /* 
06328       ROW_FORMAT=COMPRESSED without KEY_BLOCK_SIZE implies half the maximum KEY_BLOCK_SIZE.
06329       @todo implement KEY_BLOCK_SIZE
06330     */
06331     iflags= (DICT_TF_ZSSIZE_MAX - 1)
06332       << DICT_TF_ZSSIZE_SHIFT
06333       | DICT_TF_COMPACT
06334       | DICT_TF_FORMAT_ZIP
06335       << DICT_TF_FORMAT_SHIFT;
06336 
06337     if (strict_mode)
06338     {
06339       if (! srv_file_per_table)
06340       {
06341         push_warning_printf(
06342                             &session,
06343                             DRIZZLE_ERROR::WARN_LEVEL_WARN,
06344                             ER_ILLEGAL_HA_CREATE_OPTION,
06345                             "InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.");
06346       } 
06347       else if (file_format < DICT_TF_FORMAT_ZIP) 
06348       {
06349         push_warning_printf(
06350                             &session,
06351                             DRIZZLE_ERROR::WARN_LEVEL_WARN,
06352                             ER_ILLEGAL_HA_CREATE_OPTION,
06353                             "InnoDB: ROW_FORMAT=compressed requires innodb_file_format > Antelope.");
06354       }
06355     }
06356   }
06357 
06358   /* Look for a primary key */
06359 
06360   primary_key_no= (form.getShare()->hasPrimaryKey() ?
06361                    (int) form.getShare()->getPrimaryKey() :
06362                    -1);
06363 
06364   /* Our function innobase_get_mysql_key_number_for_index assumes
06365     the primary key is always number 0, if it exists */
06366 
06367   assert(primary_key_no == -1 || primary_key_no == 0);
06368 
06369   /* Check for name conflicts (with reserved name) for
06370      any user indices to be created. */
06371   if (innobase_index_name_is_reserved(trx, form.key_info,
06372                                       form.getShare()->keys)) {
06373     error = -1;
06374     goto cleanup;
06375   }
06376 
06377   if (lex_identified_temp_table)
06378     iflags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
06379 
06380   error= create_table_def(trx, &form, identifier.getKeyPath().c_str(),
06381                           lex_identified_temp_table ? identifier.getKeyPath().c_str() : NULL,
06382                           iflags);
06383 
06384   session.setXaId(trx->id);
06385 
06386   if (error) {
06387     goto cleanup;
06388   }
06389 
06390   /* Create the keys */
06391 
06392   if (form.getShare()->sizeKeys() == 0 || primary_key_no == -1) {
06393     /* Create an index which is used as the clustered index;
06394       order the rows by their row id which is internally generated
06395       by InnoDB */
06396 
06397     error = create_clustered_index_when_no_primary(trx, iflags, identifier.getKeyPath().c_str());
06398     if (error) {
06399       goto cleanup;
06400     }
06401   }
06402 
06403   if (primary_key_no != -1) {
06404     /* In InnoDB the clustered index must always be created first */
06405     if ((error = create_index(trx, &form, iflags, identifier.getKeyPath().c_str(),
06406                               (uint) primary_key_no))) {
06407       goto cleanup;
06408     }
06409   }
06410 
06411   for (i = 0; i < form.getShare()->sizeKeys(); i++) {
06412     if (i != (uint) primary_key_no) {
06413 
06414       if ((error = create_index(trx, &form, iflags, identifier.getKeyPath().c_str(),
06415                                 i))) {
06416         goto cleanup;
06417       }
06418     }
06419   }
06420 
06421   stmt= session.getQueryStringCopy(stmt_len);
06422 
06423   if (stmt) {
06424     string generated_create_table;
06425     const char *query= stmt;
06426 
06427     if (session.getSqlCommand() == SQLCOM_CREATE_TABLE)
06428     {
06429       message::transformTableDefinitionToSql(create_proto,
06430                                              generated_create_table,
06431                                              message::DRIZZLE, true);
06432       query= generated_create_table.c_str();
06433     }
06434 
06435     error = row_table_add_foreign_constraints(trx,
06436                                               query, strlen(query),
06437                                               identifier.getKeyPath().c_str(),
06438                                               lex_identified_temp_table);
06439     switch (error) {
06440 
06441     case DB_PARENT_NO_INDEX:
06442       push_warning_printf(
06443                           &session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
06444                           HA_ERR_CANNOT_ADD_FOREIGN,
06445                           "Create table '%s' with foreign key constraint"
06446                           " failed. There is no index in the referenced"
06447                           " table where the referenced columns appear"
06448                           " as the first columns.\n", identifier.getKeyPath().c_str());
06449       break;
06450 
06451     case DB_CHILD_NO_INDEX:
06452       push_warning_printf(
06453                           &session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
06454                           HA_ERR_CANNOT_ADD_FOREIGN,
06455                           "Create table '%s' with foreign key constraint"
06456                           " failed. There is no index in the referencing"
06457                           " table where referencing columns appear"
06458                           " as the first columns.\n", identifier.getKeyPath().c_str());
06459       break;
06460     }
06461 
06462     error = convert_error_code_to_mysql(error, iflags, NULL);
06463 
06464     if (error) {
06465       goto cleanup;
06466     }
06467   }
06468 
06469   innobase_commit_low(trx);
06470 
06471   row_mysql_unlock_data_dictionary(trx);
06472 
06473   /* Flush the log to reduce probability that the .frm files and
06474     the InnoDB data dictionary get out-of-sync if the user runs
06475     with innodb_flush_log_at_trx_commit = 0 */
06476 
06477   log_buffer_flush_to_disk();
06478 
06479   innobase_table = dict_table_get(identifier.getKeyPath().c_str(), FALSE);
06480 
06481   assert(innobase_table != 0);
06482 
06483   if (innobase_table) {
06484     /* We update the highest file format in the system table
06485       space, if this table has higher file format setting. */
06486 
06487     char changed_file_format_max[100];
06488     strcpy(changed_file_format_max, innobase_file_format_max.c_str());
06489     trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
06490       dict_table_get_format(innobase_table));
06491     innobase_file_format_max= changed_file_format_max;
06492   }
06493 
06494   /* Note: We can't call update_session() as prebuilt will not be
06495     setup at this stage and so we use session. */
06496 
06497   /* We need to copy the AUTOINC value from the old table if
06498     this is an ALTER TABLE or CREATE INDEX because CREATE INDEX
06499     does a table copy too. */
06500 
06501   if ((create_proto.options().has_auto_increment_value()
06502        || session.getSqlCommand() == SQLCOM_ALTER_TABLE
06503        || session.getSqlCommand() == SQLCOM_CREATE_INDEX)
06504       && create_proto.options().auto_increment_value() != 0) {
06505 
06506     /* Query was one of :
06507        CREATE TABLE ...AUTO_INCREMENT = x; or
06508        ALTER TABLE...AUTO_INCREMENT = x;   or
06509        CREATE INDEX x on t(...);
06510        Find out a table definition from the dictionary and get
06511        the current value of the auto increment field. Set a new
06512        value to the auto increment field if the value is greater
06513        than the maximum value in the column. */
06514 
06515     auto_inc_value = create_proto.options().auto_increment_value();
06516 
06517     dict_table_autoinc_lock(innobase_table);
06518     dict_table_autoinc_initialize(innobase_table, auto_inc_value);
06519     dict_table_autoinc_unlock(innobase_table);
06520   }
06521 
06522   /* Tell the InnoDB server that there might be work for
06523     utility threads: */
06524 
06525   srv_active_wake_master_thread();
06526 
06527   trx_free_for_mysql(trx);
06528 
06529   if (lex_identified_temp_table)
06530   {
06531     session.getMessageCache().storeTableMessage(identifier, create_proto);
06532   }
06533   else
06534   {
06535     StorageEngine::writeDefinitionFromPath(identifier, create_proto);
06536   }
06537 
06538   return(0);
06539 
06540 cleanup:
06541   innobase_commit_low(trx);
06542 
06543   row_mysql_unlock_data_dictionary(trx);
06544 
06545   trx_free_for_mysql(trx);
06546 
06547   return(error);
06548 }
06549 
06550 /*****************************************************************/
06553 UNIV_INTERN
06554 int
06555 ha_innobase::discard_or_import_tablespace(
06556 /*======================================*/
06557   my_bool discard)  
06558 {
06559   dict_table_t* dict_table;
06560   trx_t*    trx;
06561   int   err;
06562 
06563   ut_a(prebuilt->trx);
06564   ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
06565   ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
06566 
06567   dict_table = prebuilt->table;
06568   trx = prebuilt->trx;
06569 
06570   if (discard) {
06571     err = row_discard_tablespace_for_mysql(dict_table->name, trx);
06572   } else {
06573     err = row_import_tablespace_for_mysql(dict_table->name, trx);
06574   }
06575 
06576   err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
06577 
06578   return(err);
06579 }
06580 
06581 /*****************************************************************/
06584 UNIV_INTERN
06585 int
06586 ha_innobase::delete_all_rows(void)
06587 /*==============================*/
06588 {
06589   int   error;
06590 
06591   /* Get the transaction associated with the current session, or create one
06592   if not yet created, and update prebuilt->trx */
06593 
06594   update_session(getTable()->in_use);
06595 
06596   if (user_session->getSqlCommand() != SQLCOM_TRUNCATE) {
06597   fallback:
06598     /* We only handle TRUNCATE TABLE t as a special case.
06599     DELETE FROM t will have to use ha_innobase::doDeleteRecord(),
06600     because DELETE is transactional while TRUNCATE is not. */
06601     return(errno=HA_ERR_WRONG_COMMAND);
06602   }
06603 
06604   /* Truncate the table in InnoDB */
06605 
06606   error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
06607   if (error == DB_ERROR) {
06608     /* Cannot truncate; resort to ha_innobase::doDeleteRecord() */
06609     goto fallback;
06610   }
06611 
06612   error = convert_error_code_to_mysql(error, prebuilt->table->flags,
06613               NULL);
06614 
06615   return(error);
06616 }
06617 
06618 /*****************************************************************/
06625 UNIV_INTERN
06626 int
06627 InnobaseEngine::doDropTable(
06628 /*======================*/
06629         Session &session,
06630         const identifier::Table &identifier)
06631 {
06632   int error;
06633   trx_t*  parent_trx;
06634   trx_t*  trx;
06635 
06636   ut_a(identifier.getPath().length() < 1000);
06637 
06638   std::string search_string(identifier.getSchemaName());
06639   boost::algorithm::to_lower(search_string);
06640 
06641   if (search_string.compare("data_dictionary") == 0)
06642   {
06643     return HA_ERR_TABLE_READONLY;
06644   }
06645 
06646   /* Get the transaction associated with the current session, or create one
06647     if not yet created */
06648 
06649   parent_trx = check_trx_exists(&session);
06650 
06651   /* In case MySQL calls this in the middle of a SELECT query, release
06652     possible adaptive hash latch to avoid deadlocks of threads */
06653 
06654   trx_search_latch_release_if_reserved(parent_trx);
06655 
06656   trx = innobase_trx_allocate(&session);
06657 
06658   srv_lower_case_table_names = TRUE;
06659 
06660   /* Drop the table in InnoDB */
06661 
06662   error = row_drop_table_for_mysql(identifier.getKeyPath().c_str(), trx,
06663                                    session.getSqlCommand()
06664                                    == SQLCOM_DROP_DB);
06665 
06666   session.setXaId(trx->id);
06667 
06668   /* Flush the log to reduce probability that the .frm files and
06669     the InnoDB data dictionary get out-of-sync if the user runs
06670     with innodb_flush_log_at_trx_commit = 0 */
06671 
06672   log_buffer_flush_to_disk();
06673 
06674   /* Tell the InnoDB server that there might be work for
06675     utility threads: */
06676 
06677   srv_active_wake_master_thread();
06678 
06679   innobase_commit_low(trx);
06680 
06681   trx_free_for_mysql(trx);
06682 
06683   if (error != ENOENT)
06684     error = convert_error_code_to_mysql(error, 0, NULL);
06685 
06686   if (error == 0 || error == ENOENT)
06687   {
06688     if (identifier.getType() == message::Table::TEMPORARY)
06689     {
06690       session.getMessageCache().removeTableMessage(identifier);
06691       ulint sql_command = session.getSqlCommand();
06692 
06693       // If this was the final removal to an alter table then we will need
06694       // to remove the .dfe that was left behind.
06695       if ((sql_command == SQLCOM_ALTER_TABLE
06696        || sql_command == SQLCOM_CREATE_INDEX
06697        || sql_command == SQLCOM_DROP_INDEX))
06698       {
06699         string path(identifier.getPath());
06700 
06701         path.append(DEFAULT_FILE_EXTENSION);
06702 
06703         (void)internal::my_delete(path.c_str(), MYF(0));
06704       }
06705     }
06706     else
06707     {
06708       string path(identifier.getPath());
06709 
06710       path.append(DEFAULT_FILE_EXTENSION);
06711 
06712       (void)internal::my_delete(path.c_str(), MYF(0));
06713     }
06714   }
06715 
06716   return(error);
06717 }
06718 
06719 /*****************************************************************/
06721 bool
06722 InnobaseEngine::doDropSchema(
06723 /*===================*/
06724                              const identifier::Schema &identifier)
06729 {
06730   trx_t*  trx;
06731   int error;
06732   string schema_path(identifier.getPath());
06733   Session*  session   = current_session;
06734 
06735   /* Get the transaction associated with the current session, or create one
06736     if not yet created */
06737 
06738   assert(this == innodb_engine_ptr);
06739 
06740   /* In the Windows plugin, session = current_session is always NULL */
06741   if (session) {
06742     trx_t*  parent_trx = check_trx_exists(session);
06743 
06744     /* In case Drizzle calls this in the middle of a SELECT
06745       query, release possible adaptive hash latch to avoid
06746       deadlocks of threads */
06747 
06748     trx_search_latch_release_if_reserved(parent_trx);
06749   }
06750 
06751   schema_path.append("/");
06752   trx = innobase_trx_allocate(session);
06753   error = row_drop_database_for_mysql(schema_path.c_str(), trx);
06754 
06755   /* Flush the log to reduce probability that the .frm files and
06756     the InnoDB data dictionary get out-of-sync if the user runs
06757     with innodb_flush_log_at_trx_commit = 0 */
06758 
06759   log_buffer_flush_to_disk();
06760 
06761   /* Tell the InnoDB server that there might be work for
06762     utility threads: */
06763 
06764   srv_active_wake_master_thread();
06765 
06766   innobase_commit_low(trx);
06767   trx_free_for_mysql(trx);
06768 
06769   if (error) {
06770     // What do we do here?
06771   }
06772 
06773   return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement. 
06774 }
06775 
06776 void InnobaseEngine::dropTemporarySchema()
06777 {
06778   string schema_path(GLOBAL_TEMPORARY_EXT);
06779   schema_path += "/";
06780 
06781   trx_t* trx = trx_allocate_for_mysql();
06782 
06783   trx->mysql_thd = NULL;
06784 
06785   trx->check_foreigns = false;
06786   trx->check_unique_secondary = false;
06787 
06788   (void)row_drop_database_for_mysql(schema_path.c_str(), trx);
06789 
06790   /* Flush the log to reduce probability that the .frm files and
06791     the InnoDB data dictionary get out-of-sync if the user runs
06792     with innodb_flush_log_at_trx_commit = 0 */
06793 
06794   log_buffer_flush_to_disk();
06795 
06796   /* Tell the InnoDB server that there might be work for
06797     utility threads: */
06798 
06799   srv_active_wake_master_thread();
06800 
06801   innobase_commit_low(trx);
06802   trx_free_for_mysql(trx);
06803 }
06804 /*********************************************************************/
06807 static
06808 int
06809 innobase_rename_table(
06810 /*==================*/
06811   trx_t*    trx,  
06812   const identifier::Table &from,
06813   const identifier::Table &to,
06814   ibool   lock_and_commit)
06816 {
06817   int error;
06818 
06819   srv_lower_case_table_names = TRUE;
06820 
06821   /* Serialize data dictionary operations with dictionary mutex:
06822   no deadlocks can occur then in these operations */
06823 
06824   if (lock_and_commit) {
06825     row_mysql_lock_data_dictionary(trx);
06826   }
06827 
06828   error = row_rename_table_for_mysql(from.getKeyPath().c_str(), to.getKeyPath().c_str(), trx, lock_and_commit);
06829 
06830   if (error != DB_SUCCESS) {
06831     FILE* ef = dict_foreign_err_file;
06832 
06833     fputs("InnoDB: Renaming table ", ef);
06834     ut_print_name(ef, trx, TRUE, from.getKeyPath().c_str());
06835     fputs(" to ", ef);
06836     ut_print_name(ef, trx, TRUE, to.getKeyPath().c_str());
06837     fputs(" failed!\n", ef);
06838   }
06839 
06840   if (lock_and_commit) {
06841     row_mysql_unlock_data_dictionary(trx);
06842 
06843     /* Flush the log to reduce probability that the .frm
06844     files and the InnoDB data dictionary get out-of-sync
06845     if the user runs with innodb_flush_log_at_trx_commit = 0 */
06846 
06847     log_buffer_flush_to_disk();
06848   }
06849 
06850   return error;
06851 }
06852 /*********************************************************************/
06855 UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
06856 {
06857   // A temp table alter table/rename is a shallow rename and only the
06858   // definition needs to be updated.
06859   if (to.getType() == message::Table::TEMPORARY && from.getType() == message::Table::TEMPORARY)
06860   {
06861     session.getMessageCache().renameTableMessage(from, to);
06862     return 0;
06863   }
06864 
06865   trx_t*  trx;
06866   int error;
06867   trx_t*  parent_trx;
06868 
06869   /* Get the transaction associated with the current session, or create one
06870     if not yet created */
06871 
06872   parent_trx = check_trx_exists(&session);
06873 
06874   /* In case MySQL calls this in the middle of a SELECT query, release
06875     possible adaptive hash latch to avoid deadlocks of threads */
06876 
06877   trx_search_latch_release_if_reserved(parent_trx);
06878 
06879   trx = innobase_trx_allocate(&session);
06880 
06881   error = innobase_rename_table(trx, from, to, TRUE);
06882 
06883   session.setXaId(trx->id);
06884 
06885   /* Tell the InnoDB server that there might be work for
06886     utility threads: */
06887 
06888   srv_active_wake_master_thread();
06889 
06890   innobase_commit_low(trx);
06891   trx_free_for_mysql(trx);
06892 
06893   /* Add a special case to handle the Duplicated Key error
06894      and return DB_ERROR instead.
06895      This is to avoid a possible SIGSEGV error from mysql error
06896      handling code. Currently, mysql handles the Duplicated Key
06897      error by re-entering the storage layer and getting dup key
06898      info by calling get_dup_key(). This operation requires a valid
06899      table handle ('row_prebuilt_t' structure) which could no
06900      longer be available in the error handling stage. The suggested
06901      solution is to report a 'table exists' error message (since
06902      the dup key error here is due to an existing table whose name
06903      is the one we are trying to rename to) and return the generic
06904      error code. */
06905   if (error == (int) DB_DUPLICATE_KEY) {
06906     my_error(ER_TABLE_EXISTS_ERROR, to);
06907     error = DB_ERROR;
06908   }
06909 
06910   error = convert_error_code_to_mysql(error, 0, NULL);
06911 
06912   if (not error)
06913   {
06914     // If this fails, we are in trouble
06915     plugin::StorageEngine::renameDefinitionFromPath(to, from);
06916   }
06917 
06918   return(error);
06919 }
06920 
06921 /*********************************************************************/
06924 UNIV_INTERN
06925 ha_rows
06926 ha_innobase::records_in_range(
06927 /*==========================*/
06928   uint      keynr,    
06929   key_range   *min_key, 
06931   key_range   *max_key) 
06933 {
06934   KeyInfo*    key;
06935   dict_index_t* index;
06936   unsigned char*    key_val_buff2 = (unsigned char*) malloc(
06937               getTable()->getShare()->sizeStoredRecord()
06938           + getTable()->getShare()->max_key_length + 100);
06939   ulint   buff2_len = getTable()->getShare()->sizeStoredRecord()
06940           + getTable()->getShare()->max_key_length + 100;
06941   dtuple_t* range_start;
06942   dtuple_t* range_end;
06943   ib_int64_t  n_rows;
06944   ulint   mode1;
06945   ulint   mode2;
06946   mem_heap_t* heap;
06947 
06948   ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
06949 
06950   prebuilt->trx->op_info = "estimating records in index range";
06951 
06952   /* In case MySQL calls this in the middle of a SELECT query, release
06953   possible adaptive hash latch to avoid deadlocks of threads */
06954 
06955   trx_search_latch_release_if_reserved(prebuilt->trx);
06956 
06957   active_index = keynr;
06958 
06959   key = &getTable()->key_info[active_index];
06960 
06961   index = innobase_get_index(keynr);
06962 
06963   /* There exists possibility of not being able to find requested
06964      index due to inconsistency between MySQL and InoDB dictionary info.
06965      Necessary message should have been printed in innobase_get_index() */
06966   if (UNIV_UNLIKELY(!index)) {
06967     n_rows = HA_POS_ERROR;
06968     goto func_exit;
06969   }
06970 
06971   if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) {
06972     n_rows = HA_ERR_TABLE_DEF_CHANGED;
06973     goto func_exit;
06974   }
06975 
06976   heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
06977             + sizeof(dtuple_t)));
06978 
06979   range_start = dtuple_create(heap, key->key_parts);
06980   dict_index_copy_types(range_start, index, key->key_parts);
06981 
06982   range_end = dtuple_create(heap, key->key_parts);
06983   dict_index_copy_types(range_end, index, key->key_parts);
06984 
06985   row_sel_convert_mysql_key_to_innobase(
06986         range_start, (byte*) &key_val_buff[0],
06987         (ulint)upd_and_key_val_buff_len,
06988         index,
06989         (byte*) (min_key ? min_key->key :
06990            (const unsigned char*) 0),
06991         (ulint) (min_key ? min_key->length : 0),
06992         prebuilt->trx);
06993 
06994   row_sel_convert_mysql_key_to_innobase(
06995         range_end, (byte*) key_val_buff2,
06996         buff2_len, index,
06997         (byte*) (max_key ? max_key->key :
06998            (const unsigned char*) 0),
06999         (ulint) (max_key ? max_key->length : 0),
07000         prebuilt->trx);
07001 
07002   mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
07003             HA_READ_KEY_EXACT);
07004   mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
07005             HA_READ_KEY_EXACT);
07006 
07007   if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
07008 
07009     n_rows = btr_estimate_n_rows_in_range(index, range_start,
07010                   mode1, range_end,
07011                   mode2);
07012   } else {
07013 
07014     n_rows = HA_POS_ERROR;
07015   }
07016 
07017   mem_heap_free(heap);
07018 
07019 func_exit:
07020   free(key_val_buff2);
07021 
07022   prebuilt->trx->op_info = "";
07023 
07024   /* The MySQL optimizer seems to believe an estimate of 0 rows is
07025   always accurate and may return the result 'Empty set' based on that.
07026   The accuracy is not guaranteed, and even if it were, for a locking
07027   read we should anyway perform the search to set the next-key lock.
07028   Add 1 to the value to make sure MySQL does not make the assumption! */
07029 
07030   if (n_rows == 0) {
07031     n_rows = 1;
07032   }
07033 
07034   return((ha_rows) n_rows);
07035 }
07036 
07037 /*********************************************************************/
07041 UNIV_INTERN
07042 ha_rows
07043 ha_innobase::estimate_rows_upper_bound(void)
07044 /*======================================*/
07045 {
07046   dict_index_t* index;
07047   uint64_t  estimate;
07048   uint64_t  local_data_file_length;
07049   ulint stat_n_leaf_pages;
07050 
07051   /* We do not know if MySQL can call this function before calling
07052   external_lock(). To be safe, update the session of the current table
07053   handle. */
07054 
07055   update_session(getTable()->in_use);
07056 
07057   prebuilt->trx->op_info = (char*)
07058          "calculating upper bound for table rows";
07059 
07060   /* In case MySQL calls this in the middle of a SELECT query, release
07061   possible adaptive hash latch to avoid deadlocks of threads */
07062 
07063   trx_search_latch_release_if_reserved(prebuilt->trx);
07064 
07065   index = dict_table_get_first_index(prebuilt->table);
07066 
07067   stat_n_leaf_pages = index->stat_n_leaf_pages;
07068 
07069   ut_a(stat_n_leaf_pages > 0);
07070 
07071   local_data_file_length =
07072     ((uint64_t) stat_n_leaf_pages) * UNIV_PAGE_SIZE;
07073 
07074 
07075   /* Calculate a minimum length for a clustered index record and from
07076   that an upper bound for the number of rows. Since we only calculate
07077   new statistics in row0mysql.c when a table has grown by a threshold
07078   factor, we must add a safety factor 2 in front of the formula below. */
07079 
07080   estimate = 2 * local_data_file_length /
07081            dict_index_calc_min_rec_len(index);
07082 
07083   prebuilt->trx->op_info = "";
07084 
07085   return((ha_rows) estimate);
07086 }
07087 
07088 /*********************************************************************/
07093 UNIV_INTERN
07094 double
07095 ha_innobase::scan_time()
07096 /*====================*/
07097 {
07098   /* Since MySQL seems to favor table scans too much over index
07099   searches, we pretend that a sequential read takes the same time
07100   as a random disk read, that is, we do not divide the following
07101   by 10, which would be physically realistic. */
07102 
07103   return((double) (prebuilt->table->stat_clustered_index_size));
07104 }
07105 
07106 /******************************************************************/
07110 UNIV_INTERN
07111 double
07112 ha_innobase::read_time(
07113 /*===================*/
07114   uint  index,  
07115   uint  ranges, 
07116   ha_rows rows) 
07117 {
07118   ha_rows total_rows;
07119   double  time_for_scan;
07120 
07121   if (index != getTable()->getShare()->getPrimaryKey()) {
07122     /* Not clustered */
07123     return(Cursor::read_time(index, ranges, rows));
07124   }
07125 
07126   if (rows <= 2) {
07127 
07128     return((double) rows);
07129   }
07130 
07131   /* Assume that the read time is proportional to the scan time for all
07132   rows + at most one seek per range. */
07133 
07134   time_for_scan = scan_time();
07135 
07136   if ((total_rows = estimate_rows_upper_bound()) < rows) {
07137 
07138     return(time_for_scan);
07139   }
07140 
07141   return(ranges + (double) rows / (double) total_rows * time_for_scan);
07142 }
07143 
07144 /*********************************************************************/
07153 static
07154 unsigned int
07155 innobase_get_mysql_key_number_for_index(
07156 /*====================================*/
07157   INNOBASE_SHARE*   share,  
07159   const drizzled::Table*  table,  
07161   dict_table_t*   ib_table,
07163         const dict_index_t*     index)  
07164 {
07165   const dict_index_t* ind;
07166   unsigned int    i;
07167 
07168   ut_ad(index);
07169   ut_ad(ib_table);
07170   ut_ad(table);
07171   ut_ad(share);
07172 
07173   /* If index does not belong to the table of share structure. Search
07174   index->table instead */
07175   if (index->table != ib_table) {
07176     i = 0;
07177     ind = dict_table_get_first_index(index->table);
07178 
07179     while (index != ind) {
07180       ind = dict_table_get_next_index(ind);
07181       i++;
07182     }
07183 
07184     if (row_table_got_default_clust_index(index->table)) {
07185       ut_a(i > 0);
07186       i--;
07187     }
07188 
07189     return(i);
07190   }
07191 
07192   /* If index does not belong to the table of share structure. Search
07193   index->table instead */
07194   if (index->table != ib_table) {
07195     i = 0;
07196     ind = dict_table_get_first_index(index->table);
07197 
07198     while (index != ind) {
07199       ind = dict_table_get_next_index(ind);
07200       i++;
07201     }
07202 
07203     if (row_table_got_default_clust_index(index->table)) {
07204       ut_a(i > 0);
07205       i--;
07206     }
07207 
07208     return(i);
07209   }
07210 
07211   /* If index translation table exists, we will first check
07212   the index through index translation table for a match. */
07213         if (share->idx_trans_tbl.index_mapping) {
07214     for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
07215       if (share->idx_trans_tbl.index_mapping[i] == index) {
07216         return(i);
07217       }
07218     }
07219 
07220     /* Print an error message if we cannot find the index
07221     ** in the "index translation table". */
07222     errmsg_printf(error::ERROR,
07223                               "Cannot find index %s in InnoDB index "
07224         "translation table.", index->name);
07225   }
07226 
07227   /* If we do not have an "index translation table", or not able
07228   to find the index in the translation table, we'll directly find
07229   matching index in the dict_index_t list */
07230   for (i = 0; i < table->getShare()->keys; i++) {
07231     ind = dict_table_get_index_on_name(
07232       ib_table, table->key_info[i].name);
07233 
07234           if (index == ind) {
07235       return(i);
07236     }
07237         }
07238 
07239     errmsg_printf(error::ERROR,
07240                               "Cannot find matching index number for index %s "
07241                               "in InnoDB index list.", index->name);
07242 
07243         return(0);
07244 }
07245 /*********************************************************************/
07248 UNIV_INTERN
07249 int
07250 ha_innobase::info(
07251 /*==============*/
07252   uint flag)  
07253 {
07254   dict_table_t* ib_table;
07255   dict_index_t* index;
07256   ha_rows   rec_per_key;
07257   ib_int64_t  n_rows;
07258   os_file_stat_t  stat_info;
07259 
07260   /* If we are forcing recovery at a high level, we will suppress
07261   statistics calculation on tables, because that may crash the
07262   server if an index is badly corrupted. */
07263 
07264   /* We do not know if MySQL can call this function before calling
07265   external_lock(). To be safe, update the session of the current table
07266   handle. */
07267 
07268   update_session(getTable()->in_use);
07269 
07270   /* In case MySQL calls this in the middle of a SELECT query, release
07271   possible adaptive hash latch to avoid deadlocks of threads */
07272 
07273   prebuilt->trx->op_info = "returning various info to MySQL";
07274 
07275   trx_search_latch_release_if_reserved(prebuilt->trx);
07276 
07277   ib_table = prebuilt->table;
07278 
07279   if (flag & HA_STATUS_TIME) {
07280     /* In Analyze we call with this flag: update
07281        then statistics so that they are up-to-date */
07282 
07283     prebuilt->trx->op_info = "updating table statistics";
07284 
07285     dict_update_statistics(ib_table,
07286                            FALSE /* update even if stats
07287                                     are initialized */);
07288 
07289 
07290     prebuilt->trx->op_info = "returning various info to MySQL";
07291 
07292     fs::path get_status_path(catalog::local_identifier().getPath());
07293     get_status_path /= ib_table->name;
07294     fs::change_extension(get_status_path, "dfe");
07295 
07296     /* Note that we do not know the access time of the table,
07297     nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
07298 
07299     if (os_file_get_status(get_status_path.file_string().c_str(), &stat_info)) {
07300       stats.create_time = (ulong) stat_info.ctime;
07301     }
07302   }
07303 
07304   if (flag & HA_STATUS_VARIABLE) {
07305 
07306     dict_table_stats_lock(ib_table, RW_S_LATCH);
07307 
07308     n_rows = ib_table->stat_n_rows;
07309 
07310     /* Because we do not protect stat_n_rows by any mutex in a
07311     delete, it is theoretically possible that the value can be
07312     smaller than zero! TODO: fix this race.
07313 
07314     The MySQL optimizer seems to assume in a left join that n_rows
07315     is an accurate estimate if it is zero. Of course, it is not,
07316     since we do not have any locks on the rows yet at this phase.
07317     Since SHOW TABLE STATUS seems to call this function with the
07318     HA_STATUS_TIME flag set, while the left join optimizer does not
07319     set that flag, we add one to a zero value if the flag is not
07320     set. That way SHOW TABLE STATUS will show the best estimate,
07321     while the optimizer never sees the table empty. */
07322 
07323     if (n_rows < 0) {
07324       n_rows = 0;
07325     }
07326 
07327     if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
07328       n_rows++;
07329     }
07330 
07331     /* Fix bug#40386: Not flushing query cache after truncate.
07332     n_rows can not be 0 unless the table is empty, set to 1
07333     instead. The original problem of bug#29507 is actually
07334     fixed in the server code. */
07335     if (user_session->getSqlCommand() == SQLCOM_TRUNCATE) {
07336 
07337       n_rows = 1;
07338 
07339       /* We need to reset the prebuilt value too, otherwise
07340       checks for values greater than the last value written
07341       to the table will fail and the autoinc counter will
07342       not be updated. This will force doInsertRecord() into
07343       attempting an update of the table's AUTOINC counter. */
07344 
07345       prebuilt->autoinc_last_value = 0;
07346     }
07347 
07348     stats.records = (ha_rows)n_rows;
07349     stats.deleted = 0;
07350     stats.data_file_length = ((uint64_t)
07351         ib_table->stat_clustered_index_size)
07352           * UNIV_PAGE_SIZE;
07353     stats.index_file_length = ((uint64_t)
07354         ib_table->stat_sum_of_other_index_sizes)
07355           * UNIV_PAGE_SIZE;
07356 
07357     dict_table_stats_unlock(ib_table, RW_S_LATCH);
07358 
07359     /* Since fsp_get_available_space_in_free_extents() is
07360     acquiring latches inside InnoDB, we do not call it if we
07361     are asked by MySQL to avoid locking. Another reason to
07362     avoid the call is that it uses quite a lot of CPU.
07363     See Bug#38185. */
07364     if (flag & HA_STATUS_NO_LOCK) {
07365       /* We do not update delete_length if no
07366          locking is requested so the "old" value can
07367          remain. delete_length is initialized to 0 in
07368          the ha_statistics' constructor. */
07369     } else if (UNIV_UNLIKELY
07370                (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) {
07371       /* Avoid accessing the tablespace if
07372          innodb_crash_recovery is set to a high value. */
07373       stats.delete_length = 0;
07374     } else {
07375       ullint  avail_space;
07376 
07377       avail_space = fsp_get_available_space_in_free_extents(ib_table->space);
07378 
07379       if (avail_space == ULLINT_UNDEFINED) {
07380         Session*  session;
07381 
07382         session= getTable()->in_use;
07383         assert(session);
07384 
07385         push_warning_printf(
07386           session,
07387           DRIZZLE_ERROR::WARN_LEVEL_WARN,
07388           ER_CANT_GET_STAT,
07389           "InnoDB: Trying to get the free "
07390           "space for table %s but its "
07391           "tablespace has been discarded or "
07392           "the .ibd file is missing. Setting "
07393           "the free space to zero.",
07394           ib_table->name);
07395 
07396         stats.delete_length = 0;
07397       } else {
07398         stats.delete_length = avail_space * 1024;
07399       }
07400     }
07401 
07402     stats.check_time = 0;
07403 
07404     if (stats.records == 0) {
07405       stats.mean_rec_length = 0;
07406     } else {
07407       stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
07408     }
07409   }
07410 
07411   if (flag & HA_STATUS_CONST) {
07412     ulong i;
07413     /* Verify the number of index in InnoDB and MySQL
07414        matches up. If prebuilt->clust_index_was_generated
07415        holds, InnoDB defines GEN_CLUST_INDEX internally */
07416     ulint num_innodb_index = UT_LIST_GET_LEN(ib_table->indexes) - prebuilt->clust_index_was_generated;
07417 
07418     if (getTable()->getShare()->keys != num_innodb_index) {
07419       errmsg_printf(error::ERROR, "Table %s contains %lu "
07420                       "indexes inside InnoDB, which "
07421                       "is different from the number of "
07422                       "indexes %u defined in the MySQL ",
07423                       ib_table->name, num_innodb_index,
07424                       getTable()->getShare()->keys);
07425     }
07426 
07427     dict_table_stats_lock(ib_table, RW_S_LATCH);
07428 
07429     for (i = 0; i < getTable()->getShare()->sizeKeys(); i++) {
07430       ulong j;
07431       /* We could get index quickly through internal
07432          index mapping with the index translation table.
07433          The identity of index (match up index name with
07434          that of table->key_info[i]) is already verified in
07435          innobase_get_index().  */
07436       index = innobase_get_index(i);
07437 
07438       if (index == NULL) {
07439         errmsg_printf(error::ERROR, "Table %s contains fewer "
07440             "indexes inside InnoDB than "
07441             "are defined in the MySQL "
07442             ".frm file. Have you mixed up "
07443             ".frm files from different "
07444             "installations? See "
07445             REFMAN
07446             "innodb-troubleshooting.html\n",
07447             ib_table->name);
07448         break;
07449       }
07450 
07451       for (j = 0; j < getTable()->key_info[i].key_parts; j++) {
07452 
07453         if (j + 1 > index->n_uniq) {
07454           errmsg_printf(error::ERROR, 
07455 "Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
07456 "statistics for %lu columns. Have you mixed up .frm files from different "
07457 "installations? "
07458 "See " REFMAN "innodb-troubleshooting.html\n",
07459               index->name,
07460               ib_table->name,
07461               (unsigned long)
07462               index->n_uniq, j + 1);
07463           break;
07464         }
07465 
07466         if (index->stat_n_diff_key_vals[j + 1] == 0) {
07467 
07468           rec_per_key = stats.records;
07469         } else {
07470           rec_per_key = (ha_rows)(stats.records /
07471            index->stat_n_diff_key_vals[j + 1]);
07472         }
07473 
07474         /* Since MySQL seems to favor table scans
07475         too much over index searches, we pretend
07476         index selectivity is 2 times better than
07477         our estimate: */
07478 
07479         rec_per_key = rec_per_key / 2;
07480 
07481         if (rec_per_key == 0) {
07482           rec_per_key = 1;
07483         }
07484 
07485         getTable()->key_info[i].rec_per_key[j]=
07486           rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
07487           (ulong) rec_per_key;
07488       }
07489     }
07490 
07491     dict_table_stats_unlock(ib_table, RW_S_LATCH);
07492   }
07493 
07494   if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
07495     goto func_exit;
07496   }
07497 
07498   if (flag & HA_STATUS_ERRKEY) {
07499     const dict_index_t* err_index;
07500 
07501     ut_a(prebuilt->trx);
07502     ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
07503 
07504     err_index = trx_get_error_info(prebuilt->trx);
07505 
07506     if (err_index) {
07507       errkey = (unsigned int)
07508         innobase_get_mysql_key_number_for_index(share, getTable(), ib_table,
07509                                                 err_index);
07510     } else {
07511       errkey = (unsigned int) prebuilt->trx->error_key_num;
07512     }
07513   }
07514 
07515   if ((flag & HA_STATUS_AUTO) && getTable()->found_next_number_field) {
07516     stats.auto_increment_value = innobase_peek_autoinc();
07517   }
07518 
07519 func_exit:
07520   prebuilt->trx->op_info = "";
07521 
07522   return(0);
07523 }
07524 
07525 /**********************************************************************/
07529 UNIV_INTERN
07530 int
07531 ha_innobase::analyze(
07532 /*=================*/
07533   Session*)   
07534 {
07535   /* Simply call ::info() with all the flags */
07536   info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
07537 
07538   return(0);
07539 }
07540 
07541 /*******************************************************************/
07546 UNIV_INTERN
07547 int
07548 ha_innobase::check(
07549 /*===============*/
07550   Session*  session)  
07551 {
07552   dict_index_t* index;
07553   ulint   n_rows;
07554   ulint   n_rows_in_table = ULINT_UNDEFINED;
07555   ibool   is_ok   = TRUE;
07556   ulint   old_isolation_level;
07557 
07558   assert(session == getTable()->in_use);
07559   ut_a(prebuilt->trx);
07560   ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
07561   ut_a(prebuilt->trx == session_to_trx(session));
07562 
07563   if (prebuilt->mysql_template == NULL) {
07564     /* Build the template; we will use a dummy template
07565     in index scans done in checking */
07566 
07567     build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
07568   }
07569 
07570   if (prebuilt->table->ibd_file_missing) {
07571         errmsg_printf(error::ERROR, "InnoDB: Error:\n"
07572                     "InnoDB: MySQL is trying to use a table handle"
07573                     " but the .ibd file for\n"
07574                     "InnoDB: table %s does not exist.\n"
07575                     "InnoDB: Have you deleted the .ibd file"
07576                     " from the database directory under\n"
07577                     "InnoDB: the MySQL datadir, or have you"
07578                     " used DISCARD TABLESPACE?\n"
07579                     "InnoDB: Please refer to\n"
07580                     "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
07581                     "InnoDB: how you can resolve the problem.\n",
07582                     prebuilt->table->name);
07583     return(HA_ADMIN_CORRUPT);
07584   }
07585 
07586   prebuilt->trx->op_info = "checking table";
07587 
07588   old_isolation_level = prebuilt->trx->isolation_level;
07589 
07590   /* We must run the index record counts at an isolation level
07591      >= READ COMMITTED, because a dirty read can see a wrong number
07592      of records in some index; to play safe, we use always
07593      REPEATABLE READ here */
07594 
07595   prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
07596 
07597   /* Enlarge the fatal lock wait timeout during CHECK TABLE. */
07598   mutex_enter(&kernel_mutex);
07599   srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
07600   mutex_exit(&kernel_mutex);
07601 
07602   for (index = dict_table_get_first_index(prebuilt->table);
07603        index != NULL;
07604        index = dict_table_get_next_index(index)) {
07605 #if 0
07606     fputs("Validating index ", stderr);
07607     ut_print_name(stderr, trx, FALSE, index->name);
07608     putc('\n', stderr);
07609 #endif
07610 
07611     if (!btr_validate_index(index, prebuilt->trx)) {
07612       is_ok = FALSE;
07613       push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
07614                           ER_NOT_KEYFILE,
07615                           "InnoDB: The B-tree of"
07616                           " index '%-.200s' is corrupted.",
07617                           index->name);
07618       continue;
07619     }
07620 
07621     /* Instead of invoking change_active_index(), set up
07622        a dummy template for non-locking reads, disabling
07623        access to the clustered index. */
07624     prebuilt->index = index;
07625 
07626     prebuilt->index_usable = row_merge_is_index_usable(
07627       prebuilt->trx, prebuilt->index);
07628 
07629     if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
07630       push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
07631                           HA_ERR_TABLE_DEF_CHANGED,
07632                           "InnoDB: Insufficient history for"
07633                           " index '%-.200s'",
07634                           index->name);
07635       continue;
07636     }
07637 
07638     prebuilt->sql_stat_start = TRUE;
07639     prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
07640     prebuilt->n_template = 0;
07641     prebuilt->need_to_access_clustered = FALSE;
07642 
07643     dtuple_set_n_fields(prebuilt->search_tuple, 0);
07644 
07645     prebuilt->select_lock_type = LOCK_NONE;
07646 
07647     if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) {
07648       push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
07649                           ER_NOT_KEYFILE,
07650                           "InnoDB: The B-tree of"
07651                           " index '%-.200s' is corrupted.",
07652                           index->name);
07653       is_ok = FALSE;
07654     }
07655 
07656     if (user_session->getKilled()) {
07657       break;
07658     }
07659 
07660 #if 0
07661     fprintf(stderr, "%lu entries in index %s\n", n_rows,
07662             index->name);
07663 #endif
07664 
07665     if (index == dict_table_get_first_index(prebuilt->table)) {
07666       n_rows_in_table = n_rows;
07667     } else if (n_rows != n_rows_in_table) {
07668       push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
07669                           ER_NOT_KEYFILE,
07670                           "InnoDB: Index '%-.200s'"
07671                           " contains %lu entries,"
07672                           " should be %lu.",
07673                           index->name,
07674                           (ulong) n_rows,
07675                           (ulong) n_rows_in_table);
07676       is_ok = FALSE;
07677     }
07678   }
07679 
07680   /* Restore the original isolation level */
07681   prebuilt->trx->isolation_level = old_isolation_level;
07682 
07683   /* We validate also the whole adaptive hash index for all tables
07684      at every CHECK TABLE */
07685 
07686   if (!btr_search_validate()) {
07687     push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
07688                  ER_NOT_KEYFILE,
07689                  "InnoDB: The adaptive hash index is corrupted.");
07690     is_ok = FALSE;
07691   }
07692 
07693   /* Restore the fatal lock wait timeout after CHECK TABLE. */
07694   mutex_enter(&kernel_mutex);
07695   srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
07696   mutex_exit(&kernel_mutex);
07697 
07698   prebuilt->trx->op_info = "";
07699   if (user_session->getKilled()) {
07700     my_error(ER_QUERY_INTERRUPTED, MYF(0));
07701   }
07702 
07703   return(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
07704 }
07705 
07706 /*************************************************************/
07711 UNIV_INTERN
07712 char*
07713 ha_innobase::update_table_comment(
07714 /*==============================*/
07715   const char* comment)
07716 {
07717   uint  length = (uint) strlen(comment);
07718   char* str;
07719   long  flen;
07720 
07721   /* We do not know if MySQL can call this function before calling
07722   external_lock(). To be safe, update the session of the current table
07723   handle. */
07724 
07725   if (length > 64000 - 3) {
07726     return((char*)comment); /* string too long */
07727   }
07728 
07729   update_session(getTable()->in_use);
07730 
07731   prebuilt->trx->op_info = "returning table comment";
07732 
07733   /* In case MySQL calls this in the middle of a SELECT query, release
07734   possible adaptive hash latch to avoid deadlocks of threads */
07735 
07736   trx_search_latch_release_if_reserved(prebuilt->trx);
07737   str = NULL;
07738 
07739   /* output the data to a temporary file */
07740 
07741   mutex_enter(&srv_dict_tmpfile_mutex);
07742   rewind(srv_dict_tmpfile);
07743 
07744   fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
07745     fsp_get_available_space_in_free_extents(
07746       prebuilt->table->space));
07747 
07748   dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
07749         prebuilt->trx, prebuilt->table);
07750   flen = ftell(srv_dict_tmpfile);
07751   if (flen < 0) {
07752     flen = 0;
07753   } else if (length + flen + 3 > 64000) {
07754     flen = 64000 - 3 - length;
07755   }
07756 
07757   /* allocate buffer for the full string, and
07758   read the contents of the temporary file */
07759 
07760   str = (char*) malloc(length + flen + 3);
07761 
07762   if (str) {
07763     char* pos = str + length;
07764     if (length) {
07765       memcpy(str, comment, length);
07766       *pos++ = ';';
07767       *pos++ = ' ';
07768     }
07769     rewind(srv_dict_tmpfile);
07770     flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
07771     pos[flen] = 0;
07772   }
07773 
07774   mutex_exit(&srv_dict_tmpfile_mutex);
07775 
07776   prebuilt->trx->op_info = "";
07777 
07778   return(str ? str : (char*) comment);
07779 }
07780 
07781 /*******************************************************************/
07786 UNIV_INTERN
07787 char*
07788 ha_innobase::get_foreign_key_create_info(void)
07789 /*==========================================*/
07790 {
07791   char* str = 0;
07792   long  flen;
07793 
07794   ut_a(prebuilt != NULL);
07795 
07796   /* We do not know if MySQL can call this function before calling
07797   external_lock(). To be safe, update the session of the current table
07798   handle. */
07799 
07800   update_session(getTable()->in_use);
07801 
07802   prebuilt->trx->op_info = "getting info on foreign keys";
07803 
07804   /* In case MySQL calls this in the middle of a SELECT query,
07805   release possible adaptive hash latch to avoid
07806   deadlocks of threads */
07807 
07808   trx_search_latch_release_if_reserved(prebuilt->trx);
07809 
07810   mutex_enter(&srv_dict_tmpfile_mutex);
07811   rewind(srv_dict_tmpfile);
07812 
07813   /* output the data to a temporary file */
07814   dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
07815         prebuilt->trx, prebuilt->table);
07816   prebuilt->trx->op_info = "";
07817 
07818   flen = ftell(srv_dict_tmpfile);
07819   if (flen < 0) {
07820     flen = 0;
07821   }
07822 
07823   /* allocate buffer for the string, and
07824   read the contents of the temporary file */
07825 
07826   str = (char*) malloc(flen + 1);
07827 
07828   if (str) {
07829     rewind(srv_dict_tmpfile);
07830     flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
07831     str[flen] = 0;
07832   }
07833 
07834   mutex_exit(&srv_dict_tmpfile_mutex);
07835 
07836   return(str);
07837 }
07838 
07839 
07840 UNIV_INTERN
07841 int
07842 ha_innobase::get_foreign_key_list(Session *session, List<ForeignKeyInfo> *f_key_list)
07843 {
07844   ut_a(prebuilt != NULL);
07845   update_session(getTable()->in_use);
07846   prebuilt->trx->op_info = "getting list of foreign keys";
07847   trx_search_latch_release_if_reserved(prebuilt->trx);
07848   mutex_enter(&(dict_sys->mutex));
07849   dict_foreign_t* foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
07850 
07851   while (foreign != NULL) 
07852   {
07853     uint ulen;
07854     char uname[NAME_LEN + 1];           /* Unencoded name */
07855     char db_name[NAME_LEN + 1];
07856     const char *tmp_buff;
07857 
07859     tmp_buff = foreign->id;
07860     uint i = 0;
07861     while (tmp_buff[i] != '/')
07862       i++;
07863     tmp_buff += i + 1;
07864     lex_string_t *tmp_foreign_id = session->make_lex_string(NULL, str_ref(tmp_buff));
07865 
07866     /* Database name */
07867     tmp_buff = foreign->referenced_table_name;
07868 
07869     i= 0;
07870     while (tmp_buff[i] != '/')
07871     {
07872       db_name[i]= tmp_buff[i];
07873       i++;
07874     }
07875     db_name[i] = 0;
07876     ulen= identifier::Table::filename_to_tablename(db_name, uname, sizeof(uname));
07877     lex_string_t *tmp_referenced_db = session->make_lex_string(NULL, str_ref(uname, ulen));
07878 
07879     /* Table name */
07880     tmp_buff += i + 1;
07881     ulen= identifier::Table::filename_to_tablename(tmp_buff, uname, sizeof(uname));
07882     lex_string_t *tmp_referenced_table = session->make_lex_string(NULL, str_ref(uname, ulen));
07883 
07885     List<lex_string_t> tmp_foreign_fields;
07886     List<lex_string_t> tmp_referenced_fields;
07887     for (i= 0;;) 
07888     {
07889       tmp_foreign_fields.push_back(session->make_lex_string(NULL, str_ref(foreign->foreign_col_names[i])));
07890       tmp_referenced_fields.push_back(session->make_lex_string(NULL, str_ref(foreign->referenced_col_names[i])));
07891       if (++i >= foreign->n_fields)
07892         break;
07893     }
07894 
07895     if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
07896       tmp_buff= "CASCADE";
07897     else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
07898       tmp_buff= "SET NULL";
07899     else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
07900       tmp_buff= "NO ACTION";
07901     else
07902       tmp_buff= "RESTRICT";
07903     lex_string_t *tmp_delete_method = session->make_lex_string(NULL, str_ref(tmp_buff));
07904 
07905     if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
07906       tmp_buff= "CASCADE";
07907     else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
07908       tmp_buff= "SET NULL";
07909     else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
07910       tmp_buff= "NO ACTION";
07911     else
07912       tmp_buff= "RESTRICT";
07913     lex_string_t *tmp_update_method = session->make_lex_string(NULL, str_ref(tmp_buff));
07914 
07915     lex_string_t *tmp_referenced_key_name = foreign->referenced_index && foreign->referenced_index->name
07916       ? session->make_lex_string(NULL, str_ref(foreign->referenced_index->name))
07917       : NULL;
07918 
07919     ForeignKeyInfo f_key_info(
07920       tmp_foreign_id, tmp_referenced_db, tmp_referenced_table,
07921       tmp_update_method, tmp_delete_method, tmp_referenced_key_name,
07922       tmp_foreign_fields, tmp_referenced_fields);
07923 
07924     f_key_list->push_back((ForeignKeyInfo*)session->mem.memdup(&f_key_info, sizeof(ForeignKeyInfo)));
07925     foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
07926   }
07927   mutex_exit(&(dict_sys->mutex));
07928   prebuilt->trx->op_info = "";
07929 
07930   return 0;
07931 }
07932 
07933 /*****************************************************************/
07938 UNIV_INTERN
07939 bool
07940 ha_innobase::can_switch_engines(void)
07941 /*=================================*/
07942 {
07943   bool  can_switch;
07944 
07945   ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
07946 
07947   prebuilt->trx->op_info =
07948       "determining if there are foreign key constraints";
07949   row_mysql_lock_data_dictionary(prebuilt->trx);
07950 
07951   can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
07952       && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
07953 
07954   row_mysql_unlock_data_dictionary(prebuilt->trx);
07955   prebuilt->trx->op_info = "";
07956 
07957   return(can_switch);
07958 }
07959 
07960 /*******************************************************************/
07966 UNIV_INTERN
07967 uint
07968 ha_innobase::referenced_by_foreign_key(void)
07969 /*========================================*/
07970 {
07971   if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
07972 
07973     return(1);
07974   }
07975 
07976   return(0);
07977 }
07978 
07979 /*******************************************************************/
07982 UNIV_INTERN
07983 void
07984 ha_innobase::free_foreign_key_create_info(
07985 /*======================================*/
07986   char* str)  
07987 {
07988   free(str);
07989 }
07990 
07991 /*******************************************************************/
07994 UNIV_INTERN
07995 int
07996 ha_innobase::extra(
07997 /*===============*/
07998   enum ha_extra_function operation)
08000 {
08001   /* Warning: since it is not sure that MySQL calls external_lock
08002   before calling this function, the trx field in prebuilt can be
08003   obsolete! */
08004 
08005   switch (operation) {
08006     case HA_EXTRA_FLUSH:
08007       if (prebuilt->blob_heap) {
08008         row_mysql_prebuilt_free_blob_heap(prebuilt);
08009       }
08010       break;
08011     case HA_EXTRA_RESET_STATE:
08012       reset_template(prebuilt);
08013       break;
08014     case HA_EXTRA_NO_KEYREAD:
08015       prebuilt->read_just_key = 0;
08016       break;
08017     case HA_EXTRA_KEYREAD:
08018       prebuilt->read_just_key = 1;
08019       break;
08020     case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
08021       prebuilt->keep_other_fields_on_keyread = 1;
08022       break;
08023 
08024       /* IMPORTANT: prebuilt->trx can be obsolete in
08025       this method, because it is not sure that MySQL
08026       calls external_lock before this method with the
08027       parameters below.  We must not invoke update_session()
08028       either, because the calling threads may change.
08029       CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
08030     case HA_EXTRA_IGNORE_DUP_KEY:
08031       session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_IGNORE;
08032       break;
08033     case HA_EXTRA_WRITE_CAN_REPLACE:
08034       session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_REPLACE;
08035       break;
08036     case HA_EXTRA_WRITE_CANNOT_REPLACE:
08037       session_to_trx(getTable()->in_use)->duplicates &= ~TRX_DUP_REPLACE;
08038       break;
08039     case HA_EXTRA_NO_IGNORE_DUP_KEY:
08040       session_to_trx(getTable()->in_use)->duplicates &=
08041         ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
08042       break;
08043     default:/* Do nothing */
08044       ;
08045   }
08046 
08047   return(0);
08048 }
08049 
08050 UNIV_INTERN
08051 int
08052 ha_innobase::reset()
08053 {
08054   if (prebuilt->blob_heap) {
08055     row_mysql_prebuilt_free_blob_heap(prebuilt);
08056   }
08057 
08058   reset_template(prebuilt);
08059 
08060   /* TODO: This should really be reset in reset_template() but for now
08061   it's safer to do it explicitly here. */
08062 
08063   /* This is a statement level counter. */
08064   prebuilt->autoinc_last_value = 0;
08065 
08066   return(0);
08067 }
08068 
08069 /******************************************************************/
08072 static inline
08073 ulint
08074 innobase_map_isolation_level(
08075 /*=========================*/
08076   enum_tx_isolation iso)  
08077 {
08078   switch(iso) {
08079     case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
08080     case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
08081     case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
08082     case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
08083     default: ut_a(0); return(0);
08084   }
08085 }
08086 
08087 /******************************************************************/
08092 UNIV_INTERN
08093 int
08094 ha_innobase::external_lock(
08095 /*=======================*/
08096   Session*  session,  
08097   int lock_type)  
08098 {
08099   update_session(session);
08100 
08101   trx_t *trx= prebuilt->trx;
08102 
08103   prebuilt->sql_stat_start = TRUE;
08104   prebuilt->hint_need_to_fetch_extra_cols = 0;
08105 
08106   reset_template(prebuilt);
08107 
08108   if (lock_type == F_WRLCK) {
08109 
08110     /* If this is a SELECT, then it is in UPDATE TABLE ...
08111     or SELECT ... FOR UPDATE */
08112     prebuilt->select_lock_type = LOCK_X;
08113     prebuilt->stored_select_lock_type = LOCK_X;
08114   }
08115 
08116   if (lock_type != F_UNLCK) {
08117     /* MySQL is setting a new table lock */
08118 
08119     if (trx->isolation_level == TRX_ISO_SERIALIZABLE
08120       && prebuilt->select_lock_type == LOCK_NONE
08121       && session_test_options(session,
08122         OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
08123 
08124       /* To get serializable execution, we let InnoDB
08125       conceptually add 'LOCK IN SHARE MODE' to all SELECTs
08126       which otherwise would have been consistent reads. An
08127       exception is consistent reads in the AUTOCOMMIT=1 mode:
08128       we know that they are read-only transactions, and they
08129       can be serialized also if performed as consistent
08130       reads. */
08131 
08132       prebuilt->select_lock_type = LOCK_S;
08133       prebuilt->stored_select_lock_type = LOCK_S;
08134     }
08135 
08136     /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
08137     TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
08138     an InnoDB table lock if it is released immediately at the end
08139     of LOCK TABLES, and InnoDB's table locks in that case cause
08140     VERY easily deadlocks.
08141 
08142     We do not set InnoDB table locks if user has not explicitly
08143     requested a table lock. Note that session_in_lock_tables(session)
08144     can hold in some cases, e.g., at the start of a stored
08145     procedure call (SQLCOM_CALL). */
08146 
08147     if (prebuilt->select_lock_type != LOCK_NONE) {
08148       trx->mysql_n_tables_locked++;
08149     }
08150 
08151     prebuilt->mysql_has_locked = TRUE;
08152 
08153     return(0);
08154   }
08155 
08156   /* MySQL is releasing a table lock */
08157   prebuilt->mysql_has_locked = FALSE;
08158   trx->mysql_n_tables_locked= 0;
08159 
08160   return(0);
08161 }
08162 
08163 /************************************************************************/
08166 static
08167 bool
08168 innodb_show_status(
08169 /*===============*/
08170   plugin::StorageEngine*  engine, 
08171   Session*  session,
08172   stat_print_fn *stat_print)
08173 {
08174   trx_t*      trx;
08175   static const char truncated_msg[] = "... truncated...\n";
08176   const long    MAX_STATUS_SIZE = 1048576;
08177   ulint     trx_list_start = ULINT_UNDEFINED;
08178   ulint     trx_list_end = ULINT_UNDEFINED;
08179 
08180   assert(engine == innodb_engine_ptr);
08181 
08182   trx = check_trx_exists(session);
08183 
08184   innobase_release_stat_resources(trx);
08185 
08186   /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
08187   bytes of text. */
08188 
08189   long  flen, usable_len;
08190   char* str;
08191 
08192   mutex_enter(&srv_monitor_file_mutex);
08193   rewind(srv_monitor_file);
08194   srv_printf_innodb_monitor(srv_monitor_file, FALSE,
08195         &trx_list_start, &trx_list_end);
08196   flen = ftell(srv_monitor_file);
08197   os_file_set_eof(srv_monitor_file);
08198 
08199   if (flen < 0) {
08200     flen = 0;
08201   }
08202 
08203   if (flen > MAX_STATUS_SIZE) {
08204     usable_len = MAX_STATUS_SIZE;
08205     srv_truncated_status_writes++;
08206   } else {
08207     usable_len = flen;
08208   }
08209 
08210   /* allocate buffer for the string, and
08211   read the contents of the temporary file */
08212 
08213   if (!(str = (char*) malloc(usable_len + 1))) {
08214     mutex_exit(&srv_monitor_file_mutex);
08215     return(TRUE);
08216   }
08217 
08218   rewind(srv_monitor_file);
08219   if (flen < MAX_STATUS_SIZE) {
08220     /* Display the entire output. */
08221     flen = (long) fread(str, 1, flen, srv_monitor_file);
08222   } else if (trx_list_end < (ulint) flen
08223       && trx_list_start < trx_list_end
08224       && trx_list_start + (flen - trx_list_end)
08225       < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
08226     /* Omit the beginning of the list of active transactions. */
08227     long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
08228     memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
08229     len += sizeof truncated_msg - 1;
08230     usable_len = (MAX_STATUS_SIZE - 1) - len;
08231     fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
08232     len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
08233     flen = len;
08234   } else {
08235     /* Omit the end of the output. */
08236     flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
08237   }
08238 
08239   mutex_exit(&srv_monitor_file_mutex);
08240 
08241   stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
08242              STRING_WITH_LEN(""), str, flen);
08243 
08244   free(str);
08245 
08246   return(FALSE);
08247 }
08248 
08249 /************************************************************************/
08252 static
08253 bool
08254 innodb_mutex_show_status(
08255 /*=====================*/
08256   plugin::StorageEngine*  engine,   
08257   Session*  session,  
08259   stat_print_fn*  stat_print) 
08261 {
08262   char buf1[IO_SIZE], buf2[IO_SIZE];
08263   mutex_t*  mutex;
08264   rw_lock_t*  lock;
08265   ulint   block_mutex_oswait_count = 0;
08266   ulint   block_lock_oswait_count = 0;
08267   mutex_t*  block_mutex = NULL;
08268   rw_lock_t*  block_lock = NULL;
08269 #ifdef UNIV_DEBUG
08270   ulint   rw_lock_count= 0;
08271   ulint   rw_lock_count_spin_loop= 0;
08272   ulint   rw_lock_count_spin_rounds= 0;
08273   ulint   rw_lock_count_os_wait= 0;
08274   ulint   rw_lock_count_os_yield= 0;
08275   uint64_t rw_lock_wait_time= 0;
08276 #endif /* UNIV_DEBUG */
08277   uint    engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
08278   assert(engine == innodb_engine_ptr);
08279 
08280   mutex_enter(&mutex_list_mutex);
08281 
08282   for (mutex = UT_LIST_GET_FIRST(mutex_list); mutex != NULL;
08283        mutex = UT_LIST_GET_NEXT(list, mutex)) {
08284     if (mutex->count_os_wait == 0) {
08285       continue;
08286     }
08287 
08288 
08289     if (buf_pool_is_block_mutex(mutex)) {
08290       block_mutex = mutex;
08291       block_mutex_oswait_count += mutex->count_os_wait;
08292       continue;
08293     }
08294 #ifdef UNIV_DEBUG
08295     if (mutex->mutex_type != 1) {
08296       if (mutex->count_using > 0) {
08297         buf1len= my_snprintf(buf1, sizeof(buf1),
08298           "%s:%s",
08299           mutex->cmutex_name, mutex->cfile_name);
08300         buf2len= my_snprintf(buf2, sizeof(buf2),
08301           "count=%lu, spin_waits=%lu,"
08302           " spin_rounds=%lu, "
08303           "os_waits=%lu, os_yields=%lu,"
08304           " os_wait_times=%lu",
08305           mutex->count_using,
08306           mutex->count_spin_loop,
08307           mutex->count_spin_rounds,
08308           mutex->count_os_wait,
08309           mutex->count_os_yield,
08310           (ulong) (mutex->lspent_time/1000));
08311 
08312         if (stat_print(session, innobase_engine_name,
08313             engine_name_len, buf1, buf1len,
08314             buf2, buf2len)) {
08315           mutex_exit(&mutex_list_mutex);
08316           return(1);
08317         }
08318       }
08319     } else {
08320       rw_lock_count += mutex->count_using;
08321       rw_lock_count_spin_loop += mutex->count_spin_loop;
08322       rw_lock_count_spin_rounds += mutex->count_spin_rounds;
08323       rw_lock_count_os_wait += mutex->count_os_wait;
08324       rw_lock_count_os_yield += mutex->count_os_yield;
08325       rw_lock_wait_time += mutex->lspent_time;
08326     }
08327 #else /* UNIV_DEBUG */
08328     buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
08329           mutex->cfile_name, (ulong) mutex->cline);
08330     buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
08331                       (ulong) mutex->count_os_wait);
08332 
08333     if (stat_print(session, innobase_engine_name,
08334              engine_name_len, buf1, buf1len,
08335              buf2, buf2len)) {
08336       mutex_exit(&mutex_list_mutex);
08337       return(1);
08338     }
08339 #endif /* UNIV_DEBUG */
08340   }
08341 
08342   if (block_mutex) {
08343     buf1len = snprintf(buf1, sizeof buf1,
08344                        "combined %s:%lu",
08345                        block_mutex->cfile_name,
08346                        (ulong) block_mutex->cline);
08347     buf2len = snprintf(buf2, sizeof buf2,
08348                        "os_waits=%lu",
08349                        (ulong) block_mutex_oswait_count);
08350 
08351     if (stat_print(session, innobase_engine_name,
08352                    strlen(innobase_engine_name), buf1, buf1len,
08353                    buf2, buf2len)) {
08354       mutex_exit(&mutex_list_mutex);
08355       return(1);
08356     }
08357   }
08358 
08359   mutex_exit(&mutex_list_mutex);
08360 
08361   mutex_enter(&rw_lock_list_mutex);
08362 
08363   for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL;
08364        lock = UT_LIST_GET_NEXT(list, lock)) {
08365     if (lock->count_os_wait == 0) {
08366       continue;
08367     }
08368 
08369     if (buf_pool_is_block_lock(lock)) {
08370       block_lock = lock;
08371       block_lock_oswait_count += lock->count_os_wait;
08372       continue;
08373     }
08374 
08375     buf1len = snprintf(buf1, sizeof buf1, "%s:%lu",
08376                        lock->cfile_name, (ulong) lock->cline);
08377     buf2len = snprintf(buf2, sizeof buf2, "os_waits=%lu",
08378                        (ulong) lock->count_os_wait);
08379 
08380     if (stat_print(session, innobase_engine_name,
08381                    strlen(innobase_engine_name), buf1, buf1len,
08382                    buf2, buf2len)) {
08383       mutex_exit(&rw_lock_list_mutex);
08384       return(1);
08385     }
08386   }
08387 
08388   if (block_lock) {
08389     buf1len = snprintf(buf1, sizeof buf1,
08390                        "combined %s:%lu",
08391                        block_lock->cfile_name,
08392                        (ulong) block_lock->cline);
08393     buf2len = snprintf(buf2, sizeof buf2,
08394                        "os_waits=%lu",
08395                        (ulong) block_lock_oswait_count);
08396 
08397     if (stat_print(session, innobase_engine_name,
08398                    strlen(innobase_engine_name), buf1, buf1len,
08399                    buf2, buf2len)) {
08400       mutex_exit(&rw_lock_list_mutex);
08401       return(1);
08402     }
08403   }
08404 
08405   mutex_exit(&rw_lock_list_mutex);
08406 
08407 #ifdef UNIV_DEBUG
08408   buf2len = snprintf(buf2, sizeof buf2,
08409                      "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
08410                      "os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
08411                      (ulong) rw_lock_count,
08412                      (ulong) rw_lock_count_spin_loop,
08413                      (ulong) rw_lock_count_spin_rounds,
08414                      (ulong) rw_lock_count_os_wait,
08415                      (ulong) rw_lock_count_os_yield,
08416                      (ulong) (rw_lock_wait_time / 1000));
08417 
08418   if (stat_print(session, innobase_engine_name, engine_name_len,
08419       STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
08420     return(1);
08421   }
08422 #endif /* UNIV_DEBUG */
08423 
08424   return(FALSE);
08425 }
08426 
08427 bool InnobaseEngine::show_status(Session* session, 
08428                                  stat_print_fn* stat_print,
08429                                  enum ha_stat_type stat_type)
08430 {
08431   assert(this == innodb_engine_ptr);
08432 
08433   switch (stat_type) {
08434   case HA_ENGINE_STATUS:
08435     return innodb_show_status(this, session, stat_print);
08436   case HA_ENGINE_MUTEX:
08437     return innodb_mutex_show_status(this, session, stat_print);
08438   default:
08439     return(FALSE);
08440   }
08441 }
08442 
08443 /************************************************************************/
08448 static INNOBASE_SHARE* get_share(const char* table_name)
08449 {
08450   INNOBASE_SHARE *share;
08451   boost::mutex::scoped_lock scopedLock(innobase_share_mutex);
08452 
08453   ulint fold = ut_fold_string(table_name);
08454 
08455   HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
08456         INNOBASE_SHARE*, share,
08457         ut_ad(share->use_count > 0),
08458         !strcmp(share->table_name, table_name));
08459 
08460   if (!share) {
08461     /* TODO: invoke HASH_MIGRATE if innobase_open_tables
08462     grows too big */
08463 
08464     share= new INNOBASE_SHARE(table_name);
08465 
08466     HASH_INSERT(INNOBASE_SHARE, table_name_hash,
08467           innobase_open_tables, fold, share);
08468 
08469     thr_lock_init(&share->lock);
08470 
08471     /* Index translation table initialization */
08472     share->idx_trans_tbl.index_mapping = NULL;
08473     share->idx_trans_tbl.index_count = 0;
08474     share->idx_trans_tbl.array_size = 0;
08475   }
08476 
08477   share->use_count++;
08478 
08479   return(share);
08480 }
08481 
08482 static void free_share(INNOBASE_SHARE* share)
08483 {
08484   boost::mutex::scoped_lock scopedLock(innobase_share_mutex);
08485 
08486 #ifdef UNIV_DEBUG
08487   INNOBASE_SHARE* share2;
08488   ulint fold = ut_fold_string(share->table_name);
08489 
08490   HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
08491         INNOBASE_SHARE*, share2,
08492         ut_ad(share->use_count > 0),
08493         !strcmp(share->table_name, share2->table_name));
08494 
08495   ut_a(share2 == share);
08496 #endif /* UNIV_DEBUG */
08497 
08498   if (!--share->use_count) {
08499     ulint fold = ut_fold_string(share->table_name);
08500 
08501     HASH_DELETE(INNOBASE_SHARE, table_name_hash,
08502           innobase_open_tables, fold, share);
08503 
08504     /* Free any memory from index translation table */
08505     free(share->idx_trans_tbl.index_mapping);
08506 
08507     delete share;
08508 
08509     /* TODO: invoke HASH_MIGRATE if innobase_open_tables
08510     shrinks too much */
08511   }
08512 }
08513 
08514 /*****************************************************************/
08523 UNIV_INTERN
08524 THR_LOCK_DATA**
08525 ha_innobase::store_lock(
08526 /*====================*/
08527   Session*    session,  
08528   THR_LOCK_DATA**   to,   
08533   enum thr_lock_type  lock_type)  
08536 {
08537   trx_t*    trx;
08538 
08539   /* Note that trx in this function is NOT necessarily prebuilt->trx
08540   because we call update_session() later, in ::external_lock()! Failure to
08541   understand this caused a serious memory corruption bug in 5.1.11. */
08542 
08543   trx = check_trx_exists(session);
08544 
08545   assert(EQ_CURRENT_SESSION(session));
08546   const uint32_t sql_command = session->getSqlCommand();
08547 
08548   if (sql_command == SQLCOM_DROP_TABLE) {
08549 
08550     /* MySQL calls this function in DROP Table though this table
08551     handle may belong to another session that is running a query.
08552     Let us in that case skip any changes to the prebuilt struct. */ 
08553 
08554   } else if (lock_type == TL_READ_WITH_SHARED_LOCKS
08555        || lock_type == TL_READ_NO_INSERT
08556        || (lock_type != TL_IGNORE
08557            && sql_command != SQLCOM_SELECT)) {
08558 
08559     /* The OR cases above are in this order:
08560     1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
08561     are processing a stored procedure or function, or
08562     2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
08563     3) this is a SELECT ... IN SHARE MODE, or
08564     4) we are doing a complex SQL statement like
08565     INSERT INTO ... SELECT ... and the logical logging (MySQL
08566     binlog) requires the use of a locking read, or
08567     MySQL is doing LOCK TABLES ... READ.
08568     5) we let InnoDB do locking reads for all SQL statements that
08569     are not simple SELECTs; note that select_lock_type in this
08570     case may get strengthened in ::external_lock() to LOCK_X.
08571     Note that we MUST use a locking read in all data modifying
08572     SQL statements, because otherwise the execution would not be
08573     serializable, and also the results from the update could be
08574     unexpected if an obsolete consistent read view would be
08575     used. */
08576 
08577     ulint isolation_level;
08578 
08579     isolation_level = trx->isolation_level;
08580 
08581     if ((srv_locks_unsafe_for_binlog
08582          || isolation_level <= TRX_ISO_READ_COMMITTED)
08583         && isolation_level != TRX_ISO_SERIALIZABLE
08584         && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
08585         && (sql_command == SQLCOM_INSERT_SELECT
08586             || sql_command == SQLCOM_REPLACE_SELECT
08587             || sql_command == SQLCOM_UPDATE
08588             || sql_command == SQLCOM_CREATE_TABLE
08589             || sql_command == SQLCOM_SET_OPTION)) {
08590 
08591       /* If we either have innobase_locks_unsafe_for_binlog
08592       option set or this session is using READ COMMITTED
08593       isolation level and isolation level of the transaction
08594       is not set to serializable and MySQL is doing
08595       INSERT INTO...SELECT or REPLACE INTO...SELECT
08596       or UPDATE ... = (SELECT ...) or CREATE  ...
08597       SELECT... or SET ... = (SELECT ...) without
08598       FOR UPDATE or IN SHARE MODE in select,
08599       then we use consistent read for select. */
08600 
08601       prebuilt->select_lock_type = LOCK_NONE;
08602       prebuilt->stored_select_lock_type = LOCK_NONE;
08603     } else if (sql_command == SQLCOM_CHECKSUM) {
08604       /* Use consistent read for checksum table */
08605 
08606       prebuilt->select_lock_type = LOCK_NONE;
08607       prebuilt->stored_select_lock_type = LOCK_NONE;
08608     } else {
08609       prebuilt->select_lock_type = LOCK_S;
08610       prebuilt->stored_select_lock_type = LOCK_S;
08611     }
08612 
08613   } else if (lock_type != TL_IGNORE) {
08614 
08615     /* We set possible LOCK_X value in external_lock, not yet
08616     here even if this would be SELECT ... FOR UPDATE */
08617 
08618     prebuilt->select_lock_type = LOCK_NONE;
08619     prebuilt->stored_select_lock_type = LOCK_NONE;
08620   }
08621 
08622   if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
08623 
08624     /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
08625     TABLESPACE or TRUNCATE TABLE then allow multiple
08626     writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
08627     < TL_WRITE_CONCURRENT_INSERT.
08628     */
08629 
08630     if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
08631          && lock_type <= TL_WRITE)
08632         && ! session->doing_tablespace_operation()
08633         && sql_command != SQLCOM_TRUNCATE
08634         && sql_command != SQLCOM_CREATE_TABLE) {
08635 
08636       lock_type = TL_WRITE_ALLOW_WRITE;
08637     }
08638 
08639     /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
08640     MySQL would use the lock TL_READ_NO_INSERT on t2, and that
08641     would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
08642     to t2. Convert the lock to a normal read lock to allow
08643     concurrent inserts to t2.
08644     */
08645 
08646     if (lock_type == TL_READ_NO_INSERT) {
08647 
08648       lock_type = TL_READ;
08649     }
08650 
08651     lock.type = lock_type;
08652   }
08653 
08654   *to++= &lock;
08655 
08656   return(to);
08657 }
08658 
08659 /*********************************************************************/
08664 UNIV_INTERN
08665 ulint
08666 ha_innobase::innobase_get_autoinc(
08667 /*==============================*/
08668   uint64_t* value)    
08669 {
08670   *value = 0;
08671 
08672   dict_table_autoinc_lock(prebuilt->table);
08673   prebuilt->autoinc_error= DB_SUCCESS;
08674   /* Determine the first value of the interval */
08675   *value = dict_table_autoinc_read(prebuilt->table);
08676 
08677   /* It should have been initialized during open. */
08678   if (*value == 0) {
08679     prebuilt->autoinc_error = DB_UNSUPPORTED;
08680     dict_table_autoinc_unlock(prebuilt->table);
08681   }
08682 
08683   return(DB_SUCCESS);
08684 }
08685 
08686 /*******************************************************************/
08690 UNIV_INTERN
08691 uint64_t
08692 ha_innobase::innobase_peek_autoinc(void)
08693 /*====================================*/
08694 {
08695   uint64_t  auto_inc;
08696   dict_table_t* innodb_table;
08697 
08698   ut_a(prebuilt != NULL);
08699   ut_a(prebuilt->table != NULL);
08700 
08701   innodb_table = prebuilt->table;
08702 
08703   dict_table_autoinc_lock(innodb_table);
08704 
08705   auto_inc = dict_table_autoinc_read(innodb_table);
08706 
08707   if (auto_inc == 0) {
08708     ut_print_timestamp(stderr);
08709     errmsg_printf(error::ERROR, "  InnoDB: AUTOINC next value generation is disabled for '%s'\n", innodb_table->name);
08710   }
08711 
08712   dict_table_autoinc_unlock(innodb_table);
08713 
08714   return(auto_inc);
08715 }
08716 
08717 /*********************************************************************/
08724 UNIV_INTERN
08725 void
08726 ha_innobase::get_auto_increment(
08727 /*============================*/
08728         uint64_t  offset,              
08729         uint64_t  increment,           
08730         uint64_t  nb_desired_values,   
08731         uint64_t  *first_value,        
08732         uint64_t  *nb_reserved_values) 
08733 {
08734   trx_t*    trx;
08735   ulint   error;
08736   uint64_t  autoinc = 0;
08737 
08738   /* Prepare prebuilt->trx in the table handle */
08739   update_session(getTable()->in_use);
08740 
08741   error = innobase_get_autoinc(&autoinc);
08742 
08743   if (error != DB_SUCCESS) {
08744     *first_value = (~(uint64_t) 0);
08745     return;
08746   }
08747 
08748   /* This is a hack, since nb_desired_values seems to be accurate only
08749   for the first call to get_auto_increment() for multi-row INSERT and
08750   meaningless for other statements e.g, LOAD etc. Subsequent calls to
08751   this method for the same statement results in different values which
08752   don't make sense. Therefore we store the value the first time we are
08753   called and count down from that as rows are written (see doInsertRecord()).
08754   */
08755 
08756   trx = prebuilt->trx;
08757 
08758   /* Note: We can't rely on *first_value since some MySQL engines,
08759   in particular the partition engine, don't initialize it to 0 when
08760   invoking this method. So we are not sure if it's guaranteed to
08761   be 0 or not. */
08762 
08763   /* We need the upper limit of the col type to check for
08764      whether we update the table autoinc counter or not. */
08765   uint64_t col_max_value = innobase_get_int_col_max_value(getTable()->next_number_field);
08766 
08767   /* Called for the first time ? */
08768   if (trx->n_autoinc_rows == 0) {
08769 
08770     trx->n_autoinc_rows = (ulint) nb_desired_values;
08771 
08772     /* It's possible for nb_desired_values to be 0:
08773     e.g., INSERT INTO T1(C) SELECT C FROM T2; */
08774     if (nb_desired_values == 0) {
08775 
08776       trx->n_autoinc_rows = 1;
08777     }
08778 
08779     set_if_bigger(*first_value, autoinc);
08780   /* Not in the middle of a mult-row INSERT. */
08781   } else if (prebuilt->autoinc_last_value == 0) {
08782     set_if_bigger(*first_value, autoinc);
08783     /* Check for -ve values. */
08784   } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
08785     /* Set to next logical value. */
08786     ut_a(autoinc > trx->n_autoinc_rows);
08787     *first_value = (autoinc - trx->n_autoinc_rows) - 1;
08788   }
08789 
08790   *nb_reserved_values = trx->n_autoinc_rows;
08791 
08792   /* This all current style autoinc. */
08793   {
08794     uint64_t  need;
08795     uint64_t  current;
08796     uint64_t  next_value;
08797 
08798     current = *first_value > col_max_value ? autoinc : *first_value;
08799     need = *nb_reserved_values * increment;
08800 
08801     /* Compute the last value in the interval */
08802     next_value = innobase_next_autoinc(current, need, offset, col_max_value);
08803 
08804     prebuilt->autoinc_last_value = next_value;
08805 
08806     if (prebuilt->autoinc_last_value < *first_value) {
08807       *first_value = (~(unsigned long long) 0);
08808     } else {
08809       /* Update the table autoinc variable */
08810       dict_table_autoinc_update_if_greater(
08811         prebuilt->table, prebuilt->autoinc_last_value);
08812     }
08813   }
08814 
08815   /* The increment to be used to increase the AUTOINC value, we use
08816   this in doInsertRecord() and doUpdateRecord() to increase the autoinc counter
08817   for columns that are filled by the user. We need the offset and
08818   the increment. */
08819   prebuilt->autoinc_offset = offset;
08820   prebuilt->autoinc_increment = increment;
08821 
08822   dict_table_autoinc_unlock(prebuilt->table);
08823 }
08824 
08825 /*******************************************************************/
08831 UNIV_INTERN
08832 int
08833 ha_innobase::reset_auto_increment(
08834 /*==============================*/
08835   uint64_t  value)    
08836 {
08837   int error;
08838 
08839   update_session(getTable()->in_use);
08840 
08841   error = row_lock_table_autoinc_for_mysql(prebuilt);
08842 
08843   if (error != DB_SUCCESS) {
08844     error = convert_error_code_to_mysql(error,
08845                 prebuilt->table->flags,
08846                 user_session);
08847 
08848     return(error);
08849   }
08850 
08851   /* The next value can never be 0. */
08852   if (value == 0) {
08853     value = 1;
08854   }
08855 
08856   innobase_reset_autoinc(value);
08857 
08858   return 0;
08859 }
08860 
08861 /* See comment in Cursor.cc */
08862 UNIV_INTERN
08863 bool
08864 InnobaseEngine::get_error_message(int, String *buf) const
08865 {
08866   trx_t*  trx = check_trx_exists(current_session);
08867 
08868   buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
08869     system_charset_info);
08870 
08871   return(FALSE);
08872 }
08873 
08874 /*******************************************************************/
08879 UNIV_INTERN
08880 int
08881 ha_innobase::cmp_ref(
08882 /*=================*/
08883   const unsigned char*  ref1, 
08885   const unsigned char*  ref2) 
08887 {
08888   enum_field_types mysql_type;
08889   Field*    field;
08890   KeyPartInfo*  key_part;
08891   KeyPartInfo*  key_part_end;
08892   uint    len1;
08893   uint    len2;
08894   int   result;
08895 
08896   if (prebuilt->clust_index_was_generated) {
08897     /* The 'ref' is an InnoDB row id */
08898 
08899     return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
08900   }
08901 
08902   /* Do a type-aware comparison of primary key fields. PK fields
08903   are always NOT NULL, so no checks for NULL are performed. */
08904 
08905   key_part = getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_part;
08906 
08907   key_part_end = key_part
08908       + getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_parts;
08909 
08910   for (; key_part != key_part_end; ++key_part) {
08911     field = key_part->field;
08912     mysql_type = field->type();
08913 
08914     if (mysql_type == DRIZZLE_TYPE_BLOB) {
08915 
08916       /* In the MySQL key value format, a column prefix of
08917       a BLOB is preceded by a 2-byte length field */
08918 
08919       len1 = innobase_read_from_2_little_endian(ref1);
08920       len2 = innobase_read_from_2_little_endian(ref2);
08921 
08922       ref1 += 2;
08923       ref2 += 2;
08924       result = ((Field_blob*)field)->cmp( ref1, len1,
08925                                                             ref2, len2);
08926     } else {
08927       result = field->key_cmp(ref1, ref2);
08928     }
08929 
08930     if (result) {
08931 
08932       return(result);
08933     }
08934 
08935     ref1 += key_part->store_length;
08936     ref2 += key_part->store_length;
08937   }
08938 
08939   return(0);
08940 }
08941 
08942 /**********************************************************************
08943 This function is used to find the storage length in bytes of the first n
08944 characters for prefix indexes using a multibyte character set. The function
08945 finds charset information and returns length of prefix_len characters in the
08946 index field in bytes.
08947 @return number of bytes occupied by the first n characters */
08948 
08949 ulint
08950 innobase_get_at_most_n_mbchars(
08951 /*===========================*/
08952   ulint charset_id, 
08953   ulint prefix_len, 
08956   ulint data_len,   
08957   const char* str)  
08958 {
08959   ulint char_length;    
08960   ulint n_chars;      
08961   const charset_info_st* charset;  
08963   charset = get_charset((uint) charset_id);
08964 
08965   ut_ad(charset);
08966   ut_ad(charset->mbmaxlen);
08967 
08968   /* Calculate how many characters at most the prefix index contains */
08969 
08970   n_chars = prefix_len / charset->mbmaxlen;
08971 
08972   /* If the charset is multi-byte, then we must find the length of the
08973   first at most n chars in the string. If the string contains less
08974   characters than n, then we return the length to the end of the last
08975   character. */
08976 
08977   if (charset->mbmaxlen > 1) {
08978     /* my_charpos() returns the byte length of the first n_chars
08979     characters, or a value bigger than the length of str, if
08980     there were not enough full characters in str.
08981 
08982     Why does the code below work:
08983     Suppose that we are looking for n UTF-8 characters.
08984 
08985     1) If the string is long enough, then the prefix contains at
08986     least n complete UTF-8 characters + maybe some extra
08987     characters + an incomplete UTF-8 character. No problem in
08988     this case. The function returns the pointer to the
08989     end of the nth character.
08990 
08991     2) If the string is not long enough, then the string contains
08992     the complete value of a column, that is, only complete UTF-8
08993     characters, and we can store in the column prefix index the
08994     whole string. */
08995 
08996     char_length = my_charpos(charset, str,
08997             str + data_len, (int) n_chars);
08998     if (char_length > data_len) {
08999       char_length = data_len;
09000     }
09001   } else {
09002     if (data_len < prefix_len) {
09003       char_length = data_len;
09004     } else {
09005       char_length = prefix_len;
09006     }
09007   }
09008 
09009   return(char_length);
09010 }
09017 void
09018 InnobaseEngine::doStartStatement(
09019   Session *session) 
09020 {
09021   /* 
09022    * Create the InnoDB transaction structure
09023    * for the session
09024    */
09025   trx_t *trx= check_trx_exists(session);
09026 
09027   /* "reset" the error message for the transaction */
09028   trx->detailed_error[0]= '\0';
09029 
09030   /* Set the isolation level of the transaction. */
09031   trx->isolation_level= innobase_map_isolation_level(session->getTxIsolation());
09032 }
09033 
09034 void
09035 InnobaseEngine::doEndStatement(
09036   Session *session)
09037 {
09038   trx_t *trx= check_trx_exists(session);
09039 
09040   /* Release a possible FIFO ticket and search latch. Since we
09041   may reserve the kernel mutex, we have to release the search
09042   system latch first to obey the latching order. */
09043 
09044   innobase_release_stat_resources(trx);
09045 
09046 }
09047 
09048 /*******************************************************************/
09051 int
09052 InnobaseEngine::doXaPrepare(
09053 /*================*/
09054   Session*  session,
09057   bool    all)  
09060 {
09061   int error = 0;
09062   trx_t* trx = check_trx_exists(session);
09063 
09064   assert(this == innodb_engine_ptr);
09065 
09066   /* we use support_xa value as it was seen at transaction start
09067   time, not the current session variable value. Any possible changes
09068   to the session variable take effect only in the next transaction */
09069   if (!trx->support_xa) {
09070 
09071     return(0);
09072   }
09073 
09074   session->get_xid(reinterpret_cast<DrizzleXid*>(&trx->xid));
09075 
09076   /* Release a possible FIFO ticket and search latch. Since we will
09077   reserve the kernel mutex, we have to release the search system latch
09078   first to obey the latching order. */
09079 
09080   innobase_release_stat_resources(trx);
09081 
09082   if (all
09083     || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
09084 
09085     /* We were instructed to prepare the whole transaction, or
09086     this is an SQL statement end and autocommit is on */
09087 
09088     ut_ad(trx->conc_state != TRX_NOT_STARTED);
09089 
09090     error = (int) trx_prepare_for_mysql(trx);
09091   } else {
09092     /* We just mark the SQL statement ended and do not do a
09093     transaction prepare */
09094 
09095     /* If we had reserved the auto-inc lock for some
09096     table in this SQL statement we release it now */
09097 
09098     row_unlock_table_autoinc_for_mysql(trx);
09099 
09100     /* Store the current undo_no of the transaction so that we
09101     know where to roll back if we have to roll back the next
09102     SQL statement */
09103 
09104     trx_mark_sql_stat_end(trx);
09105   }
09106 
09107   /* Tell the InnoDB server that there might be work for utility
09108   threads: */
09109 
09110   srv_active_wake_master_thread();
09111 
09112   return(error);
09113 }
09114 
09115 uint64_t InnobaseEngine::doGetCurrentTransactionId(Session *session)
09116 {
09117   trx_t *trx= session_to_trx(session);
09118   return (trx->id);
09119 }
09120 
09121 uint64_t InnobaseEngine::doGetNewTransactionId(Session *session)
09122 {
09123   trx_t*& trx = session_to_trx(session);
09124 
09125   if (trx == NULL)
09126   {
09127     trx = innobase_trx_allocate(session);
09128 
09129     innobase_trx_init(session, trx);
09130   }
09131 
09132   mutex_enter(&kernel_mutex);
09133   trx->id= trx_sys_get_new_trx_id();
09134   mutex_exit(&kernel_mutex);
09135 
09136   uint64_t transaction_id= trx->id;
09137 
09138   return transaction_id;
09139 }
09140 
09141 /*******************************************************************/
09144 int
09145 InnobaseEngine::doXaRecover(
09146 /*================*/
09147   ::drizzled::XID*  xid_list,
09148   size_t len) 
09149 {
09150   assert(this == innodb_engine_ptr);
09151 
09152   if (len == 0 || xid_list == NULL) {
09153 
09154     return(0);
09155   }
09156 
09157   return(trx_recover_for_mysql((::XID *)xid_list, len));
09158 }
09159 
09160 /*******************************************************************/
09164 int
09165 InnobaseEngine::doXaCommitXid(
09166 /*===================*/
09167   ::drizzled::XID*  xid)  
09168 {
09169   trx_t*  trx;
09170 
09171   assert(this == innodb_engine_ptr);
09172 
09173   trx = trx_get_trx_by_xid((::XID *)xid);
09174 
09175   if (trx) {
09176     innobase_commit_low(trx);
09177 
09178     return(XA_OK);
09179   } else {
09180     return(XAER_NOTA);
09181   }
09182 }
09183 
09184 /*******************************************************************/
09188 int
09189 InnobaseEngine::doXaRollbackXid(
09190 /*=====================*/
09191   ::drizzled::XID*    xid)  
09193 {
09194   trx_t*  trx;
09195 
09196   assert(this == innodb_engine_ptr);
09197 
09198   trx = trx_get_trx_by_xid((::XID *)xid);
09199 
09200   if (trx) {
09201     return(innobase_rollback_trx(trx));
09202   } else {
09203     return(XAER_NOTA);
09204   }
09205 }
09206 
09207 
09208 /************************************************************/
09211 static
09212 uint
09213 innobase_file_format_name_lookup(
09214 /*=============================*/
09215   const char* format_name)  
09216 {
09217   char* endp;
09218   uint  format_id;
09219 
09220   ut_a(format_name != NULL);
09221 
09222   /* The format name can contain the format id itself instead of
09223   the name and we check for that. */
09224   format_id = (uint) strtoul(format_name, &endp, 10);
09225 
09226   /* Check for valid parse. */
09227   if (*endp == '\0' && *format_name != '\0') {
09228 
09229     if (format_id <= DICT_TF_FORMAT_MAX) {
09230 
09231       return(format_id);
09232     }
09233   } else {
09234 
09235     for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
09236          format_id++) {
09237       const char* name;
09238 
09239       name = trx_sys_file_format_id_to_name(format_id);
09240 
09241       if (!innobase_strcasecmp(format_name, name)) {
09242 
09243         return(format_id);
09244       }
09245     }
09246   }
09247 
09248   return(DICT_TF_FORMAT_MAX + 1);
09249 }
09250 
09251 /************************************************************/
09255 static
09256 int
09257 innobase_file_format_validate_and_set(
09258 /*================================*/
09259   const char* format_max) 
09260 {
09261   uint    format_id;
09262 
09263   format_id = innobase_file_format_name_lookup(format_max);
09264 
09265   if (format_id < DICT_TF_FORMAT_MAX + 1) {
09266     srv_max_file_format_at_startup = format_id;
09267     return((int) format_id);
09268   } else {
09269     return(-1);
09270   }
09271 }
09272 
09273 
09274 
09275 static void init_options(drizzled::module::option_context &context)
09276 {
09277   context("disable-checksums",
09278           "Disable InnoDB checksums validation.");
09279   context("data-home-dir",
09280           po::value<string>(),
09281           "The common part for InnoDB table spaces.");
09282   context("disable-doublewrite",
09283           "Disable InnoDB doublewrite buffer.");
09284   context("io-capacity",
09285           po::value<io_capacity_constraint>(&innodb_io_capacity)->default_value(200),
09286           "Number of IOPs the server can do. Tunes the background IO rate");
09287   context("fast-shutdown",
09288           po::value<trinary_constraint>(&innobase_fast_shutdown)->default_value(1), 
09289           "Speeds up the shutdown process of the InnoDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like).");
09290   context("purge-batch-size",
09291           po::value<purge_batch_constraint>(&innodb_purge_batch_size)->default_value(20),
09292           "Number of UNDO logs to purge in one batch from the history list. "
09293           "Default is 20.");
09294   context("purge-threads",
09295           po::value<purge_threads_constraint>(&innodb_n_purge_threads)->default_value(1),
09296           "Purge threads can be either 0 or 1. Default is 1.");
09297   context("file-per-table",
09298           po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
09299            "Stores each InnoDB table to an .ibd file in the database dir.");
09300   context("file-format-max",
09301           po::value<string>(&innobase_file_format_max)->default_value("Antelope"),
09302           "The highest file format in the tablespace.");
09303   context("file-format-check",
09304           po::value<bool>(&innobase_file_format_check)->default_value(true)->zero_tokens(),
09305           "Whether to perform system file format check.");
09306   context("file-format",
09307           po::value<string>(&innobase_file_format_name)->default_value("Antelope"),
09308           "File format to use for new tables in .ibd files.");
09309   context("flush-log-at-trx-commit",
09310           po::value<trinary_constraint>(&innodb_flush_log_at_trx_commit)->default_value(1),
09311           "Set to 0 (write and flush once per second), 1 (write and flush at each commit) or 2 (write at commit, flush once per second).");
09312   context("flush-method",
09313           po::value<string>(),
09314           "With which method to flush data.");
09315   context("log-group-home-dir",
09316           po::value<string>(),
09317           "Path to InnoDB log files.");
09318   context("max-dirty-pages-pct",
09319           po::value<max_dirty_pages_constraint>(&innodb_max_dirty_pages_pct)->default_value(75),
09320           "Percentage of dirty pages allowed in bufferpool.");
09321   context("disable-adaptive-flushing",
09322           "Do not attempt flushing dirty pages to avoid IO bursts at checkpoints.");
09323   context("max-purge-lag",
09324           po::value<uint64_constraint>(&innodb_max_purge_lag)->default_value(0),
09325           "Desired maximum length of the purge queue (0 = no limit)");
09326   context("status-file",
09327           po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
09328           "Enable SHOW INNODB STATUS output in the innodb_status.<pid> file");
09329   context("disable-stats-on-metadata",
09330           "Disable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)");
09331   context("stats-sample-pages",
09332           po::value<uint64_nonzero_constraint>(&innodb_stats_sample_pages)->default_value(8),
09333           "The number of index pages to sample when calculating statistics (default 8)");
09334   context("disable-adaptive-hash-index",
09335           "Enable InnoDB adaptive hash index (enabled by default)");
09336   context("replication-delay",
09337           po::value<uint64_constraint>(&innodb_replication_delay)->default_value(0),
09338           "Replication thread delay (ms) on the slave server if innodb_thread_concurrency is reached (0 by default)");
09339   context("additional-mem-pool-size",
09340           po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
09341           "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.");
09342   context("autoextend-increment",
09343           po::value<autoextend_constraint>(&innodb_auto_extend_increment)->default_value(64L),
09344           "Data file autoextend increment in megabytes");
09345   context("buffer-pool-size",
09346           po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
09347           "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.");
09348   context("buffer-pool-instances",
09349           po::value<buffer_pool_instances_constraint>(&innobase_buffer_pool_instances)->default_value(1),
09350           "Number of buffer pool instances, set to higher value on high-end machines to increase scalability");
09351 
09352   context("commit-concurrency",
09353           po::value<concurrency_constraint>(&innobase_commit_concurrency)->default_value(0),
09354           "Helps in performance tuning in heavily concurrent environments.");
09355   context("concurrency-tickets",
09356           po::value<uint32_nonzero_constraint>(&innodb_concurrency_tickets)->default_value(500L),
09357           "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket");
09358   context("read-io-threads",
09359           po::value<io_threads_constraint>(&innobase_read_io_threads)->default_value(4),
09360           "Number of background read I/O threads in InnoDB.");
09361   context("write-io-threads",
09362           po::value<io_threads_constraint>(&innobase_write_io_threads)->default_value(4),
09363           "Number of background write I/O threads in InnoDB.");
09364   context("force-recovery",
09365           po::value<force_recovery_constraint>(&innobase_force_recovery)->default_value(0),
09366           "Helps to save your data in case the disk image of the database becomes corrupt.");
09367   context("log-buffer-size",
09368           po::value<log_buffer_constraint>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
09369           "The size of the buffer which InnoDB uses to write log to the log files on disk.");
09370   context("log-file-size",
09371           po::value<log_file_constraint>(&innobase_log_file_size)->default_value(20*1024*1024L),
09372           "The size of the buffer which InnoDB uses to write log to the log files on disk.");
09373   context("page-size",
09374     po::value<page_size_constraint>(&innobase_page_size)->default_value(1 << 14),
09375     "###EXPERIMENTAL###: The universal page size of the database. Changing for created database is not supported. Use on your own risk!");
09376   context("log-block-size",
09377     po::value<log_block_size_constraint>(&innobase_log_block_size)->default_value(1 << 9),
09378     "###EXPERIMENTAL###: The log block size of the transaction log file. Changing for created log file is not supported. Use on your own risk!");
09379   context("log-files-in-group",
09380           po::value<log_files_in_group_constraint>(&innobase_log_files_in_group)->default_value(2),
09381           "Number of log files in the log group. InnoDB writes to the files in a circular fashion.");
09382   context("mirrored-log-groups",
09383           po::value<mirrored_log_groups_constraint>(&innobase_mirrored_log_groups)->default_value(1),
09384           "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.");
09385   context("open-files",
09386           po::value<open_files_constraint>(&innobase_open_files)->default_value(300L),
09387           "How many files at the maximum InnoDB keeps open at the same time.");
09388   context("sync-spin-loops",
09389           po::value<uint32_constraint>(&innodb_sync_spin_loops)->default_value(30L),
09390           "Count of spin-loop rounds in InnoDB mutexes (30 by default)");
09391   context("spin-wait-delay",
09392           po::value<uint32_constraint>(&innodb_spin_wait_delay)->default_value(6L),
09393           "Maximum delay between polling for a spin lock (6 by default)");
09394   context("thread-concurrency",
09395           po::value<concurrency_constraint>(&innobase_thread_concurrency)->default_value(0),
09396           "Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.");
09397   context("thread-sleep-delay",
09398           po::value<uint32_constraint>(&innodb_thread_sleep_delay)->default_value(10000L),
09399           "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep");
09400   context("data-file-path",
09401           po::value<string>(),
09402           "Path to individual files and their sizes.");
09403   context("version",
09404           po::value<string>()->default_value(INNODB_VERSION_STR),
09405           "InnoDB version");
09406   context("use-internal-malloc",
09407           "Use InnoDB's internal memory allocator instal of the OS memory allocator.");
09408   context("disable-native-aio",
09409           _("Do not use Native AIO library for IO, even if available"));
09410   context("change-buffering",
09411           po::value<string>(&innobase_change_buffering),
09412           "Buffer changes to reduce random access: OFF, ON, inserting, deleting, changing, or purging.");
09413   context("read-ahead-threshold",
09414           po::value<read_ahead_threshold_constraint>(&innodb_read_ahead_threshold)->default_value(56),
09415           "Number of pages that must be accessed sequentially for InnoDB to trigger a readahead.");
09416   context("auto-lru-dump",
09417     po::value<uint32_constraint>(&buffer_pool_restore_at_startup)->default_value(0),
09418     "Time in seconds between automatic buffer pool dumps. "
09419     "0 (the default) disables automatic dumps.");
09420   context("ibuf-max-size",
09421           po::value<uint64_constraint>(&ibuf_max_size)->default_value(UINT64_MAX),
09422           "The maximum size of the insert buffer (in bytes).");
09423   context("ibuf-active-contract",
09424           po::value<binary_constraint>(&ibuf_active_contract)->default_value(1),
09425           "Enable/Disable active_contract of insert buffer. 0:disable 1:enable");
09426   context("ibuf-accel-rate",
09427           po::value<ibuf_accel_rate_constraint>(&ibuf_accel_rate)->default_value(100),
09428           "Tunes amount of insert buffer processing of background, in addition to innodb_io_capacity. (in percentage)");
09429   context("checkpoint-age-target",
09430           po::value<uint32_constraint>(&checkpoint_age_target)->default_value(0),
09431           "Control soft limit of checkpoint age. (0 : not control)");
09432   context("flush-neighbor-pages",
09433           po::value<binary_constraint>(&flush_neighbor_pages)->default_value(1),
09434           "Enable/Disable flushing also neighbor pages. 0:disable 1:enable");
09435   context("read-ahead",
09436           po::value<string>(&read_ahead)->default_value("linear"),
09437           "Control read ahead activity (none, random, [linear], both). [from 1.0.5: random read ahead is ignored]");
09438   context("adaptive-flushing-method",
09439           po::value<string>(&adaptive_flushing_method)->default_value("estimate"),
09440           "Choose method of innodb_adaptive_flushing. (native, [estimate], keep_average)");
09441   context("disable-xa",
09442           "Disable InnoDB support for the XA two-phase commit");
09443   context("disable-table-locks",
09444           "Disable InnoDB locking in LOCK TABLES");
09445   context("strict-mode",
09446           po::value<bool>(&strict_mode)->default_value(false)->zero_tokens(),
09447           "Use strict mode when evaluating create options.");
09448   context("replication-log",
09449           po::value<bool>(&innobase_use_replication_log)->default_value(false)->zero_tokens(),
09450           _("Enable internal replication log."));
09451   context("lock-wait-timeout",
09452           po::value<lock_wait_constraint>(&lock_wait_timeout)->default_value(50),
09453           _("Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
09454   context("old-blocks-pct",
09455           po::value<old_blocks_constraint>(&innobase_old_blocks_pct)->default_value(100 * 3 / 8),
09456           _("Percentage of the buffer pool to reserve for 'old' blocks."));
09457   context("old-blocks-time",
09458           po::value<uint32_t>(&buf_LRU_old_threshold_ms)->default_value(0),
09459           _("ove blocks to the 'new' end of the buffer pool if the first access"
09460             " was at least this many milliseconds ago."
09461             " The timeout is disabled if 0 (the default)."));
09462 }
09463 
09464 
09465 
09466 DRIZZLE_DECLARE_PLUGIN
09467 {
09468   DRIZZLE_VERSION_ID,
09469   innobase_engine_name,
09470   INNODB_VERSION_STR,
09471   "Innobase Oy",
09472   "Supports transactions, row-level locking, and foreign keys",
09473   PLUGIN_LICENSE_GPL,
09474   innobase_init, /* Plugin Init */
09475   NULL, /* depends */
09476   init_options /* reserved */
09477 }
09478 DRIZZLE_DECLARE_PLUGIN_END;
09479 
09480 int ha_innobase::read_range_first(const key_range *start_key,
09481           const key_range *end_key,
09482           bool eq_range_arg,
09483           bool sorted)
09484 {
09485   int res;
09486   //if (!eq_range_arg)
09487     //in_range_read= TRUE;
09488   res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
09489   //if (res)
09490   //  in_range_read= FALSE;
09491   return res;
09492 }
09493 
09494 
09495 int ha_innobase::read_range_next()
09496 {
09497   int res= Cursor::read_range_next();
09498   //if (res)
09499   //  in_range_read= FALSE;
09500   return res;
09501 }
09502 
09503 /***********************************************************************
09504 This function checks each index name for a table against reserved
09505 system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
09506 this function pushes an warning message to the client, and returns true. */
09507 UNIV_INTERN
09508 bool
09509 innobase_index_name_is_reserved(
09510 /*============================*/
09511           /* out: true if an index name
09512           matches the reserved name */
09513   const trx_t*  trx,    /* in: InnoDB transaction handle */
09514   const KeyInfo*  key_info, /* in: Indexes to be created */
09515   ulint   num_of_keys)  /* in: Number of indexes to
09516           be created. */
09517 {
09518   const KeyInfo*  key;
09519   uint    key_num;  /* index number */
09520 
09521   for (key_num = 0; key_num < num_of_keys; key_num++) {
09522     key = &key_info[key_num];
09523 
09524     if (innobase_strcasecmp(key->name,
09525                             innobase_index_reserve_name) == 0) {
09526       /* Push warning to drizzle */
09527       push_warning_printf(trx->mysql_thd,
09528                           DRIZZLE_ERROR::WARN_LEVEL_WARN,
09529                           ER_WRONG_NAME_FOR_INDEX,
09530                           "Cannot Create Index with name "
09531                           "'%s'. The name is reserved "
09532                           "for the system default primary "
09533                           "index.",
09534                           innobase_index_reserve_name);
09535 
09536       my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
09537                innobase_index_reserve_name);
09538 
09539       return(true);
09540     }
09541   }
09542 
09543   return(false);
09544 }
09545 
09546 #ifdef UNIV_COMPILE_TEST_FUNCS
09547 
09548 typedef struct innobase_convert_name_test_struct {
09549   char*   buf;
09550   ulint   buflen;
09551   const char* id;
09552   ulint   idlen;
09553   drizzled::Session *session;
09554   ibool   file_id;
09555 
09556   const char* expected;
09557 } innobase_convert_name_test_t;
09558 
09559 void
09560 test_innobase_convert_name()
09561 {
09562   char  buf[1024];
09563   ulint i;
09564 
09565   innobase_convert_name_test_t test_input[] = {
09566     {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
09567     {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
09568     {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
09569     {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
09570     {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
09571 
09572     {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
09573     {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
09574     {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
09575     {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
09576     {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
09577     {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
09578     {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
09579 
09580     {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
09581       "\"#mysql50#ab\"\"cd\""},
09582     {buf, 17, "ab\"cd", 5, NULL, TRUE,
09583       "\"#mysql50#ab\"\"cd\""},
09584     {buf, 16, "ab\"cd", 5, NULL, TRUE,
09585       "\"#mysql50#ab\"\"c\""},
09586     {buf, 15, "ab\"cd", 5, NULL, TRUE,
09587       "\"#mysql50#ab\"\"\""},
09588     {buf, 14, "ab\"cd", 5, NULL, TRUE,
09589       "\"#mysql50#ab\""},
09590     {buf, 13, "ab\"cd", 5, NULL, TRUE,
09591       "\"#mysql50#ab\""},
09592     {buf, 12, "ab\"cd", 5, NULL, TRUE,
09593       "\"#mysql50#a\""},
09594     {buf, 11, "ab\"cd", 5, NULL, TRUE,
09595       "\"#mysql50#\""},
09596     {buf, 10, "ab\"cd", 5, NULL, TRUE,
09597       "\"#mysql50\""},
09598 
09599     {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
09600     {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
09601     {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
09602     {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
09603     {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
09604     {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
09605     {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
09606     {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
09607     {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
09608     /* XXX probably "" is a better result in this case
09609     {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
09610     */
09611     {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
09612   };
09613 
09614   for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
09615 
09616     char* end;
09617     ibool ok = TRUE;
09618     size_t  res_len;
09619 
09620     fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
09621       test_input[i].buflen,
09622       test_input[i].id,
09623       test_input[i].idlen,
09624       test_input[i].expected);
09625 
09626     end = innobase_convert_name(
09627       test_input[i].buf,
09628       test_input[i].buflen,
09629       test_input[i].id,
09630       test_input[i].idlen,
09631       test_input[i].session,
09632       test_input[i].file_id);
09633 
09634     res_len = (size_t) (end - test_input[i].buf);
09635 
09636     if (res_len != strlen(test_input[i].expected)) {
09637 
09638       fprintf(stderr, "unexpected len of the result: %u, "
09639         "expected: %u\n", (unsigned) res_len,
09640         (unsigned) strlen(test_input[i].expected));
09641       ok = FALSE;
09642     }
09643 
09644     if (memcmp(test_input[i].buf,
09645          test_input[i].expected,
09646          strlen(test_input[i].expected)) != 0
09647         || !ok) {
09648 
09649       fprintf(stderr, "unexpected result: %.*s, "
09650         "expected: %s\n", (int) res_len,
09651         test_input[i].buf,
09652         test_input[i].expected);
09653       ok = FALSE;
09654     }
09655 
09656     if (ok) {
09657       fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
09658         buf);
09659     } else {
09660       fprintf(stderr, "FAILED\n\n");
09661       return;
09662     }
09663   }
09664 }
09665 
09666 #endif /* UNIV_COMPILE_TEST_FUNCS */