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