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