1
/*****************************************************************************
3
Copyright (C) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved.
4
Copyright (C) 2008, 2009 Google Inc.
5
Copyright (C) 2009, Percona Inc.
7
Portions of this file contain modifications contributed and copyrighted by
8
Google, Inc. Those modifications are gratefully acknowledged and are described
9
briefly in the InnoDB documentation. The contributions by Google are
10
incorporated with their permission, and subject to the conditions contained in
11
the file COPYING.Google.
13
Portions of this file contain modifications contributed and copyrighted
14
by Percona Inc.. Those modifications are
15
gratefully acknowledged and are described briefly in the InnoDB
16
documentation. The contributions by Percona Inc. are incorporated with
17
their permission, and subject to the conditions contained in the file
20
This program is free software; you can redistribute it and/or modify it under
21
the terms of the GNU General Public License as published by the Free Software
22
Foundation; version 2 of the License.
24
This program is distributed in the hope that it will be useful, but WITHOUT
25
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
26
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
28
You should have received a copy of the GNU General Public License along with
29
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
30
St, Fifth Floor, Boston, MA 02110-1301 USA
32
*****************************************************************************/
34
/* TODO list for the InnoDB Cursor in 5.0:
35
- fix savepoint functions to use savepoint storage area
36
- Find out what kind of problems the OS X case-insensitivity causes to
37
table and database names; should we 'normalize' the names like we do
46
#include <drizzled/error.h>
47
#include <drizzled/errmsg_print.h>
48
#include <drizzled/internal/m_string.h>
49
#include <drizzled/internal/my_sys.h>
50
#include <drizzled/plugin.h>
51
#include <drizzled/show.h>
52
#include <drizzled/data_home.h>
53
#include <drizzled/error.h>
54
#include <drizzled/field.h>
55
#include <drizzled/charset.h>
56
#include <drizzled/session.h>
57
#include <drizzled/current_session.h>
58
#include <drizzled/table.h>
59
#include <drizzled/field/blob.h>
60
#include <drizzled/field/varstring.h>
61
#include <drizzled/plugin/xa_storage_engine.h>
62
#include <drizzled/plugin/daemon.h>
63
#include <drizzled/memory/multi_malloc.h>
64
#include <drizzled/pthread_globals.h>
65
#include <drizzled/named_savepoint.h>
66
#include <drizzled/session/table_messages.h>
67
#include <drizzled/transaction_services.h>
68
#include <drizzled/message/statement_transform.h>
69
#include <drizzled/cached_directory.h>
70
#include <drizzled/statistics_variables.h>
71
#include <drizzled/system_variables.h>
72
#include <drizzled/session/times.h>
73
#include <drizzled/session/transactions.h>
74
#include <drizzled/typelib.h>
76
#include <boost/algorithm/string.hpp>
77
#include <boost/program_options.hpp>
78
#include <boost/scoped_array.hpp>
79
#include <boost/filesystem.hpp>
80
#include <drizzled/module/option_map.h>
83
namespace po= boost::program_options;
84
namespace fs=boost::filesystem;
87
/** @file ha_innodb.cc */
89
/* Include necessary InnoDB headers */
94
#include "os0thread.h"
95
#include "srv0start.h"
102
#include "row0mysql.h"
106
#include "lock0lock.h"
107
#include "dict0crea.h"
108
#include "create_replication.h"
112
#include "sync0sync.h"
115
#include "row0merge.h"
117
#include "dict0boot.h"
118
#include "ha_prototypes.h"
120
#include "ibuf0ibuf.h"
122
#include "ha_innodb.h"
123
#include "data_dictionary.h"
124
#include "replication_dictionary.h"
125
#include "internal_dictionary.h"
126
#include "handler0vars.h"
132
#include <plugin/innobase/handler/status_function.h>
133
#include <plugin/innobase/handler/replication_log.h>
135
#include <google/protobuf/io/zero_copy_stream.h>
136
#include <google/protobuf/io/zero_copy_stream_impl.h>
137
#include <google/protobuf/io/coded_stream.h>
138
#include <google/protobuf/text_format.h>
140
#include <boost/thread/mutex.hpp>
143
using namespace drizzled;
145
/** to protect innobase_open_files */
146
static boost::mutex innobase_share_mutex;
148
/** to force correct commit order in binlog */
149
static ulong commit_threads = 0;
150
static boost::condition_variable commit_cond;
151
static boost::mutex commit_cond_m;
152
static bool innodb_inited = 0;
154
#define INSIDE_HA_INNOBASE_CC
156
/* In the Windows plugin, the return value of current_session is
157
undefined. Map it to NULL. */
158
#if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
159
# undef current_session
160
# define current_session NULL
161
# define EQ_CURRENT_SESSION(session) TRUE
162
#else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
163
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
164
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
166
static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
168
typedef constrained_check<uint32_t, UINT32_MAX, 10> open_files_constraint;
169
static open_files_constraint innobase_open_files;
170
typedef constrained_check<uint32_t, 10, 1> mirrored_log_groups_constraint;
171
static mirrored_log_groups_constraint innobase_mirrored_log_groups;
172
typedef constrained_check<uint32_t, 100, 2> log_files_in_group_constraint;
173
static log_files_in_group_constraint innobase_log_files_in_group;
174
typedef constrained_check<uint32_t, 6, 0> force_recovery_constraint;
175
force_recovery_constraint innobase_force_recovery;
176
typedef constrained_check<size_t, SIZE_MAX, 256*1024, 1024> log_buffer_constraint;
177
static log_buffer_constraint innobase_log_buffer_size;
178
typedef constrained_check<size_t, SIZE_MAX, 512*1024, 1024> additional_mem_pool_constraint;
179
static additional_mem_pool_constraint innobase_additional_mem_pool_size;
180
typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
181
static autoextend_constraint innodb_auto_extend_increment;
182
typedef constrained_check<size_t, SIZE_MAX, 33554432, 1048576> buffer_pool_constraint;
183
static buffer_pool_constraint innobase_buffer_pool_size;
184
typedef constrained_check<uint32_t, MAX_BUFFER_POOLS, 1> buffer_pool_instances_constraint;
185
static buffer_pool_instances_constraint innobase_buffer_pool_instances;
186
typedef constrained_check<uint32_t,
187
(1 << UNIV_PAGE_SIZE_SHIFT_MAX),
188
(1 << 12)> page_size_constraint;
189
static page_size_constraint innobase_page_size;
190
typedef constrained_check<uint32_t,
191
(1 << UNIV_PAGE_SIZE_SHIFT_MAX),
192
(1 << 9)> log_block_size_constraint;
193
static log_block_size_constraint innobase_log_block_size;
194
typedef constrained_check<uint32_t, UINT32_MAX, 100> io_capacity_constraint;
195
static io_capacity_constraint innodb_io_capacity;
196
typedef constrained_check<uint32_t, 5000, 1> purge_batch_constraint;
197
static purge_batch_constraint innodb_purge_batch_size;
198
typedef constrained_check<uint32_t, 1, 0> purge_threads_constraint;
199
static purge_threads_constraint innodb_n_purge_threads;
200
typedef constrained_check<uint32_t, 2, 0> trinary_constraint;
201
static trinary_constraint innodb_flush_log_at_trx_commit;
202
typedef constrained_check<unsigned int, 99, 0> max_dirty_pages_constraint;
203
static max_dirty_pages_constraint innodb_max_dirty_pages_pct;
204
static uint64_constraint innodb_max_purge_lag;
205
static uint64_nonzero_constraint innodb_stats_sample_pages;
206
typedef constrained_check<uint32_t, 64, 1> io_threads_constraint;
207
static io_threads_constraint innobase_read_io_threads;
208
static io_threads_constraint innobase_write_io_threads;
210
typedef constrained_check<uint32_t, 1000, 0> concurrency_constraint;
211
static concurrency_constraint innobase_commit_concurrency;
212
static concurrency_constraint innobase_thread_concurrency;
213
static uint32_nonzero_constraint innodb_concurrency_tickets;
215
typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
216
static log_file_constraint innobase_log_file_size;
218
static uint64_constraint innodb_replication_delay;
220
static uint32_constraint buffer_pool_restore_at_startup;
222
/** Percentage of the buffer pool to reserve for 'old' blocks.
223
Connected to buf_LRU_old_ratio. */
224
typedef constrained_check<uint32_t, 95, 5> old_blocks_constraint;
225
static old_blocks_constraint innobase_old_blocks_pct;
227
static uint32_constraint innodb_sync_spin_loops;
228
static uint32_constraint innodb_spin_wait_delay;
229
static uint32_constraint innodb_thread_sleep_delay;
231
typedef constrained_check<uint32_t, 64, 0> read_ahead_threshold_constraint;
232
static read_ahead_threshold_constraint innodb_read_ahead_threshold;
234
static uint64_constraint ibuf_max_size;
236
typedef constrained_check<uint32_t, 1, 0> binary_constraint;
237
static binary_constraint ibuf_active_contract;
239
typedef constrained_check<uint32_t, 999999999, 100> ibuf_accel_rate_constraint;
240
static ibuf_accel_rate_constraint ibuf_accel_rate;
241
static uint32_constraint checkpoint_age_target;
242
static binary_constraint flush_neighbor_pages;
244
/* The default values for the following char* start-up parameters
245
are determined in innobase_init below: */
247
std::string innobase_data_home_dir;
248
std::string innobase_data_file_path;
249
std::string innobase_log_group_home_dir;
250
static string innobase_file_format_name;
251
static string innobase_change_buffering;
253
static string read_ahead;
254
static string adaptive_flushing_method;
256
/* The highest file format being used in the database. The value can be
257
set by user, however, it will be adjusted to the newer file format if
258
a table of such format is created/opened. */
259
static string innobase_file_format_max;
261
/* Below we have boolean-valued start-up parameters, and their default
264
static trinary_constraint innobase_fast_shutdown;
266
/* "innobase_file_format_check" decides whether we would continue
267
booting the server if the file format stamped on the system
268
table space exceeds the maximum file format supported
269
by the server. Can be set during server startup at command
270
line or configure file, and a read only variable after
273
/* If a new file format is introduced, the file format
274
name needs to be updated accordingly. Please refer to
275
file_format_name_map[] defined in trx0sys.c for the next
278
static my_bool innobase_file_format_check = TRUE;
279
static my_bool innobase_use_doublewrite = TRUE;
280
static my_bool innobase_use_checksums = TRUE;
281
static my_bool innobase_rollback_on_timeout = FALSE;
282
static my_bool innobase_create_status_file = FALSE;
283
static bool innobase_use_replication_log;
284
static bool support_xa;
285
static bool strict_mode;
286
typedef constrained_check<uint32_t, 1024*1024*1024, 1> lock_wait_constraint;
287
static lock_wait_constraint lock_wait_timeout;
289
static char* internal_innobase_data_file_path = NULL;
291
/* The following counter is used to convey information to InnoDB
292
about server activity: in selects it is not sensible to call
293
srv_active_wake_master_thread after each fetch or search, we only do
294
it every INNOBASE_WAKE_INTERVAL'th step. */
296
#define INNOBASE_WAKE_INTERVAL 32
297
static ulong innobase_active_counter = 0;
299
static hash_table_t* innobase_open_tables;
301
#ifdef __NETWARE__ /* some special cleanup for NetWare */
302
bool nw_panic = FALSE;
305
/** Allowed values of innodb_change_buffering */
306
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
307
"none", /* IBUF_USE_NONE */
308
"inserts", /* IBUF_USE_INSERT */
309
"deletes", /* IBUF_USE_DELETE_MARK */
310
"changes", /* IBUF_USE_INSERT_DELETE_MARK */
311
"purges", /* IBUF_USE_DELETE */
312
"all" /* IBUF_USE_ALL */
315
/** Allowed values of read_ahead */
316
static const char* read_ahead_names[] = {
321
/* For compatibility with the older Percona patch */
322
"0", /* 4 ("none" + 4) */
325
"3", /* 7 ("both" + 4) */
329
static TYPELIB read_ahead_typelib = {
330
array_elements(read_ahead_names) - 1, "read_ahead_typelib",
331
read_ahead_names, NULL
334
/** Allowed values of adaptive_flushing_method */
335
static const char* adaptive_flushing_method_names[] = {
338
"keep_average", /* 2 */
339
/* For compatibility with the older Percona patch */
340
"0", /* 3 ("native" + 3) */
341
"1", /* 4 ("estimate" + 3) */
342
"2", /* 5 ("keep_average" + 3) */
346
static TYPELIB adaptive_flushing_method_typelib = {
347
array_elements(adaptive_flushing_method_names) - 1,
348
"adaptive_flushing_method_typelib",
349
adaptive_flushing_method_names, NULL
352
/* "GEN_CLUST_INDEX" is the name reserved for Innodb default
353
system primary index. */
354
static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX";
356
/********************************************************************
357
Gives the file extension of an InnoDB single-table tablespace. */
358
static const char* ha_innobase_exts[] = {
363
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
365
static INNOBASE_SHARE *get_share(const char *table_name);
366
static void free_share(INNOBASE_SHARE *share);
368
class InnobaseEngine : public plugin::XaStorageEngine
371
explicit InnobaseEngine(string name_arg) :
372
plugin::XaStorageEngine(name_arg,
374
HTON_CAN_INDEX_BLOBS |
375
HTON_PRIMARY_KEY_IN_READ_INDEX |
376
HTON_PARTIAL_COLUMN_READ |
377
HTON_TABLE_SCAN_ON_INDEX |
378
HTON_HAS_FOREIGN_KEYS |
379
HTON_HAS_DOES_TRANSACTIONS)
381
table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
382
addAlias("INNOBASE");
385
virtual ~InnobaseEngine()
388
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
390
hash_table_free(innobase_open_tables);
391
innobase_open_tables = NULL;
392
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
395
srv_free_paths_and_sizes();
396
free(internal_innobase_data_file_path);
399
/* These get strdup'd from vm variables */
404
virtual int doStartTransaction(Session *session, start_transaction_option_t options);
405
virtual void doStartStatement(Session *session);
406
virtual void doEndStatement(Session *session);
411
/*======================*/
412
/* out: 0 or error number */
413
Session* session); /* in: handle to the MySQL thread of the user
414
whose resources should be free'd */
416
virtual int doSetSavepoint(Session* session,
417
drizzled::NamedSavepoint &savepoint);
418
virtual int doRollbackToSavepoint(Session* session,
419
drizzled::NamedSavepoint &savepoint);
420
virtual int doReleaseSavepoint(Session* session,
421
drizzled::NamedSavepoint &savepoint);
422
virtual int doXaCommit(Session* session, bool all)
424
return doCommit(session, all); /* XA commit just does a SQL COMMIT */
426
virtual int doXaRollback(Session *session, bool all)
428
return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
430
virtual uint64_t doGetCurrentTransactionId(Session *session);
431
virtual uint64_t doGetNewTransactionId(Session *session);
432
virtual int doCommit(Session* session, bool all);
433
virtual int doRollback(Session* session, bool all);
435
/***********************************************************************
436
This function is used to prepare X/Open XA distributed transaction */
441
/* out: 0 or error number */
442
Session* session, /* in: handle to the MySQL thread of the user
443
whose XA transaction should be prepared */
444
bool all); /* in: TRUE - commit transaction
445
FALSE - the current SQL statement ended */
446
/***********************************************************************
447
This function is used to recover X/Open XA distributed transactions */
452
/* out: number of prepared transactions
453
stored in xid_list */
454
::drizzled::XID* xid_list, /* in/out: prepared transactions */
455
size_t len); /* in: number of slots in xid_list */
456
/***********************************************************************
457
This function is used to commit one X/Open XA distributed transaction
458
which is in the prepared state */
462
/*===================*/
463
/* out: 0 or error number */
464
::drizzled::XID* xid); /* in: X/Open XA transaction identification */
465
/***********************************************************************
466
This function is used to rollback one X/Open XA distributed transaction
467
which is in the prepared state */
471
/*=====================*/
472
/* out: 0 or error number */
473
::drizzled::XID *xid); /* in: X/Open XA transaction identification */
475
virtual Cursor *create(Table &table)
477
return new ha_innobase(*this, table);
480
/*********************************************************************
481
Removes all tables in the named database inside InnoDB. */
484
/*===================*/
485
/* out: error number */
486
const identifier::Schema &identifier); /* in: database path; inside InnoDB the name
487
of the last directory in the path is used as
488
the database name: for example, in 'mysql/data/test'
489
the database name is 'test' */
491
/********************************************************************
492
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
493
the logs, and the name of this function should be innobase_checkpoint. */
498
/* out: TRUE if error */
500
/****************************************************************************
501
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
502
Monitor to the client. */
507
Session* session, /* in: the MySQL query thread of the caller */
508
stat_print_fn *stat_print,
509
enum ha_stat_type stat_type);
513
doReleaseTemporaryLatches(
514
/*===============================*/
516
Session* session); /* in: MySQL thread */
519
const char** bas_ext() const {
520
return(ha_innobase_exts);
523
UNIV_INTERN int doCreateTable(Session &session,
525
const identifier::Table &identifier,
526
const message::Table&);
527
UNIV_INTERN int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
528
UNIV_INTERN int doDropTable(Session &session, const identifier::Table &identifier);
530
UNIV_INTERN virtual bool get_error_message(int error, String *buf) const;
532
UNIV_INTERN uint32_t max_supported_keys() const;
533
UNIV_INTERN uint32_t max_supported_key_length() const;
534
UNIV_INTERN uint32_t max_supported_key_part_length() const;
537
UNIV_INTERN uint32_t index_flags(enum ha_key_alg) const
539
return (HA_READ_NEXT |
546
int doGetTableDefinition(drizzled::Session& session,
547
const identifier::Table &identifier,
548
drizzled::message::Table &table_proto);
550
bool doDoesTableExist(drizzled::Session& session, const identifier::Table &identifier);
552
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
553
const drizzled::identifier::Schema &schema_identifier,
554
drizzled::identifier::table::vector &set_of_identifiers);
555
bool validateCreateTableOption(const std::string &key, const std::string &state);
556
void dropTemporarySchema();
561
bool InnobaseEngine::validateCreateTableOption(const std::string &key, const std::string &state)
563
if (boost::iequals(key, "ROW_FORMAT"))
565
if (boost::iequals(state, "COMPRESSED"))
568
if (boost::iequals(state, "COMPACT"))
571
if (boost::iequals(state, "DYNAMIC"))
574
if (boost::iequals(state, "REDUNDANT"))
581
void InnobaseEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
582
const drizzled::identifier::Schema &schema_identifier,
583
drizzled::identifier::table::vector &set_of_identifiers)
585
CachedDirectory::Entries entries= directory.getEntries();
587
std::string search_string(schema_identifier.getSchemaName());
589
boost::algorithm::to_lower(search_string);
591
if (search_string.compare("data_dictionary") == 0)
593
set_of_identifiers.push_back(identifier::Table(schema_identifier.getSchemaName(), "SYS_REPLICATION_LOG"));
596
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
597
entry_iter != entries.end(); ++entry_iter)
599
CachedDirectory::Entry *entry= *entry_iter;
600
const string *filename= &entry->filename;
602
assert(filename->size());
604
const char *ext= strchr(filename->c_str(), '.');
606
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
607
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
612
path+= directory.getPath();
614
path+= entry->filename;
616
message::Table definition;
617
if (StorageEngine::readTableFile(path, definition))
620
Using schema_identifier here to stop unused warning, could use
621
definition.schema() instead
623
identifier::Table identifier(schema_identifier.getSchemaName(), definition.name());
624
set_of_identifiers.push_back(identifier);
630
bool InnobaseEngine::doDoesTableExist(Session &session, const identifier::Table &identifier)
632
string proto_path(identifier.getPath());
633
proto_path.append(DEFAULT_FILE_EXTENSION);
635
if (session.getMessageCache().doesTableMessageExist(identifier))
638
std::string search_string(identifier.getPath());
639
boost::algorithm::to_lower(search_string);
641
if (search_string.compare("data_dictionary/sys_replication_log") == 0)
644
if (access(proto_path.c_str(), F_OK))
652
int InnobaseEngine::doGetTableDefinition(Session &session,
653
const identifier::Table &identifier,
654
message::Table &table_proto)
656
string proto_path(identifier.getPath());
657
proto_path.append(DEFAULT_FILE_EXTENSION);
659
// First we check the temporary tables.
660
if (session.getMessageCache().getTableMessage(identifier, table_proto))
663
if (read_replication_log_table_message(identifier.getTableName().c_str(), &table_proto) == 0)
666
if (access(proto_path.c_str(), F_OK))
671
if (StorageEngine::readTableFile(proto_path, table_proto))
678
/************************************************************//**
679
Validate the file format name and return its corresponding id.
680
@return valid file format id */
683
innobase_file_format_name_lookup(
684
/*=============================*/
685
const char* format_name); /*!< in: pointer to file format
687
/************************************************************//**
688
Validate the file format check config parameters, as a side effect it
689
sets the srv_max_file_format_at_startup variable.
690
@return the format_id if valid config value, otherwise, return -1 */
693
innobase_file_format_validate_and_set(
694
/*================================*/
695
const char* format_max); /*!< in: parameter value */
697
static const char innobase_engine_name[]= "InnoDB";
700
/*****************************************************************//**
701
Commits a transaction in an InnoDB database. */
706
trx_t* trx); /*!< in: transaction handle */
708
static drizzle_show_var innodb_status_variables[]= {
709
{"buffer_pool_pages_data",
710
(char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
711
{"buffer_pool_pages_dirty",
712
(char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
713
{"buffer_pool_pages_flushed",
714
(char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
715
{"buffer_pool_pages_free",
716
(char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
718
{"buffer_pool_pages_latched",
719
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
720
#endif /* UNIV_DEBUG */
721
{"buffer_pool_pages_misc",
722
(char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
723
{"buffer_pool_pages_total",
724
(char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
725
{"buffer_pool_read_ahead",
726
(char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG},
727
{"buffer_pool_read_ahead_evicted",
728
(char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG},
729
{"buffer_pool_read_requests",
730
(char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
731
{"buffer_pool_reads",
732
(char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
733
{"buffer_pool_wait_free",
734
(char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
735
{"buffer_pool_write_requests",
736
(char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
738
(char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
739
{"data_pending_fsyncs",
740
(char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
741
{"data_pending_reads",
742
(char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
743
{"data_pending_writes",
744
(char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
746
(char*) &export_vars.innodb_data_read, SHOW_LONG},
748
(char*) &export_vars.innodb_data_reads, SHOW_LONG},
750
(char*) &export_vars.innodb_data_writes, SHOW_LONG},
752
(char*) &export_vars.innodb_data_written, SHOW_LONG},
753
{"dblwr_pages_written",
754
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
756
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
757
{"have_atomic_builtins",
758
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
760
(char*) &export_vars.innodb_log_waits, SHOW_LONG},
761
{"log_write_requests",
762
(char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
764
(char*) &export_vars.innodb_log_writes, SHOW_LONG},
766
(char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
767
{"os_log_pending_fsyncs",
768
(char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
769
{"os_log_pending_writes",
770
(char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
772
(char*) &export_vars.innodb_os_log_written, SHOW_LONG},
774
(char*) &export_vars.innodb_page_size, SHOW_LONG},
776
(char*) &export_vars.innodb_pages_created, SHOW_LONG},
778
(char*) &export_vars.innodb_pages_read, SHOW_LONG},
780
(char*) &export_vars.innodb_pages_written, SHOW_LONG},
781
{"row_lock_current_waits",
782
(char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
784
(char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
785
{"row_lock_time_avg",
786
(char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
787
{"row_lock_time_max",
788
(char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
790
(char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
792
(char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
794
(char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
796
(char*) &export_vars.innodb_rows_read, SHOW_LONG},
798
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
799
{NULL, NULL, SHOW_LONG}
802
InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
803
plugin::TableFunction::Generator(fields)
805
srv_export_innodb_status();
806
status_var_ptr= innodb_status_variables;
809
bool InnodbStatusTool::Generator::populate()
811
if (status_var_ptr->name)
813
std::ostringstream oss;
815
const char *value= status_var_ptr->value;
818
push(status_var_ptr->name);
820
switch (status_var_ptr->type)
823
oss << *(int64_t*) value;
824
return_value= oss.str();
827
oss << *(int64_t*) value;
828
return_value= oss.str();
831
return_value= *(bool*) value ? "ON" : "OFF";
838
if (return_value.length())
850
/* General functions */
852
/******************************************************************//**
853
Returns true if the thread is the replication thread on the slave
854
server. Used in srv_conc_enter_innodb() to determine if the thread
855
should be allowed to enter InnoDB - the replication thread is treated
856
differently than other threads. Also used in
857
srv_conc_force_exit_innodb().
859
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
861
@return true if session is the replication thread */
864
thd_is_replication_slave_thread(
865
/*============================*/
866
drizzled::Session* ) /*!< in: thread handle (Session*) */
871
/******************************************************************//**
872
Save some CPU by testing the value of srv_thread_concurrency in inline
876
innodb_srv_conc_enter_innodb(
877
/*=========================*/
878
trx_t* trx) /*!< in: transaction handle */
880
if (UNIV_LIKELY(!srv_thread_concurrency)) {
885
srv_conc_enter_innodb(trx);
888
/******************************************************************//**
889
Save some CPU by testing the value of srv_thread_concurrency in inline
893
innodb_srv_conc_exit_innodb(
894
/*========================*/
895
trx_t* trx) /*!< in: transaction handle */
897
if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
902
srv_conc_exit_innodb(trx);
905
/******************************************************************//**
906
Releases possible search latch and InnoDB thread FIFO ticket. These should
907
be released at each SQL statement end, and also when mysqld passes the
908
control to the client. It does no harm to release these also in the middle
909
of an SQL statement. */
912
innobase_release_stat_resources(
913
/*============================*/
914
trx_t* trx) /*!< in: transaction object */
916
if (trx->has_search_latch) {
917
trx_search_latch_release_if_reserved(trx);
920
if (trx->declared_to_be_inside_innodb) {
921
/* Release our possible ticket in the FIFO */
923
srv_conc_force_exit_innodb(trx);
927
/******************************************************************//**
928
Returns true if the transaction this thread is processing has edited
929
non-transactional tables. Used by the deadlock detector when deciding
930
which transaction to rollback in case of a deadlock - we try to avoid
931
rolling back transactions that have edited non-transactional tables.
933
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
935
@return true if non-transactional tables have been edited */
938
thd_has_edited_nontrans_tables(
939
/*===========================*/
940
drizzled::Session *session) /*!< in: thread handle (Session*) */
942
return((ibool)session->transaction.all.hasModifiedNonTransData());
945
/******************************************************************//**
946
Returns true if the thread is executing a SELECT statement.
947
@return true if session is executing SELECT */
952
const drizzled::Session *session) /*!< in: thread handle (Session*) */
954
return(session->getSqlCommand() == SQLCOM_SELECT);
957
/******************************************************************//**
958
Returns true if the thread supports XA,
959
global value of innodb_supports_xa if session is NULL.
960
@return true if session has XA support */
965
drizzled::Session* ) /*!< in: thread handle (Session*), or NULL to query
966
the global innodb_supports_xa */
968
/* TODO: Add support here for per-session value */
972
/******************************************************************//**
973
Returns the lock wait timeout for the current connection.
974
@return the lock wait timeout, in seconds */
977
thd_lock_wait_timeout(
978
/*==================*/
979
drizzled::Session*) /*!< in: thread handle (Session*), or NULL to query
980
the global innodb_lock_wait_timeout */
982
/* TODO: Add support here for per-session value */
983
/* According to <drizzle/plugin.h>, passing session == NULL
984
returns the global value of the session variable. */
985
return((ulong)lock_wait_timeout.get());
988
/******************************************************************//**
989
Set the time waited for the lock for the current query. */
992
thd_set_lock_wait_time(
993
/*===================*/
994
drizzled::Session* in_session, /*!< in: thread handle (THD*) */
995
ulint value) /*!< in: time waited for the lock */
998
in_session->times.utime_after_lock+= value;
1001
/********************************************************************//**
1002
Obtain the InnoDB transaction of a MySQL thread.
1003
@return reference to transaction pointer */
1008
Session* session) /*!< in: Drizzle Session */
1010
return *(trx_t**) session->getEngineData(innodb_engine_ptr);
1014
plugin::ReplicationReturnCode ReplicationLog::apply(Session &session,
1015
const message::Transaction &message)
1017
char *data= new char[message.ByteSize()];
1019
message.SerializeToArray(data, message.ByteSize());
1021
trx_t *trx= session_to_trx(&session);
1023
uint64_t trx_id= message.transaction_context().transaction_id();
1024
uint32_t seg_id= message.segment_id();
1025
uint64_t end_timestamp= message.transaction_context().end_timestamp();
1026
bool is_end_segment= message.end_segment();
1027
trx->log_commit_id= TRUE;
1029
string server_uuid= session.getServerUUID();
1030
string originating_server_uuid= session.getOriginatingServerUUID();
1031
uint64_t originating_commit_id= session.getOriginatingCommitID();
1032
bool use_originating_server_uuid= session.isOriginatingServerUUIDSet();
1034
ulint error= insert_replication_message(data, message.ByteSize(), trx, trx_id,
1035
end_timestamp, is_end_segment, seg_id, server_uuid.c_str(),
1036
use_originating_server_uuid, originating_server_uuid.c_str(),
1037
originating_commit_id);
1043
return plugin::SUCCESS;
1046
/********************************************************************//**
1047
Call this function when mysqld passes control to the client. That is to
1048
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
1049
documentation, see Cursor.cc.
1052
InnobaseEngine::doReleaseTemporaryLatches(
1053
/*===============================*/
1054
Session* session) /*!< in: MySQL thread */
1058
assert(this == innodb_engine_ptr);
1060
if (!innodb_inited) {
1065
trx = session_to_trx(session);
1068
innobase_release_stat_resources(trx);
1073
/********************************************************************//**
1074
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
1075
time calls srv_active_wake_master_thread. This function should be used
1076
when a single database operation may introduce a small need for
1077
server utility activity, like checkpointing. */
1080
innobase_active_small(void)
1081
/*=======================*/
1083
innobase_active_counter++;
1085
if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
1086
srv_active_wake_master_thread();
1090
/********************************************************************//**
1091
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
1092
about a possible transaction rollback inside InnoDB caused by a lock wait
1093
timeout or a deadlock.
1094
@return MySQL error code */
1097
convert_error_code_to_mysql(
1098
/*========================*/
1099
int error, /*!< in: InnoDB error code */
1100
ulint flags, /*!< in: InnoDB table flags, or 0 */
1101
Session* session)/*!< in: user thread handle or NULL */
1107
case DB_INTERRUPTED:
1108
my_error(ER_QUERY_INTERRUPTED, MYF(0));
1111
case DB_FOREIGN_EXCEED_MAX_CASCADE:
1112
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1113
HA_ERR_ROW_IS_REFERENCED,
1114
"InnoDB: Cannot delete/update "
1115
"rows with cascading foreign key "
1116
"constraints that exceed max "
1117
"depth of %d. Please "
1118
"drop extra constraints and try "
1119
"again", DICT_FK_MAX_RECURSIVE_LOAD);
1124
return(-1); /* unspecified error */
1126
case DB_DUPLICATE_KEY:
1127
/* Be cautious with returning this error, since
1128
mysql could re-enter the storage layer to get
1129
duplicated key info, the operation requires a
1130
valid table handle and/or transaction information,
1131
which might not always be available in the error
1133
return(HA_ERR_FOUND_DUPP_KEY);
1135
case DB_FOREIGN_DUPLICATE_KEY:
1136
return(HA_ERR_FOREIGN_DUPLICATE_KEY);
1138
case DB_MISSING_HISTORY:
1139
return(HA_ERR_TABLE_DEF_CHANGED);
1141
case DB_RECORD_NOT_FOUND:
1142
return(HA_ERR_NO_ACTIVE_RECORD);
1145
/* Since we rolled back the whole transaction, we must
1146
tell it also to MySQL so that MySQL knows to empty the
1147
cached binlog for this transaction */
1149
session->markTransactionForRollback(TRUE);
1151
return(HA_ERR_LOCK_DEADLOCK);
1153
case DB_LOCK_WAIT_TIMEOUT:
1154
/* Starting from 5.0.13, we let MySQL just roll back the
1155
latest SQL statement in a lock wait timeout. Previously, we
1156
rolled back the whole transaction. */
1158
session->markTransactionForRollback((bool)row_rollback_on_timeout);
1160
return(HA_ERR_LOCK_WAIT_TIMEOUT);
1162
case DB_NO_REFERENCED_ROW:
1163
return(HA_ERR_NO_REFERENCED_ROW);
1165
case DB_ROW_IS_REFERENCED:
1166
return(HA_ERR_ROW_IS_REFERENCED);
1168
case DB_CANNOT_ADD_CONSTRAINT:
1169
case DB_CHILD_NO_INDEX:
1170
case DB_PARENT_NO_INDEX:
1171
return(HA_ERR_CANNOT_ADD_FOREIGN);
1173
case DB_CANNOT_DROP_CONSTRAINT:
1175
return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
1176
misleading, a new MySQL error
1177
code should be introduced */
1179
case DB_COL_APPEARS_TWICE_IN_INDEX:
1181
return(HA_ERR_CRASHED);
1183
case DB_OUT_OF_FILE_SPACE:
1184
return(HA_ERR_RECORD_FILE_FULL);
1186
case DB_TABLE_IS_BEING_USED:
1187
return(HA_ERR_WRONG_COMMAND);
1189
case DB_TABLE_NOT_FOUND:
1190
return(HA_ERR_NO_SUCH_TABLE);
1192
case DB_TOO_BIG_RECORD:
1193
my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
1194
page_get_free_space_of_empty(flags & DICT_TF_COMPACT) / 2);
1195
return(HA_ERR_TO_BIG_ROW);
1197
case DB_NO_SAVEPOINT:
1198
return(HA_ERR_NO_SAVEPOINT);
1200
case DB_LOCK_TABLE_FULL:
1201
/* Since we rolled back the whole transaction, we must
1202
tell it also to MySQL so that MySQL knows to empty the
1203
cached binlog for this transaction */
1205
session->markTransactionForRollback(TRUE);
1207
return(HA_ERR_LOCK_TABLE_FULL);
1209
case DB_PRIMARY_KEY_IS_NULL:
1210
return(ER_PRIMARY_CANT_HAVE_NULL);
1212
case DB_TOO_MANY_CONCURRENT_TRXS:
1214
/* Once MySQL add the appropriate code to errmsg.txt then
1215
we can get rid of this #ifdef. NOTE: The code checked by
1216
the #ifdef is the suggested name for the error condition
1217
and the actual error code name could very well be different.
1218
This will require some monitoring, ie. the status
1219
of this request on our part.*/
1221
/* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only
1222
available in 5.1.38 and later, but the plugin should still
1223
work with previous versions of MySQL.
1224
In Drizzle we seem to not have this yet.
1226
#ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS
1227
return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
1228
#else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1229
return(HA_ERR_RECORD_FILE_FULL);
1230
#endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1231
case DB_UNSUPPORTED:
1232
return(HA_ERR_UNSUPPORTED);
1237
/*************************************************************//**
1238
Prints info of a Session object (== user session thread) to the given file. */
1241
innobase_mysql_print_thd(
1242
/*=====================*/
1243
FILE* f, /*!< in: output stream */
1244
drizzled::Session *in_session, /*!< in: pointer to a Drizzle Session object */
1245
uint ) /*!< in: max query length to print, or 0 to
1246
use the default max length */
1248
drizzled::identifier::user::ptr user_identifier(in_session->user());
1251
"Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
1252
static_cast<uint64_t>(in_session->getSessionId()),
1253
static_cast<uint64_t>(in_session->getQueryId()),
1254
getServerHostname().c_str(),
1255
user_identifier->address().c_str(),
1256
user_identifier->username().c_str()
1258
fprintf(f, "\n%s", in_session->getQueryString()->c_str());
1262
/******************************************************************//**
1263
Get the variable length bounds of the given character set. */
1266
innobase_get_cset_width(
1267
/*====================*/
1268
ulint cset, /*!< in: MySQL charset-collation code */
1269
ulint* mbminlen, /*!< out: minimum length of a char (in bytes) */
1270
ulint* mbmaxlen) /*!< out: maximum length of a char (in bytes) */
1272
charset_info_st* cs;
1277
cs = all_charsets[cset];
1279
*mbminlen = cs->mbminlen;
1280
*mbmaxlen = cs->mbmaxlen;
1281
ut_ad(*mbminlen < DATA_MBMAX);
1282
ut_ad(*mbmaxlen < DATA_MBMAX);
1285
*mbminlen = *mbmaxlen = 0;
1289
/******************************************************************//**
1290
Converts an identifier to a table name. */
1293
innobase_convert_from_table_id(
1294
/*===========================*/
1295
const void*, /*!< in: the 'from' character set */
1296
char* to, /*!< out: converted identifier */
1297
const char* from, /*!< in: identifier to convert */
1298
ulint len) /*!< in: length of 'to', in bytes */
1300
strncpy(to, from, len);
1303
/******************************************************************//**
1304
Converts an identifier to UTF-8. */
1307
innobase_convert_from_id(
1308
/*=====================*/
1309
const void*, /*!< in: the 'from' character set */
1310
char* to, /*!< out: converted identifier */
1311
const char* from, /*!< in: identifier to convert */
1312
ulint len) /*!< in: length of 'to', in bytes */
1314
strncpy(to, from, len);
1317
/******************************************************************//**
1318
Compares NUL-terminated UTF-8 strings case insensitively.
1319
@return 0 if a=b, <0 if a<b, >1 if a>b */
1322
innobase_strcasecmp(
1323
/*================*/
1324
const char* a, /*!< in: first string to compare */
1325
const char* b) /*!< in: second string to compare */
1327
return(my_strcasecmp(system_charset_info, a, b));
1330
/******************************************************************//**
1331
Makes all characters in a NUL-terminated UTF-8 string lower case. */
1334
innobase_casedn_str(
1335
/*================*/
1336
char* a) /*!< in/out: string to put in lower case */
1338
my_casedn_str(system_charset_info, a);
1347
return my_isspace(static_cast<const charset_info_st *>(cs), char_to_test);
1350
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1351
/*******************************************************************//**
1352
Map an OS error to an errno value. The OS error number is stored in
1353
_doserrno and the mapped value is stored in errno) */
1356
unsigned long); /*!< in: OS error value */
1358
/*********************************************************************//**
1359
Creates a temporary file.
1360
@return temporary file descriptor, or < 0 on error */
1363
innobase_mysql_tmpfile(void)
1364
/*========================*/
1366
int fd; /* handle of opened file */
1367
HANDLE osfh; /* OS handle of opened file */
1368
char* tmpdir; /* point to the directory
1369
where to create file */
1370
TCHAR path_buf[MAX_PATH - 14]; /* buffer for tmp file path.
1371
The length cannot be longer
1372
than MAX_PATH - 14, or
1373
GetTempFileName will fail. */
1374
char filename[MAX_PATH]; /* name of the tmpfile */
1375
DWORD fileaccess = GENERIC_READ /* OS file access */
1378
DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
1380
| FILE_SHARE_DELETE;
1381
DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
1382
DWORD fileattrib = /* OS file attribute flags */
1383
FILE_ATTRIBUTE_NORMAL
1384
| FILE_FLAG_DELETE_ON_CLOSE
1385
| FILE_ATTRIBUTE_TEMPORARY
1386
| FILE_FLAG_SEQUENTIAL_SCAN;
1388
tmpdir = my_tmpdir(&mysql_tmpdir_list);
1390
/* The tmpdir parameter can not be NULL for GetTempFileName. */
1394
/* Use GetTempPath to determine path for temporary files. */
1395
ret = GetTempPath(sizeof(path_buf), path_buf);
1396
if (ret > sizeof(path_buf) || (ret == 0)) {
1398
_dosmaperr(GetLastError()); /* map error */
1405
/* Use GetTempFileName to generate a unique filename. */
1406
if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
1408
_dosmaperr(GetLastError()); /* map error */
1412
/* Open/Create the file. */
1413
osfh = CreateFile(filename, fileaccess, fileshare, NULL,
1414
filecreate, fileattrib, NULL);
1415
if (osfh == INVALID_HANDLE_VALUE) {
1417
/* open/create file failed! */
1418
_dosmaperr(GetLastError()); /* map error */
1423
/* Associates a CRT file descriptor with the OS file handle. */
1424
fd = _open_osfhandle((intptr_t) osfh, 0);
1425
} while (fd == -1 && errno == EINTR);
1428
/* Open failed, close the file handle. */
1430
_dosmaperr(GetLastError()); /* map error */
1431
CloseHandle(osfh); /* no need to check if
1432
CloseHandle fails */
1438
/*********************************************************************//**
1439
Creates a temporary file.
1440
@return temporary file descriptor, or < 0 on error */
1443
innobase_mysql_tmpfile(void)
1444
/*========================*/
1447
int fd = ::drizzled::tmpfile("ib");
1449
/* Copy the file descriptor, so that the additional resources
1450
allocated by create_temp_file() can be freed by invoking
1451
internal::my_close().
1453
Because the file descriptor returned by this function
1454
will be passed to fdopen(), it will be closed by invoking
1455
fclose(), which in turn will invoke close() instead of
1456
internal::my_close(). */
1460
my_error(EE_OUT_OF_FILERESOURCES,
1461
MYF(ME_BELL+ME_WAITTANG),
1464
internal::my_close(fd, MYF(MY_WME));
1468
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
1471
/*******************************************************************//**
1472
Formats the raw data in "data" (in InnoDB on-disk format) that is of
1473
type DATA_(CHAR|VARCHAR|DRIZZLE|VARDRIZZLE) using "charset_coll" and writes
1474
the result to "buf". The result is converted to "system_charset_info".
1475
Not more than "buf_size" bytes are written to "buf".
1476
The result is always NUL-terminated (provided buf_size > 0) and the
1477
number of bytes that were written to "buf" is returned (including the
1479
@return number of bytes that were written */
1482
innobase_raw_format(
1483
/*================*/
1484
const char* data, /*!< in: raw data */
1485
ulint data_len, /*!< in: raw data length
1487
ulint , /*!< in: charset collation */
1488
char* buf, /*!< out: output buffer */
1489
ulint buf_size) /*!< in: output buffer size
1492
return(ut_str_sql_format(data, data_len, buf, buf_size));
1495
/*********************************************************************//**
1496
Compute the next autoinc value.
1498
For MySQL replication the autoincrement values can be partitioned among
1499
the nodes. The offset is the start or origin of the autoincrement value
1500
for a particular node. For n nodes the increment will be n and the offset
1501
will be in the interval [1, n]. The formula tries to allocate the next
1502
value for a particular node.
1504
Note: This function is also called with increment set to the number of
1505
values we want to reserve for multi-value inserts e.g.,
1507
INSERT INTO T VALUES(), (), ();
1509
innobase_next_autoinc() will be called with increment set to
1510
to reserve 3 values for the multi-value INSERT above.
1511
@return the next value */
1514
innobase_next_autoinc(
1515
/*==================*/
1516
uint64_t current, /*!< in: Current value */
1517
uint64_t increment, /*!< in: increment current by */
1518
uint64_t offset, /*!< in: AUTOINC offset */
1519
uint64_t max_value) /*!< in: max value for type */
1521
uint64_t next_value;
1523
/* Should never be 0. */
1524
ut_a(increment > 0);
1526
/* According to MySQL documentation, if the offset is greater than
1527
the increment then the offset is ignored. */
1528
if (offset > increment) {
1532
if (max_value <= current) {
1533
next_value = max_value;
1534
} else if (offset <= 1) {
1535
/* Offset 0 and 1 are the same, because there must be at
1536
least one node in the system. */
1537
if (max_value - current <= increment) {
1538
next_value = max_value;
1540
next_value = current + increment;
1542
} else if (max_value > current) {
1543
if (current > offset) {
1544
next_value = ((current - offset) / increment) + 1;
1546
next_value = ((offset - current) / increment) + 1;
1549
ut_a(increment > 0);
1550
ut_a(next_value > 0);
1552
/* Check for multiplication overflow. */
1553
if (increment > (max_value / next_value)) {
1555
next_value = max_value;
1557
next_value *= increment;
1559
ut_a(max_value >= next_value);
1561
/* Check for overflow. */
1562
if (max_value - next_value <= offset) {
1563
next_value = max_value;
1565
next_value += offset;
1569
next_value = max_value;
1572
ut_a(next_value <= max_value);
1577
/*********************************************************************//**
1578
Initializes some fields in an InnoDB transaction object. */
1583
Session* session, /*!< in: user thread handle */
1584
trx_t* trx) /*!< in/out: InnoDB transaction handle */
1586
assert(session == trx->mysql_thd);
1588
trx->check_foreigns = !session_test_options(
1589
session, OPTION_NO_FOREIGN_KEY_CHECKS);
1591
trx->check_unique_secondary = !session_test_options(
1592
session, OPTION_RELAXED_UNIQUE_CHECKS);
1597
/*********************************************************************//**
1598
Allocates an InnoDB transaction for a MySQL Cursor object.
1599
@return InnoDB transaction handle */
1602
innobase_trx_allocate(
1603
/*==================*/
1604
Session* session) /*!< in: user thread handle */
1608
assert(session != NULL);
1609
assert(EQ_CURRENT_SESSION(session));
1611
trx = trx_allocate_for_mysql();
1613
trx->mysql_thd = session;
1615
innobase_trx_init(session, trx);
1620
/*********************************************************************//**
1621
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1622
an InnoDB transaction struct if the corresponding MySQL thread struct still
1624
@return InnoDB transaction handle */
1629
Session* session) /*!< in: user thread handle */
1631
trx_t*& trx = session_to_trx(session);
1633
ut_ad(EQ_CURRENT_SESSION(session));
1636
trx = innobase_trx_allocate(session);
1637
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1638
mem_analyze_corruption(trx);
1642
innobase_trx_init(session, trx);
1648
/*********************************************************************//**
1649
Construct ha_innobase Cursor. */
1651
ha_innobase::ha_innobase(plugin::StorageEngine &engine_arg,
1653
:Cursor(engine_arg, table_arg),
1654
primary_key(0), /* needs initialization because index_flags() may be called
1655
before this is set to the real value. It's ok to have any
1656
value here because it doesn't matter if we return the
1657
HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
1662
/*********************************************************************//**
1663
Destruct ha_innobase Cursor. */
1665
ha_innobase::~ha_innobase()
1669
/*********************************************************************//**
1670
Updates the user_thd field in a handle and also allocates a new InnoDB
1671
transaction handle if needed, and updates the transaction fields in the
1675
ha_innobase::update_session(
1676
/*====================*/
1677
Session* session) /*!< in: thd to use the handle */
1682
trx = check_trx_exists(session);
1684
if (prebuilt->trx != trx) {
1686
row_update_prebuilt_trx(prebuilt, trx);
1689
user_session = session;
1692
/*****************************************************************//**
1693
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1694
and quote it if needed.
1695
@return pointer to the end of buf */
1698
innobase_convert_identifier(
1699
/*========================*/
1700
char* buf, /*!< out: buffer for converted identifier */
1701
ulint buflen, /*!< in: length of buf, in bytes */
1702
const char* id, /*!< in: identifier to convert */
1703
ulint idlen, /*!< in: length of id, in bytes */
1704
drizzled::Session *session,/*!< in: MySQL connection thread, or NULL */
1705
ibool file_id)/*!< in: TRUE=id is a table or database name;
1706
FALSE=id is an UTF-8 string */
1708
char nz[NAME_LEN + 1];
1709
const size_t nz2_size= NAME_LEN + 1 + srv_mysql50_table_name_prefix.size();
1710
boost::scoped_array<char> nz2(new char[nz2_size]);
1716
/* Decode the table name. The filename_to_tablename()
1717
function expects a NUL-terminated string. The input and
1718
output strings buffers must not be shared. */
1720
if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1721
idlen = (sizeof nz) - 1;
1724
memcpy(nz, id, idlen);
1728
idlen = identifier::Table::filename_to_tablename(nz, nz2.get(), nz2_size);
1731
/* See if the identifier needs to be quoted. */
1732
if (UNIV_UNLIKELY(!session)) {
1735
q = get_quote_char_for_identifier();
1739
if (UNIV_UNLIKELY(idlen > buflen)) {
1742
memcpy(buf, s, idlen);
1743
return(buf + idlen);
1746
/* Quote the identifier. */
1754
for (; idlen; idlen--) {
1756
if (UNIV_UNLIKELY(c == q)) {
1757
if (UNIV_UNLIKELY(buflen < 3)) {
1765
if (UNIV_UNLIKELY(buflen < 2)) {
1778
/*****************************************************************//**
1779
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1780
and quote it if needed.
1781
@return pointer to the end of buf */
1784
innobase_convert_name(
1785
/*==================*/
1786
char* buf, /*!< out: buffer for converted identifier */
1787
ulint buflen, /*!< in: length of buf, in bytes */
1788
const char* id, /*!< in: identifier to convert */
1789
ulint idlen, /*!< in: length of id, in bytes */
1790
drizzled::Session *session,/*!< in: MySQL connection thread, or NULL */
1791
ibool table_id)/*!< in: TRUE=id is a table or database name;
1792
FALSE=id is an index name */
1795
const char* bufend = buf + buflen;
1798
const char* slash = (const char*) memchr(id, '/', idlen);
1804
/* Print the database name and table name separately. */
1805
s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1807
if (UNIV_LIKELY(s < bufend)) {
1809
s = innobase_convert_identifier(s, bufend - s,
1814
} else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1815
/* Temporary index name (smart ALTER TABLE) */
1816
const char temp_index_suffix[]= "--temporary--";
1818
s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1820
if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1821
memcpy(s, temp_index_suffix,
1822
sizeof temp_index_suffix - 1);
1823
s += sizeof temp_index_suffix - 1;
1827
s = innobase_convert_identifier(buf, buflen, id, idlen,
1835
/**********************************************************************//**
1836
Determines if the currently running transaction has been interrupted.
1837
@return TRUE if interrupted */
1842
trx_t* trx) /*!< in: transaction */
1844
return(trx && trx->mysql_thd && trx->mysql_thd->getKilled());
1847
/**********************************************************************//**
1848
Determines if the currently running transaction is in strict mode.
1849
@return TRUE if strict */
1854
trx_t* trx) /*!< in: transaction */
1856
return(trx && trx->mysql_thd
1860
/**************************************************************//**
1861
Resets some fields of a prebuilt struct. The template is used in fast
1862
retrieval of just those column values MySQL needs in its processing. */
1867
row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1869
prebuilt->keep_other_fields_on_keyread = 0;
1870
prebuilt->read_just_key = 0;
1874
void align_value(T& value, size_t align_val= 1024)
1876
value= value - (value % align_val);
1879
static void auto_extend_update(Session *, sql_var_t)
1881
srv_auto_extend_increment= innodb_auto_extend_increment.get();
1884
static void io_capacity_update(Session *, sql_var_t)
1886
srv_io_capacity= innodb_io_capacity.get();
1889
static void purge_batch_update(Session *, sql_var_t)
1891
srv_purge_batch_size= innodb_purge_batch_size.get();
1894
static void purge_threads_update(Session *, sql_var_t)
1896
srv_n_purge_threads= innodb_n_purge_threads.get();
1899
static void innodb_adaptive_hash_index_update(Session *, sql_var_t)
1901
if (btr_search_enabled)
1903
btr_search_enable();
1905
btr_search_disable();
1909
static void innodb_old_blocks_pct_update(Session *, sql_var_t)
1911
innobase_old_blocks_pct= buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(), TRUE);
1914
static void innodb_thread_concurrency_update(Session *, sql_var_t)
1916
srv_thread_concurrency= innobase_thread_concurrency.get();
1919
static void innodb_sync_spin_loops_update(Session *, sql_var_t)
1921
srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
1924
static void innodb_spin_wait_delay_update(Session *, sql_var_t)
1926
srv_spin_wait_delay= innodb_spin_wait_delay.get();
1929
static void innodb_thread_sleep_delay_update(Session *, sql_var_t)
1931
srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
1934
static void innodb_read_ahead_threshold_update(Session *, sql_var_t)
1936
srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
1939
static void auto_lru_dump_update(Session *, sql_var_t)
1941
srv_auto_lru_dump= buffer_pool_restore_at_startup.get();
1944
static void ibuf_active_contract_update(Session *, sql_var_t)
1946
srv_ibuf_active_contract= ibuf_active_contract.get();
1949
static void ibuf_accel_rate_update(Session *, sql_var_t)
1951
srv_ibuf_accel_rate= ibuf_accel_rate.get();
1954
static void checkpoint_age_target_update(Session *, sql_var_t)
1956
srv_checkpoint_age_target= checkpoint_age_target.get();
1959
static void flush_neighbor_pages_update(Session *, sql_var_t)
1961
srv_flush_neighbor_pages= flush_neighbor_pages.get();
1964
static int innodb_commit_concurrency_validate(Session *session, set_var *var)
1966
uint64_t new_value= var->getInteger();
1968
if ((innobase_commit_concurrency.get() == 0 && new_value != 0) ||
1969
(innobase_commit_concurrency.get() != 0 && new_value == 0))
1971
push_warning_printf(session,
1972
DRIZZLE_ERROR::WARN_LEVEL_WARN,
1974
_("Once InnoDB is running, innodb_commit_concurrency "
1975
"must not change between zero and nonzero."));
1981
/*************************************************************//**
1982
Check if it is a valid file format. This function is registered as
1983
a callback with MySQL.
1984
@return 0 for valid file format */
1987
innodb_file_format_name_validate(
1988
/*=============================*/
1989
Session* , /*!< in: thread handle */
1992
const char *file_format_input = var->value->str_value.ptr();
1993
if (file_format_input == NULL)
1996
if (file_format_input != NULL) {
1999
format_id = innobase_file_format_name_lookup(
2002
if (format_id <= DICT_TF_FORMAT_MAX) {
2003
innobase_file_format_name =
2004
trx_sys_file_format_id_to_name(format_id);
2013
/*************************************************************//**
2014
Check if it is a valid value of innodb_change_buffering. This function is
2015
registered as a callback with MySQL.
2016
@return 0 for valid innodb_change_buffering */
2019
innodb_change_buffering_validate(
2020
/*=============================*/
2021
Session* , /*!< in: thread handle */
2024
const char *change_buffering_input = var->value->str_value.ptr();
2026
if (change_buffering_input == NULL)
2032
use < UT_ARR_SIZE(innobase_change_buffering_values);
2034
if (!innobase_strcasecmp(change_buffering_input,
2035
innobase_change_buffering_values[use]))
2037
ibuf_use= static_cast<ibuf_use_t>(use);
2046
/*************************************************************//**
2047
Check if valid argument to innodb_file_format_max. This function
2048
is registered as a callback with MySQL.
2049
@return 0 for valid file format */
2052
innodb_file_format_max_validate(
2053
/*==============================*/
2054
Session* session, /*!< in: thread handle */
2057
const char *file_format_input = var->value->str_value.ptr();
2058
if (file_format_input == NULL)
2061
if (file_format_input != NULL) {
2062
int format_id = innobase_file_format_validate_and_set(file_format_input);
2064
if (format_id > DICT_TF_FORMAT_MAX) {
2065
/* DEFAULT is "on", which is invalid at runtime. */
2069
if (format_id >= 0) {
2070
innobase_file_format_max.assign(
2071
trx_sys_file_format_id_to_name((uint)format_id));
2073
/* Update the max format id in the system tablespace. */
2074
const char *name_buff;
2076
if (trx_sys_file_format_max_set(format_id, &name_buff))
2078
errmsg_printf(error::WARN,
2079
" [Info] InnoDB: the file format in the system "
2080
"tablespace is now set to %s.\n", name_buff);
2081
innobase_file_format_max= name_buff;
2086
push_warning_printf(session,
2087
DRIZZLE_ERROR::WARN_LEVEL_WARN,
2089
"InnoDB: invalid innodb_file_format_max "
2090
"value; can be any format up to %s "
2091
"or equivalent id of %d",
2092
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX),
2093
DICT_TF_FORMAT_MAX);
2100
/*********************************************************************//**
2101
Check if argument is a valid value for srv_read_ahead and set it. This
2102
function is registered as a callback with MySQL.
2103
@return 0 for valid read_ahead value */
2106
read_ahead_validate(
2107
/*================*/
2108
Session*, /*!< in: thread handle */
2111
const char *read_ahead_input = var->value->str_value.ptr();
2112
int res = read_ahead_typelib.find_type(read_ahead_input, TYPELIB::e_none); // e_none is wrong
2115
srv_read_ahead = res - 1;
2122
/*********************************************************************//**
2123
Check if argument is a valid value for srv_adaptive_flushing_method and
2124
set it. This function is registered as a callback with MySQL.
2125
@return 0 for valid read_ahead value */
2128
adaptive_flushing_method_validate(
2129
/*==============================*/
2130
Session*, /*!< in: thread handle */
2133
const char *adaptive_flushing_method_input = var->value->str_value.ptr();
2134
int res = adaptive_flushing_method_typelib.find_type(adaptive_flushing_method_input, TYPELIB::e_none); // e_none is wrong
2137
srv_adaptive_flushing_method = res - 1;
2144
/*********************************************************************//**
2145
Opens an InnoDB database.
2146
@return 0 on success, error code on failure */
2151
module::Context &context) /*!< in: Drizzle Plugin Context */
2156
InnobaseEngine *actuall_engine_ptr;
2157
const module::option_map &vm= context.getOptions();
2159
srv_auto_extend_increment= innodb_auto_extend_increment.get();
2160
srv_io_capacity= innodb_io_capacity.get();
2161
srv_purge_batch_size= innodb_purge_batch_size.get();
2162
srv_n_purge_threads= innodb_n_purge_threads.get();
2163
srv_flush_log_at_trx_commit= innodb_flush_log_at_trx_commit.get();
2164
srv_max_buf_pool_modified_pct= innodb_max_dirty_pages_pct.get();
2165
srv_max_purge_lag= innodb_max_purge_lag.get();
2166
srv_stats_sample_pages= innodb_stats_sample_pages.get();
2167
srv_n_free_tickets_to_enter= innodb_concurrency_tickets.get();
2168
srv_replication_delay= innodb_replication_delay.get();
2169
srv_thread_concurrency= innobase_thread_concurrency.get();
2170
srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
2171
srv_spin_wait_delay= innodb_spin_wait_delay.get();
2172
srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
2173
srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
2174
srv_auto_lru_dump= buffer_pool_restore_at_startup.get();
2175
srv_ibuf_max_size= ibuf_max_size.get();
2176
srv_ibuf_active_contract= ibuf_active_contract.get();
2177
srv_ibuf_accel_rate= ibuf_accel_rate.get();
2178
srv_checkpoint_age_target= checkpoint_age_target.get();
2179
srv_flush_neighbor_pages= flush_neighbor_pages.get();
2181
srv_read_ahead = read_ahead_typelib.find_type_or_exit(vm["read-ahead"].as<string>().c_str(),
2182
"read_ahead_typelib") + 1;
2184
srv_adaptive_flushing_method = adaptive_flushing_method_typelib.find_type_or_exit(vm["adaptive-flushing-method"].as<string>().c_str(),
2185
"adaptive_flushing_method_typelib") + 1;
2187
/* Inverted Booleans */
2189
innobase_use_checksums= not vm.count("disable-checksums");
2190
innobase_use_doublewrite= not vm.count("disable-doublewrite");
2191
srv_adaptive_flushing= not vm.count("disable-adaptive-flushing");
2192
srv_use_sys_malloc= not vm.count("use-internal-malloc");
2193
srv_use_native_aio= not vm.count("disable-native-aio");
2194
support_xa= not vm.count("disable-xa");
2195
btr_search_enabled= not vm.count("disable-adaptive-hash-index");
2197
/* Hafta do this here because we need to late-bind the default value */
2198
innobase_data_home_dir= vm.count("data-home-dir") ? vm["data-home-dir"].as<string>() : getDataHome().file_string();
2200
if (vm.count("data-file-path"))
2202
innobase_data_file_path= vm["data-file-path"].as<string>();
2206
innodb_engine_ptr= actuall_engine_ptr= new InnobaseEngine(innobase_engine_name);
2208
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
2211
static const char test_filename[] = "-@";
2212
const size_t test_tablename_size= sizeof test_filename
2213
+ srv_mysql50_table_name_prefix.size();
2214
boost::scoped_array test_tablename(new char[test_tablename_size]);
2215
if ((test_tablename_size) - 1
2216
!= filename_to_tablename(test_filename, test_tablename.get(),
2217
test_tablename_size)
2218
|| strncmp(test_tablename.get(),
2219
srv_mysql50_table_name_prefix.c_str(),
2220
srv_mysql50_table_name_prefix.size())
2221
|| strcmp(test_tablename.get()
2222
+ srv_mysql50_table_name_prefix.size(),
2224
errmsg_printf(error::ERROR, "tablename encoding has been changed");
2227
#endif /* UNIV_DEBUG */
2230
srv_page_size_shift = 0;
2232
uint32_t page_size = innobase_page_size.get();
2233
uint32_t log_block_size = innobase_log_block_size.get();
2235
if (innobase_page_size != (1 << 14)) {
2238
errmsg_printf(error::WARN,
2239
"InnoDB: Warning: innodb_page_size has been changed from default value 16384. (###EXPERIMENTAL### operation)\n");
2240
for (n_shift = 12; n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX; n_shift++) {
2241
if (innobase_page_size == (1UL << n_shift)) {
2242
srv_page_size_shift = n_shift;
2243
srv_page_size = (1 << srv_page_size_shift);
2244
errmsg_printf(error::WARN,
2245
"InnoDB: The universal page size of the database is set to %lu.\n",
2251
srv_page_size_shift = 14;
2252
srv_page_size = (1 << srv_page_size_shift);
2255
if (!srv_page_size_shift) {
2256
errmsg_printf(error::ERROR,
2257
"InnoDB: Error: %"PRIu32" is not a valid value for innodb_page_size.\n"
2258
"InnoDB: Error: Valid values are 4096, 8192, and 16384 (default=16384).\n",
2263
srv_log_block_size = 0;
2264
if (log_block_size != (1 << 9)) { /*!=512*/
2267
errmsg_printf(error::WARN,
2268
"InnoDB: Warning: innodb_log_block_size has been changed from default value 512. (###EXPERIMENTAL### operation)\n");
2269
for (n_shift = 9; n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX; n_shift++) {
2270
if (log_block_size == (1UL << n_shift)) {
2271
srv_log_block_size = (1 << n_shift);
2272
errmsg_printf(error::WARN, "InnoDB: The log block size is set to %"PRIu32".\n",
2273
srv_log_block_size);
2278
srv_log_block_size = 512;
2281
if (!srv_log_block_size) {
2282
errmsg_printf(error::ERROR,
2283
"InnoDB: Error: %"PRIu32" is not a valid value for innodb_log_block_size.\n"
2284
"InnoDB: Error: A valid value for innodb_log_block_size is\n"
2285
"InnoDB: Error: a power of 2 from 512 to 16384.\n",
2290
os_innodb_umask = (ulint)internal::my_umask;
2293
/* Set InnoDB initialization parameters according to the values
2294
read from MySQL .cnf file */
2296
/*--------------- Data files -------------------------*/
2298
/* The default dir for data files is the datadir of MySQL */
2300
srv_data_home = (char *)innobase_data_home_dir.c_str();
2302
/* Set default InnoDB data file size to 10 MB and let it be
2303
auto-extending. Thus users can use InnoDB in >= 4.0 without having
2304
to specify any startup options. */
2306
if (innobase_data_file_path.empty())
2308
innobase_data_file_path= std::string("ibdata1:10M:autoextend");
2311
/* Since InnoDB edits the argument in the next call, we make another
2314
internal_innobase_data_file_path = strdup(innobase_data_file_path.c_str());
2316
ret = (bool) srv_parse_data_file_paths_and_sizes(
2317
internal_innobase_data_file_path);
2319
errmsg_printf(error::ERROR, "InnoDB: syntax error in innodb_data_file_path");
2322
srv_free_paths_and_sizes();
2323
free(internal_innobase_data_file_path);
2327
/* -------------- Log files ---------------------------*/
2329
/* The default dir for log files is the datadir of MySQL */
2331
if (vm.count("log-group-home-dir"))
2333
innobase_log_group_home_dir= vm["log-group-home-dir"].as<string>();
2337
innobase_log_group_home_dir= getDataHome().file_string();
2341
srv_parse_log_group_home_dirs((char *)innobase_log_group_home_dir.c_str());
2343
if (ret == FALSE || innobase_mirrored_log_groups.get() != 1) {
2344
errmsg_printf(error::ERROR, _("syntax error in innodb_log_group_home_dir, or a "
2345
"wrong number of mirrored log groups"));
2347
goto mem_free_and_error;
2351
/* Validate the file format by animal name */
2352
if (vm.count("file-format"))
2354
format_id = innobase_file_format_name_lookup(
2355
vm["file-format"].as<string>().c_str());
2357
if (format_id > DICT_TF_FORMAT_MAX) {
2359
errmsg_printf(error::ERROR, "InnoDB: wrong innodb_file_format.");
2361
goto mem_free_and_error;
2364
/* Set it to the default file format id.*/
2368
srv_file_format = format_id;
2370
innobase_file_format_name =
2371
trx_sys_file_format_id_to_name(format_id);
2373
/* Check innobase_file_format_check variable */
2374
if (!innobase_file_format_check)
2376
/* Set the value to disable checking. */
2377
srv_max_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
2379
/* Set the value to the lowest supported format. */
2380
srv_max_file_format_at_startup = DICT_TF_FORMAT_MIN;
2383
/* Did the user specify a format name that we support?
2384
As a side effect it will update the variable
2385
srv_max_file_format_at_startup */
2386
if (innobase_file_format_validate_and_set(innobase_file_format_max.c_str()) < 0)
2388
errmsg_printf(error::ERROR, _("InnoDB: invalid innodb_file_format_max value: "
2389
"should be any value up to %s or its equivalent numeric id"),
2390
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
2391
goto mem_free_and_error;
2394
if (vm.count("change-buffering"))
2399
use < UT_ARR_SIZE(innobase_change_buffering_values);
2401
if (!innobase_strcasecmp(
2402
innobase_change_buffering.c_str(),
2403
innobase_change_buffering_values[use])) {
2404
ibuf_use = static_cast<ibuf_use_t>(use);
2405
goto innobase_change_buffering_inited_ok;
2409
errmsg_printf(error::ERROR, "InnoDB: invalid value innodb_change_buffering=%s",
2410
vm["change-buffering"].as<string>().c_str());
2411
goto mem_free_and_error;
2414
innobase_change_buffering_inited_ok:
2415
ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
2416
innobase_change_buffering = innobase_change_buffering_values[ibuf_use];
2418
/* --------------------------------------------------*/
2420
if (vm.count("flush-method") != 0)
2422
srv_file_flush_method_str = (char *)vm["flush-method"].as<string>().c_str();
2425
srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
2426
srv_n_log_files = (ulint) innobase_log_files_in_group;
2427
srv_log_file_size = (ulint) innobase_log_file_size;
2429
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
2431
srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
2432
srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances;
2434
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
2436
srv_n_read_io_threads = (ulint) innobase_read_io_threads;
2437
srv_n_write_io_threads = (ulint) innobase_write_io_threads;
2439
srv_read_ahead &= 3;
2440
srv_adaptive_flushing_method %= 3;
2442
srv_force_recovery = (ulint) innobase_force_recovery;
2444
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
2445
srv_use_checksums = (ibool) innobase_use_checksums;
2447
#ifdef HAVE_LARGE_PAGES
2448
if ((os_use_large_pages = (ibool) my_use_large_pages))
2449
os_large_page_size = (ulint) opt_large_page_size;
2452
row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
2454
srv_locks_unsafe_for_binlog = (ibool) TRUE;
2456
srv_max_n_open_files = (ulint) innobase_open_files;
2457
srv_innodb_status = (ibool) innobase_create_status_file;
2459
srv_print_verbose_log = true;
2461
/* Store the default charset-collation number of this MySQL
2464
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
2466
/* Since we in this module access directly the fields of a trx
2467
struct, and due to different headers and flags it might happen that
2468
mutex_t has a different size in this module and in InnoDB
2469
modules, we check at run time that the size is the same in
2470
these compilation modules. */
2472
err = innobase_start_or_create_for_mysql();
2474
if (err != DB_SUCCESS)
2476
goto mem_free_and_error;
2479
err = dict_create_sys_replication_log();
2481
if (err != DB_SUCCESS) {
2482
goto mem_free_and_error;
2486
innobase_old_blocks_pct = buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(),
2489
innobase_open_tables = hash_create(200);
2492
actuall_engine_ptr->dropTemporarySchema();
2494
context.add(new InnodbStatusTool);
2495
context.add(innodb_engine_ptr);
2496
context.add(new CmpTool(false));
2497
context.add(new CmpTool(true));
2498
context.add(new CmpmemTool(false));
2499
context.add(new CmpmemTool(true));
2500
context.add(new InnodbTrxTool("INNODB_TRX"));
2501
context.add(new InnodbTrxTool("INNODB_LOCKS"));
2502
context.add(new InnodbTrxTool("INNODB_LOCK_WAITS"));
2503
context.add(new InnodbSysTablesTool());
2504
context.add(new InnodbSysTableStatsTool());
2505
context.add(new InnodbSysIndexesTool());
2506
context.add(new InnodbSysColumnsTool());
2507
context.add(new InnodbSysFieldsTool());
2508
context.add(new InnodbSysForeignTool());
2509
context.add(new InnodbSysForeignColsTool());
2510
context.add(new InnodbInternalTables());
2511
context.add(new InnodbReplicationTable());
2513
if (innobase_use_replication_log)
2515
ReplicationLog *replication_logger= new ReplicationLog();
2516
context.add(replication_logger);
2517
ReplicationLog::setup(replication_logger);
2520
context.registerVariable(new sys_var_const_string_val("data-home-dir", innobase_data_home_dir));
2521
context.registerVariable(new sys_var_const_string_val("flush-method",
2522
vm.count("flush-method") ? vm["flush-method"].as<string>() : ""));
2523
context.registerVariable(new sys_var_const_string_val("log-group-home-dir", innobase_log_group_home_dir));
2524
context.registerVariable(new sys_var_const_string_val("data-file-path", innobase_data_file_path));
2525
context.registerVariable(new sys_var_const_string_val("version", vm["version"].as<string>()));
2528
context.registerVariable(new sys_var_bool_ptr_readonly("replication_log", &innobase_use_replication_log));
2529
context.registerVariable(new sys_var_bool_ptr_readonly("checksums", &innobase_use_checksums));
2530
context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite", &innobase_use_doublewrite));
2531
context.registerVariable(new sys_var_bool_ptr("file-per-table", &srv_file_per_table));
2532
context.registerVariable(new sys_var_bool_ptr_readonly("file-format-check", &innobase_file_format_check));
2533
context.registerVariable(new sys_var_bool_ptr("adaptive-flushing", &srv_adaptive_flushing));
2534
context.registerVariable(new sys_var_bool_ptr("status-file", &innobase_create_status_file));
2535
context.registerVariable(new sys_var_bool_ptr_readonly("use-sys-malloc", &srv_use_sys_malloc));
2536
context.registerVariable(new sys_var_bool_ptr_readonly("use-native-aio", &srv_use_native_aio));
2538
context.registerVariable(new sys_var_bool_ptr("support-xa", &support_xa));
2539
context.registerVariable(new sys_var_bool_ptr("strict_mode", &strict_mode));
2540
context.registerVariable(new sys_var_constrained_value<uint32_t>("lock_wait_timeout", lock_wait_timeout));
2542
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
2543
context.registerVariable(new sys_var_constrained_value<uint32_t>("autoextend_increment",
2544
innodb_auto_extend_increment,
2545
auto_extend_update));
2546
context.registerVariable(new sys_var_constrained_value<uint32_t>("io_capacity",
2548
io_capacity_update));
2549
context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_batch_size",
2550
innodb_purge_batch_size,
2551
purge_batch_update));
2552
context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_threads",
2553
innodb_n_purge_threads,
2554
purge_threads_update));
2555
context.registerVariable(new sys_var_constrained_value<uint32_t>("fast_shutdown", innobase_fast_shutdown));
2556
context.registerVariable(new sys_var_std_string("file_format",
2557
innobase_file_format_name,
2558
innodb_file_format_name_validate));
2559
context.registerVariable(new sys_var_std_string("change_buffering",
2560
innobase_change_buffering,
2561
innodb_change_buffering_validate));
2562
context.registerVariable(new sys_var_std_string("file_format_max",
2563
innobase_file_format_max,
2564
innodb_file_format_max_validate));
2565
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
2566
context.registerVariable(new sys_var_constrained_value_readonly<int64_t>("log_file_size", innobase_log_file_size));
2567
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("page_size", innobase_page_size));
2568
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("log_block_size", innobase_log_block_size));
2569
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("flush_log_at_trx_commit",
2570
innodb_flush_log_at_trx_commit));
2571
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("max_dirty_pages_pct",
2572
innodb_max_dirty_pages_pct));
2573
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", innodb_max_purge_lag));
2574
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("stats_sample_pages", innodb_stats_sample_pages));
2575
context.registerVariable(new sys_var_bool_ptr("adaptive_hash_index", &btr_search_enabled, innodb_adaptive_hash_index_update));
2577
context.registerVariable(new sys_var_constrained_value<uint32_t>("commit_concurrency",
2578
innobase_commit_concurrency,
2579
innodb_commit_concurrency_validate));
2580
context.registerVariable(new sys_var_constrained_value<uint32_t>("concurrency_tickets",
2581
innodb_concurrency_tickets));
2582
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_io_threads", innobase_read_io_threads));
2583
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_io_threads", innobase_write_io_threads));
2584
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("replication_delay", innodb_replication_delay));
2585
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("force_recovery", innobase_force_recovery));
2586
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("log_buffer_size", innobase_log_buffer_size));
2587
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("log_files_in_group", innobase_log_files_in_group));
2588
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("mirrored_log_groups", innobase_mirrored_log_groups));
2589
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("open_files", innobase_open_files));
2590
context.registerVariable(new sys_var_constrained_value<uint32_t>("old_blocks_pct",
2591
innobase_old_blocks_pct,
2592
innodb_old_blocks_pct_update));
2593
context.registerVariable(new sys_var_uint32_t_ptr("old_blocks_time", &buf_LRU_old_threshold_ms));
2594
context.registerVariable(new sys_var_constrained_value<uint32_t>("sync_spin_loops", innodb_sync_spin_loops, innodb_sync_spin_loops_update));
2595
context.registerVariable(new sys_var_constrained_value<uint32_t>("spin_wait_delay", innodb_spin_wait_delay, innodb_spin_wait_delay_update));
2596
context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_sleep_delay", innodb_thread_sleep_delay, innodb_thread_sleep_delay_update));
2597
context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_concurrency",
2598
innobase_thread_concurrency,
2599
innodb_thread_concurrency_update));
2600
context.registerVariable(new sys_var_constrained_value<uint32_t>("read_ahead_threshold",
2601
innodb_read_ahead_threshold,
2602
innodb_read_ahead_threshold_update));
2603
context.registerVariable(new sys_var_constrained_value<uint32_t>("auto_lru_dump",
2604
buffer_pool_restore_at_startup,
2605
auto_lru_dump_update));
2606
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("ibuf_max_size",
2608
context.registerVariable(new sys_var_constrained_value<uint32_t>("ibuf_active_contract",
2609
ibuf_active_contract,
2610
ibuf_active_contract_update));
2611
context.registerVariable(new sys_var_constrained_value<uint32_t>("ibuf_accel_rate",
2613
ibuf_accel_rate_update));
2614
context.registerVariable(new sys_var_constrained_value<uint32_t>("checkpoint_age_target",
2615
checkpoint_age_target,
2616
checkpoint_age_target_update));
2617
context.registerVariable(new sys_var_constrained_value<uint32_t>("flush_neighbor_pages",
2618
flush_neighbor_pages,
2619
flush_neighbor_pages_update));
2620
context.registerVariable(new sys_var_std_string("read_ahead",
2622
read_ahead_validate));
2623
context.registerVariable(new sys_var_std_string("adaptive_flushing_method",
2624
adaptive_flushing_method,
2625
adaptive_flushing_method_validate));
2626
/* Get the current high water mark format. */
2627
innobase_file_format_max = trx_sys_file_format_max_get();
2628
btr_search_fully_disabled = (!btr_search_enabled);
2637
/****************************************************************//**
2638
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2639
the logs, and the name of this function should be innobase_checkpoint.
2640
@return TRUE if error */
2642
InnobaseEngine::flush_logs()
2643
/*=====================*/
2647
assert(this == innodb_engine_ptr);
2649
log_buffer_flush_to_disk();
2654
/*****************************************************************//**
2655
Commits a transaction in an InnoDB database. */
2658
innobase_commit_low(
2659
/*================*/
2660
trx_t* trx) /*!< in: transaction handle */
2662
if (trx->conc_state == TRX_NOT_STARTED) {
2667
trx_commit_for_mysql(trx);
2670
/*****************************************************************//**
2671
Creates an InnoDB transaction struct for the thd if it does not yet have one.
2672
Starts a new InnoDB transaction if a transaction is not yet started. And
2673
assigns a new snapshot for a consistent read if the transaction does not yet
2677
InnobaseEngine::doStartTransaction(
2678
/*====================================*/
2679
Session* session, /*!< in: MySQL thread handle of the user for whom
2680
the transaction should be committed */
2681
start_transaction_option_t options)
2683
assert(this == innodb_engine_ptr);
2685
/* Create a new trx struct for session, if it does not yet have one */
2686
trx_t *trx = check_trx_exists(session);
2688
/* This is just to play safe: release a possible FIFO ticket and
2689
search latch. Since we will reserve the kernel mutex, we have to
2690
release the search system latch first to obey the latching order. */
2691
innobase_release_stat_resources(trx);
2693
/* If the transaction is not started yet, start it */
2694
trx_start_if_not_started(trx);
2696
/* Assign a read view if the transaction does not have it yet */
2697
if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2698
trx_assign_read_view(trx);
2703
/*****************************************************************//**
2704
Commits a transaction in an InnoDB database or marks an SQL statement
2708
InnobaseEngine::doCommit(
2710
Session* session, /*!< in: MySQL thread handle of the user for whom
2711
the transaction should be committed */
2712
bool all) /*!< in: TRUE - commit transaction
2713
FALSE - the current SQL statement ended */
2717
assert(this == innodb_engine_ptr);
2719
trx = check_trx_exists(session);
2721
/* Since we will reserve the kernel mutex, we have to release
2722
the search system latch first to obey the latching order. */
2724
if (trx->has_search_latch) {
2725
trx_search_latch_release_if_reserved(trx);
2730
/* We were instructed to commit the whole transaction, or
2731
this is an SQL statement end and autocommit is on */
2733
/* We need current binlog position for ibbackup to work.
2734
Note, the position is current because of
2735
prepare_commit_mutex */
2736
const uint32_t commit_concurrency= innobase_commit_concurrency.get();
2737
if (commit_concurrency)
2741
boost::mutex::scoped_lock scopedLock(commit_cond_m);
2744
if (commit_threads <= commit_concurrency)
2748
commit_cond.wait(scopedLock);
2752
trx->mysql_log_file_name = NULL;
2753
trx->mysql_log_offset = 0;
2755
/* Don't do write + flush right now. For group commit
2756
to work we want to do the flush after releasing the
2757
prepare_commit_mutex. */
2758
trx->flush_log_later = TRUE;
2759
innobase_commit_low(trx);
2760
trx->flush_log_later = FALSE;
2762
if (commit_concurrency)
2764
boost::mutex::scoped_lock scopedLock(commit_cond_m);
2766
commit_cond.notify_one();
2769
/* Now do a write + flush of logs. */
2770
trx_commit_complete_for_mysql(trx);
2773
/* We just mark the SQL statement ended and do not do a
2774
transaction commit */
2776
/* If we had reserved the auto-inc lock for some
2777
table in this SQL statement we release it now */
2779
row_unlock_table_autoinc_for_mysql(trx);
2781
/* Store the current undo_no of the transaction so that we
2782
know where to roll back if we have to roll back the next
2785
trx_mark_sql_stat_end(trx);
2787
if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
2789
if (trx->conc_state != TRX_NOT_STARTED)
2791
commit(session, TRUE);
2796
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2798
if (trx->declared_to_be_inside_innodb) {
2799
/* Release our possible ticket in the FIFO */
2801
srv_conc_force_exit_innodb(trx);
2804
/* Tell the InnoDB server that there might be work for utility
2806
srv_active_wake_master_thread();
2808
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2809
trx->global_read_view)
2811
/* At low transaction isolation levels we let
2812
each consistent read set its own snapshot */
2813
read_view_close_for_mysql(trx);
2819
/*****************************************************************//**
2820
Rolls back a transaction or the latest SQL statement.
2821
@return 0 or error number */
2823
InnobaseEngine::doRollback(
2825
Session* session,/*!< in: handle to the MySQL thread of the user
2826
whose transaction should be rolled back */
2827
bool all) /*!< in: TRUE - commit transaction
2828
FALSE - the current SQL statement ended */
2833
assert(this == innodb_engine_ptr);
2835
trx = check_trx_exists(session);
2837
/* Release a possible FIFO ticket and search latch. Since we will
2838
reserve the kernel mutex, we have to release the search system latch
2839
first to obey the latching order. */
2841
innobase_release_stat_resources(trx);
2843
trx->n_autoinc_rows = 0;
2845
/* If we had reserved the auto-inc lock for some table (if
2846
we come here to roll back the latest SQL statement) we
2847
release it now before a possibly lengthy rollback */
2849
row_unlock_table_autoinc_for_mysql(trx);
2853
error = trx_rollback_for_mysql(trx);
2855
error = trx_rollback_last_sql_stat_for_mysql(trx);
2858
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2859
trx->global_read_view)
2861
/* At low transaction isolation levels we let
2862
each consistent read set its own snapshot */
2863
read_view_close_for_mysql(trx);
2866
return(convert_error_code_to_mysql(error, 0, NULL));
2869
/*****************************************************************//**
2870
Rolls back a transaction
2871
@return 0 or error number */
2874
innobase_rollback_trx(
2875
/*==================*/
2876
trx_t* trx) /*!< in: transaction */
2880
/* Release a possible FIFO ticket and search latch. Since we will
2881
reserve the kernel mutex, we have to release the search system latch
2882
first to obey the latching order. */
2884
innobase_release_stat_resources(trx);
2886
/* If we had reserved the auto-inc lock for some table (if
2887
we come here to roll back the latest SQL statement) we
2888
release it now before a possibly lengthy rollback */
2890
row_unlock_table_autoinc_for_mysql(trx);
2892
error = trx_rollback_for_mysql(trx);
2894
return(convert_error_code_to_mysql(error, 0, NULL));
2897
/*****************************************************************//**
2898
Rolls back a transaction to a savepoint.
2899
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2902
InnobaseEngine::doRollbackToSavepoint(
2903
/*===========================*/
2904
Session* session, /*!< in: handle to the MySQL thread of the user
2905
whose transaction should be rolled back */
2906
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2908
ib_int64_t mysql_binlog_cache_pos;
2912
assert(this == innodb_engine_ptr);
2914
trx = check_trx_exists(session);
2916
/* Release a possible FIFO ticket and search latch. Since we will
2917
reserve the kernel mutex, we have to release the search system latch
2918
first to obey the latching order. */
2920
innobase_release_stat_resources(trx);
2922
error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2923
&mysql_binlog_cache_pos);
2924
return(convert_error_code_to_mysql(error, 0, NULL));
2927
/*****************************************************************//**
2928
Release transaction savepoint name.
2929
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2932
InnobaseEngine::doReleaseSavepoint(
2933
/*=======================*/
2934
Session* session, /*!< in: handle to the MySQL thread of the user
2935
whose transaction should be rolled back */
2936
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2941
assert(this == innodb_engine_ptr);
2943
trx = check_trx_exists(session);
2945
error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2947
return(convert_error_code_to_mysql(error, 0, NULL));
2950
/*****************************************************************//**
2951
Sets a transaction savepoint.
2952
@return always 0, that is, always succeeds */
2954
InnobaseEngine::doSetSavepoint(
2956
Session* session,/*!< in: handle to the MySQL thread */
2957
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2962
assert(this == innodb_engine_ptr);
2965
In the autocommit mode there is no sense to set a savepoint
2966
(unless we are in sub-statement), so SQL layer ensures that
2967
this method is never called in such situation.
2970
trx = check_trx_exists(session);
2972
/* Release a possible FIFO ticket and search latch. Since we will
2973
reserve the kernel mutex, we have to release the search system latch
2974
first to obey the latching order. */
2976
innobase_release_stat_resources(trx);
2978
/* cannot happen outside of transaction */
2979
assert(trx->conc_state != TRX_NOT_STARTED);
2981
error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2983
return(convert_error_code_to_mysql(error, 0, NULL));
2986
/*****************************************************************//**
2987
Frees a possible InnoDB trx object associated with the current Session.
2988
@return 0 or error number */
2990
InnobaseEngine::close_connection(
2991
/*======================*/
2992
Session* session)/*!< in: handle to the MySQL thread of the user
2993
whose resources should be free'd */
2997
assert(this == innodb_engine_ptr);
2998
trx = session_to_trx(session);
3002
assert(session->getKilled() != Session::NOT_KILLED ||
3003
trx->conc_state == TRX_NOT_STARTED);
3005
/* Warn if rolling back some things... */
3006
if (session->getKilled() != Session::NOT_KILLED &&
3007
trx->conc_state != TRX_NOT_STARTED &&
3009
global_system_variables.log_warnings)
3011
errmsg_printf(error::WARN,
3012
"Drizzle is closing a connection during a KILL operation\n"
3013
"that has an active InnoDB transaction. %llu row modifications will "
3015
(ullint) trx->undo_no);
3018
innobase_rollback_trx(trx);
3020
thr_local_free(trx->mysql_thread_id);
3021
trx_free_for_mysql(trx);
3027
/*************************************************************************//**
3028
** InnoDB database tables
3029
*****************************************************************************/
3031
/****************************************************************//**
3032
Returns the index type. */
3035
ha_innobase::index_type(
3036
/*====================*/
3038
/*!< out: index type */
3043
/****************************************************************//**
3044
Returns the maximum number of keys.
3048
InnobaseEngine::max_supported_keys() const
3049
/*===================================*/
3054
/****************************************************************//**
3055
Returns the maximum key length.
3056
@return maximum supported key length, in bytes */
3059
InnobaseEngine::max_supported_key_length() const
3060
/*=========================================*/
3062
/* An InnoDB page must store >= 2 keys; a secondary key record
3063
must also contain the primary key value: max key length is
3064
therefore set to slightly less than 1 / 4 of page size which
3065
is 16 kB; but currently MySQL does not work with keys whose
3066
size is > MAX_KEY_LENGTH */
3070
/****************************************************************//**
3071
Returns the key map of keys that are usable for scanning.
3072
@return key_map_full */
3075
ha_innobase::keys_to_use_for_scanning()
3077
return(&key_map_full);
3081
/****************************************************************//**
3082
Determines if the primary key is clustered index.
3086
ha_innobase::primary_key_is_clustered()
3091
/********************************************************************//**
3092
Get the upper limit of the MySQL integral and floating-point type.
3093
@return maximum allowed value for the field */
3096
innobase_get_int_col_max_value(
3097
/*===========================*/
3098
const Field* field) /*!< in: MySQL field */
3100
uint64_t max_value = 0;
3102
switch(field->key_type()) {
3104
case HA_KEYTYPE_BINARY:
3105
max_value = 0xFFULL;
3108
case HA_KEYTYPE_ULONG_INT:
3109
max_value = 0xFFFFFFFFULL;
3111
case HA_KEYTYPE_LONG_INT:
3112
max_value = 0x7FFFFFFFULL;
3115
case HA_KEYTYPE_ULONGLONG:
3116
max_value = 0xFFFFFFFFFFFFFFFFULL;
3118
case HA_KEYTYPE_LONGLONG:
3119
max_value = 0x7FFFFFFFFFFFFFFFULL;
3121
case HA_KEYTYPE_DOUBLE:
3122
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
3123
max_value = 0x20000000000000ULL;
3132
/*******************************************************************//**
3133
This function checks whether the index column information
3134
is consistent between KEY info from mysql and that from innodb index.
3135
@return TRUE if all column types match. */
3138
innobase_match_index_columns(
3139
/*=========================*/
3140
const KeyInfo* key_info, /*!< in: Index info
3142
const dict_index_t* index_info) /*!< in: Index info
3145
const KeyPartInfo* key_part;
3146
const KeyPartInfo* key_end;
3147
const dict_field_t* innodb_idx_fld;
3148
const dict_field_t* innodb_idx_fld_end;
3150
/* Check whether user defined index column count matches */
3151
if (key_info->key_parts != index_info->n_user_defined_cols) {
3155
key_part = key_info->key_part;
3156
key_end = key_part + key_info->key_parts;
3157
innodb_idx_fld = index_info->fields;
3158
innodb_idx_fld_end = index_info->fields + index_info->n_fields;
3160
/* Check each index column's datatype. We do not check
3161
column name because there exists case that index
3162
column name got modified in mysql but such change does not
3163
propagate to InnoDB.
3164
One hidden assumption here is that the index column sequences
3165
are matched up between those in mysql and Innodb. */
3166
for (; key_part != key_end; ++key_part) {
3169
ulint mtype = innodb_idx_fld->col->mtype;
3171
/* Need to translate to InnoDB column type before
3173
col_type = get_innobase_type_from_mysql_type(&is_unsigned,
3176
/* Ignore Innodb specific system columns. */
3177
while (mtype == DATA_SYS) {
3180
if (innodb_idx_fld >= innodb_idx_fld_end) {
3185
if (col_type != mtype) {
3186
/* Column Type mismatches */
3196
/*******************************************************************//**
3197
This function builds a translation table in INNOBASE_SHARE
3198
structure for fast index location with mysql array number from its
3199
table->key_info structure. This also provides the necessary translation
3200
between the key order in mysql key_info and Innodb ib_table->indexes if
3201
they are not fully matched with each other.
3202
Note we do not have any mutex protecting the translation table
3203
building based on the assumption that there is no concurrent
3204
index creation/drop and DMLs that requires index lookup. All table
3205
handle will be closed before the index creation/drop.
3206
@return TRUE if index translation table built successfully */
3209
innobase_build_index_translation(
3210
/*=============================*/
3211
const Table* table, /*!< in: table in MySQL data
3213
dict_table_t* ib_table, /*!< in: table in Innodb data
3215
INNOBASE_SHARE* share) /*!< in/out: share structure
3216
where index translation table
3217
will be constructed in. */
3219
ulint mysql_num_index;
3221
dict_index_t** index_mapping;
3224
mutex_enter(&dict_sys->mutex);
3226
mysql_num_index = table->getShare()->keys;
3227
ib_num_index = UT_LIST_GET_LEN(ib_table->indexes);
3229
index_mapping = share->idx_trans_tbl.index_mapping;
3231
/* If there exists inconsistency between MySQL and InnoDB dictionary
3232
(metadata) information, the number of index defined in MySQL
3233
could exceed that in InnoDB, do not build index translation
3234
table in such case */
3235
if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) {
3240
/* If index entry count is non-zero, nothing has
3241
changed since last update, directly return TRUE */
3242
if (share->idx_trans_tbl.index_count) {
3243
/* Index entry count should still match mysql_num_index */
3244
ut_a(share->idx_trans_tbl.index_count == mysql_num_index);
3248
/* The number of index increased, rebuild the mapping table */
3249
if (mysql_num_index > share->idx_trans_tbl.array_size) {
3250
index_mapping = (dict_index_t**) realloc(index_mapping,
3252
sizeof(*index_mapping));
3254
if (!index_mapping) {
3255
/* Report an error if index_mapping continues to be
3256
NULL and mysql_num_index is a non-zero value */
3257
errmsg_printf(error::ERROR, "InnoDB: fail to allocate memory for "
3258
"index translation table. Number of Index:%lu, array size:%lu",
3260
share->idx_trans_tbl.array_size);
3265
share->idx_trans_tbl.array_size = mysql_num_index;
3268
/* For each index in the mysql key_info array, fetch its
3269
corresponding InnoDB index pointer into index_mapping
3271
for (ulint count = 0; count < mysql_num_index; count++) {
3273
/* Fetch index pointers into index_mapping according to mysql
3275
index_mapping[count] = dict_table_get_index_on_name(
3276
ib_table, table->key_info[count].name);
3278
if (!index_mapping[count]) {
3279
errmsg_printf(error::ERROR, "Cannot find index %s in InnoDB index dictionary.",
3280
table->key_info[count].name);
3285
/* Double check fetched index has the same
3286
column info as those in mysql key_info. */
3287
if (!innobase_match_index_columns(&table->key_info[count], index_mapping[count])) {
3288
errmsg_printf(error::ERROR, "Found index %s whose column info does not match that of MySQL.",
3289
table->key_info[count].name);
3295
/* Successfully built the translation table */
3296
share->idx_trans_tbl.index_count = mysql_num_index;
3300
/* Build translation table failed. */
3301
free(index_mapping);
3303
share->idx_trans_tbl.array_size = 0;
3304
share->idx_trans_tbl.index_count = 0;
3305
index_mapping = NULL;
3308
share->idx_trans_tbl.index_mapping = index_mapping;
3310
mutex_exit(&dict_sys->mutex);
3315
/*******************************************************************//**
3316
This function uses index translation table to quickly locate the
3317
requested index structure.
3318
Note we do not have mutex protection for the index translatoin table
3319
access, it is based on the assumption that there is no concurrent
3320
translation table rebuild (fter create/drop index) and DMLs that
3321
require index lookup.
3322
@return dict_index_t structure for requested index. NULL if
3323
fail to locate the index structure. */
3326
innobase_index_lookup(
3327
/*==================*/
3328
INNOBASE_SHARE* share, /*!< in: share structure for index
3329
translation table. */
3330
uint keynr) /*!< in: index number for the requested
3333
if (!share->idx_trans_tbl.index_mapping
3334
|| keynr >= share->idx_trans_tbl.index_count) {
3338
return(share->idx_trans_tbl.index_mapping[keynr]);
3341
/********************************************************************//**
3342
Set the autoinc column max value. This should only be called once from
3343
ha_innobase::open(). Therefore there's no need for a covering lock. */
3346
ha_innobase::innobase_initialize_autoinc()
3347
/*======================================*/
3350
const Field* field = getTable()->found_next_number_field;
3352
if (field != NULL) {
3353
auto_inc = innobase_get_int_col_max_value(field);
3355
/* We have no idea what's been passed in to us as the
3356
autoinc column. We set it to the 0, effectively disabling
3357
updates to the table. */
3360
ut_print_timestamp(stderr);
3361
errmsg_printf(error::ERROR, "InnoDB: Unable to determine the AUTOINC column name");
3364
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3365
/* If the recovery level is set so high that writes
3366
are disabled we force the AUTOINC counter to 0
3367
value effectively disabling writes to the table.
3368
Secondly, we avoid reading the table in case the read
3369
results in failure due to a corrupted table/index.
3371
We will not return an error to the client, so that the
3372
tables can be dumped with minimal hassle. If an error
3373
were returned in this case, the first attempt to read
3374
the table would fail and subsequent SELECTs would succeed. */
3376
} else if (field == NULL) {
3377
/* This is a far more serious error, best to avoid
3378
opening the table and return failure. */
3379
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
3381
dict_index_t* index;
3382
const char* col_name;
3383
uint64_t read_auto_inc;
3386
update_session(getTable()->in_use);
3387
col_name = field->field_name;
3389
ut_a(prebuilt->trx == session_to_trx(user_session));
3391
index = innobase_get_index(getTable()->getShare()->next_number_index);
3393
/* Execute SELECT MAX(col_name) FROM TABLE; */
3394
err = row_search_max_autoinc(index, col_name, &read_auto_inc);
3398
uint64_t col_max_value;
3400
col_max_value = innobase_get_int_col_max_value(field);
3402
/* At the this stage we do not know the increment
3403
nor the offset, so use a default increment of 1. */
3405
auto_inc = innobase_next_autoinc(read_auto_inc, 1, 1, col_max_value);
3409
case DB_RECORD_NOT_FOUND:
3410
ut_print_timestamp(stderr);
3411
errmsg_printf(error::ERROR, "InnoDB: MySQL and InnoDB data dictionaries are out of sync.\n"
3412
"InnoDB: Unable to find the AUTOINC column %s in the InnoDB table %s.\n"
3413
"InnoDB: We set the next AUTOINC column value to 0,\n"
3414
"InnoDB: in effect disabling the AUTOINC next value generation.\n"
3415
"InnoDB: You can either set the next AUTOINC value explicitly using ALTER TABLE\n"
3416
"InnoDB: or fix the data dictionary by recreating the table.\n",
3417
col_name, index->table->name);
3419
/* This will disable the AUTOINC generation. */
3422
/* We want the open to succeed, so that the user can
3423
take corrective action. ie. reads should succeed but
3424
updates should fail. */
3428
/* row_search_max_autoinc() should only return
3429
one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
3434
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
3437
/*****************************************************************//**
3438
Creates and opens a handle to a table which already exists in an InnoDB
3440
@return 1 if error, 0 if success */
3443
ha_innobase::doOpen(const identifier::Table &identifier,
3444
int mode, /*!< in: not used */
3445
uint test_if_locked) /*!< in: not used */
3447
dict_table_t* ib_table;
3451
UT_NOT_USED(test_if_locked);
3453
session= getTable()->in_use;
3455
/* Under some cases Drizzle seems to call this function while
3456
holding btr_search_latch. This breaks the latching order as
3457
we acquire dict_sys->mutex below and leads to a deadlock. */
3458
if (session != NULL) {
3459
getTransactionalEngine()->releaseTemporaryLatches(session);
3462
user_session = NULL;
3464
std::string search_string(identifier.getSchemaName());
3465
boost::algorithm::to_lower(search_string);
3467
if (search_string.compare("data_dictionary") == 0)
3469
std::string table_name(identifier.getTableName());
3470
boost::algorithm::to_upper(table_name);
3471
if (!(share=get_share(table_name.c_str())))
3478
if (!(share=get_share(identifier.getKeyPath().c_str())))
3484
/* Create buffers for packing the fields of a record. Why
3485
table->stored_rec_length did not work here? Obviously, because char
3486
fields when packed actually became 1 byte longer, when we also
3487
stored the string length as the first byte. */
3489
upd_and_key_val_buff_len =
3490
getTable()->getShare()->sizeStoredRecord()
3491
+ getTable()->getShare()->max_key_length
3492
+ MAX_REF_PARTS * 3;
3494
upd_buff.resize(upd_and_key_val_buff_len);
3496
if (upd_buff.size() < upd_and_key_val_buff_len)
3501
key_val_buff.resize(upd_and_key_val_buff_len);
3502
if (key_val_buff.size() < upd_and_key_val_buff_len)
3507
/* Get pointer to a table object in InnoDB dictionary cache */
3508
if (search_string.compare("data_dictionary") == 0)
3510
std::string table_name(identifier.getTableName());
3511
boost::algorithm::to_upper(table_name);
3512
ib_table = dict_table_get(table_name.c_str(), TRUE);
3516
ib_table = dict_table_get(identifier.getKeyPath().c_str(), TRUE);
3519
if (NULL == ib_table) {
3520
errmsg_printf(error::ERROR, "Cannot find or open table %s from\n"
3521
"the internal data dictionary of InnoDB "
3522
"though the .frm file for the\n"
3523
"table exists. Maybe you have deleted and "
3524
"recreated InnoDB data\n"
3525
"files but have forgotten to delete the "
3526
"corresponding .frm files\n"
3527
"of InnoDB tables, or you have moved .frm "
3528
"files to another database?\n"
3529
"or, the table contains indexes that this "
3530
"version of the engine\n"
3531
"doesn't support.\n"
3532
"See " REFMAN "innodb-troubleshooting.html\n"
3533
"how you can resolve the problem.\n",
3534
identifier.getKeyPath().c_str());
3537
key_val_buff.resize(0);
3540
return(HA_ERR_NO_SUCH_TABLE);
3543
if (ib_table->ibd_file_missing && ! session->doing_tablespace_operation()) {
3544
errmsg_printf(error::ERROR, "MySQL is trying to open a table handle but "
3545
"the .ibd file for\ntable %s does not exist.\n"
3546
"Have you deleted the .ibd file from the "
3547
"database directory under\nthe MySQL datadir, "
3548
"or have you used DISCARD TABLESPACE?\n"
3549
"See " REFMAN "innodb-troubleshooting.html\n"
3550
"how you can resolve the problem.\n",
3551
identifier.getKeyPath().c_str());
3554
key_val_buff.resize(0);
3557
dict_table_decrement_handle_count(ib_table, FALSE);
3558
return(HA_ERR_NO_SUCH_TABLE);
3561
prebuilt = row_create_prebuilt(ib_table);
3563
prebuilt->mysql_row_len = getTable()->getShare()->sizeStoredRecord();
3564
prebuilt->default_rec = getTable()->getDefaultValues();
3565
ut_ad(prebuilt->default_rec);
3567
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
3569
primary_key = getTable()->getShare()->getPrimaryKey();
3570
key_used_on_scan = primary_key;
3572
if (!innobase_build_index_translation(getTable(), ib_table, share)) {
3573
errmsg_printf(error::ERROR, "Build InnoDB index translation table for"
3574
" Table %s failed", identifier.getKeyPath().c_str());
3577
/* Allocate a buffer for a 'row reference'. A row reference is
3578
a string of bytes of length ref_length which uniquely specifies
3579
a row in our table. Note that MySQL may also compare two row
3580
references for equality by doing a simple memcmp on the strings
3581
of length ref_length! */
3583
if (!row_table_got_default_clust_index(ib_table)) {
3585
prebuilt->clust_index_was_generated = FALSE;
3587
if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
3588
errmsg_printf(error::ERROR, "Table %s has a primary key in "
3589
"InnoDB data dictionary, but not "
3590
"in MySQL!", identifier.getTableName().c_str());
3592
/* This mismatch could cause further problems
3593
if not attended, bring this to the user's attention
3594
by printing a warning in addition to log a message
3596
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3598
"InnoDB: Table %s has a "
3599
"primary key in InnoDB data "
3600
"dictionary, but not in "
3601
"MySQL!", identifier.getTableName().c_str());
3603
/* If primary_key >= MAX_KEY, its (primary_key)
3604
value could be out of bound if continue to index
3605
into key_info[] array. Find InnoDB primary index,
3606
and assign its key_length to ref_length.
3607
In addition, since MySQL indexes are sorted starting
3608
with primary index, unique index etc., initialize
3609
ref_length to the first index key length in
3610
case we fail to find InnoDB cluster index.
3612
Please note, this will not resolve the primary
3613
index mismatch problem, other side effects are
3614
possible if users continue to use the table.
3615
However, we allow this table to be opened so
3616
that user can adopt necessary measures for the
3617
mismatch while still being accessible to the table
3619
ref_length = getTable()->key_info[0].key_length;
3621
/* Find correspoinding cluster index
3622
key length in MySQL's key_info[] array */
3623
for (ulint i = 0; i < getTable()->getShare()->keys; i++) {
3624
dict_index_t* index;
3625
index = innobase_get_index(i);
3626
if (dict_index_is_clust(index)) {
3628
getTable()->key_info[i].key_length;
3632
/* MySQL allocates the buffer for ref.
3633
key_info->key_length includes space for all key
3634
columns + one byte for each column that may be
3635
NULL. ref_length must be as exact as possible to
3636
save space, because all row reference buffers are
3637
allocated based on ref_length. */
3639
ref_length = getTable()->key_info[primary_key].key_length;
3642
if (primary_key != MAX_KEY) {
3643
errmsg_printf(error::ERROR,
3644
"Table %s has no primary key in InnoDB data "
3645
"dictionary, but has one in MySQL! If you "
3646
"created the table with a MySQL version < "
3647
"3.23.54 and did not define a primary key, "
3648
"but defined a unique key with all non-NULL "
3649
"columns, then MySQL internally treats that "
3650
"key as the primary key. You can fix this "
3651
"error by dump + DROP + CREATE + reimport "
3652
"of the table.", identifier.getTableName().c_str());
3654
/* This mismatch could cause further problems
3655
if not attended, bring this to the user attention
3656
by printing a warning in addition to log a message
3658
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3660
"InnoDB: Table %s has no "
3661
"primary key in InnoDB data "
3662
"dictionary, but has one in "
3663
"MySQL!", identifier.getTableName().c_str());
3666
prebuilt->clust_index_was_generated = TRUE;
3668
ref_length = DATA_ROW_ID_LEN;
3670
/* If we automatically created the clustered index, then
3671
MySQL does not know about it, and MySQL must NOT be aware
3672
of the index used on scan, to make it avoid checking if we
3673
update the column of the index. That is why we assert below
3674
that key_used_on_scan is the undefined value MAX_KEY.
3675
The column is the row id in the automatical generation case,
3676
and it will never be updated anyway. */
3678
if (key_used_on_scan != MAX_KEY) {
3679
errmsg_printf(error::WARN,
3680
"Table %s key_used_on_scan is %lu even "
3681
"though there is no primary key inside "
3682
"InnoDB.", identifier.getTableName().c_str(), (ulong) key_used_on_scan);
3686
/* Index block size in InnoDB: used by MySQL in query optimization */
3687
stats.block_size = 16 * 1024;
3689
/* Init table lock structure */
3690
lock.init(&share->lock);
3692
if (prebuilt->table) {
3693
/* We update the highest file format in the system table
3694
space, if this table has higher file format setting. */
3696
char changed_file_format_max[100];
3697
strcpy(changed_file_format_max, innobase_file_format_max.c_str());
3698
trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
3699
dict_table_get_format(prebuilt->table));
3700
innobase_file_format_max= changed_file_format_max;
3703
/* Only if the table has an AUTOINC column. */
3704
if (prebuilt->table != NULL && getTable()->found_next_number_field != NULL) {
3706
dict_table_autoinc_lock(prebuilt->table);
3708
/* Since a table can already be "open" in InnoDB's internal
3709
data dictionary, we only init the autoinc counter once, the
3710
first time the table is loaded. We can safely reuse the
3711
autoinc value from a previous Drizzle open. */
3712
if (dict_table_autoinc_read(prebuilt->table) == 0) {
3714
innobase_initialize_autoinc();
3717
dict_table_autoinc_unlock(prebuilt->table);
3720
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
3727
InnobaseEngine::max_supported_key_part_length() const
3729
return(DICT_MAX_INDEX_COL_LEN - 1);
3732
/******************************************************************//**
3733
Closes a handle to an InnoDB table.
3737
ha_innobase::close(void)
3738
/*====================*/
3742
session= getTable()->in_use;
3743
if (session != NULL) {
3744
getTransactionalEngine()->releaseTemporaryLatches(session);
3747
row_prebuilt_free(prebuilt, FALSE);
3750
key_val_buff.clear();
3753
/* Tell InnoDB server that there might be work for
3756
srv_active_wake_master_thread();
3761
/* The following accessor functions should really be inside MySQL code! */
3763
/**************************************************************//**
3764
Gets field offset for a field in a table.
3770
Table* table, /*!< in: MySQL table object */
3771
Field* field) /*!< in: MySQL field object */
3773
return((uint) (field->ptr - table->getInsertRecord()));
3776
/**************************************************************//**
3777
Checks if a field in a record is SQL NULL. Uses the record format
3778
information in table to track the null bit in record.
3779
@return 1 if NULL, 0 otherwise */
3782
field_in_record_is_null(
3783
/*====================*/
3784
Table* table, /*!< in: MySQL table object */
3785
Field* field, /*!< in: MySQL field object */
3786
char* record) /*!< in: a row in MySQL format */
3790
if (!field->null_ptr) {
3795
null_offset = (uint) ((char*) field->null_ptr
3796
- (char*) table->getInsertRecord());
3798
if (record[null_offset] & field->null_bit) {
3806
/**************************************************************//**
3807
Sets a field in a record to SQL NULL. Uses the record format
3808
information in table to track the null bit in record. */
3811
set_field_in_record_to_null(
3812
/*========================*/
3813
Table* table, /*!< in: MySQL table object */
3814
Field* field, /*!< in: MySQL field object */
3815
char* record) /*!< in: a row in MySQL format */
3819
null_offset = (uint) ((char*) field->null_ptr
3820
- (char*) table->getInsertRecord());
3822
record[null_offset] = record[null_offset] | field->null_bit;
3825
/*************************************************************//**
3826
InnoDB uses this function to compare two data fields for which the data type
3827
is such that we must use MySQL code to compare them. NOTE that the prototype
3828
of this function is in rem0cmp.c in InnoDB source code! If you change this
3829
function, remember to update the prototype there!
3830
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
3834
int mysql_type, /*!< in: MySQL type */
3835
uint charset_number, /*!< in: number of the charset */
3836
const unsigned char* a, /*!< in: data field */
3837
unsigned int a_length, /*!< in: data field length,
3838
not UNIV_SQL_NULL */
3839
const unsigned char* b, /* in: data field */
3840
unsigned int b_length); /* in: data field length,
3841
not UNIV_SQL_NULL */
3846
/* out: 1, 0, -1, if a is greater, equal, less than b, respectively */
3847
int mysql_type, /* in: MySQL type */
3848
uint charset_number, /* in: number of the charset */
3849
const unsigned char* a, /* in: data field */
3850
unsigned int a_length, /* in: data field length, not UNIV_SQL_NULL */
3851
const unsigned char* b, /* in: data field */
3852
unsigned int b_length) /* in: data field length, not UNIV_SQL_NULL */
3854
const charset_info_st* charset;
3855
enum_field_types mysql_tp;
3858
assert(a_length != UNIV_SQL_NULL);
3859
assert(b_length != UNIV_SQL_NULL);
3861
mysql_tp = (enum_field_types) mysql_type;
3865
case DRIZZLE_TYPE_BLOB:
3866
case DRIZZLE_TYPE_VARCHAR:
3867
/* Use the charset number to pick the right charset struct for
3868
the comparison. Since the MySQL function get_charset may be
3869
slow before Bar removes the mutex operation there, we first
3870
look at 2 common charsets directly. */
3872
if (charset_number == default_charset_info->number) {
3873
charset = default_charset_info;
3875
charset = get_charset(charset_number);
3877
if (charset == NULL) {
3878
errmsg_printf(error::ERROR, "InnoDB needs charset %lu for doing "
3879
"a comparison, but MySQL cannot "
3880
"find that charset.",
3881
(ulong) charset_number);
3886
/* Starting from 4.1.3, we use strnncollsp() in comparisons of
3887
non-latin1_swedish_ci strings. NOTE that the collation order
3888
changes then: 'b\0\0...' is ordered BEFORE 'b ...'. Users
3889
having indexes on such data need to rebuild their tables! */
3891
ret = charset->coll->strnncollsp(charset,
3896
} else if (ret > 0) {
3908
/**************************************************************//**
3909
Converts a MySQL type to an InnoDB type. Note that this function returns
3910
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3911
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3912
@return DATA_BINARY, DATA_VARCHAR, ... */
3915
get_innobase_type_from_mysql_type(
3916
/*==============================*/
3917
ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
3919
at least ENUM and SET,
3920
and unsigned integer
3921
types are 'unsigned types' */
3922
const void* f) /*!< in: MySQL Field */
3924
const class Field* field = reinterpret_cast<const class Field*>(f);
3926
/* The following asserts try to check that the MySQL type code fits in
3927
8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3930
assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3932
if (field->flags & UNSIGNED_FLAG) {
3934
*unsigned_flag = DATA_UNSIGNED;
3939
if (field->real_type() == DRIZZLE_TYPE_ENUM)
3941
/* MySQL has field->type() a string type for these, but the
3942
data is actually internally stored as an unsigned integer
3945
*unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3946
flag set to zero, even though
3947
internally this is an unsigned
3952
switch (field->type()) {
3953
/* NOTE that we only allow string types in DATA_DRIZZLE and
3955
case DRIZZLE_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
3956
if (field->binary()) {
3957
return(DATA_BINARY);
3959
return(DATA_VARMYSQL);
3961
case DRIZZLE_TYPE_DECIMAL:
3962
case DRIZZLE_TYPE_MICROTIME:
3963
return(DATA_FIXBINARY);
3964
case DRIZZLE_TYPE_LONG:
3965
case DRIZZLE_TYPE_LONGLONG:
3966
case DRIZZLE_TYPE_DATETIME:
3967
case DRIZZLE_TYPE_TIME:
3968
case DRIZZLE_TYPE_DATE:
3969
case DRIZZLE_TYPE_TIMESTAMP:
3970
case DRIZZLE_TYPE_ENUM:
3972
case DRIZZLE_TYPE_DOUBLE:
3973
return(DATA_DOUBLE);
3974
case DRIZZLE_TYPE_BLOB:
3976
case DRIZZLE_TYPE_BOOLEAN:
3977
case DRIZZLE_TYPE_UUID:
3978
return(DATA_FIXBINARY);
3979
case DRIZZLE_TYPE_IPV6:
3980
return(DATA_FIXBINARY);
3981
case DRIZZLE_TYPE_NULL:
3988
/*******************************************************************//**
3989
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
3993
innobase_write_to_2_little_endian(
3994
/*==============================*/
3995
byte* buf, /*!< in: where to store */
3996
ulint val) /*!< in: value to write, must be < 64k */
3998
ut_a(val < 256 * 256);
4000
buf[0] = (byte)(val & 0xFF);
4001
buf[1] = (byte)(val / 256);
4004
/*******************************************************************//**
4005
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
4010
innobase_read_from_2_little_endian(
4011
/*===============================*/
4012
const unsigned char* buf) /*!< in: from where to read */
4014
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
4017
/*******************************************************************//**
4018
Stores a key value for a row to a buffer.
4019
@return key value length as stored in buff */
4022
ha_innobase::store_key_val_for_row(
4023
/*===============================*/
4024
uint keynr, /*!< in: key number */
4025
char* buff, /*!< in/out: buffer for the key value (in MySQL
4027
uint buff_len,/*!< in: buffer length */
4028
const unsigned char* record)/*!< in: row in MySQL format */
4030
KeyInfo* key_info = &getTable()->key_info[keynr];
4031
KeyPartInfo* key_part = key_info->key_part;
4032
KeyPartInfo* end = key_part + key_info->key_parts;
4033
char* buff_start = buff;
4034
enum_field_types mysql_type;
4038
/* The format for storing a key field in MySQL is the following:
4040
1. If the column can be NULL, then in the first byte we put 1 if the
4041
field value is NULL, 0 otherwise.
4043
2. If the column is of a BLOB type (it must be a column prefix field
4044
in this case), then we put the length of the data in the field to the
4045
next 2 bytes, in the little-endian format. If the field is SQL NULL,
4046
then these 2 bytes are set to 0. Note that the length of data in the
4047
field is <= column prefix length.
4049
3. In a column prefix field, prefix_len next bytes are reserved for
4050
data. In a normal field the max field length next bytes are reserved
4051
for data. For a VARCHAR(n) the max field length is n. If the stored
4052
value is the SQL NULL then these data bytes are set to 0.
4054
4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
4055
in the MySQL row format, the length is stored in 1 or 2 bytes,
4056
depending on the maximum allowed length. But in the MySQL key value
4057
format, the length always takes 2 bytes.
4059
We have to zero-fill the buffer so that MySQL is able to use a
4060
simple memcmp to compare two key values to determine if they are
4061
equal. MySQL does this to compare contents of two 'ref' values. */
4063
bzero(buff, buff_len);
4065
for (; key_part != end; key_part++) {
4068
if (key_part->null_bit) {
4069
if (record[key_part->null_offset]
4070
& key_part->null_bit) {
4079
field = key_part->field;
4080
mysql_type = field->type();
4082
if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
4083
/* >= 5.0.3 true VARCHAR */
4089
const charset_info_st* cs;
4092
key_len = key_part->length;
4095
buff += key_len + 2;
4099
cs = field->charset();
4102
(((Field_varstring*)field)->pack_length_no_ptr());
4104
data = row_mysql_read_true_varchar(&len,
4106
+ (ulint)get_field_offset(getTable(), field)),
4111
/* For multi byte character sets we need to calculate
4112
the true length of the key */
4114
if (len > 0 && cs->mbmaxlen > 1) {
4115
true_len = (ulint) cs->cset->well_formed_len(cs,
4116
(const char *) data,
4117
(const char *) data + len,
4123
/* In a column prefix index, we may need to truncate
4124
the stored value: */
4126
if (true_len > key_len) {
4130
/* The length in a key value is always stored in 2
4133
row_mysql_store_true_var_len((byte*)buff, true_len, 2);
4136
memcpy(buff, data, true_len);
4138
/* Note that we always reserve the maximum possible
4139
length of the true VARCHAR in the key value, though
4140
only len first bytes after the 2 length bytes contain
4141
actual data. The rest of the space was reset to zero
4142
in the bzero() call above. */
4146
} else if (mysql_type == DRIZZLE_TYPE_BLOB) {
4148
const charset_info_st* cs;
4153
const byte* blob_data;
4155
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
4157
key_len = key_part->length;
4160
buff += key_len + 2;
4165
cs = field->charset();
4167
blob_data = row_mysql_read_blob_ref(&blob_len,
4169
+ (ulint)get_field_offset(getTable(), field)),
4170
(ulint) field->pack_length());
4172
true_len = blob_len;
4174
ut_a(get_field_offset(getTable(), field)
4175
== key_part->offset);
4177
/* For multi byte character sets we need to calculate
4178
the true length of the key */
4180
if (blob_len > 0 && cs->mbmaxlen > 1) {
4181
true_len = (ulint) cs->cset->well_formed_len(cs,
4182
(const char *) blob_data,
4183
(const char *) blob_data
4190
/* All indexes on BLOB and TEXT are column prefix
4191
indexes, and we may need to truncate the data to be
4192
stored in the key value: */
4194
if (true_len > key_len) {
4198
/* MySQL reserves 2 bytes for the length and the
4199
storage of the number is little-endian */
4201
innobase_write_to_2_little_endian(
4202
(byte*)buff, true_len);
4205
memcpy(buff, blob_data, true_len);
4207
/* Note that we always reserve the maximum possible
4208
length of the BLOB prefix in the key value. */
4212
/* Here we handle all other data types except the
4213
true VARCHAR, BLOB and TEXT. Note that the column
4214
value we store may be also in a column prefix
4219
const unsigned char* src_start;
4220
const charset_info_st* cs= field->charset();
4222
key_len = key_part->length;
4230
src_start = record + key_part->offset;
4233
/* Character set for the field is defined only
4234
to fields whose type is string and real field
4235
type is not enum or set. For these fields check
4236
if character set is multi byte. */
4238
memcpy(buff, src_start, true_len);
4241
/* Pad the unused space with spaces. */
4243
if (true_len < key_len) {
4244
ulint pad_len = key_len - true_len;
4245
ut_a(!(pad_len % cs->mbminlen));
4247
cs->cset->fill(cs, buff, pad_len,
4254
ut_a(buff <= buff_start + buff_len);
4256
return((uint)(buff - buff_start));
4259
/**************************************************************//**
4260
Builds a 'template' to the prebuilt struct. The template is used in fast
4261
retrieval of just those column values MySQL needs in its processing. */
4266
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
4267
Session* , /*!< in: current user thread, used
4268
only if templ_type is
4269
ROW_DRIZZLE_REC_FIELDS */
4270
Table* table, /*!< in: MySQL table */
4271
uint templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
4272
ROW_DRIZZLE_REC_FIELDS */
4274
dict_index_t* index;
4275
dict_index_t* clust_index;
4276
mysql_row_templ_t* templ;
4279
ulint n_requested_fields = 0;
4280
ibool fetch_all_in_key = FALSE;
4281
ibool fetch_primary_key_cols = FALSE;
4283
/* byte offset of the end of last requested column */
4284
ulint mysql_prefix_len = 0;
4286
if (prebuilt->select_lock_type == LOCK_X) {
4287
/* We always retrieve the whole clustered index record if we
4288
use exclusive row level locks, for example, if the read is
4289
done in an UPDATE statement. */
4291
templ_type = ROW_MYSQL_WHOLE_ROW;
4294
if (templ_type == ROW_MYSQL_REC_FIELDS) {
4295
if (prebuilt->hint_need_to_fetch_extra_cols
4296
== ROW_RETRIEVE_ALL_COLS) {
4298
/* We know we must at least fetch all columns in the
4299
key, or all columns in the table */
4301
if (prebuilt->read_just_key) {
4302
/* MySQL has instructed us that it is enough
4303
to fetch the columns in the key; looks like
4304
MySQL can set this flag also when there is
4305
only a prefix of the column in the key: in
4306
that case we retrieve the whole column from
4307
the clustered index */
4309
fetch_all_in_key = TRUE;
4311
templ_type = ROW_MYSQL_WHOLE_ROW;
4313
} else if (prebuilt->hint_need_to_fetch_extra_cols
4314
== ROW_RETRIEVE_PRIMARY_KEY) {
4315
/* We must at least fetch all primary key cols. Note
4316
that if the clustered index was internally generated
4317
by InnoDB on the row id (no primary key was
4318
defined), then row_search_for_mysql() will always
4319
retrieve the row id to a special buffer in the
4322
fetch_primary_key_cols = TRUE;
4326
clust_index = dict_table_get_first_index(prebuilt->table);
4328
if (templ_type == ROW_MYSQL_REC_FIELDS) {
4329
index = prebuilt->index;
4331
index = clust_index;
4334
if (index == clust_index) {
4335
prebuilt->need_to_access_clustered = TRUE;
4337
prebuilt->need_to_access_clustered = FALSE;
4338
/* Below we check column by column if we need to access
4339
the clustered index */
4342
n_fields = (ulint)table->getShare()->sizeFields(); /* number of columns */
4344
if (!prebuilt->mysql_template) {
4345
prebuilt->mysql_template = (mysql_row_templ_t*)
4346
mem_alloc(n_fields * sizeof(mysql_row_templ_t));
4349
prebuilt->template_type = templ_type;
4350
prebuilt->null_bitmap_len = table->getShare()->null_bytes;
4352
prebuilt->templ_contains_blob = FALSE;
4354
/* Note that in InnoDB, i is the column number. MySQL calls columns
4356
for (i = 0; i < n_fields; i++)
4358
const dict_col_t *col= &index->table->cols[i];
4359
templ = prebuilt->mysql_template + n_requested_fields;
4360
field = table->getField(i);
4362
if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
4363
/* Decide which columns we should fetch
4364
and which we can skip. */
4365
register const ibool index_contains_field =
4366
dict_index_contains_col_or_prefix(index, i);
4368
if (!index_contains_field && prebuilt->read_just_key) {
4369
/* If this is a 'key read', we do not need
4370
columns that are not in the key */
4375
if (index_contains_field && fetch_all_in_key) {
4376
/* This field is needed in the query */
4381
if (field->isReadSet() || field->isWriteSet())
4382
/* This field is needed in the query */
4385
assert(table->isReadSet(i) == field->isReadSet());
4386
assert(table->isWriteSet(i) == field->isWriteSet());
4388
if (fetch_primary_key_cols
4389
&& dict_table_col_in_clustered_key(
4391
/* This field is needed in the query */
4396
/* This field is not needed in the query, skip it */
4401
n_requested_fields++;
4404
templ->clust_rec_field_no = dict_col_get_clust_pos(col, clust_index);
4405
ut_ad(templ->clust_rec_field_no != ULINT_UNDEFINED);
4407
if (index == clust_index) {
4408
templ->rec_field_no = templ->clust_rec_field_no;
4410
templ->rec_field_no = dict_index_get_nth_col_pos(
4412
if (templ->rec_field_no == ULINT_UNDEFINED) {
4413
prebuilt->need_to_access_clustered = TRUE;
4417
if (field->null_ptr) {
4418
templ->mysql_null_byte_offset =
4419
(ulint) ((char*) field->null_ptr
4420
- (char*) table->getInsertRecord());
4422
templ->mysql_null_bit_mask = (ulint) field->null_bit;
4424
templ->mysql_null_bit_mask = 0;
4427
templ->mysql_col_offset = (ulint)
4428
get_field_offset(table, field);
4430
templ->mysql_col_len = (ulint) field->pack_length();
4431
if (mysql_prefix_len < templ->mysql_col_offset
4432
+ templ->mysql_col_len) {
4433
mysql_prefix_len = templ->mysql_col_offset
4434
+ templ->mysql_col_len;
4436
templ->type = col->mtype;
4437
templ->mysql_type = (ulint)field->type();
4439
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
4440
templ->mysql_length_bytes = (ulint)
4441
(((Field_varstring*)field)->pack_length_no_ptr());
4444
templ->charset = dtype_get_charset_coll(col->prtype);
4445
templ->mbminlen = dict_col_get_mbminlen(col);
4446
templ->mbmaxlen = dict_col_get_mbmaxlen(col);
4447
templ->is_unsigned = col->prtype & DATA_UNSIGNED;
4448
if (templ->type == DATA_BLOB) {
4449
prebuilt->templ_contains_blob = TRUE;
4455
prebuilt->n_template = n_requested_fields;
4456
prebuilt->mysql_prefix_len = mysql_prefix_len;
4458
if (index != clust_index && prebuilt->need_to_access_clustered) {
4459
/* Change rec_field_no's to correspond to the clustered index
4461
for (i = 0; i < n_requested_fields; i++) {
4462
templ = prebuilt->mysql_template + i;
4464
templ->rec_field_no = templ->clust_rec_field_no;
4469
/********************************************************************//**
4470
This special handling is really to overcome the limitations of MySQL's
4471
binlogging. We need to eliminate the non-determinism that will arise in
4472
INSERT ... SELECT type of statements, since MySQL binlog only stores the
4473
min value of the autoinc interval. Once that is fixed we can get rid of
4474
the special lock handling.
4475
@return DB_SUCCESS if all OK else error code */
4478
ha_innobase::innobase_lock_autoinc(void)
4479
/*====================================*/
4481
ulint error = DB_SUCCESS;
4483
dict_table_autoinc_lock(prebuilt->table);
4485
return(ulong(error));
4488
/********************************************************************//**
4489
Reset the autoinc value in the table.
4490
@return DB_SUCCESS if all went well else error code */
4493
ha_innobase::innobase_reset_autoinc(
4494
/*================================*/
4495
uint64_t autoinc) /*!< in: value to store */
4497
dict_table_autoinc_lock(prebuilt->table);
4498
dict_table_autoinc_initialize(prebuilt->table, autoinc);
4499
dict_table_autoinc_unlock(prebuilt->table);
4501
return(ulong(DB_SUCCESS));
4504
/********************************************************************//**
4505
Store the autoinc value in the table. The autoinc value is only set if
4506
it's greater than the existing autoinc value in the table.
4507
@return DB_SUCCESS if all went well else error code */
4510
ha_innobase::innobase_set_max_autoinc(
4511
/*==================================*/
4512
uint64_t auto_inc) /*!< in: value to store */
4514
dict_table_autoinc_lock(prebuilt->table);
4515
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4516
dict_table_autoinc_unlock(prebuilt->table);
4518
return(ulong(DB_SUCCESS));
4521
/********************************************************************//**
4522
Stores a row in an InnoDB database, to the table specified in this
4524
@return error code */
4527
ha_innobase::doInsertRecord(
4528
/*===================*/
4529
unsigned char* record) /*!< in: a row in MySQL format */
4532
int error_result= 0;
4533
ibool auto_inc_used= FALSE;
4535
trx_t* trx = session_to_trx(user_session);
4537
if (prebuilt->trx != trx) {
4538
errmsg_printf(error::ERROR, "The transaction object for the table handle is at "
4539
"%p, but for the current thread it is at %p",
4540
(const void*) prebuilt->trx, (const void*) trx);
4542
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
4543
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
4545
"InnoDB: Dump of 200 bytes around ha_data: ",
4547
ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
4552
sql_command = user_session->getSqlCommand();
4554
if ((sql_command == SQLCOM_ALTER_TABLE
4555
|| sql_command == SQLCOM_CREATE_INDEX
4556
|| sql_command == SQLCOM_DROP_INDEX)
4557
&& num_write_row >= 10000) {
4558
/* ALTER TABLE is COMMITted at every 10000 copied rows.
4559
The IX table lock for the original table has to be re-issued.
4560
As this method will be called on a temporary table where the
4561
contents of the original table is being copied to, it is
4562
a bit tricky to determine the source table. The cursor
4563
position in the source table need not be adjusted after the
4564
intermediate COMMIT, since writes by other transactions are
4565
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
4567
dict_table_t* src_table;
4568
enum lock_mode mode;
4572
/* Commit the transaction. This will release the table
4573
locks, so they have to be acquired again. */
4575
/* Altering an InnoDB table */
4576
/* Get the source table. */
4577
src_table = lock_get_src_table(
4578
prebuilt->trx, prebuilt->table, &mode);
4581
/* Unknown situation: do not commit */
4583
ut_print_timestamp(stderr);
4585
" InnoDB: ALTER TABLE is holding lock"
4586
" on %lu tables!\n",
4587
prebuilt->trx->mysql_n_tables_locked);
4590
} else if (src_table == prebuilt->table) {
4591
/* Source table is not in InnoDB format:
4592
no need to re-acquire locks on it. */
4594
/* Altering to InnoDB format */
4595
getTransactionalEngine()->commit(user_session, 1);
4596
/* We will need an IX lock on the destination table. */
4597
prebuilt->sql_stat_start = TRUE;
4599
/* Ensure that there are no other table locks than
4600
LOCK_IX and LOCK_AUTO_INC on the destination table. */
4602
if (!lock_is_table_exclusive(prebuilt->table,
4607
/* Commit the transaction. This will release the table
4608
locks, so they have to be acquired again. */
4609
getTransactionalEngine()->commit(user_session, 1);
4610
/* Re-acquire the table lock on the source table. */
4611
row_lock_table_for_mysql(prebuilt, src_table, mode);
4612
/* We will need an IX lock on the destination table. */
4613
prebuilt->sql_stat_start = TRUE;
4619
/* This is the case where the table has an auto-increment column */
4620
if (getTable()->next_number_field && record == getTable()->getInsertRecord()) {
4622
/* Reset the error code before calling
4623
innobase_get_auto_increment(). */
4624
prebuilt->autoinc_error = DB_SUCCESS;
4626
if ((error = update_auto_increment())) {
4627
/* We don't want to mask autoinc overflow errors. */
4629
/* Handle the case where the AUTOINC sub-system
4630
failed during initialization. */
4631
if (prebuilt->autoinc_error == DB_UNSUPPORTED) {
4632
error_result = ER_AUTOINC_READ_FAILED;
4633
/* Set the error message to report too. */
4634
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
4636
} else if (prebuilt->autoinc_error != DB_SUCCESS) {
4637
error = (int) prebuilt->autoinc_error;
4642
/* MySQL errors are passed straight back. */
4643
error_result = (int) error;
4647
auto_inc_used = TRUE;
4650
if (prebuilt->mysql_template == NULL
4651
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
4653
/* Build the template used in converting quickly between
4654
the two database formats */
4656
build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
4659
innodb_srv_conc_enter_innodb(prebuilt->trx);
4661
error = row_insert_for_mysql((byte*) record, prebuilt);
4663
user_session->setXaId(trx->id);
4665
/* Handle duplicate key errors */
4666
if (auto_inc_used) {
4669
uint64_t col_max_value;
4671
/* Note the number of rows processed for this statement, used
4672
by get_auto_increment() to determine the number of AUTO-INC
4673
values to reserve. This is only useful for a mult-value INSERT
4674
and is a statement level counter.*/
4675
if (trx->n_autoinc_rows > 0) {
4676
--trx->n_autoinc_rows;
4679
/* We need the upper limit of the col type to check for
4680
whether we update the table autoinc counter or not. */
4681
col_max_value = innobase_get_int_col_max_value(
4682
getTable()->next_number_field);
4683
/* Get the value that MySQL attempted to store in the table.*/
4684
auto_inc = getTable()->next_number_field->val_int();
4687
case DB_DUPLICATE_KEY:
4689
/* A REPLACE command and LOAD DATA INFILE REPLACE
4690
handle a duplicate key error themselves, but we
4691
must update the autoinc counter if we are performing
4692
those statements. */
4694
switch (sql_command) {
4696
if ((trx->duplicates
4697
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
4699
goto set_max_autoinc;
4703
case SQLCOM_REPLACE:
4704
case SQLCOM_INSERT_SELECT:
4705
case SQLCOM_REPLACE_SELECT:
4706
goto set_max_autoinc;
4715
/* If the actual value inserted is greater than
4716
the upper limit of the interval, then we try and
4717
update the table upper limit. Note: last_value
4718
will be 0 if get_auto_increment() was not called.*/
4720
if (auto_inc >= prebuilt->autoinc_last_value) {
4722
/* This should filter out the negative
4723
values set explicitly by the user. */
4724
if (auto_inc <= col_max_value) {
4725
ut_a(prebuilt->autoinc_increment > 0);
4730
offset = prebuilt->autoinc_offset;
4731
need = prebuilt->autoinc_increment;
4733
auto_inc = innobase_next_autoinc(
4735
need, offset, col_max_value);
4737
err = innobase_set_max_autoinc(
4740
if (err != DB_SUCCESS) {
4749
innodb_srv_conc_exit_innodb(prebuilt->trx);
4752
error_result = convert_error_code_to_mysql((int) error,
4753
prebuilt->table->flags,
4757
innobase_active_small();
4759
return(error_result);
4762
/**********************************************************************//**
4763
Checks which fields have changed in a row and stores information
4764
of them to an update vector.
4765
@return error number or 0 */
4768
calc_row_difference(
4769
/*================*/
4770
upd_t* uvect, /*!< in/out: update vector */
4771
unsigned char* old_row, /*!< in: old row in MySQL format */
4772
unsigned char* new_row, /*!< in: new row in MySQL format */
4773
Table* table, /*!< in: table in MySQL data
4775
unsigned char* upd_buff, /*!< in: buffer to use */
4776
ulint buff_len, /*!< in: buffer length */
4777
row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
4778
Session* ) /*!< in: user thread */
4780
unsigned char* original_upd_buff = upd_buff;
4781
enum_field_types field_mysql_type;
4786
const byte* new_mysql_row_col;
4790
upd_field_t* ufield;
4792
ulint n_changed = 0;
4794
dict_index_t* clust_index;
4797
n_fields = table->getShare()->sizeFields();
4798
clust_index = dict_table_get_first_index(prebuilt->table);
4800
/* We use upd_buff to convert changed fields */
4801
buf = (byte*) upd_buff;
4803
for (i = 0; i < n_fields; i++) {
4804
Field *field= table->getField(i);
4806
o_ptr = (const byte*) old_row + get_field_offset(table, field);
4807
n_ptr = (const byte*) new_row + get_field_offset(table, field);
4809
/* Use new_mysql_row_col and col_pack_len save the values */
4811
new_mysql_row_col = n_ptr;
4812
col_pack_len = field->pack_length();
4814
o_len = col_pack_len;
4815
n_len = col_pack_len;
4817
/* We use o_ptr and n_ptr to dig up the actual data for
4820
field_mysql_type = field->type();
4822
col_type = prebuilt->table->cols[i].mtype;
4827
o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4828
n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4835
if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4836
/* This is a >= 5.0.3 type true VARCHAR where
4837
the real payload data length is stored in
4840
o_ptr = row_mysql_read_true_varchar(
4843
(((Field_varstring*)field)->pack_length_no_ptr()));
4845
n_ptr = row_mysql_read_true_varchar(
4848
(((Field_varstring*)field)->pack_length_no_ptr()));
4856
if (field->null_ptr) {
4857
if (field_in_record_is_null(table, field,
4859
o_len = UNIV_SQL_NULL;
4862
if (field_in_record_is_null(table, field,
4864
n_len = UNIV_SQL_NULL;
4868
if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4869
0 != memcmp(o_ptr, n_ptr, o_len))) {
4870
/* The field has changed */
4872
ufield = uvect->fields + n_changed;
4874
/* Let us use a dummy dfield to make the conversion
4875
from the MySQL column format to the InnoDB format */
4877
dict_col_copy_type(prebuilt->table->cols + i,
4880
if (n_len != UNIV_SQL_NULL) {
4881
buf = row_mysql_store_col_in_innobase_format(
4887
dict_table_is_comp(prebuilt->table));
4888
dfield_copy_data(&ufield->new_val, &dfield);
4890
dfield_set_null(&ufield->new_val);
4894
ufield->orig_len = 0;
4895
ufield->field_no = dict_col_get_clust_pos(
4896
&prebuilt->table->cols[i], clust_index);
4901
uvect->n_fields = n_changed;
4902
uvect->info_bits = 0;
4904
ut_a(buf <= (byte*)original_upd_buff + buff_len);
4909
/**********************************************************************//**
4910
Updates a row given as a parameter to a new value. Note that we are given
4911
whole rows, not just the fields which are updated: this incurs some
4912
overhead for CPU when we check which fields are actually updated.
4913
TODO: currently InnoDB does not prevent the 'Halloween problem':
4914
in a searched update a single row can get updated several times
4915
if its index columns are updated!
4916
@return error number or 0 */
4919
ha_innobase::doUpdateRecord(
4920
/*====================*/
4921
const unsigned char* old_row,/*!< in: old row in MySQL format */
4922
unsigned char* new_row)/*!< in: new row in MySQL format */
4926
trx_t* trx = session_to_trx(user_session);
4928
ut_a(prebuilt->trx == trx);
4930
if (prebuilt->upd_node) {
4931
uvect = prebuilt->upd_node->update;
4933
uvect = row_get_prebuilt_update_vector(prebuilt);
4936
/* Build an update vector from the modified fields in the rows
4937
(uses upd_buff of the handle) */
4939
calc_row_difference(uvect, (unsigned char*) old_row, new_row, getTable(),
4940
&upd_buff[0], (ulint)upd_and_key_val_buff_len,
4941
prebuilt, user_session);
4943
/* This is not a delete */
4944
prebuilt->upd_node->is_delete = FALSE;
4946
ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4948
if (getTable()->found_next_number_field)
4951
uint64_t col_max_value;
4953
auto_inc = getTable()->found_next_number_field->val_int();
4955
/* We need the upper limit of the col type to check for
4956
whether we update the table autoinc counter or not. */
4957
col_max_value = innobase_get_int_col_max_value(
4958
getTable()->found_next_number_field);
4960
uint64_t current_autoinc;
4961
ulint autoinc_error= innobase_get_autoinc(¤t_autoinc);
4962
if (autoinc_error == DB_SUCCESS
4963
&& auto_inc <= col_max_value && auto_inc != 0
4964
&& auto_inc >= current_autoinc)
4970
offset = prebuilt->autoinc_offset;
4971
need = prebuilt->autoinc_increment;
4973
auto_inc = innobase_next_autoinc(
4974
auto_inc, need, offset, col_max_value);
4976
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4979
dict_table_autoinc_unlock(prebuilt->table);
4982
innodb_srv_conc_enter_innodb(trx);
4984
error = row_update_for_mysql((byte*) old_row, prebuilt);
4986
user_session->setXaId(trx->id);
4988
/* We need to do some special AUTOINC handling for the following case:
4990
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4992
We need to use the AUTOINC counter that was actually used by
4993
MySQL in the UPDATE statement, which can be different from the
4994
value used in the INSERT statement.*/
4996
if (error == DB_SUCCESS
4997
&& getTable()->next_number_field
4998
&& new_row == getTable()->getInsertRecord()
4999
&& user_session->getSqlCommand() == SQLCOM_INSERT
5000
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
5001
== TRX_DUP_IGNORE) {
5004
uint64_t col_max_value;
5006
auto_inc = getTable()->next_number_field->val_int();
5008
/* We need the upper limit of the col type to check for
5009
whether we update the table autoinc counter or not. */
5010
col_max_value = innobase_get_int_col_max_value(
5011
getTable()->next_number_field);
5013
if (auto_inc <= col_max_value && auto_inc != 0) {
5018
offset = prebuilt->autoinc_offset;
5019
need = prebuilt->autoinc_increment;
5021
auto_inc = innobase_next_autoinc(
5022
auto_inc, need, offset, col_max_value);
5024
error = innobase_set_max_autoinc(auto_inc);
5028
innodb_srv_conc_exit_innodb(trx);
5030
error = convert_error_code_to_mysql(error,
5031
prebuilt->table->flags,
5034
if (error == 0 /* success */
5035
&& uvect->n_fields == 0 /* no columns were updated */) {
5037
/* This is the same as success, but instructs
5038
MySQL that the row is not really updated and it
5039
should not increase the count of updated rows.
5040
This is fix for http://bugs.mysql.com/29157 */
5041
error = HA_ERR_RECORD_IS_THE_SAME;
5044
/* Tell InnoDB server that there might be work for
5047
innobase_active_small();
5052
/**********************************************************************//**
5053
Deletes a row given as the parameter.
5054
@return error number or 0 */
5057
ha_innobase::doDeleteRecord(
5058
/*====================*/
5059
const unsigned char* record) /*!< in: a row in MySQL format */
5062
trx_t* trx = session_to_trx(user_session);
5064
ut_a(prebuilt->trx == trx);
5066
if (!prebuilt->upd_node) {
5067
row_get_prebuilt_update_vector(prebuilt);
5070
/* This is a delete */
5072
prebuilt->upd_node->is_delete = TRUE;
5074
innodb_srv_conc_enter_innodb(trx);
5076
error = row_update_for_mysql((byte*) record, prebuilt);
5078
user_session->setXaId(trx->id);
5080
innodb_srv_conc_exit_innodb(trx);
5082
error = convert_error_code_to_mysql(
5083
error, prebuilt->table->flags, user_session);
5085
/* Tell the InnoDB server that there might be work for
5088
innobase_active_small();
5093
/**********************************************************************//**
5094
Removes a new lock set on a row, if it was not read optimistically. This can
5095
be called after a row has been read in the processing of an UPDATE or a DELETE
5096
query, if the option innodb_locks_unsafe_for_binlog is set. */
5099
ha_innobase::unlock_row(void)
5100
/*=========================*/
5102
/* Consistent read does not take any locks, thus there is
5103
nothing to unlock. */
5105
if (prebuilt->select_lock_type == LOCK_NONE) {
5109
switch (prebuilt->row_read_type) {
5110
case ROW_READ_WITH_LOCKS:
5111
if (!srv_locks_unsafe_for_binlog
5112
&& prebuilt->trx->isolation_level
5113
> TRX_ISO_READ_COMMITTED) {
5117
case ROW_READ_TRY_SEMI_CONSISTENT:
5118
row_unlock_for_mysql(prebuilt, FALSE);
5120
case ROW_READ_DID_SEMI_CONSISTENT:
5121
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
5128
/* See Cursor.h and row0mysql.h for docs on this function. */
5131
ha_innobase::was_semi_consistent_read(void)
5132
/*=======================================*/
5134
return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
5137
/* See Cursor.h and row0mysql.h for docs on this function. */
5140
ha_innobase::try_semi_consistent_read(bool yes)
5141
/*===========================================*/
5143
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5145
/* Row read type is set to semi consistent read if this was
5146
requested by the MySQL and either innodb_locks_unsafe_for_binlog
5147
option is used or this session is using READ COMMITTED isolation
5151
&& (srv_locks_unsafe_for_binlog
5152
|| prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED)) {
5153
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
5155
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
5159
/******************************************************************//**
5160
Initializes a handle to use an index.
5161
@return 0 or error number */
5164
ha_innobase::doStartIndexScan(
5165
/*====================*/
5166
uint keynr, /*!< in: key (index) number */
5167
bool ) /*!< in: 1 if result MUST be sorted according to index */
5169
return(change_active_index(keynr));
5172
/******************************************************************//**
5173
Currently does nothing.
5177
ha_innobase::doEndIndexScan(void)
5178
/*========================*/
5181
active_index=MAX_KEY;
5185
/*********************************************************************//**
5186
Converts a search mode flag understood by MySQL to a flag understood
5190
convert_search_mode_to_innobase(
5191
/*============================*/
5192
enum ha_rkey_function find_flag)
5194
switch (find_flag) {
5195
case HA_READ_KEY_EXACT:
5196
/* this does not require the index to be UNIQUE */
5197
return(PAGE_CUR_GE);
5198
case HA_READ_KEY_OR_NEXT:
5199
return(PAGE_CUR_GE);
5200
case HA_READ_KEY_OR_PREV:
5201
return(PAGE_CUR_LE);
5202
case HA_READ_AFTER_KEY:
5204
case HA_READ_BEFORE_KEY:
5206
case HA_READ_PREFIX:
5207
return(PAGE_CUR_GE);
5208
case HA_READ_PREFIX_LAST:
5209
return(PAGE_CUR_LE);
5210
case HA_READ_PREFIX_LAST_OR_PREV:
5211
return(PAGE_CUR_LE);
5212
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
5213
pass a complete-field prefix of a key value as the search
5214
tuple. I.e., it is not allowed that the last field would
5215
just contain n first bytes of the full field value.
5216
MySQL uses a 'padding' trick to convert LIKE 'abc%'
5217
type queries so that it can use as a search tuple
5218
a complete-field-prefix of a key value. Thus, the InnoDB
5219
search mode PAGE_CUR_LE_OR_EXTENDS is never used.
5220
TODO: when/if MySQL starts to use also partial-field
5221
prefixes, we have to deal with stripping of spaces
5222
and comparison of non-latin1 char type fields in
5223
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
5225
case HA_READ_MBR_CONTAIN:
5226
case HA_READ_MBR_INTERSECT:
5227
case HA_READ_MBR_WITHIN:
5228
case HA_READ_MBR_DISJOINT:
5229
case HA_READ_MBR_EQUAL:
5230
return(PAGE_CUR_UNSUPP);
5231
/* do not use "default:" in order to produce a gcc warning:
5232
enumeration value '...' not handled in switch
5233
(if -Wswitch or -Wall is used) */
5236
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
5238
return(PAGE_CUR_UNSUPP);
5242
BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
5243
---------------------------------------------------
5244
The following does not cover all the details, but explains how we determine
5245
the start of a new SQL statement, and what is associated with it.
5247
For each table in the database the MySQL interpreter may have several
5248
table handle instances in use, also in a single SQL query. For each table
5249
handle instance there is an InnoDB 'prebuilt' struct which contains most
5250
of the InnoDB data associated with this table handle instance.
5252
A) if the user has not explicitly set any MySQL table level locks:
5254
1) Drizzle calls StorageEngine::doStartStatement(), indicating to
5255
InnoDB that a new SQL statement has begun.
5257
2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
5258
to set an 'intention' table level lock on the table of the Cursor instance.
5259
There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should
5260
be set true if we are taking this table handle instance to use in a new SQL
5261
statement issued by the user.
5263
2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
5264
instructions to prebuilt->template of the table handle instance in
5265
::index_read. The template is used to save CPU time in large joins.
5267
3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
5268
allocate a new consistent read view for the trx if it does not yet have one,
5269
or in the case of a locking read, set an InnoDB 'intention' table level
5272
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
5273
same table handle instance, if it is a join.
5275
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
5277
(a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter
5278
does NOT execute autocommit for pure read transactions, though it should.
5279
That is why we must execute the COMMIT in ::doEndStatement().
5280
(b) we also release possible 'SQL statement level resources' InnoDB may
5281
have for this SQL statement.
5285
Remove need for InnoDB to call autocommit for read-only trx
5287
@todo Check the below is still valid (I don't think it is...)
5289
B) If the user has explicitly set MySQL table level locks, then MySQL
5290
does NOT call ::external_lock at the start of the statement. To determine
5291
when we are at the start of a new SQL statement we at the start of
5292
::index_read also compare the query id to the latest query id where the
5293
table handle instance was used. If it has changed, we know we are at the
5294
start of a new SQL statement. Since the query id can theoretically
5295
overwrap, we use this test only as a secondary way of determining the
5296
start of a new SQL statement. */
5299
/**********************************************************************//**
5300
Positions an index cursor to the index specified in the handle. Fetches the
5302
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
5305
ha_innobase::index_read(
5306
/*====================*/
5307
unsigned char* buf, /*!< in/out: buffer for the returned
5309
const unsigned char* key_ptr,/*!< in: key value; if this is NULL
5310
we position the cursor at the
5311
start or end of index; this can
5312
also contain an InnoDB row id, in
5313
which case key_len is the InnoDB
5314
row id length; the key value can
5315
also be a prefix of a full key value,
5316
and the last column can be a prefix
5318
uint key_len,/*!< in: key value length */
5319
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5322
dict_index_t* index;
5323
ulint match_mode = 0;
5327
ut_a(prebuilt->trx == session_to_trx(user_session));
5329
ha_statistic_increment(&system_status_var::ha_read_key_count);
5331
index = prebuilt->index;
5333
if (UNIV_UNLIKELY(index == NULL)) {
5334
prebuilt->index_usable = FALSE;
5335
return(HA_ERR_CRASHED);
5338
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5339
return(HA_ERR_TABLE_DEF_CHANGED);
5342
/* Note that if the index for which the search template is built is not
5343
necessarily prebuilt->index, but can also be the clustered index */
5345
if (prebuilt->sql_stat_start) {
5346
build_template(prebuilt, user_session, getTable(),
5347
ROW_MYSQL_REC_FIELDS);
5351
/* Convert the search key value to InnoDB format into
5352
prebuilt->search_tuple */
5354
row_sel_convert_mysql_key_to_innobase(
5355
prebuilt->search_tuple,
5356
(byte*) &key_val_buff[0],
5357
(ulint)upd_and_key_val_buff_len,
5363
/* We position the cursor to the last or the first entry
5366
dtuple_set_n_fields(prebuilt->search_tuple, 0);
5369
mode = convert_search_mode_to_innobase(find_flag);
5373
if (find_flag == HA_READ_KEY_EXACT) {
5375
match_mode = ROW_SEL_EXACT;
5377
} else if (find_flag == HA_READ_PREFIX
5378
|| find_flag == HA_READ_PREFIX_LAST) {
5380
match_mode = ROW_SEL_EXACT_PREFIX;
5383
last_match_mode = (uint) match_mode;
5385
if (mode != PAGE_CUR_UNSUPP) {
5387
innodb_srv_conc_enter_innodb(prebuilt->trx);
5389
ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
5392
innodb_srv_conc_exit_innodb(prebuilt->trx);
5395
ret = DB_UNSUPPORTED;
5401
getTable()->status = 0;
5403
case DB_RECORD_NOT_FOUND:
5404
error = HA_ERR_KEY_NOT_FOUND;
5405
getTable()->status = STATUS_NOT_FOUND;
5407
case DB_END_OF_INDEX:
5408
error = HA_ERR_KEY_NOT_FOUND;
5409
getTable()->status = STATUS_NOT_FOUND;
5412
error = convert_error_code_to_mysql((int) ret,
5413
prebuilt->table->flags,
5415
getTable()->status = STATUS_NOT_FOUND;
5422
/*******************************************************************//**
5423
The following functions works like index_read, but it find the last
5424
row with the current key value or prefix.
5425
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
5428
ha_innobase::index_read_last(
5429
/*=========================*/
5430
unsigned char* buf, /*!< out: fetched row */
5431
const unsigned char* key_ptr,/*!< in: key value, or a prefix of a full
5433
uint key_len)/*!< in: length of the key val or prefix
5436
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
5439
/********************************************************************//**
5440
Get the index for a handle. Does not change active index.
5441
@return NULL or index instance. */
5444
ha_innobase::innobase_get_index(
5445
/*============================*/
5446
uint keynr) /*!< in: use this index; MAX_KEY means always
5447
clustered index, even if it was internally
5448
generated by InnoDB */
5450
dict_index_t* index = 0;
5452
ha_statistic_increment(&system_status_var::ha_read_key_count);
5454
if (keynr != MAX_KEY && getTable()->getShare()->sizeKeys() > 0)
5456
KeyInfo *key = getTable()->key_info + keynr;
5457
index = innobase_index_lookup(share, keynr);
5460
ut_a(ut_strcmp(index->name, key->name) == 0);
5462
/* Can't find index with keynr in the translation
5463
table. Only print message if the index translation
5465
if (share->idx_trans_tbl.index_mapping) {
5466
errmsg_printf(error::ERROR,
5467
"InnoDB could not find "
5468
"index %s key no %u for "
5469
"table %s through its "
5470
"index translation table",
5471
key ? key->name : "NULL",
5473
prebuilt->table->name);
5476
index = dict_table_get_index_on_name(prebuilt->table,
5480
index = dict_table_get_first_index(prebuilt->table);
5484
errmsg_printf(error::ERROR,
5485
"Innodb could not find key n:o %u with name %s "
5486
"from dict cache for table %s",
5487
keynr, getTable()->getShare()->getTableMessage()->indexes(keynr).name().c_str(),
5488
prebuilt->table->name);
5494
/********************************************************************//**
5495
Changes the active index of a handle.
5496
@return 0 or error code */
5499
ha_innobase::change_active_index(
5500
/*=============================*/
5501
uint keynr) /*!< in: use this index; MAX_KEY means always clustered
5502
index, even if it was internally generated by
5505
ut_ad(user_session == table->in_use);
5506
ut_a(prebuilt->trx == session_to_trx(user_session));
5508
active_index = keynr;
5510
prebuilt->index = innobase_get_index(keynr);
5512
if (UNIV_UNLIKELY(!prebuilt->index)) {
5513
errmsg_printf(error::WARN, "InnoDB: change_active_index(%u) failed",
5515
prebuilt->index_usable = FALSE;
5519
prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
5522
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5523
push_warning_printf(user_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5524
HA_ERR_TABLE_DEF_CHANGED,
5525
"InnoDB: insufficient history for index %u",
5527
/* The caller seems to ignore this. Thus, we must check
5528
this again in row_search_for_mysql(). */
5532
ut_a(prebuilt->search_tuple != 0);
5534
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
5536
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
5537
prebuilt->index->n_fields);
5539
/* MySQL changes the active index for a handle also during some
5540
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
5541
and then calculates the sum. Previously we played safe and used
5542
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
5543
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
5545
build_template(prebuilt, user_session, getTable(), ROW_MYSQL_REC_FIELDS);
5550
/**********************************************************************//**
5551
Positions an index cursor to the index specified in keynr. Fetches the
5553
??? This is only used to read whole keys ???
5554
@return error number or 0 */
5557
ha_innobase::index_read_idx(
5558
/*========================*/
5559
unsigned char* buf, /*!< in/out: buffer for the returned
5561
uint keynr, /*!< in: use this index */
5562
const unsigned char* key, /*!< in: key value; if this is NULL
5563
we position the cursor at the
5564
start or end of index */
5565
uint key_len, /*!< in: key value length */
5566
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5568
if (change_active_index(keynr)) {
5573
return(index_read(buf, key, key_len, find_flag));
5576
/***********************************************************************//**
5577
Reads the next or previous row from a cursor, which must have previously been
5578
positioned using index_read.
5579
@return 0, HA_ERR_END_OF_FILE, or error number */
5582
ha_innobase::general_fetch(
5583
/*=======================*/
5584
unsigned char* buf, /*!< in/out: buffer for next row in MySQL
5586
uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
5587
uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
5588
ROW_SEL_EXACT_PREFIX */
5593
ut_a(prebuilt->trx == session_to_trx(user_session));
5595
innodb_srv_conc_enter_innodb(prebuilt->trx);
5597
ret = row_search_for_mysql(
5598
(byte*)buf, 0, prebuilt, match_mode, direction);
5600
innodb_srv_conc_exit_innodb(prebuilt->trx);
5605
getTable()->status = 0;
5607
case DB_RECORD_NOT_FOUND:
5608
error = HA_ERR_END_OF_FILE;
5609
getTable()->status = STATUS_NOT_FOUND;
5611
case DB_END_OF_INDEX:
5612
error = HA_ERR_END_OF_FILE;
5613
getTable()->status = STATUS_NOT_FOUND;
5616
error = convert_error_code_to_mysql(
5617
(int) ret, prebuilt->table->flags, user_session);
5618
getTable()->status = STATUS_NOT_FOUND;
5625
/***********************************************************************//**
5626
Reads the next row from a cursor, which must have previously been
5627
positioned using index_read.
5628
@return 0, HA_ERR_END_OF_FILE, or error number */
5631
ha_innobase::index_next(
5632
/*====================*/
5633
unsigned char* buf) /*!< in/out: buffer for next row in MySQL
5636
ha_statistic_increment(&system_status_var::ha_read_next_count);
5638
return(general_fetch(buf, ROW_SEL_NEXT, 0));
5641
/*******************************************************************//**
5642
Reads the next row matching to the key value given as the parameter.
5643
@return 0, HA_ERR_END_OF_FILE, or error number */
5646
ha_innobase::index_next_same(
5647
/*=========================*/
5648
unsigned char* buf, /*!< in/out: buffer for the row */
5649
const unsigned char* , /*!< in: key value */
5650
uint ) /*!< in: key value length */
5652
ha_statistic_increment(&system_status_var::ha_read_next_count);
5654
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
5657
/***********************************************************************//**
5658
Reads the previous row from a cursor, which must have previously been
5659
positioned using index_read.
5660
@return 0, HA_ERR_END_OF_FILE, or error number */
5663
ha_innobase::index_prev(
5664
/*====================*/
5665
unsigned char* buf) /*!< in/out: buffer for previous row in MySQL format */
5667
ha_statistic_increment(&system_status_var::ha_read_prev_count);
5669
return(general_fetch(buf, ROW_SEL_PREV, 0));
5672
/********************************************************************//**
5673
Positions a cursor on the first record in an index and reads the
5674
corresponding row to buf.
5675
@return 0, HA_ERR_END_OF_FILE, or error code */
5678
ha_innobase::index_first(
5679
/*=====================*/
5680
unsigned char* buf) /*!< in/out: buffer for the row */
5684
ha_statistic_increment(&system_status_var::ha_read_first_count);
5686
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
5688
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5690
if (error == HA_ERR_KEY_NOT_FOUND) {
5691
error = HA_ERR_END_OF_FILE;
5697
/********************************************************************//**
5698
Positions a cursor on the last record in an index and reads the
5699
corresponding row to buf.
5700
@return 0, HA_ERR_END_OF_FILE, or error code */
5703
ha_innobase::index_last(
5704
/*====================*/
5705
unsigned char* buf) /*!< in/out: buffer for the row */
5709
ha_statistic_increment(&system_status_var::ha_read_last_count);
5711
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
5713
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5715
if (error == HA_ERR_KEY_NOT_FOUND) {
5716
error = HA_ERR_END_OF_FILE;
5722
/****************************************************************//**
5723
Initialize a table scan.
5724
@return 0 or error number */
5727
ha_innobase::doStartTableScan(
5728
/*==================*/
5729
bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
5733
/* Store the active index value so that we can restore the original
5734
value after a scan */
5736
if (prebuilt->clust_index_was_generated) {
5737
err = change_active_index(MAX_KEY);
5739
err = change_active_index(primary_key);
5742
/* Don't use semi-consistent read in random row reads (by position).
5743
This means we must disable semi_consistent_read if scan is false */
5746
try_semi_consistent_read(0);
5754
/*****************************************************************//**
5756
@return 0 or error number */
5759
ha_innobase::doEndTableScan(void)
5760
/*======================*/
5762
return(doEndIndexScan());
5765
/*****************************************************************//**
5766
Reads the next row in a table scan (also used to read the FIRST row
5768
@return 0, HA_ERR_END_OF_FILE, or error number */
5771
ha_innobase::rnd_next(
5772
/*==================*/
5773
unsigned char* buf) /*!< in/out: returns the row in this buffer,
5778
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
5780
if (start_of_scan) {
5781
error = index_first(buf);
5783
if (error == HA_ERR_KEY_NOT_FOUND) {
5784
error = HA_ERR_END_OF_FILE;
5789
error = general_fetch(buf, ROW_SEL_NEXT, 0);
5795
/**********************************************************************//**
5796
Fetches a row from the table based on a row reference.
5797
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
5800
ha_innobase::rnd_pos(
5801
/*=================*/
5802
unsigned char* buf, /*!< in/out: buffer for the row */
5803
unsigned char* pos) /*!< in: primary key value of the row in the
5804
MySQL format, or the row id if the clustered
5805
index was internally generated by InnoDB; the
5806
length of data in pos has to be ref_length */
5809
uint keynr = active_index;
5811
ha_statistic_increment(&system_status_var::ha_read_rnd_count);
5813
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5815
if (prebuilt->clust_index_was_generated) {
5816
/* No primary key was defined for the table and we
5817
generated the clustered index from the row id: the
5818
row reference is the row id, not any key value
5819
that MySQL knows of */
5821
error = change_active_index(MAX_KEY);
5823
error = change_active_index(primary_key);
5830
/* Note that we assume the length of the row reference is fixed
5831
for the table, and it is == ref_length */
5833
error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5838
change_active_index(keynr);
5843
/*********************************************************************//**
5844
Stores a reference to the current row to 'ref' field of the handle. Note
5845
that in the case where we have generated the clustered index for the
5846
table, the function parameter is illogical: we MUST ASSUME that 'record'
5847
is the current 'position' of the handle, because if row ref is actually
5848
the row id internally generated in InnoDB, then 'record' does not contain
5849
it. We just guess that the row id must be for the record where the handle
5850
was positioned the last time. */
5853
ha_innobase::position(
5854
/*==================*/
5855
const unsigned char* record) /*!< in: row in MySQL format */
5859
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5861
if (prebuilt->clust_index_was_generated) {
5862
/* No primary key was defined for the table and we
5863
generated the clustered index from row id: the
5864
row reference will be the row id, not any key value
5865
that MySQL knows of */
5867
len = DATA_ROW_ID_LEN;
5869
memcpy(ref, prebuilt->row_id, len);
5871
len = store_key_val_for_row(primary_key, (char*)ref,
5872
ref_length, record);
5875
/* We assume that the 'ref' value len is always fixed for the same
5878
if (len != ref_length) {
5879
errmsg_printf(error::ERROR, "Stored ref len is %lu, but table ref len is %lu",
5880
(ulong) len, (ulong) ref_length);
5885
/*****************************************************************//**
5886
Creates a table definition to an InnoDB database. */
5891
trx_t* trx, /*!< in: InnoDB transaction handle */
5892
Table* form, /*!< in: information on table
5893
columns and indexes */
5894
const char* table_name, /*!< in: table name */
5895
const char* path_of_temp_table,/*!< in: if this is a table explicitly
5896
created by the user with the
5897
TEMPORARY keyword, then this
5898
parameter is the dir path where the
5899
table should be placed if we create
5900
an .ibd file for it (no .ibd extension
5901
in the path, though); otherwise this
5903
ulint flags) /*!< in: table flags */
5906
dict_table_t* table;
5911
ulint nulls_allowed;
5912
ulint unsigned_type;
5914
ulint long_true_varchar;
5918
n_cols = form->getShare()->sizeFields();
5920
/* We pass 0 as the space id, and determine at a lower level the space
5921
id where to store the table */
5923
table = dict_mem_table_create(table_name, 0, n_cols, flags);
5925
if (path_of_temp_table) {
5926
table->dir_path_of_temp_table =
5927
mem_heap_strdup(table->heap, path_of_temp_table);
5930
for (i = 0; i < n_cols; i++) {
5931
field = form->getField(i);
5933
col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5937
push_warning_printf(
5939
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5940
ER_CANT_CREATE_TABLE,
5941
"Error creating table '%s' with "
5942
"column '%s'. Please check its "
5943
"column type and try to re-create "
5944
"the table with an appropriate "
5946
table->name, (char*) field->field_name);
5950
if (field->null_ptr) {
5953
nulls_allowed = DATA_NOT_NULL;
5956
if (field->binary()) {
5957
binary_type = DATA_BINARY_TYPE;
5964
if (dtype_is_string_type(col_type)) {
5966
charset_no = (ulint)field->charset()->number;
5968
if (UNIV_UNLIKELY(charset_no >= 256)) {
5969
/* in data0type.h we assume that the
5970
number fits in one byte in prtype */
5971
push_warning_printf(
5973
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5974
ER_CANT_CREATE_TABLE,
5975
"In InnoDB, charset-collation codes"
5976
" must be below 256."
5977
" Unsupported code %lu.",
5978
(ulong) charset_no);
5979
return(ER_CANT_CREATE_TABLE);
5983
ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5984
that this fits in one byte */
5985
col_len = field->pack_length();
5987
/* The MySQL pack length contains 1 or 2 bytes length field
5988
for a true VARCHAR. Let us subtract that, so that the InnoDB
5989
column length in the InnoDB data dictionary is the real
5990
maximum byte length of the actual data. */
5992
long_true_varchar = 0;
5994
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5995
col_len -= ((Field_varstring*)field)->pack_length_no_ptr();
5997
if (((Field_varstring*)field)->pack_length_no_ptr() == 2) {
5998
long_true_varchar = DATA_LONG_TRUE_VARCHAR;
6002
/* First check whether the column to be added has a
6003
system reserved name. */
6004
if (dict_col_name_is_reserved(field->field_name)){
6005
my_error(ER_WRONG_COLUMN_NAME, MYF(0), field->field_name);
6008
dict_mem_table_free(table);
6009
trx_commit_for_mysql(trx);
6015
dict_mem_table_add_col(table, table->heap,
6016
(char*) field->field_name,
6019
(ulint)field->type()
6020
| nulls_allowed | unsigned_type
6021
| binary_type | long_true_varchar,
6026
error = row_create_table_for_mysql(table, trx);
6028
if (error == DB_DUPLICATE_KEY) {
6030
char* buf_end = innobase_convert_identifier(
6031
buf, sizeof buf - 1, table_name, strlen(table_name),
6032
trx->mysql_thd, TRUE);
6035
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf);
6039
error = convert_error_code_to_mysql(error, flags, NULL);
6044
/*****************************************************************//**
6045
Creates an index in an InnoDB database. */
6050
trx_t* trx, /*!< in: InnoDB transaction handle */
6051
Table* form, /*!< in: information on table
6052
columns and indexes */
6053
ulint flags, /*!< in: InnoDB table flags */
6054
const char* table_name, /*!< in: table name */
6055
uint key_num) /*!< in: index number */
6058
dict_index_t* index;
6062
KeyPartInfo* key_part;
6069
ulint* field_lengths;
6071
key = &form->key_info[key_num];
6073
n_fields = key->key_parts;
6075
/* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */
6076
ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0);
6080
if (key_num == form->getShare()->getPrimaryKey()) {
6081
ind_type = ind_type | DICT_CLUSTERED;
6084
if (key->flags & HA_NOSAME ) {
6085
ind_type = ind_type | DICT_UNIQUE;
6088
/* We pass 0 as the space id, and determine at a lower level the space
6089
id where to store the table */
6091
index = dict_mem_index_create(table_name, key->name, 0,
6092
ind_type, n_fields);
6094
field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
6096
for (i = 0; i < n_fields; i++) {
6097
key_part = key->key_part + i;
6099
/* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
6100
field in an index: we only store a specified number of first
6101
bytes of the column to the index field.) The flag does not
6102
seem to be properly set by MySQL. Let us fall back on testing
6103
the length of the key part versus the column. */
6106
for (j = 0; j < form->getShare()->sizeFields(); j++)
6109
field = form->getField(j);
6111
if (0 == innobase_strcasecmp(
6113
key_part->field->field_name)) {
6114
/* Found the corresponding column */
6120
ut_a(j < form->getShare()->sizeFields());
6122
col_type = get_innobase_type_from_mysql_type(
6123
&is_unsigned, key_part->field);
6125
if (DATA_BLOB == col_type
6126
|| (key_part->length < field->pack_length()
6127
&& field->type() != DRIZZLE_TYPE_VARCHAR)
6128
|| (field->type() == DRIZZLE_TYPE_VARCHAR
6129
&& key_part->length < field->pack_length()
6130
- ((Field_varstring*)field)->pack_length_no_ptr())) {
6132
prefix_len = key_part->length;
6134
if (col_type == DATA_INT
6135
|| col_type == DATA_FLOAT
6136
|| col_type == DATA_DOUBLE
6137
|| col_type == DATA_DECIMAL) {
6138
errmsg_printf(error::ERROR,
6139
"MySQL is trying to create a column "
6140
"prefix index field, on an "
6141
"inappropriate data type. Table "
6142
"name %s, column name %s.",
6144
key_part->field->field_name);
6152
field_lengths[i] = key_part->length;
6154
dict_mem_index_add_field(index,
6155
(char*) key_part->field->field_name, prefix_len);
6158
/* Even though we've defined max_supported_key_part_length, we
6159
still do our own checking using field_lengths to be absolutely
6160
sure we don't create too long indexes. */
6161
error = row_create_index_for_mysql(index, trx, field_lengths);
6163
error = convert_error_code_to_mysql(error, flags, NULL);
6165
free(field_lengths);
6170
/*****************************************************************//**
6171
Creates an index to an InnoDB table when the user has defined no
6175
create_clustered_index_when_no_primary(
6176
/*===================================*/
6177
trx_t* trx, /*!< in: InnoDB transaction handle */
6178
ulint flags, /*!< in: InnoDB table flags */
6179
const char* table_name) /*!< in: table name */
6181
dict_index_t* index;
6184
/* We pass 0 as the space id, and determine at a lower level the space
6185
id where to store the table */
6187
index = dict_mem_index_create(table_name,
6188
innobase_index_reserve_name,
6189
0, DICT_CLUSTERED, 0);
6191
error = row_create_index_for_mysql(index, trx, NULL);
6193
error = convert_error_code_to_mysql(error, flags, NULL);
6198
/*****************************************************************//**
6199
Validates the create options. We may build on this function
6200
in future. For now, it checks two specifiers:
6201
KEY_BLOCK_SIZE and ROW_FORMAT
6202
If innodb_strict_mode is not set then this function is a no-op
6203
@return TRUE if valid. */
6207
create_options_are_valid(
6208
/*=====================*/
6209
Session* session, /*!< in: connection thread. */
6210
Table& form, /*!< in: information on table
6211
columns and indexes */
6212
message::Table& create_proto)
6214
ibool kbs_specified = FALSE;
6218
ut_ad(session != NULL);
6220
/* If innodb_strict_mode is not set don't do any validation. */
6221
if (!(SessionVAR(session, strict_mode))) {
6225
/* Now check for ROW_FORMAT specifier. */
6230
/*********************************************************************
6231
Creates a new table to an InnoDB database. */
6234
InnobaseEngine::doCreateTable(
6235
/*================*/
6236
Session &session, /*!< in: Session */
6237
Table& form, /*!< in: information on table columns and indexes */
6238
const identifier::Table &identifier,
6239
const message::Table& create_proto)
6242
dict_table_t* innobase_table;
6247
ib_int64_t auto_inc_value;
6249
/* Cache the value of innodb_file_format, in case it is
6250
modified by another thread while the table is being created. */
6251
const ulint file_format = srv_file_format;
6252
bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
6256
std::string search_string(identifier.getSchemaName());
6257
boost::algorithm::to_lower(search_string);
6259
if (search_string.compare("data_dictionary") == 0)
6261
return HA_WRONG_CREATE_OPTION;
6264
if (form.getShare()->sizeFields() > 1000) {
6265
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
6266
but we play safe here */
6268
return(HA_ERR_TO_BIG_ROW);
6271
/* Get the transaction associated with the current session, or create one
6272
if not yet created */
6274
parent_trx = check_trx_exists(&session);
6276
/* In case MySQL calls this in the middle of a SELECT query, release
6277
possible adaptive hash latch to avoid deadlocks of threads */
6279
trx_search_latch_release_if_reserved(parent_trx);
6281
trx = innobase_trx_allocate(&session);
6283
srv_lower_case_table_names = TRUE;
6285
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
6286
or lock waits can happen in it during a table create operation.
6287
Drop table etc. do this latching in row0mysql.c. */
6289
row_mysql_lock_data_dictionary(trx);
6291
/* Create the table definition in InnoDB */
6295
#if 0 // Since we validate the options before this stage, we no longer need to do this.
6296
/* Validate create options if innodb_strict_mode is set. */
6297
if (! create_options_are_valid(&session, form, create_proto)) {
6298
error = ER_ILLEGAL_HA_CREATE_OPTION;
6303
// We assume compact format by default
6304
iflags= DICT_TF_COMPACT;
6306
size_t num_engine_options= create_proto.engine().options_size();
6307
for (size_t x= 0; x < num_engine_options; ++x)
6309
if (boost::iequals(create_proto.engine().options(x).name(), "ROW_FORMAT"))
6311
if (boost::iequals(create_proto.engine().options(x).state(), "COMPRESSED"))
6313
iflags= DICT_TF_FORMAT_ZIP;
6315
else if (boost::iequals(create_proto.engine().options(x).state(), "COMPACT"))
6317
iflags= DICT_TF_FORMAT_ZIP;
6319
else if (boost::iequals(create_proto.engine().options(x).state(), "DYNAMIC"))
6321
iflags= DICT_TF_COMPACT;
6323
else if (boost::iequals(create_proto.engine().options(x).state(), "REDUNDANT"))
6325
iflags= DICT_TF_COMPACT;
6330
assert(0); // This should never happen since we have already validated the options.
6334
if (iflags == DICT_TF_FORMAT_ZIP)
6337
ROW_FORMAT=COMPRESSED without KEY_BLOCK_SIZE implies half the maximum KEY_BLOCK_SIZE.
6338
@todo implement KEY_BLOCK_SIZE
6340
iflags= (DICT_TF_ZSSIZE_MAX - 1)
6341
<< DICT_TF_ZSSIZE_SHIFT
6343
| DICT_TF_FORMAT_ZIP
6344
<< DICT_TF_FORMAT_SHIFT;
6348
if (! srv_file_per_table)
6350
push_warning_printf(
6352
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6353
ER_ILLEGAL_HA_CREATE_OPTION,
6354
"InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.");
6356
else if (file_format < DICT_TF_FORMAT_ZIP)
6358
push_warning_printf(
6360
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6361
ER_ILLEGAL_HA_CREATE_OPTION,
6362
"InnoDB: ROW_FORMAT=compressed requires innodb_file_format > Antelope.");
6367
/* Look for a primary key */
6369
primary_key_no= (form.getShare()->hasPrimaryKey() ?
6370
(int) form.getShare()->getPrimaryKey() :
6373
/* Our function innobase_get_mysql_key_number_for_index assumes
6374
the primary key is always number 0, if it exists */
6376
assert(primary_key_no == -1 || primary_key_no == 0);
6378
/* Check for name conflicts (with reserved name) for
6379
any user indices to be created. */
6380
if (innobase_index_name_is_reserved(trx, form.key_info,
6381
form.getShare()->keys)) {
6386
if (lex_identified_temp_table)
6387
iflags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
6389
error= create_table_def(trx, &form, identifier.getKeyPath().c_str(),
6390
lex_identified_temp_table ? identifier.getKeyPath().c_str() : NULL,
6393
session.setXaId(trx->id);
6399
/* Create the keys */
6401
if (form.getShare()->sizeKeys() == 0 || primary_key_no == -1) {
6402
/* Create an index which is used as the clustered index;
6403
order the rows by their row id which is internally generated
6406
error = create_clustered_index_when_no_primary(trx, iflags, identifier.getKeyPath().c_str());
6412
if (primary_key_no != -1) {
6413
/* In InnoDB the clustered index must always be created first */
6414
if ((error = create_index(trx, &form, iflags, identifier.getKeyPath().c_str(),
6415
(uint) primary_key_no))) {
6420
for (i = 0; i < form.getShare()->sizeKeys(); i++) {
6421
if (i != (uint) primary_key_no) {
6423
if ((error = create_index(trx, &form, iflags, identifier.getKeyPath().c_str(),
6430
stmt= session.getQueryStringCopy(stmt_len);
6433
string generated_create_table;
6434
const char *query= stmt;
6436
if (session.getSqlCommand() == SQLCOM_CREATE_TABLE)
6438
message::transformTableDefinitionToSql(create_proto,
6439
generated_create_table,
6440
message::DRIZZLE, true);
6441
query= generated_create_table.c_str();
6444
error = row_table_add_foreign_constraints(trx,
6445
query, strlen(query),
6446
identifier.getKeyPath().c_str(),
6447
lex_identified_temp_table);
6450
case DB_PARENT_NO_INDEX:
6451
push_warning_printf(
6452
&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
6453
HA_ERR_CANNOT_ADD_FOREIGN,
6454
"Create table '%s' with foreign key constraint"
6455
" failed. There is no index in the referenced"
6456
" table where the referenced columns appear"
6457
" as the first columns.\n", identifier.getKeyPath().c_str());
6460
case DB_CHILD_NO_INDEX:
6461
push_warning_printf(
6462
&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
6463
HA_ERR_CANNOT_ADD_FOREIGN,
6464
"Create table '%s' with foreign key constraint"
6465
" failed. There is no index in the referencing"
6466
" table where referencing columns appear"
6467
" as the first columns.\n", identifier.getKeyPath().c_str());
6471
error = convert_error_code_to_mysql(error, iflags, NULL);
6478
innobase_commit_low(trx);
6480
row_mysql_unlock_data_dictionary(trx);
6482
/* Flush the log to reduce probability that the .frm files and
6483
the InnoDB data dictionary get out-of-sync if the user runs
6484
with innodb_flush_log_at_trx_commit = 0 */
6486
log_buffer_flush_to_disk();
6488
innobase_table = dict_table_get(identifier.getKeyPath().c_str(), FALSE);
6490
assert(innobase_table != 0);
6492
if (innobase_table) {
6493
/* We update the highest file format in the system table
6494
space, if this table has higher file format setting. */
6496
char changed_file_format_max[100];
6497
strcpy(changed_file_format_max, innobase_file_format_max.c_str());
6498
trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
6499
dict_table_get_format(innobase_table));
6500
innobase_file_format_max= changed_file_format_max;
6503
/* Note: We can't call update_session() as prebuilt will not be
6504
setup at this stage and so we use session. */
6506
/* We need to copy the AUTOINC value from the old table if
6507
this is an ALTER TABLE or CREATE INDEX because CREATE INDEX
6508
does a table copy too. */
6510
if ((create_proto.options().has_auto_increment_value()
6511
|| session.getSqlCommand() == SQLCOM_ALTER_TABLE
6512
|| session.getSqlCommand() == SQLCOM_CREATE_INDEX)
6513
&& create_proto.options().auto_increment_value() != 0) {
6515
/* Query was one of :
6516
CREATE TABLE ...AUTO_INCREMENT = x; or
6517
ALTER TABLE...AUTO_INCREMENT = x; or
6518
CREATE INDEX x on t(...);
6519
Find out a table definition from the dictionary and get
6520
the current value of the auto increment field. Set a new
6521
value to the auto increment field if the value is greater
6522
than the maximum value in the column. */
6524
auto_inc_value = create_proto.options().auto_increment_value();
6526
dict_table_autoinc_lock(innobase_table);
6527
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
6528
dict_table_autoinc_unlock(innobase_table);
6531
/* Tell the InnoDB server that there might be work for
6534
srv_active_wake_master_thread();
6536
trx_free_for_mysql(trx);
6538
if (lex_identified_temp_table)
6540
session.getMessageCache().storeTableMessage(identifier, create_proto);
6544
StorageEngine::writeDefinitionFromPath(identifier, create_proto);
6550
innobase_commit_low(trx);
6552
row_mysql_unlock_data_dictionary(trx);
6554
trx_free_for_mysql(trx);
6559
/*****************************************************************//**
6560
Discards or imports an InnoDB tablespace.
6561
@return 0 == success, -1 == error */
6564
ha_innobase::discard_or_import_tablespace(
6565
/*======================================*/
6566
my_bool discard) /*!< in: TRUE if discard, else import */
6568
dict_table_t* dict_table;
6572
ut_a(prebuilt->trx);
6573
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6574
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6576
dict_table = prebuilt->table;
6577
trx = prebuilt->trx;
6580
err = row_discard_tablespace_for_mysql(dict_table->name, trx);
6582
err = row_import_tablespace_for_mysql(dict_table->name, trx);
6585
err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
6590
/*****************************************************************//**
6591
Deletes all rows of an InnoDB table.
6592
@return error number */
6595
ha_innobase::delete_all_rows(void)
6596
/*==============================*/
6600
/* Get the transaction associated with the current session, or create one
6601
if not yet created, and update prebuilt->trx */
6603
update_session(getTable()->in_use);
6605
if (user_session->getSqlCommand() != SQLCOM_TRUNCATE) {
6607
/* We only handle TRUNCATE TABLE t as a special case.
6608
DELETE FROM t will have to use ha_innobase::doDeleteRecord(),
6609
because DELETE is transactional while TRUNCATE is not. */
6610
return(errno=HA_ERR_WRONG_COMMAND);
6613
/* Truncate the table in InnoDB */
6615
error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
6616
if (error == DB_ERROR) {
6617
/* Cannot truncate; resort to ha_innobase::doDeleteRecord() */
6621
error = convert_error_code_to_mysql(error, prebuilt->table->flags,
6627
/*****************************************************************//**
6628
Drops a table from an InnoDB database. Before calling this function,
6629
MySQL calls innobase_commit to commit the transaction of the current user.
6630
Then the current user cannot have locks set on the table. Drop table
6631
operation inside InnoDB will remove all locks any user has on the table
6633
@return error number */
6636
InnobaseEngine::doDropTable(
6637
/*======================*/
6639
const identifier::Table &identifier)
6645
ut_a(identifier.getPath().length() < 1000);
6647
std::string search_string(identifier.getSchemaName());
6648
boost::algorithm::to_lower(search_string);
6650
if (search_string.compare("data_dictionary") == 0)
6652
return HA_ERR_TABLE_READONLY;
6655
/* Get the transaction associated with the current session, or create one
6656
if not yet created */
6658
parent_trx = check_trx_exists(&session);
6660
/* In case MySQL calls this in the middle of a SELECT query, release
6661
possible adaptive hash latch to avoid deadlocks of threads */
6663
trx_search_latch_release_if_reserved(parent_trx);
6665
trx = innobase_trx_allocate(&session);
6667
srv_lower_case_table_names = TRUE;
6669
/* Drop the table in InnoDB */
6671
error = row_drop_table_for_mysql(identifier.getKeyPath().c_str(), trx,
6672
session.getSqlCommand()
6675
session.setXaId(trx->id);
6677
/* Flush the log to reduce probability that the .frm files and
6678
the InnoDB data dictionary get out-of-sync if the user runs
6679
with innodb_flush_log_at_trx_commit = 0 */
6681
log_buffer_flush_to_disk();
6683
/* Tell the InnoDB server that there might be work for
6686
srv_active_wake_master_thread();
6688
innobase_commit_low(trx);
6690
trx_free_for_mysql(trx);
6692
if (error != ENOENT)
6693
error = convert_error_code_to_mysql(error, 0, NULL);
6695
if (error == 0 || error == ENOENT)
6697
if (identifier.getType() == message::Table::TEMPORARY)
6699
session.getMessageCache().removeTableMessage(identifier);
6700
ulint sql_command = session.getSqlCommand();
6702
// If this was the final removal to an alter table then we will need
6703
// to remove the .dfe that was left behind.
6704
if ((sql_command == SQLCOM_ALTER_TABLE
6705
|| sql_command == SQLCOM_CREATE_INDEX
6706
|| sql_command == SQLCOM_DROP_INDEX))
6708
string path(identifier.getPath());
6710
path.append(DEFAULT_FILE_EXTENSION);
6712
(void)internal::my_delete(path.c_str(), MYF(0));
6717
string path(identifier.getPath());
6719
path.append(DEFAULT_FILE_EXTENSION);
6721
(void)internal::my_delete(path.c_str(), MYF(0));
6728
/*****************************************************************//**
6729
Removes all tables in the named database inside InnoDB. */
6731
InnobaseEngine::doDropSchema(
6732
/*===================*/
6733
const identifier::Schema &identifier)
6734
/*!< in: database path; inside InnoDB the name
6735
of the last directory in the path is used as
6736
the database name: for example, in 'mysql/data/test'
6737
the database name is 'test' */
6741
string schema_path(identifier.getPath());
6742
Session* session = current_session;
6744
/* Get the transaction associated with the current session, or create one
6745
if not yet created */
6747
assert(this == innodb_engine_ptr);
6749
/* In the Windows plugin, session = current_session is always NULL */
6751
trx_t* parent_trx = check_trx_exists(session);
6753
/* In case Drizzle calls this in the middle of a SELECT
6754
query, release possible adaptive hash latch to avoid
6755
deadlocks of threads */
6757
trx_search_latch_release_if_reserved(parent_trx);
6760
schema_path.append("/");
6761
trx = innobase_trx_allocate(session);
6762
error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6764
/* Flush the log to reduce probability that the .frm files and
6765
the InnoDB data dictionary get out-of-sync if the user runs
6766
with innodb_flush_log_at_trx_commit = 0 */
6768
log_buffer_flush_to_disk();
6770
/* Tell the InnoDB server that there might be work for
6773
srv_active_wake_master_thread();
6775
innobase_commit_low(trx);
6776
trx_free_for_mysql(trx);
6779
// What do we do here?
6782
return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement.
6785
void InnobaseEngine::dropTemporarySchema()
6787
identifier::Schema schema_identifier(GLOBAL_TEMPORARY_EXT);
6789
string schema_path(GLOBAL_TEMPORARY_EXT);
6791
schema_path.append("/");
6793
trx = trx_allocate_for_mysql();
6795
trx->mysql_thd = NULL;
6797
trx->check_foreigns = false;
6798
trx->check_unique_secondary = false;
6800
(void)row_drop_database_for_mysql(schema_path.c_str(), trx);
6802
/* Flush the log to reduce probability that the .frm files and
6803
the InnoDB data dictionary get out-of-sync if the user runs
6804
with innodb_flush_log_at_trx_commit = 0 */
6806
log_buffer_flush_to_disk();
6808
/* Tell the InnoDB server that there might be work for
6811
srv_active_wake_master_thread();
6813
innobase_commit_low(trx);
6814
trx_free_for_mysql(trx);
6816
/*********************************************************************//**
6817
Renames an InnoDB table.
6818
@return 0 or error code */
6821
innobase_rename_table(
6822
/*==================*/
6823
trx_t* trx, /*!< in: transaction */
6824
const identifier::Table &from,
6825
const identifier::Table &to,
6826
ibool lock_and_commit)
6827
/*!< in: TRUE=lock data dictionary and commit */
6831
srv_lower_case_table_names = TRUE;
6833
/* Serialize data dictionary operations with dictionary mutex:
6834
no deadlocks can occur then in these operations */
6836
if (lock_and_commit) {
6837
row_mysql_lock_data_dictionary(trx);
6840
error = row_rename_table_for_mysql(from.getKeyPath().c_str(), to.getKeyPath().c_str(), trx, lock_and_commit);
6842
if (error != DB_SUCCESS) {
6843
FILE* ef = dict_foreign_err_file;
6845
fputs("InnoDB: Renaming table ", ef);
6846
ut_print_name(ef, trx, TRUE, from.getKeyPath().c_str());
6848
ut_print_name(ef, trx, TRUE, to.getKeyPath().c_str());
6849
fputs(" failed!\n", ef);
6852
if (lock_and_commit) {
6853
row_mysql_unlock_data_dictionary(trx);
6855
/* Flush the log to reduce probability that the .frm
6856
files and the InnoDB data dictionary get out-of-sync
6857
if the user runs with innodb_flush_log_at_trx_commit = 0 */
6859
log_buffer_flush_to_disk();
6864
/*********************************************************************//**
6865
Renames an InnoDB table.
6866
@return 0 or error code */
6867
UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
6869
// A temp table alter table/rename is a shallow rename and only the
6870
// definition needs to be updated.
6871
if (to.getType() == message::Table::TEMPORARY && from.getType() == message::Table::TEMPORARY)
6873
session.getMessageCache().renameTableMessage(from, to);
6881
/* Get the transaction associated with the current session, or create one
6882
if not yet created */
6884
parent_trx = check_trx_exists(&session);
6886
/* In case MySQL calls this in the middle of a SELECT query, release
6887
possible adaptive hash latch to avoid deadlocks of threads */
6889
trx_search_latch_release_if_reserved(parent_trx);
6891
trx = innobase_trx_allocate(&session);
6893
error = innobase_rename_table(trx, from, to, TRUE);
6895
session.setXaId(trx->id);
6897
/* Tell the InnoDB server that there might be work for
6900
srv_active_wake_master_thread();
6902
innobase_commit_low(trx);
6903
trx_free_for_mysql(trx);
6905
/* Add a special case to handle the Duplicated Key error
6906
and return DB_ERROR instead.
6907
This is to avoid a possible SIGSEGV error from mysql error
6908
handling code. Currently, mysql handles the Duplicated Key
6909
error by re-entering the storage layer and getting dup key
6910
info by calling get_dup_key(). This operation requires a valid
6911
table handle ('row_prebuilt_t' structure) which could no
6912
longer be available in the error handling stage. The suggested
6913
solution is to report a 'table exists' error message (since
6914
the dup key error here is due to an existing table whose name
6915
is the one we are trying to rename to) and return the generic
6917
if (error == (int) DB_DUPLICATE_KEY) {
6918
my_error(ER_TABLE_EXISTS_ERROR, to);
6922
error = convert_error_code_to_mysql(error, 0, NULL);
6926
// If this fails, we are in trouble
6927
plugin::StorageEngine::renameDefinitionFromPath(to, from);
6933
/*********************************************************************//**
6934
Estimates the number of index records in a range.
6935
@return estimated number of rows */
6938
ha_innobase::records_in_range(
6939
/*==========================*/
6940
uint keynr, /*!< in: index number */
6941
key_range *min_key, /*!< in: start key value of the
6942
range, may also be 0 */
6943
key_range *max_key) /*!< in: range end key val, may
6947
dict_index_t* index;
6948
unsigned char* key_val_buff2 = (unsigned char*) malloc(
6949
getTable()->getShare()->sizeStoredRecord()
6950
+ getTable()->getShare()->max_key_length + 100);
6951
ulint buff2_len = getTable()->getShare()->sizeStoredRecord()
6952
+ getTable()->getShare()->max_key_length + 100;
6953
dtuple_t* range_start;
6954
dtuple_t* range_end;
6960
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6962
prebuilt->trx->op_info = "estimating records in index range";
6964
/* In case MySQL calls this in the middle of a SELECT query, release
6965
possible adaptive hash latch to avoid deadlocks of threads */
6967
trx_search_latch_release_if_reserved(prebuilt->trx);
6969
active_index = keynr;
6971
key = &getTable()->key_info[active_index];
6973
index = innobase_get_index(keynr);
6975
/* There exists possibility of not being able to find requested
6976
index due to inconsistency between MySQL and InoDB dictionary info.
6977
Necessary message should have been printed in innobase_get_index() */
6978
if (UNIV_UNLIKELY(!index)) {
6979
n_rows = HA_POS_ERROR;
6983
if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) {
6984
n_rows = HA_ERR_TABLE_DEF_CHANGED;
6988
heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6989
+ sizeof(dtuple_t)));
6991
range_start = dtuple_create(heap, key->key_parts);
6992
dict_index_copy_types(range_start, index, key->key_parts);
6994
range_end = dtuple_create(heap, key->key_parts);
6995
dict_index_copy_types(range_end, index, key->key_parts);
6997
row_sel_convert_mysql_key_to_innobase(
6998
range_start, (byte*) &key_val_buff[0],
6999
(ulint)upd_and_key_val_buff_len,
7001
(byte*) (min_key ? min_key->key :
7002
(const unsigned char*) 0),
7003
(ulint) (min_key ? min_key->length : 0),
7006
row_sel_convert_mysql_key_to_innobase(
7007
range_end, (byte*) key_val_buff2,
7009
(byte*) (max_key ? max_key->key :
7010
(const unsigned char*) 0),
7011
(ulint) (max_key ? max_key->length : 0),
7014
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
7016
mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
7019
if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
7021
n_rows = btr_estimate_n_rows_in_range(index, range_start,
7026
n_rows = HA_POS_ERROR;
7029
mem_heap_free(heap);
7032
free(key_val_buff2);
7034
prebuilt->trx->op_info = "";
7036
/* The MySQL optimizer seems to believe an estimate of 0 rows is
7037
always accurate and may return the result 'Empty set' based on that.
7038
The accuracy is not guaranteed, and even if it were, for a locking
7039
read we should anyway perform the search to set the next-key lock.
7040
Add 1 to the value to make sure MySQL does not make the assumption! */
7046
return((ha_rows) n_rows);
7049
/*********************************************************************//**
7050
Gives an UPPER BOUND to the number of rows in a table. This is used in
7052
@return upper bound of rows */
7055
ha_innobase::estimate_rows_upper_bound(void)
7056
/*======================================*/
7058
dict_index_t* index;
7060
uint64_t local_data_file_length;
7061
ulint stat_n_leaf_pages;
7063
/* We do not know if MySQL can call this function before calling
7064
external_lock(). To be safe, update the session of the current table
7067
update_session(getTable()->in_use);
7069
prebuilt->trx->op_info = (char*)
7070
"calculating upper bound for table rows";
7072
/* In case MySQL calls this in the middle of a SELECT query, release
7073
possible adaptive hash latch to avoid deadlocks of threads */
7075
trx_search_latch_release_if_reserved(prebuilt->trx);
7077
index = dict_table_get_first_index(prebuilt->table);
7079
stat_n_leaf_pages = index->stat_n_leaf_pages;
7081
ut_a(stat_n_leaf_pages > 0);
7083
local_data_file_length =
7084
((uint64_t) stat_n_leaf_pages) * UNIV_PAGE_SIZE;
7087
/* Calculate a minimum length for a clustered index record and from
7088
that an upper bound for the number of rows. Since we only calculate
7089
new statistics in row0mysql.c when a table has grown by a threshold
7090
factor, we must add a safety factor 2 in front of the formula below. */
7092
estimate = 2 * local_data_file_length /
7093
dict_index_calc_min_rec_len(index);
7095
prebuilt->trx->op_info = "";
7097
return((ha_rows) estimate);
7100
/*********************************************************************//**
7101
How many seeks it will take to read through the table. This is to be
7102
comparable to the number returned by records_in_range so that we can
7103
decide if we should scan the table or use keys.
7104
@return estimated time measured in disk seeks */
7107
ha_innobase::scan_time()
7108
/*====================*/
7110
/* Since MySQL seems to favor table scans too much over index
7111
searches, we pretend that a sequential read takes the same time
7112
as a random disk read, that is, we do not divide the following
7113
by 10, which would be physically realistic. */
7115
return((double) (prebuilt->table->stat_clustered_index_size));
7118
/******************************************************************//**
7119
Calculate the time it takes to read a set of ranges through an index
7120
This enables us to optimise reads for clustered indexes.
7121
@return estimated time measured in disk seeks */
7124
ha_innobase::read_time(
7125
/*===================*/
7126
uint index, /*!< in: key number */
7127
uint ranges, /*!< in: how many ranges */
7128
ha_rows rows) /*!< in: estimated number of rows in the ranges */
7131
double time_for_scan;
7133
if (index != getTable()->getShare()->getPrimaryKey()) {
7135
return(Cursor::read_time(index, ranges, rows));
7140
return((double) rows);
7143
/* Assume that the read time is proportional to the scan time for all
7144
rows + at most one seek per range. */
7146
time_for_scan = scan_time();
7148
if ((total_rows = estimate_rows_upper_bound()) < rows) {
7150
return(time_for_scan);
7153
return(ranges + (double) rows / (double) total_rows * time_for_scan);
7156
/*********************************************************************//**
7157
Calculates the key number used inside MySQL for an Innobase index. We will
7158
first check the "index translation table" for a match of the index to get
7159
the index number. If there does not exist an "index translation table",
7160
or not able to find the index in the translation table, then we will fall back
7161
to the traditional way of looping through dict_index_t list to find a
7162
match. In this case, we have to take into account if we generated a
7163
default clustered index for the table
7164
@return the key number used inside MySQL */
7167
innobase_get_mysql_key_number_for_index(
7168
/*====================================*/
7169
INNOBASE_SHARE* share, /*!< in: share structure for index
7170
translation table. */
7171
const drizzled::Table* table, /*!< in: table in MySQL data
7173
dict_table_t* ib_table,/*!< in: table in Innodb data
7175
const dict_index_t* index) /*!< in: index */
7177
const dict_index_t* ind;
7185
/* If index does not belong to the table of share structure. Search
7186
index->table instead */
7187
if (index->table != ib_table) {
7189
ind = dict_table_get_first_index(index->table);
7191
while (index != ind) {
7192
ind = dict_table_get_next_index(ind);
7196
if (row_table_got_default_clust_index(index->table)) {
7204
/* If index does not belong to the table of share structure. Search
7205
index->table instead */
7206
if (index->table != ib_table) {
7208
ind = dict_table_get_first_index(index->table);
7210
while (index != ind) {
7211
ind = dict_table_get_next_index(ind);
7215
if (row_table_got_default_clust_index(index->table)) {
7223
/* If index translation table exists, we will first check
7224
the index through index translation table for a match. */
7225
if (share->idx_trans_tbl.index_mapping) {
7226
for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
7227
if (share->idx_trans_tbl.index_mapping[i] == index) {
7232
/* Print an error message if we cannot find the index
7233
** in the "index translation table". */
7234
errmsg_printf(error::ERROR,
7235
"Cannot find index %s in InnoDB index "
7236
"translation table.", index->name);
7239
/* If we do not have an "index translation table", or not able
7240
to find the index in the translation table, we'll directly find
7241
matching index in the dict_index_t list */
7242
for (i = 0; i < table->getShare()->keys; i++) {
7243
ind = dict_table_get_index_on_name(
7244
ib_table, table->key_info[i].name);
7251
errmsg_printf(error::ERROR,
7252
"Cannot find matching index number for index %s "
7253
"in InnoDB index list.", index->name);
7257
/*********************************************************************//**
7258
Returns statistics information of the table to the MySQL interpreter,
7259
in various fields of the handle object. */
7264
uint flag) /*!< in: what information MySQL requests */
7266
dict_table_t* ib_table;
7267
dict_index_t* index;
7268
ha_rows rec_per_key;
7270
os_file_stat_t stat_info;
7272
/* If we are forcing recovery at a high level, we will suppress
7273
statistics calculation on tables, because that may crash the
7274
server if an index is badly corrupted. */
7276
/* We do not know if MySQL can call this function before calling
7277
external_lock(). To be safe, update the session of the current table
7280
update_session(getTable()->in_use);
7282
/* In case MySQL calls this in the middle of a SELECT query, release
7283
possible adaptive hash latch to avoid deadlocks of threads */
7285
prebuilt->trx->op_info = "returning various info to MySQL";
7287
trx_search_latch_release_if_reserved(prebuilt->trx);
7289
ib_table = prebuilt->table;
7291
if (flag & HA_STATUS_TIME) {
7292
/* In Analyze we call with this flag: update
7293
then statistics so that they are up-to-date */
7295
prebuilt->trx->op_info = "updating table statistics";
7297
dict_update_statistics(ib_table,
7298
FALSE /* update even if stats
7299
are initialized */);
7302
prebuilt->trx->op_info = "returning various info to MySQL";
7304
fs::path get_status_path(getDataHomeCatalog());
7305
get_status_path /= ib_table->name;
7306
fs::change_extension(get_status_path, "dfe");
7308
/* Note that we do not know the access time of the table,
7309
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
7311
if (os_file_get_status(get_status_path.file_string().c_str(), &stat_info)) {
7312
stats.create_time = (ulong) stat_info.ctime;
7316
if (flag & HA_STATUS_VARIABLE) {
7318
dict_table_stats_lock(ib_table, RW_S_LATCH);
7320
n_rows = ib_table->stat_n_rows;
7322
/* Because we do not protect stat_n_rows by any mutex in a
7323
delete, it is theoretically possible that the value can be
7324
smaller than zero! TODO: fix this race.
7326
The MySQL optimizer seems to assume in a left join that n_rows
7327
is an accurate estimate if it is zero. Of course, it is not,
7328
since we do not have any locks on the rows yet at this phase.
7329
Since SHOW TABLE STATUS seems to call this function with the
7330
HA_STATUS_TIME flag set, while the left join optimizer does not
7331
set that flag, we add one to a zero value if the flag is not
7332
set. That way SHOW TABLE STATUS will show the best estimate,
7333
while the optimizer never sees the table empty. */
7339
if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
7343
/* Fix bug#40386: Not flushing query cache after truncate.
7344
n_rows can not be 0 unless the table is empty, set to 1
7345
instead. The original problem of bug#29507 is actually
7346
fixed in the server code. */
7347
if (user_session->getSqlCommand() == SQLCOM_TRUNCATE) {
7351
/* We need to reset the prebuilt value too, otherwise
7352
checks for values greater than the last value written
7353
to the table will fail and the autoinc counter will
7354
not be updated. This will force doInsertRecord() into
7355
attempting an update of the table's AUTOINC counter. */
7357
prebuilt->autoinc_last_value = 0;
7360
stats.records = (ha_rows)n_rows;
7362
stats.data_file_length = ((uint64_t)
7363
ib_table->stat_clustered_index_size)
7365
stats.index_file_length = ((uint64_t)
7366
ib_table->stat_sum_of_other_index_sizes)
7369
dict_table_stats_unlock(ib_table, RW_S_LATCH);
7371
/* Since fsp_get_available_space_in_free_extents() is
7372
acquiring latches inside InnoDB, we do not call it if we
7373
are asked by MySQL to avoid locking. Another reason to
7374
avoid the call is that it uses quite a lot of CPU.
7376
if (flag & HA_STATUS_NO_LOCK) {
7377
/* We do not update delete_length if no
7378
locking is requested so the "old" value can
7379
remain. delete_length is initialized to 0 in
7380
the ha_statistics' constructor. */
7381
} else if (UNIV_UNLIKELY
7382
(srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) {
7383
/* Avoid accessing the tablespace if
7384
innodb_crash_recovery is set to a high value. */
7385
stats.delete_length = 0;
7389
avail_space = fsp_get_available_space_in_free_extents(ib_table->space);
7391
if (avail_space == ULLINT_UNDEFINED) {
7394
session= getTable()->in_use;
7397
push_warning_printf(
7399
DRIZZLE_ERROR::WARN_LEVEL_WARN,
7401
"InnoDB: Trying to get the free "
7402
"space for table %s but its "
7403
"tablespace has been discarded or "
7404
"the .ibd file is missing. Setting "
7405
"the free space to zero.",
7408
stats.delete_length = 0;
7410
stats.delete_length = avail_space * 1024;
7414
stats.check_time = 0;
7416
if (stats.records == 0) {
7417
stats.mean_rec_length = 0;
7419
stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
7423
if (flag & HA_STATUS_CONST) {
7425
/* Verify the number of index in InnoDB and MySQL
7426
matches up. If prebuilt->clust_index_was_generated
7427
holds, InnoDB defines GEN_CLUST_INDEX internally */
7428
ulint num_innodb_index = UT_LIST_GET_LEN(ib_table->indexes) - prebuilt->clust_index_was_generated;
7430
if (getTable()->getShare()->keys != num_innodb_index) {
7431
errmsg_printf(error::ERROR, "Table %s contains %lu "
7432
"indexes inside InnoDB, which "
7433
"is different from the number of "
7434
"indexes %u defined in the MySQL ",
7435
ib_table->name, num_innodb_index,
7436
getTable()->getShare()->keys);
7439
dict_table_stats_lock(ib_table, RW_S_LATCH);
7441
for (i = 0; i < getTable()->getShare()->sizeKeys(); i++) {
7443
/* We could get index quickly through internal
7444
index mapping with the index translation table.
7445
The identity of index (match up index name with
7446
that of table->key_info[i]) is already verified in
7447
innobase_get_index(). */
7448
index = innobase_get_index(i);
7450
if (index == NULL) {
7451
errmsg_printf(error::ERROR, "Table %s contains fewer "
7452
"indexes inside InnoDB than "
7453
"are defined in the MySQL "
7454
".frm file. Have you mixed up "
7455
".frm files from different "
7456
"installations? See "
7458
"innodb-troubleshooting.html\n",
7463
for (j = 0; j < getTable()->key_info[i].key_parts; j++) {
7465
if (j + 1 > index->n_uniq) {
7466
errmsg_printf(error::ERROR,
7467
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
7468
"statistics for %lu columns. Have you mixed up .frm files from different "
7470
"See " REFMAN "innodb-troubleshooting.html\n",
7474
index->n_uniq, j + 1);
7478
if (index->stat_n_diff_key_vals[j + 1] == 0) {
7480
rec_per_key = stats.records;
7482
rec_per_key = (ha_rows)(stats.records /
7483
index->stat_n_diff_key_vals[j + 1]);
7486
/* Since MySQL seems to favor table scans
7487
too much over index searches, we pretend
7488
index selectivity is 2 times better than
7491
rec_per_key = rec_per_key / 2;
7493
if (rec_per_key == 0) {
7497
getTable()->key_info[i].rec_per_key[j]=
7498
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
7499
(ulong) rec_per_key;
7503
dict_table_stats_unlock(ib_table, RW_S_LATCH);
7506
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
7510
if (flag & HA_STATUS_ERRKEY) {
7511
const dict_index_t* err_index;
7513
ut_a(prebuilt->trx);
7514
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7516
err_index = trx_get_error_info(prebuilt->trx);
7519
errkey = (unsigned int)
7520
innobase_get_mysql_key_number_for_index(share, getTable(), ib_table,
7523
errkey = (unsigned int) prebuilt->trx->error_key_num;
7527
if ((flag & HA_STATUS_AUTO) && getTable()->found_next_number_field) {
7528
stats.auto_increment_value = innobase_peek_autoinc();
7532
prebuilt->trx->op_info = "";
7537
/**********************************************************************//**
7538
Updates index cardinalities of the table, based on 8 random dives into
7539
each index tree. This does NOT calculate exact statistics on the table.
7540
@return returns always 0 (success) */
7543
ha_innobase::analyze(
7544
/*=================*/
7545
Session*) /*!< in: connection thread handle */
7547
/* Simply call ::info() with all the flags */
7548
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
7553
/*******************************************************************//**
7554
Tries to check that an InnoDB table is not corrupted. If corruption is
7555
noticed, prints to stderr information about it. In case of corruption
7556
may also assert a failure and crash the server.
7557
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
7562
Session* session) /*!< in: user thread handle */
7564
dict_index_t* index;
7566
ulint n_rows_in_table = ULINT_UNDEFINED;
7568
ulint old_isolation_level;
7570
assert(session == getTable()->in_use);
7571
ut_a(prebuilt->trx);
7572
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7573
ut_a(prebuilt->trx == session_to_trx(session));
7575
if (prebuilt->mysql_template == NULL) {
7576
/* Build the template; we will use a dummy template
7577
in index scans done in checking */
7579
build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
7582
if (prebuilt->table->ibd_file_missing) {
7583
errmsg_printf(error::ERROR, "InnoDB: Error:\n"
7584
"InnoDB: MySQL is trying to use a table handle"
7585
" but the .ibd file for\n"
7586
"InnoDB: table %s does not exist.\n"
7587
"InnoDB: Have you deleted the .ibd file"
7588
" from the database directory under\n"
7589
"InnoDB: the MySQL datadir, or have you"
7590
" used DISCARD TABLESPACE?\n"
7591
"InnoDB: Please refer to\n"
7592
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
7593
"InnoDB: how you can resolve the problem.\n",
7594
prebuilt->table->name);
7595
return(HA_ADMIN_CORRUPT);
7598
prebuilt->trx->op_info = "checking table";
7600
old_isolation_level = prebuilt->trx->isolation_level;
7602
/* We must run the index record counts at an isolation level
7603
>= READ COMMITTED, because a dirty read can see a wrong number
7604
of records in some index; to play safe, we use always
7605
REPEATABLE READ here */
7607
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
7609
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
7610
mutex_enter(&kernel_mutex);
7611
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
7612
mutex_exit(&kernel_mutex);
7614
for (index = dict_table_get_first_index(prebuilt->table);
7616
index = dict_table_get_next_index(index)) {
7618
fputs("Validating index ", stderr);
7619
ut_print_name(stderr, trx, FALSE, index->name);
7623
if (!btr_validate_index(index, prebuilt->trx)) {
7625
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7627
"InnoDB: The B-tree of"
7628
" index '%-.200s' is corrupted.",
7633
/* Instead of invoking change_active_index(), set up
7634
a dummy template for non-locking reads, disabling
7635
access to the clustered index. */
7636
prebuilt->index = index;
7638
prebuilt->index_usable = row_merge_is_index_usable(
7639
prebuilt->trx, prebuilt->index);
7641
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
7642
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7643
HA_ERR_TABLE_DEF_CHANGED,
7644
"InnoDB: Insufficient history for"
7650
prebuilt->sql_stat_start = TRUE;
7651
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
7652
prebuilt->n_template = 0;
7653
prebuilt->need_to_access_clustered = FALSE;
7655
dtuple_set_n_fields(prebuilt->search_tuple, 0);
7657
prebuilt->select_lock_type = LOCK_NONE;
7659
if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) {
7660
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7662
"InnoDB: The B-tree of"
7663
" index '%-.200s' is corrupted.",
7668
if (user_session->getKilled()) {
7673
fprintf(stderr, "%lu entries in index %s\n", n_rows,
7677
if (index == dict_table_get_first_index(prebuilt->table)) {
7678
n_rows_in_table = n_rows;
7679
} else if (n_rows != n_rows_in_table) {
7680
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7682
"InnoDB: Index '%-.200s'"
7683
" contains %lu entries,"
7687
(ulong) n_rows_in_table);
7692
/* Restore the original isolation level */
7693
prebuilt->trx->isolation_level = old_isolation_level;
7695
/* We validate also the whole adaptive hash index for all tables
7696
at every CHECK TABLE */
7698
if (!btr_search_validate()) {
7699
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7701
"InnoDB: The adaptive hash index is corrupted.");
7705
/* Restore the fatal lock wait timeout after CHECK TABLE. */
7706
mutex_enter(&kernel_mutex);
7707
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
7708
mutex_exit(&kernel_mutex);
7710
prebuilt->trx->op_info = "";
7711
if (user_session->getKilled()) {
7712
my_error(ER_QUERY_INTERRUPTED, MYF(0));
7715
return(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
7718
/*************************************************************//**
7719
Adds information about free space in the InnoDB tablespace to a table comment
7720
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
7722
@return table comment + InnoDB free space + info on foreign keys */
7725
ha_innobase::update_table_comment(
7726
/*==============================*/
7727
const char* comment)/*!< in: table comment defined by user */
7729
uint length = (uint) strlen(comment);
7733
/* We do not know if MySQL can call this function before calling
7734
external_lock(). To be safe, update the session of the current table
7737
if (length > 64000 - 3) {
7738
return((char*)comment); /* string too long */
7741
update_session(getTable()->in_use);
7743
prebuilt->trx->op_info = "returning table comment";
7745
/* In case MySQL calls this in the middle of a SELECT query, release
7746
possible adaptive hash latch to avoid deadlocks of threads */
7748
trx_search_latch_release_if_reserved(prebuilt->trx);
7751
/* output the data to a temporary file */
7753
mutex_enter(&srv_dict_tmpfile_mutex);
7754
rewind(srv_dict_tmpfile);
7756
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
7757
fsp_get_available_space_in_free_extents(
7758
prebuilt->table->space));
7760
dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
7761
prebuilt->trx, prebuilt->table);
7762
flen = ftell(srv_dict_tmpfile);
7765
} else if (length + flen + 3 > 64000) {
7766
flen = 64000 - 3 - length;
7769
/* allocate buffer for the full string, and
7770
read the contents of the temporary file */
7772
str = (char*) malloc(length + flen + 3);
7775
char* pos = str + length;
7777
memcpy(str, comment, length);
7781
rewind(srv_dict_tmpfile);
7782
flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
7786
mutex_exit(&srv_dict_tmpfile_mutex);
7788
prebuilt->trx->op_info = "";
7790
return(str ? str : (char*) comment);
7793
/*******************************************************************//**
7794
Gets the foreign key create info for a table stored in InnoDB.
7795
@return own: character string in the form which can be inserted to the
7796
CREATE TABLE statement, MUST be freed with
7797
ha_innobase::free_foreign_key_create_info */
7800
ha_innobase::get_foreign_key_create_info(void)
7801
/*==========================================*/
7806
ut_a(prebuilt != NULL);
7808
/* We do not know if MySQL can call this function before calling
7809
external_lock(). To be safe, update the session of the current table
7812
update_session(getTable()->in_use);
7814
prebuilt->trx->op_info = "getting info on foreign keys";
7816
/* In case MySQL calls this in the middle of a SELECT query,
7817
release possible adaptive hash latch to avoid
7818
deadlocks of threads */
7820
trx_search_latch_release_if_reserved(prebuilt->trx);
7822
mutex_enter(&srv_dict_tmpfile_mutex);
7823
rewind(srv_dict_tmpfile);
7825
/* output the data to a temporary file */
7826
dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
7827
prebuilt->trx, prebuilt->table);
7828
prebuilt->trx->op_info = "";
7830
flen = ftell(srv_dict_tmpfile);
7835
/* allocate buffer for the string, and
7836
read the contents of the temporary file */
7838
str = (char*) malloc(flen + 1);
7841
rewind(srv_dict_tmpfile);
7842
flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
7846
mutex_exit(&srv_dict_tmpfile_mutex);
7854
ha_innobase::get_foreign_key_list(Session *session, List<ForeignKeyInfo> *f_key_list)
7856
ut_a(prebuilt != NULL);
7857
update_session(getTable()->in_use);
7858
prebuilt->trx->op_info = "getting list of foreign keys";
7859
trx_search_latch_release_if_reserved(prebuilt->trx);
7860
mutex_enter(&(dict_sys->mutex));
7861
dict_foreign_t* foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7863
while (foreign != NULL) {
7866
char uname[NAME_LEN + 1]; /* Unencoded name */
7867
char db_name[NAME_LEN + 1];
7868
const char *tmp_buff;
7871
tmp_buff = foreign->id;
7873
while (tmp_buff[i] != '/')
7876
lex_string_t *tmp_foreign_id = session->make_lex_string(NULL, str_ref(tmp_buff));
7879
tmp_buff = foreign->referenced_table_name;
7882
while (tmp_buff[i] != '/')
7884
db_name[i]= tmp_buff[i];
7888
ulen= identifier::Table::filename_to_tablename(db_name, uname, sizeof(uname));
7889
lex_string_t *tmp_referenced_db = session->make_lex_string(NULL, str_ref(uname, ulen));
7893
ulen= identifier::Table::filename_to_tablename(tmp_buff, uname, sizeof(uname));
7894
lex_string_t *tmp_referenced_table = session->make_lex_string(NULL, str_ref(uname, ulen));
7896
/** Foreign Fields **/
7897
List<lex_string_t> tmp_foreign_fields;
7898
List<lex_string_t> tmp_referenced_fields;
7901
tmp_foreign_fields.push_back(session->make_lex_string(NULL, str_ref(foreign->foreign_col_names[i])));
7902
tmp_referenced_fields.push_back(session->make_lex_string(NULL, str_ref(foreign->referenced_col_names[i])));
7903
if (++i >= foreign->n_fields)
7908
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
7911
tmp_buff= "CASCADE";
7913
else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
7916
tmp_buff= "SET NULL";
7918
else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
7921
tmp_buff= "NO ACTION";
7926
tmp_buff= "RESTRICT";
7928
lex_string_t *tmp_delete_method = session->make_lex_string(NULL, str_ref(tmp_buff, length));
7931
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
7934
tmp_buff= "CASCADE";
7936
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
7939
tmp_buff= "SET NULL";
7941
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
7944
tmp_buff= "NO ACTION";
7949
tmp_buff= "RESTRICT";
7951
lex_string_t *tmp_update_method = session->make_lex_string(NULL, str_ref(tmp_buff, length));
7953
lex_string_t *tmp_referenced_key_name = NULL;
7955
if (foreign->referenced_index && foreign->referenced_index->name)
7957
tmp_referenced_key_name = session->make_lex_string(NULL, str_ref(foreign->referenced_index->name));
7960
ForeignKeyInfo f_key_info(
7961
tmp_foreign_id, tmp_referenced_db, tmp_referenced_table,
7962
tmp_update_method, tmp_delete_method, tmp_referenced_key_name,
7963
tmp_foreign_fields, tmp_referenced_fields);
7965
f_key_list->push_back((ForeignKeyInfo*)session->mem.memdup(&f_key_info, sizeof(ForeignKeyInfo)));
7966
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
7968
mutex_exit(&(dict_sys->mutex));
7969
prebuilt->trx->op_info = "";
7974
/*****************************************************************//**
7975
Checks if ALTER TABLE may change the storage engine of the table.
7976
Changing storage engines is not allowed for tables for which there
7977
are foreign key constraints (parent or child tables).
7978
@return TRUE if can switch engines */
7981
ha_innobase::can_switch_engines(void)
7982
/*=================================*/
7986
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
7988
prebuilt->trx->op_info =
7989
"determining if there are foreign key constraints";
7990
row_mysql_lock_data_dictionary(prebuilt->trx);
7992
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
7993
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7995
row_mysql_unlock_data_dictionary(prebuilt->trx);
7996
prebuilt->trx->op_info = "";
8001
/*******************************************************************//**
8002
Checks if a table is referenced by a foreign key. The MySQL manual states that
8003
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
8004
delete is then allowed internally to resolve a duplicate key conflict in
8005
REPLACE, not an update.
8006
@return > 0 if referenced by a FOREIGN KEY */
8009
ha_innobase::referenced_by_foreign_key(void)
8010
/*========================================*/
8012
if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
8020
/*******************************************************************//**
8021
Frees the foreign key create info for a table stored in InnoDB, if it is
8025
ha_innobase::free_foreign_key_create_info(
8026
/*======================================*/
8027
char* str) /*!< in, own: create info string to free */
8032
/*******************************************************************//**
8033
Tells something additional to the Cursor about how to do things.
8034
@return 0 or error number */
8039
enum ha_extra_function operation)
8040
/*!< in: HA_EXTRA_FLUSH or some other flag */
8042
/* Warning: since it is not sure that MySQL calls external_lock
8043
before calling this function, the trx field in prebuilt can be
8046
switch (operation) {
8047
case HA_EXTRA_FLUSH:
8048
if (prebuilt->blob_heap) {
8049
row_mysql_prebuilt_free_blob_heap(prebuilt);
8052
case HA_EXTRA_RESET_STATE:
8053
reset_template(prebuilt);
8055
case HA_EXTRA_NO_KEYREAD:
8056
prebuilt->read_just_key = 0;
8058
case HA_EXTRA_KEYREAD:
8059
prebuilt->read_just_key = 1;
8061
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
8062
prebuilt->keep_other_fields_on_keyread = 1;
8065
/* IMPORTANT: prebuilt->trx can be obsolete in
8066
this method, because it is not sure that MySQL
8067
calls external_lock before this method with the
8068
parameters below. We must not invoke update_session()
8069
either, because the calling threads may change.
8070
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
8071
case HA_EXTRA_IGNORE_DUP_KEY:
8072
session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_IGNORE;
8074
case HA_EXTRA_WRITE_CAN_REPLACE:
8075
session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_REPLACE;
8077
case HA_EXTRA_WRITE_CANNOT_REPLACE:
8078
session_to_trx(getTable()->in_use)->duplicates &= ~TRX_DUP_REPLACE;
8080
case HA_EXTRA_NO_IGNORE_DUP_KEY:
8081
session_to_trx(getTable()->in_use)->duplicates &=
8082
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
8084
default:/* Do nothing */
8093
ha_innobase::reset()
8095
if (prebuilt->blob_heap) {
8096
row_mysql_prebuilt_free_blob_heap(prebuilt);
8099
reset_template(prebuilt);
8101
/* TODO: This should really be reset in reset_template() but for now
8102
it's safer to do it explicitly here. */
8104
/* This is a statement level counter. */
8105
prebuilt->autoinc_last_value = 0;
8110
/******************************************************************//**
8111
Maps a MySQL trx isolation level code to the InnoDB isolation level code
8112
@return InnoDB isolation level */
8115
innobase_map_isolation_level(
8116
/*=========================*/
8117
enum_tx_isolation iso) /*!< in: MySQL isolation level code */
8120
case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
8121
case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
8122
case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
8123
case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
8124
default: ut_a(0); return(0);
8128
/******************************************************************//**
8129
As MySQL will execute an external lock for every new table it uses when it
8130
starts to process an SQL statement. We can use this function to store the pointer to
8131
the Session in the handle.
8135
ha_innobase::external_lock(
8136
/*=======================*/
8137
Session* session, /*!< in: handle to the user thread */
8138
int lock_type) /*!< in: lock type */
8140
update_session(session);
8142
trx_t *trx= prebuilt->trx;
8144
prebuilt->sql_stat_start = TRUE;
8145
prebuilt->hint_need_to_fetch_extra_cols = 0;
8147
reset_template(prebuilt);
8149
if (lock_type == F_WRLCK) {
8151
/* If this is a SELECT, then it is in UPDATE TABLE ...
8152
or SELECT ... FOR UPDATE */
8153
prebuilt->select_lock_type = LOCK_X;
8154
prebuilt->stored_select_lock_type = LOCK_X;
8157
if (lock_type != F_UNLCK) {
8158
/* MySQL is setting a new table lock */
8160
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
8161
&& prebuilt->select_lock_type == LOCK_NONE
8162
&& session_test_options(session,
8163
OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
8165
/* To get serializable execution, we let InnoDB
8166
conceptually add 'LOCK IN SHARE MODE' to all SELECTs
8167
which otherwise would have been consistent reads. An
8168
exception is consistent reads in the AUTOCOMMIT=1 mode:
8169
we know that they are read-only transactions, and they
8170
can be serialized also if performed as consistent
8173
prebuilt->select_lock_type = LOCK_S;
8174
prebuilt->stored_select_lock_type = LOCK_S;
8177
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
8178
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
8179
an InnoDB table lock if it is released immediately at the end
8180
of LOCK TABLES, and InnoDB's table locks in that case cause
8181
VERY easily deadlocks.
8183
We do not set InnoDB table locks if user has not explicitly
8184
requested a table lock. Note that session_in_lock_tables(session)
8185
can hold in some cases, e.g., at the start of a stored
8186
procedure call (SQLCOM_CALL). */
8188
if (prebuilt->select_lock_type != LOCK_NONE) {
8189
trx->mysql_n_tables_locked++;
8192
prebuilt->mysql_has_locked = TRUE;
8197
/* MySQL is releasing a table lock */
8198
prebuilt->mysql_has_locked = FALSE;
8199
trx->mysql_n_tables_locked= 0;
8204
/************************************************************************//**
8205
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
8206
Monitor to the client. */
8211
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
8212
Session* session,/*!< in: the MySQL query thread of the caller */
8213
stat_print_fn *stat_print)
8216
static const char truncated_msg[] = "... truncated...\n";
8217
const long MAX_STATUS_SIZE = 1048576;
8218
ulint trx_list_start = ULINT_UNDEFINED;
8219
ulint trx_list_end = ULINT_UNDEFINED;
8221
assert(engine == innodb_engine_ptr);
8223
trx = check_trx_exists(session);
8225
innobase_release_stat_resources(trx);
8227
/* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
8230
long flen, usable_len;
8233
mutex_enter(&srv_monitor_file_mutex);
8234
rewind(srv_monitor_file);
8235
srv_printf_innodb_monitor(srv_monitor_file, FALSE,
8236
&trx_list_start, &trx_list_end);
8237
flen = ftell(srv_monitor_file);
8238
os_file_set_eof(srv_monitor_file);
8244
if (flen > MAX_STATUS_SIZE) {
8245
usable_len = MAX_STATUS_SIZE;
8246
srv_truncated_status_writes++;
8251
/* allocate buffer for the string, and
8252
read the contents of the temporary file */
8254
if (!(str = (char*) malloc(usable_len + 1))) {
8255
mutex_exit(&srv_monitor_file_mutex);
8259
rewind(srv_monitor_file);
8260
if (flen < MAX_STATUS_SIZE) {
8261
/* Display the entire output. */
8262
flen = (long) fread(str, 1, flen, srv_monitor_file);
8263
} else if (trx_list_end < (ulint) flen
8264
&& trx_list_start < trx_list_end
8265
&& trx_list_start + (flen - trx_list_end)
8266
< MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
8267
/* Omit the beginning of the list of active transactions. */
8268
long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
8269
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
8270
len += sizeof truncated_msg - 1;
8271
usable_len = (MAX_STATUS_SIZE - 1) - len;
8272
fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
8273
len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
8276
/* Omit the end of the output. */
8277
flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
8280
mutex_exit(&srv_monitor_file_mutex);
8282
stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
8283
STRING_WITH_LEN(""), str, flen);
8290
/************************************************************************//**
8291
Implements the SHOW MUTEX STATUS command.
8292
@return true on failure false on success*/
8295
innodb_mutex_show_status(
8296
/*=====================*/
8297
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
8298
Session* session, /*!< in: the MySQL query thread of the
8300
stat_print_fn* stat_print) /*!< in: function for printing
8303
char buf1[IO_SIZE], buf2[IO_SIZE];
8306
ulint block_mutex_oswait_count = 0;
8307
ulint block_lock_oswait_count = 0;
8308
mutex_t* block_mutex = NULL;
8309
rw_lock_t* block_lock = NULL;
8311
ulint rw_lock_count= 0;
8312
ulint rw_lock_count_spin_loop= 0;
8313
ulint rw_lock_count_spin_rounds= 0;
8314
ulint rw_lock_count_os_wait= 0;
8315
ulint rw_lock_count_os_yield= 0;
8316
uint64_t rw_lock_wait_time= 0;
8317
#endif /* UNIV_DEBUG */
8318
uint engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
8319
assert(engine == innodb_engine_ptr);
8321
mutex_enter(&mutex_list_mutex);
8323
for (mutex = UT_LIST_GET_FIRST(mutex_list); mutex != NULL;
8324
mutex = UT_LIST_GET_NEXT(list, mutex)) {
8325
if (mutex->count_os_wait == 0) {
8330
if (buf_pool_is_block_mutex(mutex)) {
8331
block_mutex = mutex;
8332
block_mutex_oswait_count += mutex->count_os_wait;
8336
if (mutex->mutex_type != 1) {
8337
if (mutex->count_using > 0) {
8338
buf1len= my_snprintf(buf1, sizeof(buf1),
8340
mutex->cmutex_name, mutex->cfile_name);
8341
buf2len= my_snprintf(buf2, sizeof(buf2),
8342
"count=%lu, spin_waits=%lu,"
8343
" spin_rounds=%lu, "
8344
"os_waits=%lu, os_yields=%lu,"
8345
" os_wait_times=%lu",
8347
mutex->count_spin_loop,
8348
mutex->count_spin_rounds,
8349
mutex->count_os_wait,
8350
mutex->count_os_yield,
8351
(ulong) (mutex->lspent_time/1000));
8353
if (stat_print(session, innobase_engine_name,
8354
engine_name_len, buf1, buf1len,
8356
mutex_exit(&mutex_list_mutex);
8361
rw_lock_count += mutex->count_using;
8362
rw_lock_count_spin_loop += mutex->count_spin_loop;
8363
rw_lock_count_spin_rounds += mutex->count_spin_rounds;
8364
rw_lock_count_os_wait += mutex->count_os_wait;
8365
rw_lock_count_os_yield += mutex->count_os_yield;
8366
rw_lock_wait_time += mutex->lspent_time;
8368
#else /* UNIV_DEBUG */
8369
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
8370
mutex->cfile_name, (ulong) mutex->cline);
8371
buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
8372
(ulong) mutex->count_os_wait);
8374
if (stat_print(session, innobase_engine_name,
8375
engine_name_len, buf1, buf1len,
8377
mutex_exit(&mutex_list_mutex);
8380
#endif /* UNIV_DEBUG */
8384
buf1len = snprintf(buf1, sizeof buf1,
8386
block_mutex->cfile_name,
8387
(ulong) block_mutex->cline);
8388
buf2len = snprintf(buf2, sizeof buf2,
8390
(ulong) block_mutex_oswait_count);
8392
if (stat_print(session, innobase_engine_name,
8393
strlen(innobase_engine_name), buf1, buf1len,
8395
mutex_exit(&mutex_list_mutex);
8400
mutex_exit(&mutex_list_mutex);
8402
mutex_enter(&rw_lock_list_mutex);
8404
for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL;
8405
lock = UT_LIST_GET_NEXT(list, lock)) {
8406
if (lock->count_os_wait == 0) {
8410
if (buf_pool_is_block_lock(lock)) {
8412
block_lock_oswait_count += lock->count_os_wait;
8416
buf1len = snprintf(buf1, sizeof buf1, "%s:%lu",
8417
lock->cfile_name, (ulong) lock->cline);
8418
buf2len = snprintf(buf2, sizeof buf2, "os_waits=%lu",
8419
(ulong) lock->count_os_wait);
8421
if (stat_print(session, innobase_engine_name,
8422
strlen(innobase_engine_name), buf1, buf1len,
8424
mutex_exit(&rw_lock_list_mutex);
8430
buf1len = snprintf(buf1, sizeof buf1,
8432
block_lock->cfile_name,
8433
(ulong) block_lock->cline);
8434
buf2len = snprintf(buf2, sizeof buf2,
8436
(ulong) block_lock_oswait_count);
8438
if (stat_print(session, innobase_engine_name,
8439
strlen(innobase_engine_name), buf1, buf1len,
8441
mutex_exit(&rw_lock_list_mutex);
8446
mutex_exit(&rw_lock_list_mutex);
8449
buf2len = snprintf(buf2, sizeof buf2,
8450
"count=%lu, spin_waits=%lu, spin_rounds=%lu, "
8451
"os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
8452
(ulong) rw_lock_count,
8453
(ulong) rw_lock_count_spin_loop,
8454
(ulong) rw_lock_count_spin_rounds,
8455
(ulong) rw_lock_count_os_wait,
8456
(ulong) rw_lock_count_os_yield,
8457
(ulong) (rw_lock_wait_time / 1000));
8459
if (stat_print(session, innobase_engine_name, engine_name_len,
8460
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
8463
#endif /* UNIV_DEBUG */
8468
bool InnobaseEngine::show_status(Session* session,
8469
stat_print_fn* stat_print,
8470
enum ha_stat_type stat_type)
8472
assert(this == innodb_engine_ptr);
8474
switch (stat_type) {
8475
case HA_ENGINE_STATUS:
8476
return innodb_show_status(this, session, stat_print);
8477
case HA_ENGINE_MUTEX:
8478
return innodb_mutex_show_status(this, session, stat_print);
8484
/************************************************************************//**
8485
Handling the shared INNOBASE_SHARE structure that is needed to provide table
8487
****************************************************************************/
8489
static INNOBASE_SHARE* get_share(const char* table_name)
8491
INNOBASE_SHARE *share;
8492
boost::mutex::scoped_lock scopedLock(innobase_share_mutex);
8494
ulint fold = ut_fold_string(table_name);
8496
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8497
INNOBASE_SHARE*, share,
8498
ut_ad(share->use_count > 0),
8499
!strcmp(share->table_name, table_name));
8502
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
8505
share= new INNOBASE_SHARE(table_name);
8507
HASH_INSERT(INNOBASE_SHARE, table_name_hash,
8508
innobase_open_tables, fold, share);
8510
thr_lock_init(&share->lock);
8512
/* Index translation table initialization */
8513
share->idx_trans_tbl.index_mapping = NULL;
8514
share->idx_trans_tbl.index_count = 0;
8515
share->idx_trans_tbl.array_size = 0;
8523
static void free_share(INNOBASE_SHARE* share)
8525
boost::mutex::scoped_lock scopedLock(innobase_share_mutex);
8528
INNOBASE_SHARE* share2;
8529
ulint fold = ut_fold_string(share->table_name);
8531
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8532
INNOBASE_SHARE*, share2,
8533
ut_ad(share->use_count > 0),
8534
!strcmp(share->table_name, share2->table_name));
8536
ut_a(share2 == share);
8537
#endif /* UNIV_DEBUG */
8539
if (!--share->use_count) {
8540
ulint fold = ut_fold_string(share->table_name);
8542
HASH_DELETE(INNOBASE_SHARE, table_name_hash,
8543
innobase_open_tables, fold, share);
8545
/* Free any memory from index translation table */
8546
free(share->idx_trans_tbl.index_mapping);
8550
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
8555
/*****************************************************************//**
8556
Converts a MySQL table lock stored in the 'lock' field of the handle to
8557
a proper type before storing pointer to the lock into an array of pointers.
8558
MySQL also calls this if it wants to reset some table locks to a not-locked
8559
state during the processing of an SQL query. An example is that during a
8560
SELECT the read lock is released early on the 'const' tables where we only
8561
fetch one row. MySQL does not call this when it releases all locks at the
8562
end of an SQL statement.
8563
@return pointer to the next element in the 'to' array */
8566
ha_innobase::store_lock(
8567
/*====================*/
8568
Session* session, /*!< in: user thread handle */
8569
THR_LOCK_DATA** to, /*!< in: pointer to an array
8570
of pointers to lock structs;
8571
pointer to the 'lock' field
8572
of current handle is stored
8573
next to this array */
8574
enum thr_lock_type lock_type) /*!< in: lock type to store in
8575
'lock'; this may also be
8580
/* Note that trx in this function is NOT necessarily prebuilt->trx
8581
because we call update_session() later, in ::external_lock()! Failure to
8582
understand this caused a serious memory corruption bug in 5.1.11. */
8584
trx = check_trx_exists(session);
8586
assert(EQ_CURRENT_SESSION(session));
8587
const uint32_t sql_command = session->getSqlCommand();
8589
if (sql_command == SQLCOM_DROP_TABLE) {
8591
/* MySQL calls this function in DROP Table though this table
8592
handle may belong to another session that is running a query.
8593
Let us in that case skip any changes to the prebuilt struct. */
8595
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
8596
|| lock_type == TL_READ_NO_INSERT
8597
|| (lock_type != TL_IGNORE
8598
&& sql_command != SQLCOM_SELECT)) {
8600
/* The OR cases above are in this order:
8601
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
8602
are processing a stored procedure or function, or
8603
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
8604
3) this is a SELECT ... IN SHARE MODE, or
8605
4) we are doing a complex SQL statement like
8606
INSERT INTO ... SELECT ... and the logical logging (MySQL
8607
binlog) requires the use of a locking read, or
8608
MySQL is doing LOCK TABLES ... READ.
8609
5) we let InnoDB do locking reads for all SQL statements that
8610
are not simple SELECTs; note that select_lock_type in this
8611
case may get strengthened in ::external_lock() to LOCK_X.
8612
Note that we MUST use a locking read in all data modifying
8613
SQL statements, because otherwise the execution would not be
8614
serializable, and also the results from the update could be
8615
unexpected if an obsolete consistent read view would be
8618
ulint isolation_level;
8620
isolation_level = trx->isolation_level;
8622
if ((srv_locks_unsafe_for_binlog
8623
|| isolation_level <= TRX_ISO_READ_COMMITTED)
8624
&& isolation_level != TRX_ISO_SERIALIZABLE
8625
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
8626
&& (sql_command == SQLCOM_INSERT_SELECT
8627
|| sql_command == SQLCOM_REPLACE_SELECT
8628
|| sql_command == SQLCOM_UPDATE
8629
|| sql_command == SQLCOM_CREATE_TABLE
8630
|| sql_command == SQLCOM_SET_OPTION)) {
8632
/* If we either have innobase_locks_unsafe_for_binlog
8633
option set or this session is using READ COMMITTED
8634
isolation level and isolation level of the transaction
8635
is not set to serializable and MySQL is doing
8636
INSERT INTO...SELECT or REPLACE INTO...SELECT
8637
or UPDATE ... = (SELECT ...) or CREATE ...
8638
SELECT... or SET ... = (SELECT ...) without
8639
FOR UPDATE or IN SHARE MODE in select,
8640
then we use consistent read for select. */
8642
prebuilt->select_lock_type = LOCK_NONE;
8643
prebuilt->stored_select_lock_type = LOCK_NONE;
8644
} else if (sql_command == SQLCOM_CHECKSUM) {
8645
/* Use consistent read for checksum table */
8647
prebuilt->select_lock_type = LOCK_NONE;
8648
prebuilt->stored_select_lock_type = LOCK_NONE;
8650
prebuilt->select_lock_type = LOCK_S;
8651
prebuilt->stored_select_lock_type = LOCK_S;
8654
} else if (lock_type != TL_IGNORE) {
8656
/* We set possible LOCK_X value in external_lock, not yet
8657
here even if this would be SELECT ... FOR UPDATE */
8659
prebuilt->select_lock_type = LOCK_NONE;
8660
prebuilt->stored_select_lock_type = LOCK_NONE;
8663
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
8665
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
8666
TABLESPACE or TRUNCATE TABLE then allow multiple
8667
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
8668
< TL_WRITE_CONCURRENT_INSERT.
8671
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
8672
&& lock_type <= TL_WRITE)
8673
&& ! session->doing_tablespace_operation()
8674
&& sql_command != SQLCOM_TRUNCATE
8675
&& sql_command != SQLCOM_CREATE_TABLE) {
8677
lock_type = TL_WRITE_ALLOW_WRITE;
8680
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
8681
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
8682
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
8683
to t2. Convert the lock to a normal read lock to allow
8684
concurrent inserts to t2.
8687
if (lock_type == TL_READ_NO_INSERT) {
8689
lock_type = TL_READ;
8692
lock.type = lock_type;
8700
/*********************************************************************//**
8701
Read the next autoinc value. Acquire the relevant locks before reading
8702
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
8703
on return and all relevant locks acquired.
8704
@return DB_SUCCESS or error code */
8707
ha_innobase::innobase_get_autoinc(
8708
/*==============================*/
8709
uint64_t* value) /*!< out: autoinc value */
8713
dict_table_autoinc_lock(prebuilt->table);
8714
prebuilt->autoinc_error= DB_SUCCESS;
8715
/* Determine the first value of the interval */
8716
*value = dict_table_autoinc_read(prebuilt->table);
8718
/* It should have been initialized during open. */
8720
prebuilt->autoinc_error = DB_UNSUPPORTED;
8721
dict_table_autoinc_unlock(prebuilt->table);
8727
/*******************************************************************//**
8728
This function reads the global auto-inc counter. It doesn't use the
8729
AUTOINC lock even if the lock mode is set to TRADITIONAL.
8730
@return the autoinc value */
8733
ha_innobase::innobase_peek_autoinc(void)
8734
/*====================================*/
8737
dict_table_t* innodb_table;
8739
ut_a(prebuilt != NULL);
8740
ut_a(prebuilt->table != NULL);
8742
innodb_table = prebuilt->table;
8744
dict_table_autoinc_lock(innodb_table);
8746
auto_inc = dict_table_autoinc_read(innodb_table);
8748
if (auto_inc == 0) {
8749
ut_print_timestamp(stderr);
8750
errmsg_printf(error::ERROR, " InnoDB: AUTOINC next value generation is disabled for '%s'\n", innodb_table->name);
8753
dict_table_autoinc_unlock(innodb_table);
8758
/*********************************************************************//**
8759
This function initializes the auto-inc counter if it has not been
8760
initialized yet. This function does not change the value of the auto-inc
8761
counter if it already has been initialized. Returns the value of the
8762
auto-inc counter in *first_value, and UINT64_T_MAX in *nb_reserved_values (as
8763
we have a table-level lock). offset, increment, nb_desired_values are ignored.
8764
*first_value is set to -1 if error (deadlock or lock wait timeout) */
8767
ha_innobase::get_auto_increment(
8768
/*============================*/
8769
uint64_t offset, /*!< in: table autoinc offset */
8770
uint64_t increment, /*!< in: table autoinc increment */
8771
uint64_t nb_desired_values, /*!< in: number of values reqd */
8772
uint64_t *first_value, /*!< out: the autoinc value */
8773
uint64_t *nb_reserved_values) /*!< out: count of reserved values */
8777
uint64_t autoinc = 0;
8779
/* Prepare prebuilt->trx in the table handle */
8780
update_session(getTable()->in_use);
8782
error = innobase_get_autoinc(&autoinc);
8784
if (error != DB_SUCCESS) {
8785
*first_value = (~(uint64_t) 0);
8789
/* This is a hack, since nb_desired_values seems to be accurate only
8790
for the first call to get_auto_increment() for multi-row INSERT and
8791
meaningless for other statements e.g, LOAD etc. Subsequent calls to
8792
this method for the same statement results in different values which
8793
don't make sense. Therefore we store the value the first time we are
8794
called and count down from that as rows are written (see doInsertRecord()).
8797
trx = prebuilt->trx;
8799
/* Note: We can't rely on *first_value since some MySQL engines,
8800
in particular the partition engine, don't initialize it to 0 when
8801
invoking this method. So we are not sure if it's guaranteed to
8804
/* We need the upper limit of the col type to check for
8805
whether we update the table autoinc counter or not. */
8806
uint64_t col_max_value = innobase_get_int_col_max_value(getTable()->next_number_field);
8808
/* Called for the first time ? */
8809
if (trx->n_autoinc_rows == 0) {
8811
trx->n_autoinc_rows = (ulint) nb_desired_values;
8813
/* It's possible for nb_desired_values to be 0:
8814
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
8815
if (nb_desired_values == 0) {
8817
trx->n_autoinc_rows = 1;
8820
set_if_bigger(*first_value, autoinc);
8821
/* Not in the middle of a mult-row INSERT. */
8822
} else if (prebuilt->autoinc_last_value == 0) {
8823
set_if_bigger(*first_value, autoinc);
8824
/* Check for -ve values. */
8825
} else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
8826
/* Set to next logical value. */
8827
ut_a(autoinc > trx->n_autoinc_rows);
8828
*first_value = (autoinc - trx->n_autoinc_rows) - 1;
8831
*nb_reserved_values = trx->n_autoinc_rows;
8833
/* This all current style autoinc. */
8837
uint64_t next_value;
8839
current = *first_value > col_max_value ? autoinc : *first_value;
8840
need = *nb_reserved_values * increment;
8842
/* Compute the last value in the interval */
8843
next_value = innobase_next_autoinc(current, need, offset, col_max_value);
8845
prebuilt->autoinc_last_value = next_value;
8847
if (prebuilt->autoinc_last_value < *first_value) {
8848
*first_value = (~(unsigned long long) 0);
8850
/* Update the table autoinc variable */
8851
dict_table_autoinc_update_if_greater(
8852
prebuilt->table, prebuilt->autoinc_last_value);
8856
/* The increment to be used to increase the AUTOINC value, we use
8857
this in doInsertRecord() and doUpdateRecord() to increase the autoinc counter
8858
for columns that are filled by the user. We need the offset and
8860
prebuilt->autoinc_offset = offset;
8861
prebuilt->autoinc_increment = increment;
8863
dict_table_autoinc_unlock(prebuilt->table);
8866
/*******************************************************************//**
8867
Reset the auto-increment counter to the given value, i.e. the next row
8868
inserted will get the given value. This is called e.g. after TRUNCATE
8869
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
8870
returned by storage engines that don't support this operation.
8871
@return 0 or error code */
8874
ha_innobase::reset_auto_increment(
8875
/*==============================*/
8876
uint64_t value) /*!< in: new value for table autoinc */
8880
update_session(getTable()->in_use);
8882
error = row_lock_table_autoinc_for_mysql(prebuilt);
8884
if (error != DB_SUCCESS) {
8885
error = convert_error_code_to_mysql(error,
8886
prebuilt->table->flags,
8892
/* The next value can never be 0. */
8897
innobase_reset_autoinc(value);
8902
/* See comment in Cursor.cc */
8905
InnobaseEngine::get_error_message(int, String *buf) const
8907
trx_t* trx = check_trx_exists(current_session);
8909
buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
8910
system_charset_info);
8915
/*******************************************************************//**
8916
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
8917
If there is no explicitly declared non-null unique key or a primary key, then
8918
InnoDB internally uses the row id as the primary key.
8919
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
8922
ha_innobase::cmp_ref(
8923
/*=================*/
8924
const unsigned char* ref1, /*!< in: an (internal) primary key value in the
8925
MySQL key value format */
8926
const unsigned char* ref2) /*!< in: an (internal) primary key value in the
8927
MySQL key value format */
8929
enum_field_types mysql_type;
8931
KeyPartInfo* key_part;
8932
KeyPartInfo* key_part_end;
8937
if (prebuilt->clust_index_was_generated) {
8938
/* The 'ref' is an InnoDB row id */
8940
return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
8943
/* Do a type-aware comparison of primary key fields. PK fields
8944
are always NOT NULL, so no checks for NULL are performed. */
8946
key_part = getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_part;
8948
key_part_end = key_part
8949
+ getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_parts;
8951
for (; key_part != key_part_end; ++key_part) {
8952
field = key_part->field;
8953
mysql_type = field->type();
8955
if (mysql_type == DRIZZLE_TYPE_BLOB) {
8957
/* In the MySQL key value format, a column prefix of
8958
a BLOB is preceded by a 2-byte length field */
8960
len1 = innobase_read_from_2_little_endian(ref1);
8961
len2 = innobase_read_from_2_little_endian(ref2);
8965
result = ((Field_blob*)field)->cmp( ref1, len1,
8968
result = field->key_cmp(ref1, ref2);
8976
ref1 += key_part->store_length;
8977
ref2 += key_part->store_length;
8983
/**********************************************************************
8984
This function is used to find the storage length in bytes of the first n
8985
characters for prefix indexes using a multibyte character set. The function
8986
finds charset information and returns length of prefix_len characters in the
8987
index field in bytes.
8988
@return number of bytes occupied by the first n characters */
8991
innobase_get_at_most_n_mbchars(
8992
/*===========================*/
8993
ulint charset_id, /*!< in: character set id */
8994
ulint prefix_len, /*!< in: prefix length in bytes of the index
8995
(this has to be divided by mbmaxlen to get the
8996
number of CHARACTERS n in the prefix) */
8997
ulint data_len, /*!< in: length of the string in bytes */
8998
const char* str) /*!< in: character string */
9000
ulint char_length; /*!< character length in bytes */
9001
ulint n_chars; /*!< number of characters in prefix */
9002
const charset_info_st* charset; /*!< charset used in the field */
9004
charset = get_charset((uint) charset_id);
9007
ut_ad(charset->mbmaxlen);
9009
/* Calculate how many characters at most the prefix index contains */
9011
n_chars = prefix_len / charset->mbmaxlen;
9013
/* If the charset is multi-byte, then we must find the length of the
9014
first at most n chars in the string. If the string contains less
9015
characters than n, then we return the length to the end of the last
9018
if (charset->mbmaxlen > 1) {
9019
/* my_charpos() returns the byte length of the first n_chars
9020
characters, or a value bigger than the length of str, if
9021
there were not enough full characters in str.
9023
Why does the code below work:
9024
Suppose that we are looking for n UTF-8 characters.
9026
1) If the string is long enough, then the prefix contains at
9027
least n complete UTF-8 characters + maybe some extra
9028
characters + an incomplete UTF-8 character. No problem in
9029
this case. The function returns the pointer to the
9030
end of the nth character.
9032
2) If the string is not long enough, then the string contains
9033
the complete value of a column, that is, only complete UTF-8
9034
characters, and we can store in the column prefix index the
9037
char_length = my_charpos(charset, str,
9038
str + data_len, (int) n_chars);
9039
if (char_length > data_len) {
9040
char_length = data_len;
9043
if (data_len < prefix_len) {
9044
char_length = data_len;
9046
char_length = prefix_len;
9050
return(char_length);
9053
* We will also use this function to communicate
9054
* to InnoDB that a new SQL statement has started and that we must store a
9055
* savepoint to our transaction handle, so that we are able to roll back
9056
* the SQL statement in case of an error.
9059
InnobaseEngine::doStartStatement(
9060
Session *session) /*!< in: handle to the Drizzle session */
9063
* Create the InnoDB transaction structure
9066
trx_t *trx= check_trx_exists(session);
9068
/* "reset" the error message for the transaction */
9069
trx->detailed_error[0]= '\0';
9071
/* Set the isolation level of the transaction. */
9072
trx->isolation_level= innobase_map_isolation_level(session->getTxIsolation());
9076
InnobaseEngine::doEndStatement(
9079
trx_t *trx= check_trx_exists(session);
9081
/* Release a possible FIFO ticket and search latch. Since we
9082
may reserve the kernel mutex, we have to release the search
9083
system latch first to obey the latching order. */
9085
innobase_release_stat_resources(trx);
9089
/*******************************************************************//**
9090
This function is used to prepare an X/Open XA distributed transaction.
9091
@return 0 or error number */
9093
InnobaseEngine::doXaPrepare(
9094
/*================*/
9095
Session* session,/*!< in: handle to the MySQL thread of
9096
the user whose XA transaction should
9098
bool all) /*!< in: TRUE - commit transaction
9099
FALSE - the current SQL statement
9103
trx_t* trx = check_trx_exists(session);
9105
assert(this == innodb_engine_ptr);
9107
/* we use support_xa value as it was seen at transaction start
9108
time, not the current session variable value. Any possible changes
9109
to the session variable take effect only in the next transaction */
9110
if (!trx->support_xa) {
9115
session->get_xid(reinterpret_cast<DrizzleXid*>(&trx->xid));
9117
/* Release a possible FIFO ticket and search latch. Since we will
9118
reserve the kernel mutex, we have to release the search system latch
9119
first to obey the latching order. */
9121
innobase_release_stat_resources(trx);
9124
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
9126
/* We were instructed to prepare the whole transaction, or
9127
this is an SQL statement end and autocommit is on */
9129
ut_ad(trx->conc_state != TRX_NOT_STARTED);
9131
error = (int) trx_prepare_for_mysql(trx);
9133
/* We just mark the SQL statement ended and do not do a
9134
transaction prepare */
9136
/* If we had reserved the auto-inc lock for some
9137
table in this SQL statement we release it now */
9139
row_unlock_table_autoinc_for_mysql(trx);
9141
/* Store the current undo_no of the transaction so that we
9142
know where to roll back if we have to roll back the next
9145
trx_mark_sql_stat_end(trx);
9148
/* Tell the InnoDB server that there might be work for utility
9151
srv_active_wake_master_thread();
9156
uint64_t InnobaseEngine::doGetCurrentTransactionId(Session *session)
9158
trx_t *trx= session_to_trx(session);
9162
uint64_t InnobaseEngine::doGetNewTransactionId(Session *session)
9164
trx_t*& trx = session_to_trx(session);
9168
trx = innobase_trx_allocate(session);
9170
innobase_trx_init(session, trx);
9173
mutex_enter(&kernel_mutex);
9174
trx->id= trx_sys_get_new_trx_id();
9175
mutex_exit(&kernel_mutex);
9177
uint64_t transaction_id= trx->id;
9179
return transaction_id;
9182
/*******************************************************************//**
9183
This function is used to recover X/Open XA distributed transactions.
9184
@return number of prepared transactions stored in xid_list */
9186
InnobaseEngine::doXaRecover(
9187
/*================*/
9188
::drizzled::XID* xid_list,/*!< in/out: prepared transactions */
9189
size_t len) /*!< in: number of slots in xid_list */
9191
assert(this == innodb_engine_ptr);
9193
if (len == 0 || xid_list == NULL) {
9198
return(trx_recover_for_mysql((::XID *)xid_list, len));
9201
/*******************************************************************//**
9202
This function is used to commit one X/Open XA distributed transaction
9203
which is in the prepared state
9204
@return 0 or error number */
9206
InnobaseEngine::doXaCommitXid(
9207
/*===================*/
9208
::drizzled::XID* xid) /*!< in: X/Open XA transaction identification */
9212
assert(this == innodb_engine_ptr);
9214
trx = trx_get_trx_by_xid((::XID *)xid);
9217
innobase_commit_low(trx);
9225
/*******************************************************************//**
9226
This function is used to rollback one X/Open XA distributed transaction
9227
which is in the prepared state
9228
@return 0 or error number */
9230
InnobaseEngine::doXaRollbackXid(
9231
/*=====================*/
9232
::drizzled::XID* xid) /*!< in: X/Open XA transaction
9237
assert(this == innodb_engine_ptr);
9239
trx = trx_get_trx_by_xid((::XID *)xid);
9242
return(innobase_rollback_trx(trx));
9249
/************************************************************//**
9250
Validate the file format name and return its corresponding id.
9251
@return valid file format id */
9254
innobase_file_format_name_lookup(
9255
/*=============================*/
9256
const char* format_name) /*!< in: pointer to file format name */
9261
ut_a(format_name != NULL);
9263
/* The format name can contain the format id itself instead of
9264
the name and we check for that. */
9265
format_id = (uint) strtoul(format_name, &endp, 10);
9267
/* Check for valid parse. */
9268
if (*endp == '\0' && *format_name != '\0') {
9270
if (format_id <= DICT_TF_FORMAT_MAX) {
9276
for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
9280
name = trx_sys_file_format_id_to_name(format_id);
9282
if (!innobase_strcasecmp(format_name, name)) {
9289
return(DICT_TF_FORMAT_MAX + 1);
9292
/************************************************************//**
9293
Validate the file format check config parameters, as a side effect it
9294
sets the srv_max_file_format_at_startup variable.
9295
@return the format_id if valid config value, otherwise, return -1 */
9298
innobase_file_format_validate_and_set(
9299
/*================================*/
9300
const char* format_max) /*!< in: parameter value */
9304
format_id = innobase_file_format_name_lookup(format_max);
9306
if (format_id < DICT_TF_FORMAT_MAX + 1) {
9307
srv_max_file_format_at_startup = format_id;
9308
return((int) format_id);
9316
static void init_options(drizzled::module::option_context &context)
9318
context("disable-checksums",
9319
"Disable InnoDB checksums validation.");
9320
context("data-home-dir",
9321
po::value<string>(),
9322
"The common part for InnoDB table spaces.");
9323
context("disable-doublewrite",
9324
"Disable InnoDB doublewrite buffer.");
9325
context("io-capacity",
9326
po::value<io_capacity_constraint>(&innodb_io_capacity)->default_value(200),
9327
"Number of IOPs the server can do. Tunes the background IO rate");
9328
context("fast-shutdown",
9329
po::value<trinary_constraint>(&innobase_fast_shutdown)->default_value(1),
9330
"Speeds up the shutdown process of the InnoDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like).");
9331
context("purge-batch-size",
9332
po::value<purge_batch_constraint>(&innodb_purge_batch_size)->default_value(20),
9333
"Number of UNDO logs to purge in one batch from the history list. "
9335
context("purge-threads",
9336
po::value<purge_threads_constraint>(&innodb_n_purge_threads)->default_value(1),
9337
"Purge threads can be either 0 or 1. Default is 1.");
9338
context("file-per-table",
9339
po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
9340
"Stores each InnoDB table to an .ibd file in the database dir.");
9341
context("file-format-max",
9342
po::value<string>(&innobase_file_format_max)->default_value("Antelope"),
9343
"The highest file format in the tablespace.");
9344
context("file-format-check",
9345
po::value<bool>(&innobase_file_format_check)->default_value(true)->zero_tokens(),
9346
"Whether to perform system file format check.");
9347
context("file-format",
9348
po::value<string>(&innobase_file_format_name)->default_value("Antelope"),
9349
"File format to use for new tables in .ibd files.");
9350
context("flush-log-at-trx-commit",
9351
po::value<trinary_constraint>(&innodb_flush_log_at_trx_commit)->default_value(1),
9352
"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).");
9353
context("flush-method",
9354
po::value<string>(),
9355
"With which method to flush data.");
9356
context("log-group-home-dir",
9357
po::value<string>(),
9358
"Path to InnoDB log files.");
9359
context("max-dirty-pages-pct",
9360
po::value<max_dirty_pages_constraint>(&innodb_max_dirty_pages_pct)->default_value(75),
9361
"Percentage of dirty pages allowed in bufferpool.");
9362
context("disable-adaptive-flushing",
9363
"Do not attempt flushing dirty pages to avoid IO bursts at checkpoints.");
9364
context("max-purge-lag",
9365
po::value<uint64_constraint>(&innodb_max_purge_lag)->default_value(0),
9366
"Desired maximum length of the purge queue (0 = no limit)");
9367
context("status-file",
9368
po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
9369
"Enable SHOW INNODB STATUS output in the innodb_status.<pid> file");
9370
context("disable-stats-on-metadata",
9371
"Disable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)");
9372
context("stats-sample-pages",
9373
po::value<uint64_nonzero_constraint>(&innodb_stats_sample_pages)->default_value(8),
9374
"The number of index pages to sample when calculating statistics (default 8)");
9375
context("disable-adaptive-hash-index",
9376
"Enable InnoDB adaptive hash index (enabled by default)");
9377
context("replication-delay",
9378
po::value<uint64_constraint>(&innodb_replication_delay)->default_value(0),
9379
"Replication thread delay (ms) on the slave server if innodb_thread_concurrency is reached (0 by default)");
9380
context("additional-mem-pool-size",
9381
po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
9382
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.");
9383
context("autoextend-increment",
9384
po::value<autoextend_constraint>(&innodb_auto_extend_increment)->default_value(64L),
9385
"Data file autoextend increment in megabytes");
9386
context("buffer-pool-size",
9387
po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
9388
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.");
9389
context("buffer-pool-instances",
9390
po::value<buffer_pool_instances_constraint>(&innobase_buffer_pool_instances)->default_value(1),
9391
"Number of buffer pool instances, set to higher value on high-end machines to increase scalability");
9393
context("commit-concurrency",
9394
po::value<concurrency_constraint>(&innobase_commit_concurrency)->default_value(0),
9395
"Helps in performance tuning in heavily concurrent environments.");
9396
context("concurrency-tickets",
9397
po::value<uint32_nonzero_constraint>(&innodb_concurrency_tickets)->default_value(500L),
9398
"Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket");
9399
context("read-io-threads",
9400
po::value<io_threads_constraint>(&innobase_read_io_threads)->default_value(4),
9401
"Number of background read I/O threads in InnoDB.");
9402
context("write-io-threads",
9403
po::value<io_threads_constraint>(&innobase_write_io_threads)->default_value(4),
9404
"Number of background write I/O threads in InnoDB.");
9405
context("force-recovery",
9406
po::value<force_recovery_constraint>(&innobase_force_recovery)->default_value(0),
9407
"Helps to save your data in case the disk image of the database becomes corrupt.");
9408
context("log-buffer-size",
9409
po::value<log_buffer_constraint>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
9410
"The size of the buffer which InnoDB uses to write log to the log files on disk.");
9411
context("log-file-size",
9412
po::value<log_file_constraint>(&innobase_log_file_size)->default_value(20*1024*1024L),
9413
"The size of the buffer which InnoDB uses to write log to the log files on disk.");
9414
context("page-size",
9415
po::value<page_size_constraint>(&innobase_page_size)->default_value(1 << 14),
9416
"###EXPERIMENTAL###: The universal page size of the database. Changing for created database is not supported. Use on your own risk!");
9417
context("log-block-size",
9418
po::value<log_block_size_constraint>(&innobase_log_block_size)->default_value(1 << 9),
9419
"###EXPERIMENTAL###: The log block size of the transaction log file. Changing for created log file is not supported. Use on your own risk!");
9420
context("log-files-in-group",
9421
po::value<log_files_in_group_constraint>(&innobase_log_files_in_group)->default_value(2),
9422
"Number of log files in the log group. InnoDB writes to the files in a circular fashion.");
9423
context("mirrored-log-groups",
9424
po::value<mirrored_log_groups_constraint>(&innobase_mirrored_log_groups)->default_value(1),
9425
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.");
9426
context("open-files",
9427
po::value<open_files_constraint>(&innobase_open_files)->default_value(300L),
9428
"How many files at the maximum InnoDB keeps open at the same time.");
9429
context("sync-spin-loops",
9430
po::value<uint32_constraint>(&innodb_sync_spin_loops)->default_value(30L),
9431
"Count of spin-loop rounds in InnoDB mutexes (30 by default)");
9432
context("spin-wait-delay",
9433
po::value<uint32_constraint>(&innodb_spin_wait_delay)->default_value(6L),
9434
"Maximum delay between polling for a spin lock (6 by default)");
9435
context("thread-concurrency",
9436
po::value<concurrency_constraint>(&innobase_thread_concurrency)->default_value(0),
9437
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.");
9438
context("thread-sleep-delay",
9439
po::value<uint32_constraint>(&innodb_thread_sleep_delay)->default_value(10000L),
9440
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep");
9441
context("data-file-path",
9442
po::value<string>(),
9443
"Path to individual files and their sizes.");
9445
po::value<string>()->default_value(INNODB_VERSION_STR),
9447
context("use-internal-malloc",
9448
"Use InnoDB's internal memory allocator instal of the OS memory allocator.");
9449
context("disable-native-aio",
9450
_("Do not use Native AIO library for IO, even if available"));
9451
context("change-buffering",
9452
po::value<string>(&innobase_change_buffering),
9453
"Buffer changes to reduce random access: OFF, ON, inserting, deleting, changing, or purging.");
9454
context("read-ahead-threshold",
9455
po::value<read_ahead_threshold_constraint>(&innodb_read_ahead_threshold)->default_value(56),
9456
"Number of pages that must be accessed sequentially for InnoDB to trigger a readahead.");
9457
context("auto-lru-dump",
9458
po::value<uint32_constraint>(&buffer_pool_restore_at_startup)->default_value(0),
9459
"Time in seconds between automatic buffer pool dumps. "
9460
"0 (the default) disables automatic dumps.");
9461
context("ibuf-max-size",
9462
po::value<uint64_constraint>(&ibuf_max_size)->default_value(UINT64_MAX),
9463
"The maximum size of the insert buffer (in bytes).");
9464
context("ibuf-active-contract",
9465
po::value<binary_constraint>(&ibuf_active_contract)->default_value(1),
9466
"Enable/Disable active_contract of insert buffer. 0:disable 1:enable");
9467
context("ibuf-accel-rate",
9468
po::value<ibuf_accel_rate_constraint>(&ibuf_accel_rate)->default_value(100),
9469
"Tunes amount of insert buffer processing of background, in addition to innodb_io_capacity. (in percentage)");
9470
context("checkpoint-age-target",
9471
po::value<uint32_constraint>(&checkpoint_age_target)->default_value(0),
9472
"Control soft limit of checkpoint age. (0 : not control)");
9473
context("flush-neighbor-pages",
9474
po::value<binary_constraint>(&flush_neighbor_pages)->default_value(1),
9475
"Enable/Disable flushing also neighbor pages. 0:disable 1:enable");
9476
context("read-ahead",
9477
po::value<string>(&read_ahead)->default_value("linear"),
9478
"Control read ahead activity (none, random, [linear], both). [from 1.0.5: random read ahead is ignored]");
9479
context("adaptive-flushing-method",
9480
po::value<string>(&adaptive_flushing_method)->default_value("estimate"),
9481
"Choose method of innodb_adaptive_flushing. (native, [estimate], keep_average)");
9482
context("disable-xa",
9483
"Disable InnoDB support for the XA two-phase commit");
9484
context("disable-table-locks",
9485
"Disable InnoDB locking in LOCK TABLES");
9486
context("strict-mode",
9487
po::value<bool>(&strict_mode)->default_value(false)->zero_tokens(),
9488
"Use strict mode when evaluating create options.");
9489
context("replication-log",
9490
po::value<bool>(&innobase_use_replication_log)->default_value(false)->zero_tokens(),
9491
_("Enable internal replication log."));
9492
context("lock-wait-timeout",
9493
po::value<lock_wait_constraint>(&lock_wait_timeout)->default_value(50),
9494
_("Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
9495
context("old-blocks-pct",
9496
po::value<old_blocks_constraint>(&innobase_old_blocks_pct)->default_value(100 * 3 / 8),
9497
_("Percentage of the buffer pool to reserve for 'old' blocks."));
9498
context("old-blocks-time",
9499
po::value<uint32_t>(&buf_LRU_old_threshold_ms)->default_value(0),
9500
_("ove blocks to the 'new' end of the buffer pool if the first access"
9501
" was at least this many milliseconds ago."
9502
" The timeout is disabled if 0 (the default)."));
9507
DRIZZLE_DECLARE_PLUGIN
9510
innobase_engine_name,
9513
"Supports transactions, row-level locking, and foreign keys",
9515
innobase_init, /* Plugin Init */
9517
init_options /* reserved */
9519
DRIZZLE_DECLARE_PLUGIN_END;
9521
int ha_innobase::read_range_first(const key_range *start_key,
9522
const key_range *end_key,
9527
//if (!eq_range_arg)
9528
//in_range_read= TRUE;
9529
res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
9531
// in_range_read= FALSE;
9536
int ha_innobase::read_range_next()
9538
int res= Cursor::read_range_next();
9540
// in_range_read= FALSE;
9544
/***********************************************************************
9545
This function checks each index name for a table against reserved
9546
system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
9547
this function pushes an warning message to the client, and returns true. */
9550
innobase_index_name_is_reserved(
9551
/*============================*/
9552
/* out: true if an index name
9553
matches the reserved name */
9554
const trx_t* trx, /* in: InnoDB transaction handle */
9555
const KeyInfo* key_info, /* in: Indexes to be created */
9556
ulint num_of_keys) /* in: Number of indexes to
9560
uint key_num; /* index number */
9562
for (key_num = 0; key_num < num_of_keys; key_num++) {
9563
key = &key_info[key_num];
9565
if (innobase_strcasecmp(key->name,
9566
innobase_index_reserve_name) == 0) {
9567
/* Push warning to drizzle */
9568
push_warning_printf(trx->mysql_thd,
9569
DRIZZLE_ERROR::WARN_LEVEL_WARN,
9570
ER_WRONG_NAME_FOR_INDEX,
9571
"Cannot Create Index with name "
9572
"'%s'. The name is reserved "
9573
"for the system default primary "
9575
innobase_index_reserve_name);
9577
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
9578
innobase_index_reserve_name);
9587
#ifdef UNIV_COMPILE_TEST_FUNCS
9589
typedef struct innobase_convert_name_test_struct {
9594
drizzled::Session *session;
9597
const char* expected;
9598
} innobase_convert_name_test_t;
9601
test_innobase_convert_name()
9606
innobase_convert_name_test_t test_input[] = {
9607
{buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
9608
{buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
9609
{buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
9610
{buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
9611
{buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
9613
{buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9614
{buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9615
{buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9616
{buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9617
{buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
9618
{buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
9619
{buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
9621
{buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
9622
"\"#mysql50#ab\"\"cd\""},
9623
{buf, 17, "ab\"cd", 5, NULL, TRUE,
9624
"\"#mysql50#ab\"\"cd\""},
9625
{buf, 16, "ab\"cd", 5, NULL, TRUE,
9626
"\"#mysql50#ab\"\"c\""},
9627
{buf, 15, "ab\"cd", 5, NULL, TRUE,
9628
"\"#mysql50#ab\"\"\""},
9629
{buf, 14, "ab\"cd", 5, NULL, TRUE,
9631
{buf, 13, "ab\"cd", 5, NULL, TRUE,
9633
{buf, 12, "ab\"cd", 5, NULL, TRUE,
9635
{buf, 11, "ab\"cd", 5, NULL, TRUE,
9637
{buf, 10, "ab\"cd", 5, NULL, TRUE,
9640
{buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9641
{buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9642
{buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
9643
{buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
9644
{buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9645
{buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9646
{buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
9647
{buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
9648
{buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
9649
/* XXX probably "" is a better result in this case
9650
{buf, 1, "ab/cd", 5, NULL, TRUE, "."},
9652
{buf, 0, "ab/cd", 5, NULL, TRUE, ""},
9655
for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
9661
fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
9662
test_input[i].buflen,
9664
test_input[i].idlen,
9665
test_input[i].expected);
9667
end = innobase_convert_name(
9669
test_input[i].buflen,
9671
test_input[i].idlen,
9672
test_input[i].session,
9673
test_input[i].file_id);
9675
res_len = (size_t) (end - test_input[i].buf);
9677
if (res_len != strlen(test_input[i].expected)) {
9679
fprintf(stderr, "unexpected len of the result: %u, "
9680
"expected: %u\n", (unsigned) res_len,
9681
(unsigned) strlen(test_input[i].expected));
9685
if (memcmp(test_input[i].buf,
9686
test_input[i].expected,
9687
strlen(test_input[i].expected)) != 0
9690
fprintf(stderr, "unexpected result: %.*s, "
9691
"expected: %s\n", (int) res_len,
9693
test_input[i].expected);
9698
fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9701
fprintf(stderr, "FAILED\n\n");
9707
#endif /* UNIV_COMPILE_TEST_FUNCS */