00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
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
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
00152
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
00158 # define EQ_CURRENT_SESSION(session) ((session) == current_session)
00159 #endif
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
00220
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
00229
00230
00231 static string innobase_file_format_max;
00232
00233
00234
00235
00236 typedef constrained_check<uint32_t, 2, 0> trinary_constraint;
00237 static trinary_constraint innobase_fast_shutdown;
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
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
00265
00266
00267
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__
00275 bool nw_panic = FALSE;
00276 #endif
00277
00279 static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
00280 "none",
00281 "inserts",
00282 "deletes",
00283 "changes",
00284 "purges",
00285 "all"
00286 };
00287
00288
00289
00290 static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX";
00291
00292
00293
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
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
00351 Session* session);
00352
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);
00363 }
00364 virtual int doXaRollback(Session *session, bool all)
00365 {
00366 return doRollback(session, all);
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
00375 virtual
00376 int
00377 doXaPrepare(
00378
00379
00380 Session* session,
00381
00382 bool all);
00383
00384
00385
00386 virtual
00387 int
00388 doXaRecover(
00389
00390
00391
00392 ::drizzled::XID* xid_list,
00393 size_t len);
00394
00395
00396
00397 virtual
00398 int
00399 doXaCommitXid(
00400
00401
00402 ::drizzled::XID* xid);
00403
00404
00405
00406 virtual
00407 int
00408 doXaRollbackXid(
00409
00410
00411 ::drizzled::XID *xid);
00412
00413 virtual Cursor *create(Table &table)
00414 {
00415 return new ha_innobase(*this, table);
00416 }
00417
00418
00419
00420 bool
00421 doDropSchema(
00422
00423
00424 const identifier::Schema &identifier);
00425
00426
00427
00428
00429
00430
00431
00432 virtual
00433 bool
00434 flush_logs();
00435
00436
00437
00438
00439
00440
00441 virtual
00442 bool
00443 show_status(
00444
00445 Session* session,
00446 stat_print_fn *stat_print,
00447 enum ha_stat_type stat_type);
00448
00449 virtual
00450 int
00451 doReleaseTemporaryLatches(
00452
00453
00454 Session* session);
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
00559
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
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
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
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
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
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
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
00907 return(support_xa);
00908 }
00909
00910
00913 UNIV_INTERN
00914 ulong
00915 thd_lock_wait_timeout(
00916
00917 drizzled::Session*)
00919 {
00920
00921
00922
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
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
01050
01051 case DB_ERROR:
01052 default:
01053 return(-1);
01054
01055 case DB_DUPLICATE_KEY:
01056
01057
01058
01059
01060
01061
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
01075
01076
01077
01078 session->markTransactionForRollback(TRUE);
01079
01080 return(HA_ERR_LOCK_DEADLOCK);
01081
01082 case DB_LOCK_WAIT_TIMEOUT:
01083
01084
01085
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);
01105
01106
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
01131
01132
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
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155 #ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS
01156 return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
01157 #else
01158 return(HA_ERR_RECORD_FILE_FULL);
01159 #endif
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;
01296 HANDLE osfh;
01297 char* tmpdir;
01298
01299 TCHAR path_buf[MAX_PATH - 14];
01300
01301
01302
01303 char filename[MAX_PATH];
01304 DWORD fileaccess = GENERIC_READ
01305 | GENERIC_WRITE
01306 | DELETE;
01307 DWORD fileshare = FILE_SHARE_READ
01308 | FILE_SHARE_WRITE
01309 | FILE_SHARE_DELETE;
01310 DWORD filecreate = CREATE_ALWAYS;
01311 DWORD fileattrib =
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
01320 if (!tmpdir) {
01321 uint ret;
01322
01323
01324 ret = GetTempPath(sizeof(path_buf), path_buf);
01325 if (ret > sizeof(path_buf) || (ret == 0)) {
01326
01327 _dosmaperr(GetLastError());
01328 return(-1);
01329 }
01330
01331 tmpdir = path_buf;
01332 }
01333
01334
01335 if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
01336
01337 _dosmaperr(GetLastError());
01338 return(-1);
01339 }
01340
01341
01342 osfh = CreateFile(filename, fileaccess, fileshare, NULL,
01343 filecreate, fileattrib, NULL);
01344 if (osfh == INVALID_HANDLE_VALUE) {
01345
01346
01347 _dosmaperr(GetLastError());
01348 return(-1);
01349 }
01350
01351 do {
01352
01353 fd = _open_osfhandle((intptr_t) osfh, 0);
01354 } while (fd == -1 && errno == EINTR);
01355
01356 if (fd == -1) {
01357
01358
01359 _dosmaperr(GetLastError());
01360 CloseHandle(osfh);
01361
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
01379
01380
01381
01382
01383
01384
01385
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
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
01453 ut_a(increment > 0);
01454
01455
01456
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
01465
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
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
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),
01584
01585
01586
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
01646
01647
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
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
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
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
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
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
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
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
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
02087
02088 os_innodb_umask = (ulint)internal::my_umask;
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098 srv_data_home = (char *)innobase_data_home_dir.c_str();
02099
02100
02101
02102
02103
02104 if (innobase_data_file_path.empty())
02105 {
02106 innobase_data_file_path= std::string("ibdata1:10M:autoextend");
02107 }
02108
02109
02110
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
02127
02128
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
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
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
02173 if (!innobase_file_format_check)
02174 {
02175
02176 srv_max_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
02177 } else {
02178
02179 srv_max_file_format_at_startup = DICT_TF_FORMAT_MIN;
02180 }
02181
02182
02183
02184
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
02258
02259
02260 data_mysql_default_charset_coll = (ulint)default_charset_info->number;
02261
02262
02263
02264
02265
02266
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
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
02473 trx_t *trx = check_trx_exists(session);
02474
02475
02476
02477
02478 innobase_release_stat_resources(trx);
02479
02480
02481 trx_start_if_not_started(trx);
02482
02483
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
02509
02510
02511 if (trx->has_search_latch) {
02512 trx_search_latch_release_if_reserved(trx);
02513 }
02514
02515 if (all)
02516 {
02517
02518
02519
02520
02521
02522
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
02543
02544
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
02557 trx_commit_complete_for_mysql(trx);
02558
02559 } else {
02560
02561
02562
02563
02564
02565
02566 row_unlock_table_autoinc_for_mysql(trx);
02567
02568
02569
02570
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;
02584
02585 if (trx->declared_to_be_inside_innodb) {
02586
02587
02588 srv_conc_force_exit_innodb(trx);
02589 }
02590
02591
02592
02593 srv_active_wake_master_thread();
02594
02595 if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
02596 trx->global_read_view)
02597 {
02598
02599
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
02625
02626
02627
02628 innobase_release_stat_resources(trx);
02629
02630 trx->n_autoinc_rows = 0;
02631
02632
02633
02634
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
02649
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
02668
02669
02670
02671 innobase_release_stat_resources(trx);
02672
02673
02674
02675
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
02704
02705
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
02753
02754
02755
02756
02757 trx = check_trx_exists(session);
02758
02759
02760
02761
02762
02763 innobase_release_stat_resources(trx);
02764
02765
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
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
02850
02851
02852
02853
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
02891 case HA_KEYTYPE_BINARY:
02892 max_value = 0xFFULL;
02893 break;
02894
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
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
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
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
02948
02949
02950
02951
02952
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
02959
02960 col_type = get_innobase_type_from_mysql_type(&is_unsigned,
02961 key_part->field);
02962
02963
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
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
03019
03020
03021
03022 if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) {
03023 ret = FALSE;
03024 goto func_exit;
03025 }
03026
03027
03028
03029 if (share->idx_trans_tbl.index_count) {
03030
03031 ut_a(share->idx_trans_tbl.index_count == mysql_num_index);
03032 goto func_exit;
03033 }
03034
03035
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
03043
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
03056
03057
03058 for (ulint count = 0; count < mysql_num_index; count++) {
03059
03060
03061
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
03073
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
03083 share->idx_trans_tbl.index_count = mysql_num_index;
03084
03085 func_exit:
03086 if (!ret) {
03087
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
03143
03144
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
03153
03154
03155
03156
03157
03158
03159
03160
03161
03162 auto_inc = 0;
03163 } else if (field == NULL) {
03164
03165
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
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
03190
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
03207 auto_inc = 0;
03208
03209
03210
03211
03212 err = DB_SUCCESS;
03213 break;
03214 default:
03215
03216
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
03243
03244
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
03272
03273
03274
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
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
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
03365
03366
03367
03368
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
03380
03381
03382
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
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406 ref_length = getTable()->key_info[0].key_length;
03407
03408
03409
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
03420
03421
03422
03423
03424
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
03442
03443
03444
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
03458
03459
03460
03461
03462
03463
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
03474 stats.block_size = 16 * 1024;
03475
03476
03477 lock.init(&share->lock);
03478
03479 if (prebuilt->table) {
03480
03481
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
03491 if (prebuilt->table != NULL && getTable()->found_next_number_field != NULL) {
03492
03493 dict_table_autoinc_lock(prebuilt->table);
03494
03495
03496
03497
03498
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
03541
03542
03543 srv_active_wake_master_thread();
03544
03545 return(0);
03546 }
03547
03548
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,
03627 unsigned int b_length);
03628
03629
03630 int
03631 innobase_mysql_cmp(
03632
03633
03634 int mysql_type,
03635 uint charset_number,
03636 const unsigned char* a,
03637 unsigned int a_length,
03638 const unsigned char* b,
03639 unsigned int b_length)
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
03655
03656
03657
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
03674
03675
03676
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
03714
03715
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
03729
03730
03731
03732 *unsigned_flag = DATA_UNSIGNED;
03733
03734
03735
03736 return(DATA_INT);
03737 }
03738
03739 switch (field->type()) {
03740
03741
03742 case DRIZZLE_TYPE_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
03824
03825
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842
03843
03844
03845
03846
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
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
03897
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
03909
03910
03911 if (true_len > key_len) {
03912 true_len = key_len;
03913 }
03914
03915
03916
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
03924
03925
03926
03927
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
03963
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
03976
03977
03978
03979 if (true_len > key_len) {
03980 true_len = key_len;
03981 }
03982
03983
03984
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
03993
03994
03995 buff += key_len;
03996 } else {
03997
03998
03999
04000
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
04021
04022
04023
04024
04025 memcpy(buff, src_start, true_len);
04026 buff += true_len;
04027
04028
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 );
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
04071 ulint mysql_prefix_len = 0;
04072
04073 if (prebuilt->select_lock_type == LOCK_X) {
04074
04075
04076
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
04086
04087
04088 if (prebuilt->read_just_key) {
04089
04090
04091
04092
04093
04094
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
04103
04104
04105
04106
04107
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
04126
04127 }
04128
04129 n_fields = (ulint)table->getShare()->sizeFields();
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
04142
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
04151
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
04157
04158
04159 goto skip_field;
04160 }
04161
04162 if (index_contains_field && fetch_all_in_key) {
04163
04164
04165 goto include_field;
04166 }
04167
04168 if (field->isReadSet() || field->isWriteSet())
04169
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
04179
04180 goto include_field;
04181 }
04182
04183
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
04247
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
04346
04347
04348
04349
04350
04351
04352
04353
04354 dict_table_t* src_table;
04355 enum lock_mode mode;
04356
04357 num_write_row = 0;
04358
04359
04360
04361
04362
04363
04364 src_table = lock_get_src_table(
04365 prebuilt->trx, prebuilt->table, &mode);
04366 if (!src_table) {
04367 no_commit:
04368
04369
04370
04371
04372
04373
04374
04375
04376 ;
04377 } else if (src_table == prebuilt->table) {
04378
04379
04380
04381
04382 getTransactionalEngine()->commit(user_session, 1);
04383
04384 prebuilt->sql_stat_start = TRUE;
04385 } else {
04386
04387
04388
04389 if (!lock_is_table_exclusive(prebuilt->table,
04390 prebuilt->trx)) {
04391 goto no_commit;
04392 }
04393
04394
04395
04396 getTransactionalEngine()->commit(user_session, 1);
04397
04398 row_lock_table_for_mysql(prebuilt, src_table, mode);
04399
04400 prebuilt->sql_stat_start = TRUE;
04401 }
04402 }
04403
04404 num_write_row++;
04405
04406
04407 if (getTable()->next_number_field && record == getTable()->getInsertRecord()) {
04408
04409
04410
04411 prebuilt->autoinc_error = DB_SUCCESS;
04412
04413 if ((error = update_auto_increment())) {
04414
04415
04416
04417
04418 if (prebuilt->autoinc_error == DB_UNSUPPORTED) {
04419 error_result = ER_AUTOINC_READ_FAILED;
04420
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
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
04441
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
04453 if (auto_inc_used) {
04454 ulint err;
04455 uint64_t auto_inc;
04456 uint64_t col_max_value;
04457
04458
04459
04460
04461
04462 if (trx->n_autoinc_rows > 0) {
04463 --trx->n_autoinc_rows;
04464 }
04465
04466
04467
04468 col_max_value = innobase_get_int_col_max_value(
04469 getTable()->next_number_field);
04470
04471 auto_inc = getTable()->next_number_field->val_int();
04472
04473 switch (error) {
04474 case DB_DUPLICATE_KEY:
04475
04476
04477
04478
04479
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
04503
04504
04505
04506
04507 if (auto_inc >= prebuilt->autoinc_last_value) {
04508 set_max_autoinc:
04509
04510
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
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
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
04605
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
04624
04625
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
04658
04659 ufield = uvect->fields + n_changed;
04660
04661
04662
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
04724
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
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
04743
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(¤t_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
04776
04777
04778
04779
04780
04781
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
04796
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
04822 && uvect->n_fields == 0 ) {
04823
04824
04825
04826
04827
04828 error = HA_ERR_RECORD_IS_THE_SAME;
04829 }
04830
04831
04832
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
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
04873
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
04890
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
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
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
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
04933
04934
04935
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
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
05000
05001
05002
05003
05004
05005
05006
05007
05008
05009
05010
05011
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
05019
05020
05021 }
05022
05023 my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
05024
05025 return(PAGE_CUR_UNSUPP);
05026 }
05027
05028
05029
05030
05031
05032
05033
05034
05035
05036
05037
05038
05039
05040
05041
05042
05043
05044
05045
05046
05047
05048
05049
05050
05051
05052
05053
05054
05055
05056
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067
05068
05069
05070
05071
05072
05073
05074
05075
05076
05077
05078
05079
05080
05081
05082
05083
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
05130
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
05139
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
05151
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
05250
05251
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
05315
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
05327
05328
05329
05330
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
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
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
05521
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
05530
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
05604
05605
05606
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
05618
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
05650
05651
05652
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
05663
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
05708
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
05757
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);
05771
05772 col_len = field->pack_length();
05773
05774
05775
05776
05777
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
05790
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
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
05876
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
05887
05888
05889
05890
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
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
05946
05947
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
05972
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
06008 if (!(SessionVAR(session, strict_mode))) {
06009 return(TRUE);
06010 }
06011
06012
06013 return(ret);
06014 }
06015 #endif
06016
06017
06018
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
06037
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
06053
06054
06055 return(HA_ERR_TO_BIG_ROW);
06056 }
06057
06058
06059
06060
06061 parent_trx = check_trx_exists(&session);
06062
06063
06064
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
06073
06074
06075
06076 row_mysql_lock_data_dictionary(trx);
06077
06078
06079
06080 iflags = 0;
06081
06082 #if 0 // Since we validate the options before this stage, we no longer need to do this.
06083
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
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);
06118 }
06119 }
06120
06121 if (iflags == DICT_TF_FORMAT_ZIP)
06122 {
06123
06124
06125
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
06158
06159 primary_key_no= (form.getShare()->hasPrimaryKey() ?
06160 (int) form.getShare()->getPrimaryKey() :
06161 -1);
06162
06163
06164
06165
06166 assert(primary_key_no == -1 || primary_key_no == 0);
06167
06168
06169
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
06190
06191 if (form.getShare()->sizeKeys() == 0 || primary_key_no == -1) {
06192
06193
06194
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
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
06273
06274
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
06284
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
06294
06295
06296
06297
06298
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
06306
06307
06308
06309
06310
06311
06312
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
06322
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
06391
06392
06393 update_session(getTable()->in_use);
06394
06395 if (user_session->getSqlCommand() != SQLCOM_TRUNCATE) {
06396 fallback:
06397
06398
06399
06400 return(errno=HA_ERR_WRONG_COMMAND);
06401 }
06402
06403
06404
06405 error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
06406 if (error == DB_ERROR) {
06407
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
06446
06447
06448 parent_trx = check_trx_exists(&session);
06449
06450
06451
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
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
06468
06469
06470
06471 log_buffer_flush_to_disk();
06472
06473
06474
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
06493
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
06535
06536
06537 assert(this == innodb_engine_ptr);
06538
06539
06540 if (session) {
06541 trx_t* parent_trx = check_trx_exists(session);
06542
06543
06544
06545
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
06555
06556
06557
06558 log_buffer_flush_to_disk();
06559
06560
06561
06562
06563 srv_active_wake_master_thread();
06564
06565 innobase_commit_low(trx);
06566 trx_free_for_mysql(trx);
06567
06568 return false;
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
06589
06590
06591
06592 log_buffer_flush_to_disk();
06593
06594
06595
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
06620
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
06642
06643
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
06656
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
06668
06669
06670 parent_trx = check_trx_exists(&session);
06671
06672
06673
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
06684
06685
06686 srv_active_wake_master_thread();
06687
06688 innobase_commit_low(trx);
06689 trx_free_for_mysql(trx);
06690
06691
06692
06693
06694
06695
06696
06697
06698
06699
06700
06701
06702
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
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
06751
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
06762
06763
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
06823
06824
06825
06826
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
06850
06851
06852
06853 update_session(getTable()->in_use);
06854
06855 prebuilt->trx->op_info = (char*)
06856 "calculating upper bound for table rows";
06857
06858
06859
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
06874
06875
06876
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
06897
06898
06899
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
06921 return(Cursor::read_time(index, ranges, rows));
06922 }
06923
06924 if (rows <= 2) {
06925
06926 return((double) rows);
06927 }
06928
06929
06930
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
06972
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
06991
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
07010
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
07019
07020 errmsg_printf(error::ERROR,
07021 "Cannot find index %s in InnoDB index "
07022 "translation table.", index->name);
07023 }
07024
07025
07026
07027
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
07059
07060
07061
07062
07063
07064
07065
07066 update_session(getTable()->in_use);
07067
07068
07069
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
07079
07080
07081 prebuilt->trx->op_info = "updating table statistics";
07082
07083 dict_update_statistics(ib_table,
07084 FALSE
07085 );
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
07095
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
07109
07110
07111
07112
07113
07114
07115
07116
07117
07118
07119
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
07130
07131
07132
07133 if (user_session->getSqlCommand() == SQLCOM_TRUNCATE) {
07134
07135 n_rows = 1;
07136
07137
07138
07139
07140
07141
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
07158
07159
07160
07161
07162 if (flag & HA_STATUS_NO_LOCK) {
07163
07164
07165
07166
07167 } else if (UNIV_UNLIKELY
07168 (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) {
07169
07170
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
07212
07213
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
07230
07231
07232
07233
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
07273
07274
07275
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
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
07363
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
07389
07390
07391
07392
07393 prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
07394
07395
07396 mutex_enter(&kernel_mutex);
07397 srv_fatal_semaphore_wait_threshold += 7200;
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
07420
07421
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
07479 prebuilt->trx->isolation_level = old_isolation_level;
07480
07481
07482
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
07492 mutex_enter(&kernel_mutex);
07493 srv_fatal_semaphore_wait_threshold -= 7200;
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
07520
07521
07522
07523 if (length > 64000 - 3) {
07524 return((char*)comment);
07525 }
07526
07527 update_session(getTable()->in_use);
07528
07529 prebuilt->trx->op_info = (char*)"returning table comment";
07530
07531
07532
07533
07534 trx_search_latch_release_if_reserved(prebuilt->trx);
07535 str = NULL;
07536
07537
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
07556
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
07595
07596
07597
07598 update_session(getTable()->in_use);
07599
07600 prebuilt->trx->op_info = (char*)"getting info on foreign keys";
07601
07602
07603
07604
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
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
07622
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];
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
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
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
07842
07843
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
07865
07866
07867
07868
07869
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:
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
07901
07902
07903
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
07951
07952 prebuilt->select_lock_type = LOCK_X;
07953 prebuilt->stored_select_lock_type = LOCK_X;
07954 }
07955
07956 if (lock_type != F_UNLCK) {
07957
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
07965
07966
07967
07968
07969
07970
07971
07972 prebuilt->select_lock_type = LOCK_S;
07973 prebuilt->stored_select_lock_type = LOCK_S;
07974 }
07975
07976
07977
07978
07979
07980
07981
07982
07983
07984
07985
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
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
08027
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
08051
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
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
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
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
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
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
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
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
08302
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
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
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
08346 free(share->idx_trans_tbl.index_mapping);
08347
08348 delete share;
08349
08350
08351
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
08381
08382
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
08392
08393
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
08401
08402
08403
08404
08405
08406
08407
08408
08409
08410
08411
08412
08413
08414
08415
08416
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
08433
08434
08435
08436
08437
08438
08439
08440
08441
08442 prebuilt->select_lock_type = LOCK_NONE;
08443 prebuilt->stored_select_lock_type = LOCK_NONE;
08444 } else if (sql_command == SQLCOM_CHECKSUM) {
08445
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
08457
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
08466
08467
08468
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
08481
08482
08483
08484
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
08516 *value = dict_table_autoinc_read(prebuilt->table);
08517
08518
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
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
08590
08591
08592
08593
08594
08595
08596
08597 trx = prebuilt->trx;
08598
08599
08600
08601
08602
08603
08604
08605
08606 uint64_t col_max_value = innobase_get_int_col_max_value(getTable()->next_number_field);
08607
08608
08609 if (trx->n_autoinc_rows == 0) {
08610
08611 trx->n_autoinc_rows = (ulint) nb_desired_values;
08612
08613
08614
08615 if (nb_desired_values == 0) {
08616
08617 trx->n_autoinc_rows = 1;
08618 }
08619
08620 set_if_bigger(*first_value, autoinc);
08621
08622 } else if (prebuilt->autoinc_last_value == 0) {
08623 set_if_bigger(*first_value, autoinc);
08624
08625 } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
08626
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
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
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
08651 dict_table_autoinc_update_if_greater(
08652 prebuilt->table, prebuilt->autoinc_last_value);
08653 }
08654 }
08655
08656
08657
08658
08659
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
08693 if (value == 0) {
08694 value = 1;
08695 }
08696
08697 innobase_reset_autoinc(value);
08698
08699 return 0;
08700 }
08701
08702
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
08739
08740 return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
08741 }
08742
08743
08744
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
08758
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
08785
08786
08787
08788
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
08810
08811 n_chars = prefix_len / charset->mbmaxlen;
08812
08813
08814
08815
08816
08817
08818 if (charset->mbmaxlen > 1) {
08819
08820
08821
08822
08823
08824
08825
08826
08827
08828
08829
08830
08831
08832
08833
08834
08835
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
08864
08865
08866 trx_t *trx= check_trx_exists(session);
08867
08868
08869 trx->detailed_error[0]= '\0';
08870
08871
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
08882
08883
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
08908
08909
08910 if (!trx->support_xa) {
08911
08912 return(0);
08913 }
08914
08915 session->get_xid(reinterpret_cast<DrizzleXid*>(&trx->xid));
08916
08917
08918
08919
08920
08921 innobase_release_stat_resources(trx);
08922
08923 if (all
08924 || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
08925
08926
08927
08928
08929 ut_ad(trx->conc_state != TRX_NOT_STARTED);
08930
08931 error = (int) trx_prepare_for_mysql(trx);
08932 } else {
08933
08934
08935
08936
08937
08938
08939 row_unlock_table_autoinc_for_mysql(trx);
08940
08941
08942
08943
08944
08945 trx_mark_sql_stat_end(trx);
08946 }
08947
08948
08949
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
09064
09065 format_id = (uint) strtoul(format_name, &endp, 10);
09066
09067
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,
09285 NULL,
09286 init_options
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
09297
09298 res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
09299
09300
09301 return res;
09302 }
09303
09304
09305 int ha_innobase::read_range_next()
09306 {
09307 int res= Cursor::read_range_next();
09308
09309
09310 return res;
09311 }
09312
09313
09314
09315
09316
09317 UNIV_INTERN
09318 bool
09319 innobase_index_name_is_reserved(
09320
09321
09322
09323 const trx_t* trx,
09324 const KeyInfo* key_info,
09325 ulint num_of_keys)
09326
09327 {
09328 const KeyInfo* key;
09329 uint key_num;
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
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
09419
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