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/charset_info.h"
49
#include "drizzled/internal/m_string.h"
50
#include "drizzled/internal/my_sys.h"
51
#include "drizzled/my_hash.h"
52
#include "drizzled/plugin.h"
53
#include "drizzled/show.h"
54
#include "drizzled/data_home.h"
55
#include "drizzled/error.h"
56
#include "drizzled/field.h"
57
#include "drizzled/charset.h"
58
#include "drizzled/session.h"
59
#include "drizzled/current_session.h"
60
#include "drizzled/table.h"
61
#include "drizzled/field/blob.h"
62
#include "drizzled/field/varstring.h"
63
#include "drizzled/field/timestamp.h"
64
#include "drizzled/plugin/xa_storage_engine.h"
65
#include "drizzled/plugin/daemon.h"
66
#include "drizzled/memory/multi_malloc.h"
67
#include "drizzled/pthread_globals.h"
68
#include "drizzled/named_savepoint.h"
70
#include <drizzled/transaction_services.h>
71
#include "drizzled/message/statement_transform.h"
73
#include <boost/algorithm/string.hpp>
74
#include <boost/program_options.hpp>
75
#include <boost/filesystem.hpp>
76
#include <drizzled/module/option_map.h>
79
namespace po= boost::program_options;
80
namespace fs=boost::filesystem;
83
/** @file ha_innodb.cc */
85
/* Include necessary InnoDB headers */
91
#include "os0thread.h"
92
#include "srv0start.h"
99
#include "row0mysql.h"
103
#include "lock0lock.h"
104
#include "dict0crea.h"
105
#include "create_replication.h"
109
#include "sync0sync.h"
112
#include "row0merge.h"
114
#include "dict0boot.h"
115
#include "ha_prototypes.h"
117
#include "ibuf0ibuf.h"
118
#include "mysql_addons.h"
121
#include "ha_innodb.h"
122
#include "data_dictionary.h"
123
#include "replication_dictionary.h"
124
#include "internal_dictionary.h"
125
#include "handler0vars.h"
131
#include "plugin/innobase/handler/status_function.h"
132
#include "plugin/innobase/handler/replication_log.h"
134
#include <google/protobuf/io/zero_copy_stream.h>
135
#include <google/protobuf/io/zero_copy_stream_impl.h>
136
#include <google/protobuf/io/coded_stream.h>
137
#include <google/protobuf/text_format.h>
140
using namespace drizzled;
142
/** to protect innobase_open_files */
143
static pthread_mutex_t innobase_share_mutex;
144
/** to force correct commit order in binlog */
145
static pthread_mutex_t prepare_commit_mutex;
146
static ulong commit_threads = 0;
147
static pthread_mutex_t commit_threads_m;
148
static pthread_cond_t commit_cond;
149
static pthread_mutex_t commit_cond_m;
150
static bool innodb_inited = 0;
152
#define INSIDE_HA_INNOBASE_CC
154
/* In the Windows plugin, the return value of current_session is
155
undefined. Map it to NULL. */
156
#if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
157
# undef current_session
158
# define current_session NULL
159
# define EQ_CURRENT_SESSION(session) TRUE
160
#else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
161
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
162
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
164
static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
165
static plugin::TableFunction* status_table_function_ptr= NULL;
166
static plugin::TableFunction* cmp_tool= NULL;
167
static plugin::TableFunction* cmp_reset_tool= NULL;
168
static plugin::TableFunction* cmp_mem_tool= NULL;
169
static plugin::TableFunction* cmp_mem_reset_tool= NULL;
170
static plugin::TableFunction* innodb_trx_tool= NULL;
171
static plugin::TableFunction* innodb_locks_tool= NULL;
172
static plugin::TableFunction* innodb_lock_waits_tool= NULL;
173
static plugin::TableFunction* innodb_sys_tables_tool= NULL;
174
static plugin::TableFunction* innodb_sys_tablestats_tool= NULL;
176
static plugin::TableFunction* innodb_sys_indexes_tool= NULL;
177
static plugin::TableFunction* innodb_sys_columns_tool= NULL;
178
static plugin::TableFunction* innodb_sys_fields_tool= NULL;
179
static plugin::TableFunction* innodb_sys_foreign_tool= NULL;
180
static plugin::TableFunction* innodb_sys_foreign_cols_tool= NULL;
182
static ReplicationLog *replication_logger= NULL;
183
typedef constrained_check<uint32_t, UINT32_MAX, 10> open_files_constraint;
184
static open_files_constraint innobase_open_files;
185
typedef constrained_check<uint32_t, 10, 1> mirrored_log_groups_constraint;
186
static mirrored_log_groups_constraint innobase_mirrored_log_groups;
187
typedef constrained_check<uint32_t, 100, 2> log_files_in_group_constraint;
188
static log_files_in_group_constraint innobase_log_files_in_group;
189
typedef constrained_check<uint32_t, 6, 0> force_recovery_constraint;
190
force_recovery_constraint innobase_force_recovery;
191
typedef constrained_check<size_t, SIZE_MAX, 256*1024, 1024> log_buffer_constraint;
192
static log_buffer_constraint innobase_log_buffer_size;
193
typedef constrained_check<size_t, SIZE_MAX, 512*1024, 1024> additional_mem_pool_constraint;
194
static additional_mem_pool_constraint innobase_additional_mem_pool_size;
195
typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
196
static autoextend_constraint innodb_auto_extend_increment;
197
typedef constrained_check<size_t, SIZE_MAX, 5242880, 1048576> buffer_pool_constraint;
198
static buffer_pool_constraint innobase_buffer_pool_size;
199
typedef constrained_check<uint32_t, MAX_BUFFER_POOLS, 1> buffer_pool_instances_constraint;
200
static buffer_pool_instances_constraint innobase_buffer_pool_instances;
201
typedef constrained_check<uint32_t, UINT32_MAX, 100> io_capacity_constraint;
202
static io_capacity_constraint innodb_io_capacity;
203
typedef constrained_check<uint32_t, 5000, 1> purge_batch_constraint;
204
static purge_batch_constraint innodb_purge_batch_size;
205
typedef constrained_check<uint32_t, 1, 0> purge_threads_constraint;
206
static purge_threads_constraint innodb_n_purge_threads;
207
typedef constrained_check<uint16_t, 2, 0> trinary_constraint;
208
static trinary_constraint innodb_flush_log_at_trx_commit;
209
typedef constrained_check<unsigned int, 99, 0> max_dirty_pages_constraint;
210
static max_dirty_pages_constraint innodb_max_dirty_pages_pct;
211
static uint64_constraint innodb_max_purge_lag;
212
static uint64_nonzero_constraint innodb_stats_sample_pages;
213
typedef constrained_check<uint32_t, 64, 1> io_threads_constraint;
214
static io_threads_constraint innobase_read_io_threads;
215
static io_threads_constraint innobase_write_io_threads;
217
typedef constrained_check<uint32_t, 1000, 0> concurrency_constraint;
218
static concurrency_constraint innobase_commit_concurrency;
219
static concurrency_constraint innobase_thread_concurrency;
220
static uint32_nonzero_constraint innodb_concurrency_tickets;
222
typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
223
static log_file_constraint innobase_log_file_size;
225
static uint64_constraint innodb_replication_delay;
227
/** Percentage of the buffer pool to reserve for 'old' blocks.
228
Connected to buf_LRU_old_ratio. */
229
typedef constrained_check<uint32_t, 95, 5> old_blocks_constraint;
230
static old_blocks_constraint innobase_old_blocks_pct;
232
static uint32_constraint innodb_sync_spin_loops;
233
static uint32_constraint innodb_spin_wait_delay;
234
static uint32_constraint innodb_thread_sleep_delay;
236
typedef constrained_check<uint32_t, 64, 0> read_ahead_threshold_constraint;
237
static read_ahead_threshold_constraint innodb_read_ahead_threshold;
239
/* The default values for the following char* start-up parameters
240
are determined in innobase_init below: */
242
std::string innobase_data_home_dir;
243
std::string innobase_data_file_path;
244
std::string innobase_log_group_home_dir;
245
static string innobase_file_format_name;
246
static string innobase_change_buffering;
248
/* The highest file format being used in the database. The value can be
249
set by user, however, it will be adjusted to the newer file format if
250
a table of such format is created/opened. */
251
static string innobase_file_format_max;
253
/* Below we have boolean-valued start-up parameters, and their default
256
typedef constrained_check<uint16_t, 2, 0> trinary_constraint;
257
static trinary_constraint innobase_fast_shutdown;
259
/* "innobase_file_format_check" decides whether we would continue
260
booting the server if the file format stamped on the system
261
table space exceeds the maximum file format supported
262
by the server. Can be set during server startup at command
263
line or configure file, and a read only variable after
266
/* If a new file format is introduced, the file format
267
name needs to be updated accordingly. Please refer to
268
file_format_name_map[] defined in trx0sys.c for the next
271
static my_bool innobase_file_format_check = TRUE;
272
static my_bool innobase_use_doublewrite = TRUE;
273
static my_bool innobase_use_checksums = TRUE;
274
static my_bool innobase_rollback_on_timeout = FALSE;
275
static my_bool innobase_create_status_file = FALSE;
276
static bool innobase_use_replication_log;
277
static bool support_xa;
278
static bool strict_mode;
279
typedef constrained_check<uint32_t, 1024*1024*1024, 1> lock_wait_constraint;
280
static lock_wait_constraint lock_wait_timeout;
282
static char* internal_innobase_data_file_path = NULL;
284
/* The following counter is used to convey information to InnoDB
285
about server activity: in selects it is not sensible to call
286
srv_active_wake_master_thread after each fetch or search, we only do
287
it every INNOBASE_WAKE_INTERVAL'th step. */
289
#define INNOBASE_WAKE_INTERVAL 32
290
static ulong innobase_active_counter = 0;
292
static hash_table_t* innobase_open_tables;
294
#ifdef __NETWARE__ /* some special cleanup for NetWare */
295
bool nw_panic = FALSE;
298
/** Allowed values of innodb_change_buffering */
299
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
300
"none", /* IBUF_USE_NONE */
301
"inserts", /* IBUF_USE_INSERT */
302
"deletes", /* IBUF_USE_DELETE_MARK */
303
"changes", /* IBUF_USE_INSERT_DELETE_MARK */
304
"purges", /* IBUF_USE_DELETE */
305
"all" /* IBUF_USE_ALL */
308
/* "GEN_CLUST_INDEX" is the name reserved for Innodb default
309
system primary index. */
310
static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX";
312
/********************************************************************
313
Gives the file extension of an InnoDB single-table tablespace. */
314
static const char* ha_innobase_exts[] = {
319
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
321
static INNOBASE_SHARE *get_share(const char *table_name);
322
static void free_share(INNOBASE_SHARE *share);
324
class InnobaseEngine : public plugin::XaStorageEngine
327
explicit InnobaseEngine(string name_arg) :
328
plugin::XaStorageEngine(name_arg,
330
HTON_CAN_INDEX_BLOBS |
331
HTON_PRIMARY_KEY_IN_READ_INDEX |
332
HTON_PARTIAL_COLUMN_READ |
333
HTON_TABLE_SCAN_ON_INDEX |
334
HTON_HAS_FOREIGN_KEYS |
335
HTON_HAS_DOES_TRANSACTIONS)
337
table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
338
addAlias("INNOBASE");
341
virtual ~InnobaseEngine()
345
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
347
hash_table_free(innobase_open_tables);
348
innobase_open_tables = NULL;
349
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
352
srv_free_paths_and_sizes();
353
if (internal_innobase_data_file_path)
354
free(internal_innobase_data_file_path);
355
pthread_mutex_destroy(&innobase_share_mutex);
356
pthread_mutex_destroy(&prepare_commit_mutex);
357
pthread_mutex_destroy(&commit_threads_m);
358
pthread_mutex_destroy(&commit_cond_m);
359
pthread_cond_destroy(&commit_cond);
362
/* These get strdup'd from vm variables */
367
virtual int doStartTransaction(Session *session, start_transaction_option_t options);
368
virtual void doStartStatement(Session *session);
369
virtual void doEndStatement(Session *session);
374
/*======================*/
375
/* out: 0 or error number */
376
Session* session); /* in: handle to the MySQL thread of the user
377
whose resources should be free'd */
379
virtual int doSetSavepoint(Session* session,
380
drizzled::NamedSavepoint &savepoint);
381
virtual int doRollbackToSavepoint(Session* session,
382
drizzled::NamedSavepoint &savepoint);
383
virtual int doReleaseSavepoint(Session* session,
384
drizzled::NamedSavepoint &savepoint);
385
virtual int doXaCommit(Session* session, bool all)
387
return doCommit(session, all); /* XA commit just does a SQL COMMIT */
389
virtual int doXaRollback(Session *session, bool all)
391
return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
393
virtual uint64_t doGetCurrentTransactionId(Session *session);
394
virtual uint64_t doGetNewTransactionId(Session *session);
395
virtual int doCommit(Session* session, bool all);
396
virtual int doRollback(Session* session, bool all);
398
/***********************************************************************
399
This function is used to prepare X/Open XA distributed transaction */
404
/* out: 0 or error number */
405
Session* session, /* in: handle to the MySQL thread of the user
406
whose XA transaction should be prepared */
407
bool all); /* in: TRUE - commit transaction
408
FALSE - the current SQL statement ended */
409
/***********************************************************************
410
This function is used to recover X/Open XA distributed transactions */
415
/* out: number of prepared transactions
416
stored in xid_list */
417
::drizzled::XID* xid_list, /* in/out: prepared transactions */
418
size_t len); /* in: number of slots in xid_list */
419
/***********************************************************************
420
This function is used to commit one X/Open XA distributed transaction
421
which is in the prepared state */
425
/*===================*/
426
/* out: 0 or error number */
427
::drizzled::XID* xid); /* in: X/Open XA transaction identification */
428
/***********************************************************************
429
This function is used to rollback one X/Open XA distributed transaction
430
which is in the prepared state */
434
/*=====================*/
435
/* out: 0 or error number */
436
::drizzled::XID *xid); /* in: X/Open XA transaction identification */
438
virtual Cursor *create(Table &table)
440
return new ha_innobase(*this, table);
443
/*********************************************************************
444
Removes all tables in the named database inside InnoDB. */
447
/*===================*/
448
/* out: error number */
449
const SchemaIdentifier &identifier); /* in: database path; inside InnoDB the name
450
of the last directory in the path is used as
451
the database name: for example, in 'mysql/data/test'
452
the database name is 'test' */
454
/********************************************************************
455
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
456
the logs, and the name of this function should be innobase_checkpoint. */
461
/* out: TRUE if error */
463
/****************************************************************************
464
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
465
Monitor to the client. */
470
Session* session, /* in: the MySQL query thread of the caller */
471
stat_print_fn *stat_print,
472
enum ha_stat_type stat_type);
476
doReleaseTemporaryLatches(
477
/*===============================*/
479
Session* session); /* in: MySQL thread */
482
const char** bas_ext() const {
483
return(ha_innobase_exts);
486
UNIV_INTERN int doCreateTable(Session &session,
488
const TableIdentifier &identifier,
490
UNIV_INTERN int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
491
UNIV_INTERN int doDropTable(Session &session, const TableIdentifier &identifier);
493
UNIV_INTERN virtual bool get_error_message(int error, String *buf);
495
UNIV_INTERN uint32_t max_supported_keys() const;
496
UNIV_INTERN uint32_t max_supported_key_length() const;
497
UNIV_INTERN uint32_t max_supported_key_part_length() const;
500
UNIV_INTERN uint32_t index_flags(enum ha_key_alg) const
502
return (HA_READ_NEXT |
509
int doGetTableDefinition(drizzled::Session& session,
510
const TableIdentifier &identifier,
511
drizzled::message::Table &table_proto);
513
bool doDoesTableExist(drizzled::Session& session, const TableIdentifier &identifier);
515
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
516
const drizzled::SchemaIdentifier &schema_identifier,
517
drizzled::TableIdentifier::vector &set_of_identifiers);
518
bool validateCreateTableOption(const std::string &key, const std::string &state);
519
void dropTemporarySchema();
524
bool InnobaseEngine::validateCreateTableOption(const std::string &key, const std::string &state)
526
if (boost::iequals(key, "ROW_FORMAT"))
528
if (boost::iequals(state, "COMPRESSED"))
531
if (boost::iequals(state, "COMPACT"))
534
if (boost::iequals(state, "DYNAMIC"))
537
if (boost::iequals(state, "REDUNDANT"))
544
void InnobaseEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
545
const drizzled::SchemaIdentifier &schema_identifier,
546
drizzled::TableIdentifier::vector &set_of_identifiers)
548
CachedDirectory::Entries entries= directory.getEntries();
550
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
551
entry_iter != entries.end(); ++entry_iter)
553
CachedDirectory::Entry *entry= *entry_iter;
554
const string *filename= &entry->filename;
556
assert(filename->size());
558
const char *ext= strchr(filename->c_str(), '.');
560
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
561
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
566
path+= directory.getPath();
568
path+= entry->filename;
570
message::Table definition;
571
if (StorageEngine::readTableFile(path, definition))
574
Using schema_identifier here to stop unused warning, could use
575
definition.schema() instead
577
TableIdentifier identifier(schema_identifier.getSchemaName(), definition.name());
578
set_of_identifiers.push_back(identifier);
584
bool InnobaseEngine::doDoesTableExist(Session &session, const TableIdentifier &identifier)
586
string proto_path(identifier.getPath());
587
proto_path.append(DEFAULT_FILE_EXTENSION);
589
if (session.getMessageCache().doesTableMessageExist(identifier))
592
if (access(proto_path.c_str(), F_OK))
600
int InnobaseEngine::doGetTableDefinition(Session &session,
601
const TableIdentifier &identifier,
602
message::Table &table_proto)
604
string proto_path(identifier.getPath());
605
proto_path.append(DEFAULT_FILE_EXTENSION);
607
// First we check the temporary tables.
608
if (session.getMessageCache().getTableMessage(identifier, table_proto))
611
if (access(proto_path.c_str(), F_OK))
616
if (StorageEngine::readTableFile(proto_path, table_proto))
623
/************************************************************//**
624
Validate the file format name and return its corresponding id.
625
@return valid file format id */
628
innobase_file_format_name_lookup(
629
/*=============================*/
630
const char* format_name); /*!< in: pointer to file format
632
/************************************************************//**
633
Validate the file format check config parameters, as a side effect it
634
sets the srv_max_file_format_at_startup variable.
635
@return the format_id if valid config value, otherwise, return -1 */
638
innobase_file_format_validate_and_set(
639
/*================================*/
640
const char* format_max); /*!< in: parameter value */
642
static const char innobase_engine_name[]= "InnoDB";
645
/*****************************************************************//**
646
Commits a transaction in an InnoDB database. */
651
trx_t* trx); /*!< in: transaction handle */
653
static drizzle_show_var innodb_status_variables[]= {
654
{"buffer_pool_pages_data",
655
(char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
656
{"buffer_pool_pages_dirty",
657
(char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
658
{"buffer_pool_pages_flushed",
659
(char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
660
{"buffer_pool_pages_free",
661
(char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
663
{"buffer_pool_pages_latched",
664
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
665
#endif /* UNIV_DEBUG */
666
{"buffer_pool_pages_misc",
667
(char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
668
{"buffer_pool_pages_total",
669
(char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
670
{"buffer_pool_read_ahead",
671
(char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG},
672
{"buffer_pool_read_ahead_evicted",
673
(char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG},
674
{"buffer_pool_read_requests",
675
(char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
676
{"buffer_pool_reads",
677
(char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
678
{"buffer_pool_wait_free",
679
(char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
680
{"buffer_pool_write_requests",
681
(char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
683
(char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
684
{"data_pending_fsyncs",
685
(char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
686
{"data_pending_reads",
687
(char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
688
{"data_pending_writes",
689
(char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
691
(char*) &export_vars.innodb_data_read, SHOW_LONG},
693
(char*) &export_vars.innodb_data_reads, SHOW_LONG},
695
(char*) &export_vars.innodb_data_writes, SHOW_LONG},
697
(char*) &export_vars.innodb_data_written, SHOW_LONG},
698
{"dblwr_pages_written",
699
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
701
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
702
{"have_atomic_builtins",
703
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
705
(char*) &export_vars.innodb_log_waits, SHOW_LONG},
706
{"log_write_requests",
707
(char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
709
(char*) &export_vars.innodb_log_writes, SHOW_LONG},
711
(char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
712
{"os_log_pending_fsyncs",
713
(char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
714
{"os_log_pending_writes",
715
(char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
717
(char*) &export_vars.innodb_os_log_written, SHOW_LONG},
719
(char*) &export_vars.innodb_page_size, SHOW_LONG},
721
(char*) &export_vars.innodb_pages_created, SHOW_LONG},
723
(char*) &export_vars.innodb_pages_read, SHOW_LONG},
725
(char*) &export_vars.innodb_pages_written, SHOW_LONG},
726
{"row_lock_current_waits",
727
(char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
729
(char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
730
{"row_lock_time_avg",
731
(char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
732
{"row_lock_time_max",
733
(char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
735
(char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
737
(char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
739
(char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
741
(char*) &export_vars.innodb_rows_read, SHOW_LONG},
743
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
744
{NULL, NULL, SHOW_LONG}
747
InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
748
plugin::TableFunction::Generator(fields)
750
srv_export_innodb_status();
751
status_var_ptr= innodb_status_variables;
754
bool InnodbStatusTool::Generator::populate()
756
if (status_var_ptr->name)
758
std::ostringstream oss;
760
const char *value= status_var_ptr->value;
763
push(status_var_ptr->name);
765
switch (status_var_ptr->type)
768
oss << *(int64_t*) value;
769
return_value= oss.str();
772
oss << *(int64_t*) value;
773
return_value= oss.str();
776
return_value= *(bool*) value ? "ON" : "OFF";
783
if (return_value.length())
795
/* General functions */
797
/******************************************************************//**
798
Returns true if the thread is the replication thread on the slave
799
server. Used in srv_conc_enter_innodb() to determine if the thread
800
should be allowed to enter InnoDB - the replication thread is treated
801
differently than other threads. Also used in
802
srv_conc_force_exit_innodb().
804
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
806
@return true if session is the replication thread */
807
extern "C" UNIV_INTERN
809
thd_is_replication_slave_thread(
810
/*============================*/
811
void* ) /*!< in: thread handle (Session*) */
816
/******************************************************************//**
817
Save some CPU by testing the value of srv_thread_concurrency in inline
821
innodb_srv_conc_enter_innodb(
822
/*=========================*/
823
trx_t* trx) /*!< in: transaction handle */
825
if (UNIV_LIKELY(!srv_thread_concurrency)) {
830
srv_conc_enter_innodb(trx);
833
/******************************************************************//**
834
Save some CPU by testing the value of srv_thread_concurrency in inline
838
innodb_srv_conc_exit_innodb(
839
/*========================*/
840
trx_t* trx) /*!< in: transaction handle */
842
if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
847
srv_conc_exit_innodb(trx);
850
/******************************************************************//**
851
Releases possible search latch and InnoDB thread FIFO ticket. These should
852
be released at each SQL statement end, and also when mysqld passes the
853
control to the client. It does no harm to release these also in the middle
854
of an SQL statement. */
857
innobase_release_stat_resources(
858
/*============================*/
859
trx_t* trx) /*!< in: transaction object */
861
if (trx->has_search_latch) {
862
trx_search_latch_release_if_reserved(trx);
865
if (trx->declared_to_be_inside_innodb) {
866
/* Release our possible ticket in the FIFO */
868
srv_conc_force_exit_innodb(trx);
872
/******************************************************************//**
873
Returns true if the transaction this thread is processing has edited
874
non-transactional tables. Used by the deadlock detector when deciding
875
which transaction to rollback in case of a deadlock - we try to avoid
876
rolling back transactions that have edited non-transactional tables.
878
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
880
@return true if non-transactional tables have been edited */
881
extern "C" UNIV_INTERN
883
thd_has_edited_nontrans_tables(
884
/*===========================*/
885
void* session) /*!< in: thread handle (Session*) */
887
return((ibool)((Session *)session)->transaction.all.hasModifiedNonTransData());
890
/******************************************************************//**
891
Returns true if the thread is executing a SELECT statement.
892
@return true if session is executing SELECT */
893
extern "C" UNIV_INTERN
897
const void* session) /*!< in: thread handle (Session*) */
899
return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
902
/******************************************************************//**
903
Returns true if the thread supports XA,
904
global value of innodb_supports_xa if session is NULL.
905
@return true if session has XA support */
906
extern "C" UNIV_INTERN
910
void* ) /*!< in: thread handle (Session*), or NULL to query
911
the global innodb_supports_xa */
913
/* TODO: Add support here for per-session value */
917
/******************************************************************//**
918
Returns the lock wait timeout for the current connection.
919
@return the lock wait timeout, in seconds */
920
extern "C" UNIV_INTERN
922
thd_lock_wait_timeout(
923
/*==================*/
924
void*) /*!< in: thread handle (Session*), or NULL to query
925
the global innodb_lock_wait_timeout */
927
/* TODO: Add support here for per-session value */
928
/* According to <drizzle/plugin.h>, passing session == NULL
929
returns the global value of the session variable. */
930
return((ulong)lock_wait_timeout.get());
933
/******************************************************************//**
934
Set the time waited for the lock for the current query. */
935
extern "C" UNIV_INTERN
937
thd_set_lock_wait_time(
938
/*===================*/
939
void* thd, /*!< in: thread handle (THD*) */
940
ulint value) /*!< in: time waited for the lock */
943
static_cast<Session*>(thd)->utime_after_lock+= value;
947
/********************************************************************//**
948
Obtain the InnoDB transaction of a MySQL thread.
949
@return reference to transaction pointer */
954
Session* session) /*!< in: Drizzle Session */
956
return *(trx_t**) session->getEngineData(innodb_engine_ptr);
960
plugin::ReplicationReturnCode ReplicationLog::apply(Session &session,
961
const message::Transaction &message)
963
char *data= new char[message.ByteSize()];
965
message.SerializeToArray(data, message.ByteSize());
967
trx_t *trx= session_to_trx(&session);
969
uint64_t trx_id= message.transaction_context().transaction_id();
970
ulint error= insert_replication_message(data, message.ByteSize(), trx, trx_id);
975
return plugin::SUCCESS;
978
/********************************************************************//**
979
Call this function when mysqld passes control to the client. That is to
980
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
981
documentation, see Cursor.cc.
984
InnobaseEngine::doReleaseTemporaryLatches(
985
/*===============================*/
986
Session* session) /*!< in: MySQL thread */
990
assert(this == innodb_engine_ptr);
992
if (!innodb_inited) {
997
trx = session_to_trx(session);
1000
innobase_release_stat_resources(trx);
1005
/********************************************************************//**
1006
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
1007
time calls srv_active_wake_master_thread. This function should be used
1008
when a single database operation may introduce a small need for
1009
server utility activity, like checkpointing. */
1012
innobase_active_small(void)
1013
/*=======================*/
1015
innobase_active_counter++;
1017
if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
1018
srv_active_wake_master_thread();
1022
/********************************************************************//**
1023
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
1024
about a possible transaction rollback inside InnoDB caused by a lock wait
1025
timeout or a deadlock.
1026
@return MySQL error code */
1027
extern "C" UNIV_INTERN
1029
convert_error_code_to_mysql(
1030
/*========================*/
1031
int error, /*!< in: InnoDB error code */
1032
ulint flags, /*!< in: InnoDB table flags, or 0 */
1033
Session* session)/*!< in: user thread handle or NULL */
1039
case DB_INTERRUPTED:
1040
my_error(ER_QUERY_INTERRUPTED, MYF(0));
1043
case DB_FOREIGN_EXCEED_MAX_CASCADE:
1044
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1045
HA_ERR_ROW_IS_REFERENCED,
1046
"InnoDB: Cannot delete/update "
1047
"rows with cascading foreign key "
1048
"constraints that exceed max "
1049
"depth of %d. Please "
1050
"drop extra constraints and try "
1051
"again", DICT_FK_MAX_RECURSIVE_LOAD);
1056
return(-1); /* unspecified error */
1058
case DB_DUPLICATE_KEY:
1059
/* Be cautious with returning this error, since
1060
mysql could re-enter the storage layer to get
1061
duplicated key info, the operation requires a
1062
valid table handle and/or transaction information,
1063
which might not always be available in the error
1065
return(HA_ERR_FOUND_DUPP_KEY);
1067
case DB_FOREIGN_DUPLICATE_KEY:
1068
return(HA_ERR_FOREIGN_DUPLICATE_KEY);
1070
case DB_MISSING_HISTORY:
1071
return(HA_ERR_TABLE_DEF_CHANGED);
1073
case DB_RECORD_NOT_FOUND:
1074
return(HA_ERR_NO_ACTIVE_RECORD);
1077
/* Since we rolled back the whole transaction, we must
1078
tell it also to MySQL so that MySQL knows to empty the
1079
cached binlog for this transaction */
1081
mark_transaction_to_rollback(session, TRUE);
1083
return(HA_ERR_LOCK_DEADLOCK);
1085
case DB_LOCK_WAIT_TIMEOUT:
1086
/* Starting from 5.0.13, we let MySQL just roll back the
1087
latest SQL statement in a lock wait timeout. Previously, we
1088
rolled back the whole transaction. */
1090
mark_transaction_to_rollback(session, (bool)row_rollback_on_timeout);
1092
return(HA_ERR_LOCK_WAIT_TIMEOUT);
1094
case DB_NO_REFERENCED_ROW:
1095
return(HA_ERR_NO_REFERENCED_ROW);
1097
case DB_ROW_IS_REFERENCED:
1098
return(HA_ERR_ROW_IS_REFERENCED);
1100
case DB_CANNOT_ADD_CONSTRAINT:
1101
return(HA_ERR_CANNOT_ADD_FOREIGN);
1103
case DB_CANNOT_DROP_CONSTRAINT:
1105
return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
1106
misleading, a new MySQL error
1107
code should be introduced */
1109
case DB_COL_APPEARS_TWICE_IN_INDEX:
1111
return(HA_ERR_CRASHED);
1113
case DB_OUT_OF_FILE_SPACE:
1114
return(HA_ERR_RECORD_FILE_FULL);
1116
case DB_TABLE_IS_BEING_USED:
1117
return(HA_ERR_WRONG_COMMAND);
1119
case DB_TABLE_NOT_FOUND:
1120
return(HA_ERR_NO_SUCH_TABLE);
1122
case DB_TOO_BIG_RECORD:
1123
my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
1124
page_get_free_space_of_empty(flags
1125
& DICT_TF_COMPACT) / 2);
1126
return(HA_ERR_TO_BIG_ROW);
1128
case DB_NO_SAVEPOINT:
1129
return(HA_ERR_NO_SAVEPOINT);
1131
case DB_LOCK_TABLE_FULL:
1132
/* Since we rolled back the whole transaction, we must
1133
tell it also to MySQL so that MySQL knows to empty the
1134
cached binlog for this transaction */
1136
mark_transaction_to_rollback(session, TRUE);
1138
return(HA_ERR_LOCK_TABLE_FULL);
1140
case DB_PRIMARY_KEY_IS_NULL:
1141
return(ER_PRIMARY_CANT_HAVE_NULL);
1143
case DB_TOO_MANY_CONCURRENT_TRXS:
1145
/* Once MySQL add the appropriate code to errmsg.txt then
1146
we can get rid of this #ifdef. NOTE: The code checked by
1147
the #ifdef is the suggested name for the error condition
1148
and the actual error code name could very well be different.
1149
This will require some monitoring, ie. the status
1150
of this request on our part.*/
1152
/* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only
1153
available in 5.1.38 and later, but the plugin should still
1154
work with previous versions of MySQL.
1155
In Drizzle we seem to not have this yet.
1157
#ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS
1158
return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
1159
#else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1160
return(HA_ERR_RECORD_FILE_FULL);
1161
#endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1162
case DB_UNSUPPORTED:
1163
return(HA_ERR_UNSUPPORTED);
1168
/*************************************************************//**
1169
Prints info of a Session object (== user session thread) to the given file. */
1170
extern "C" UNIV_INTERN
1172
innobase_mysql_print_thd(
1173
/*=====================*/
1174
FILE* f, /*!< in: output stream */
1175
void * in_session, /*!< in: pointer to a Drizzle Session object */
1176
uint ) /*!< in: max query length to print, or 0 to
1177
use the default max length */
1179
Session *session= reinterpret_cast<Session *>(in_session);
1181
"Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
1182
static_cast<uint64_t>(session->getSessionId()),
1183
static_cast<uint64_t>(session->getQueryId()),
1185
session->getSecurityContext().getIp().c_str(),
1186
session->getSecurityContext().getUser().c_str()
1188
fprintf(f, "\n%s", session->getQueryString()->c_str());
1192
/******************************************************************//**
1193
Get the variable length bounds of the given character set. */
1194
extern "C" UNIV_INTERN
1196
innobase_get_cset_width(
1197
/*====================*/
1198
ulint cset, /*!< in: MySQL charset-collation code */
1199
ulint* mbminlen, /*!< out: minimum length of a char (in bytes) */
1200
ulint* mbmaxlen) /*!< out: maximum length of a char (in bytes) */
1207
cs = all_charsets[cset];
1209
*mbminlen = cs->mbminlen;
1210
*mbmaxlen = cs->mbmaxlen;
1211
ut_ad(*mbminlen < DATA_MBMAX);
1212
ut_ad(*mbmaxlen < DATA_MBMAX);
1215
*mbminlen = *mbmaxlen = 0;
1219
/******************************************************************//**
1220
Converts an identifier to a table name. */
1221
extern "C" UNIV_INTERN
1223
innobase_convert_from_table_id(
1224
/*===========================*/
1225
const void*, /*!< in: the 'from' character set */
1226
char* to, /*!< out: converted identifier */
1227
const char* from, /*!< in: identifier to convert */
1228
ulint len) /*!< in: length of 'to', in bytes */
1230
strncpy(to, from, len);
1233
/******************************************************************//**
1234
Converts an identifier to UTF-8. */
1235
extern "C" UNIV_INTERN
1237
innobase_convert_from_id(
1238
/*=====================*/
1239
const void*, /*!< in: the 'from' character set */
1240
char* to, /*!< out: converted identifier */
1241
const char* from, /*!< in: identifier to convert */
1242
ulint len) /*!< in: length of 'to', in bytes */
1244
strncpy(to, from, len);
1247
/******************************************************************//**
1248
Compares NUL-terminated UTF-8 strings case insensitively.
1249
@return 0 if a=b, <0 if a<b, >1 if a>b */
1250
extern "C" UNIV_INTERN
1252
innobase_strcasecmp(
1253
/*================*/
1254
const char* a, /*!< in: first string to compare */
1255
const char* b) /*!< in: second string to compare */
1257
return(my_strcasecmp(system_charset_info, a, b));
1260
/******************************************************************//**
1261
Makes all characters in a NUL-terminated UTF-8 string lower case. */
1262
extern "C" UNIV_INTERN
1264
innobase_casedn_str(
1265
/*================*/
1266
char* a) /*!< in/out: string to put in lower case */
1268
my_casedn_str(system_charset_info, a);
1271
/**********************************************************************//**
1272
Determines the connection character set.
1273
@return connection character set */
1274
extern "C" UNIV_INTERN
1276
innobase_get_charset(
1277
/*=================*/
1278
void* mysql_session) /*!< in: MySQL thread handle */
1280
return static_cast<Session*>(mysql_session)->charset();
1283
extern "C" UNIV_INTERN
1289
return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
1294
innobase_fast_mutex_init(
1295
os_fast_mutex_t* fast_mutex)
1297
return pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
1300
/**********************************************************************//**
1301
Determines the current SQL statement.
1302
@return SQL statement string */
1303
extern "C" UNIV_INTERN
1307
void* session, /*!< in: MySQL thread handle */
1308
size_t* length) /*!< out: length of the SQL statement */
1310
return static_cast<Session*>(session)->getQueryStringCopy(*length);
1313
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1314
/*******************************************************************//**
1315
Map an OS error to an errno value. The OS error number is stored in
1316
_doserrno and the mapped value is stored in errno) */
1320
unsigned long); /*!< in: OS error value */
1322
/*********************************************************************//**
1323
Creates a temporary file.
1324
@return temporary file descriptor, or < 0 on error */
1325
extern "C" UNIV_INTERN
1327
innobase_mysql_tmpfile(void)
1328
/*========================*/
1330
int fd; /* handle of opened file */
1331
HANDLE osfh; /* OS handle of opened file */
1332
char* tmpdir; /* point to the directory
1333
where to create file */
1334
TCHAR path_buf[MAX_PATH - 14]; /* buffer for tmp file path.
1335
The length cannot be longer
1336
than MAX_PATH - 14, or
1337
GetTempFileName will fail. */
1338
char filename[MAX_PATH]; /* name of the tmpfile */
1339
DWORD fileaccess = GENERIC_READ /* OS file access */
1342
DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
1344
| FILE_SHARE_DELETE;
1345
DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
1346
DWORD fileattrib = /* OS file attribute flags */
1347
FILE_ATTRIBUTE_NORMAL
1348
| FILE_FLAG_DELETE_ON_CLOSE
1349
| FILE_ATTRIBUTE_TEMPORARY
1350
| FILE_FLAG_SEQUENTIAL_SCAN;
1352
tmpdir = my_tmpdir(&mysql_tmpdir_list);
1354
/* The tmpdir parameter can not be NULL for GetTempFileName. */
1358
/* Use GetTempPath to determine path for temporary files. */
1359
ret = GetTempPath(sizeof(path_buf), path_buf);
1360
if (ret > sizeof(path_buf) || (ret == 0)) {
1362
_dosmaperr(GetLastError()); /* map error */
1369
/* Use GetTempFileName to generate a unique filename. */
1370
if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
1372
_dosmaperr(GetLastError()); /* map error */
1376
/* Open/Create the file. */
1377
osfh = CreateFile(filename, fileaccess, fileshare, NULL,
1378
filecreate, fileattrib, NULL);
1379
if (osfh == INVALID_HANDLE_VALUE) {
1381
/* open/create file failed! */
1382
_dosmaperr(GetLastError()); /* map error */
1387
/* Associates a CRT file descriptor with the OS file handle. */
1388
fd = _open_osfhandle((intptr_t) osfh, 0);
1389
} while (fd == -1 && errno == EINTR);
1392
/* Open failed, close the file handle. */
1394
_dosmaperr(GetLastError()); /* map error */
1395
CloseHandle(osfh); /* no need to check if
1396
CloseHandle fails */
1402
/*********************************************************************//**
1403
Creates a temporary file.
1404
@return temporary file descriptor, or < 0 on error */
1405
extern "C" UNIV_INTERN
1407
innobase_mysql_tmpfile(void)
1408
/*========================*/
1411
int fd = mysql_tmpfile("ib");
1413
/* Copy the file descriptor, so that the additional resources
1414
allocated by create_temp_file() can be freed by invoking
1415
internal::my_close().
1417
Because the file descriptor returned by this function
1418
will be passed to fdopen(), it will be closed by invoking
1419
fclose(), which in turn will invoke close() instead of
1420
internal::my_close(). */
1424
my_error(EE_OUT_OF_FILERESOURCES,
1425
MYF(ME_BELL+ME_WAITTANG),
1428
internal::my_close(fd, MYF(MY_WME));
1432
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
1435
/*******************************************************************//**
1436
Formats the raw data in "data" (in InnoDB on-disk format) that is of
1437
type DATA_(CHAR|VARCHAR|DRIZZLE|VARDRIZZLE) using "charset_coll" and writes
1438
the result to "buf". The result is converted to "system_charset_info".
1439
Not more than "buf_size" bytes are written to "buf".
1440
The result is always NUL-terminated (provided buf_size > 0) and the
1441
number of bytes that were written to "buf" is returned (including the
1443
@return number of bytes that were written */
1444
extern "C" UNIV_INTERN
1446
innobase_raw_format(
1447
/*================*/
1448
const char* data, /*!< in: raw data */
1449
ulint data_len, /*!< in: raw data length
1451
ulint , /*!< in: charset collation */
1452
char* buf, /*!< out: output buffer */
1453
ulint buf_size) /*!< in: output buffer size
1456
return(ut_str_sql_format(data, data_len, buf, buf_size));
1459
/*********************************************************************//**
1460
Compute the next autoinc value.
1462
For MySQL replication the autoincrement values can be partitioned among
1463
the nodes. The offset is the start or origin of the autoincrement value
1464
for a particular node. For n nodes the increment will be n and the offset
1465
will be in the interval [1, n]. The formula tries to allocate the next
1466
value for a particular node.
1468
Note: This function is also called with increment set to the number of
1469
values we want to reserve for multi-value inserts e.g.,
1471
INSERT INTO T VALUES(), (), ();
1473
innobase_next_autoinc() will be called with increment set to
1474
to reserve 3 values for the multi-value INSERT above.
1475
@return the next value */
1478
innobase_next_autoinc(
1479
/*==================*/
1480
uint64_t current, /*!< in: Current value */
1481
uint64_t increment, /*!< in: increment current by */
1482
uint64_t offset, /*!< in: AUTOINC offset */
1483
uint64_t max_value) /*!< in: max value for type */
1485
uint64_t next_value;
1487
/* Should never be 0. */
1488
ut_a(increment > 0);
1490
/* According to MySQL documentation, if the offset is greater than
1491
the increment then the offset is ignored. */
1492
if (offset > increment) {
1496
if (max_value <= current) {
1497
next_value = max_value;
1498
} else if (offset <= 1) {
1499
/* Offset 0 and 1 are the same, because there must be at
1500
least one node in the system. */
1501
if (max_value - current <= increment) {
1502
next_value = max_value;
1504
next_value = current + increment;
1506
} else if (max_value > current) {
1507
if (current > offset) {
1508
next_value = ((current - offset) / increment) + 1;
1510
next_value = ((offset - current) / increment) + 1;
1513
ut_a(increment > 0);
1514
ut_a(next_value > 0);
1516
/* Check for multiplication overflow. */
1517
if (increment > (max_value / next_value)) {
1519
next_value = max_value;
1521
next_value *= increment;
1523
ut_a(max_value >= next_value);
1525
/* Check for overflow. */
1526
if (max_value - next_value <= offset) {
1527
next_value = max_value;
1529
next_value += offset;
1533
next_value = max_value;
1536
ut_a(next_value <= max_value);
1541
/*********************************************************************//**
1542
Initializes some fields in an InnoDB transaction object. */
1547
Session* session, /*!< in: user thread handle */
1548
trx_t* trx) /*!< in/out: InnoDB transaction handle */
1550
assert(session == trx->mysql_thd);
1552
trx->check_foreigns = !session_test_options(
1553
session, OPTION_NO_FOREIGN_KEY_CHECKS);
1555
trx->check_unique_secondary = !session_test_options(
1556
session, OPTION_RELAXED_UNIQUE_CHECKS);
1561
/*********************************************************************//**
1562
Allocates an InnoDB transaction for a MySQL Cursor object.
1563
@return InnoDB transaction handle */
1564
extern "C" UNIV_INTERN
1566
innobase_trx_allocate(
1567
/*==================*/
1568
Session* session) /*!< in: user thread handle */
1572
assert(session != NULL);
1573
assert(EQ_CURRENT_SESSION(session));
1575
trx = trx_allocate_for_mysql();
1577
trx->mysql_thd = session;
1579
innobase_trx_init(session, trx);
1584
/*********************************************************************//**
1585
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1586
an InnoDB transaction struct if the corresponding MySQL thread struct still
1588
@return InnoDB transaction handle */
1593
Session* session) /*!< in: user thread handle */
1595
trx_t*& trx = session_to_trx(session);
1597
ut_ad(EQ_CURRENT_SESSION(session));
1600
trx = innobase_trx_allocate(session);
1601
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1602
mem_analyze_corruption(trx);
1606
innobase_trx_init(session, trx);
1612
/*********************************************************************//**
1613
Construct ha_innobase Cursor. */
1615
ha_innobase::ha_innobase(plugin::StorageEngine &engine_arg,
1617
:Cursor(engine_arg, table_arg),
1618
primary_key(0), /* needs initialization because index_flags() may be called
1619
before this is set to the real value. It's ok to have any
1620
value here because it doesn't matter if we return the
1621
HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
1626
/*********************************************************************//**
1627
Destruct ha_innobase Cursor. */
1629
ha_innobase::~ha_innobase()
1633
/*********************************************************************//**
1634
Updates the user_thd field in a handle and also allocates a new InnoDB
1635
transaction handle if needed, and updates the transaction fields in the
1639
ha_innobase::update_session(
1640
/*====================*/
1641
Session* session) /*!< in: thd to use the handle */
1646
trx = check_trx_exists(session);
1648
if (prebuilt->trx != trx) {
1650
row_update_prebuilt_trx(prebuilt, trx);
1653
user_session = session;
1656
/*****************************************************************//**
1657
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1658
and quote it if needed.
1659
@return pointer to the end of buf */
1662
innobase_convert_identifier(
1663
/*========================*/
1664
char* buf, /*!< out: buffer for converted identifier */
1665
ulint buflen, /*!< in: length of buf, in bytes */
1666
const char* id, /*!< in: identifier to convert */
1667
ulint idlen, /*!< in: length of id, in bytes */
1668
void* session,/*!< in: MySQL connection thread, or NULL */
1669
ibool file_id)/*!< in: TRUE=id is a table or database name;
1670
FALSE=id is an UTF-8 string */
1672
char nz[NAME_LEN + 1];
1673
char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
1679
/* Decode the table name. The filename_to_tablename()
1680
function expects a NUL-terminated string. The input and
1681
output strings buffers must not be shared. */
1683
if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1684
idlen = (sizeof nz) - 1;
1687
memcpy(nz, id, idlen);
1691
idlen = TableIdentifier::filename_to_tablename(nz, nz2, sizeof nz2);
1694
/* See if the identifier needs to be quoted. */
1695
if (UNIV_UNLIKELY(!session)) {
1698
q = get_quote_char_for_identifier();
1702
if (UNIV_UNLIKELY(idlen > buflen)) {
1705
memcpy(buf, s, idlen);
1706
return(buf + idlen);
1709
/* Quote the identifier. */
1717
for (; idlen; idlen--) {
1719
if (UNIV_UNLIKELY(c == q)) {
1720
if (UNIV_UNLIKELY(buflen < 3)) {
1728
if (UNIV_UNLIKELY(buflen < 2)) {
1741
/*****************************************************************//**
1742
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1743
and quote it if needed.
1744
@return pointer to the end of buf */
1745
extern "C" UNIV_INTERN
1747
innobase_convert_name(
1748
/*==================*/
1749
char* buf, /*!< out: buffer for converted identifier */
1750
ulint buflen, /*!< in: length of buf, in bytes */
1751
const char* id, /*!< in: identifier to convert */
1752
ulint idlen, /*!< in: length of id, in bytes */
1753
void* session,/*!< in: MySQL connection thread, or NULL */
1754
ibool table_id)/*!< in: TRUE=id is a table or database name;
1755
FALSE=id is an index name */
1758
const char* bufend = buf + buflen;
1761
const char* slash = (const char*) memchr(id, '/', idlen);
1767
/* Print the database name and table name separately. */
1768
s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1770
if (UNIV_LIKELY(s < bufend)) {
1772
s = innobase_convert_identifier(s, bufend - s,
1777
} else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1778
/* Temporary index name (smart ALTER TABLE) */
1779
const char temp_index_suffix[]= "--temporary--";
1781
s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1783
if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1784
memcpy(s, temp_index_suffix,
1785
sizeof temp_index_suffix - 1);
1786
s += sizeof temp_index_suffix - 1;
1790
s = innobase_convert_identifier(buf, buflen, id, idlen,
1798
/**********************************************************************//**
1799
Determines if the currently running transaction has been interrupted.
1800
@return TRUE if interrupted */
1801
extern "C" UNIV_INTERN
1805
trx_t* trx) /*!< in: transaction */
1807
return(trx && trx->mysql_thd && static_cast<Session*>(trx->mysql_thd)->getKilled());
1810
/**********************************************************************//**
1811
Determines if the currently running transaction is in strict mode.
1812
@return TRUE if strict */
1813
extern "C" UNIV_INTERN
1817
trx_t* trx) /*!< in: transaction */
1819
return(trx && trx->mysql_thd
1823
/**************************************************************//**
1824
Resets some fields of a prebuilt struct. The template is used in fast
1825
retrieval of just those column values MySQL needs in its processing. */
1830
row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1832
prebuilt->keep_other_fields_on_keyread = 0;
1833
prebuilt->read_just_key = 0;
1837
void align_value(T& value, size_t align_val= 1024)
1839
value= value - (value % align_val);
1842
static void auto_extend_update(Session *, sql_var_t)
1844
srv_auto_extend_increment= innodb_auto_extend_increment.get();
1847
static void io_capacity_update(Session *, sql_var_t)
1849
srv_io_capacity= innodb_io_capacity.get();
1852
static void purge_batch_update(Session *, sql_var_t)
1854
srv_purge_batch_size= innodb_purge_batch_size.get();
1857
static void purge_threads_update(Session *, sql_var_t)
1859
srv_n_purge_threads= innodb_n_purge_threads.get();
1862
static void innodb_adaptive_hash_index_update(Session *, sql_var_t)
1864
if (btr_search_enabled)
1866
btr_search_enable();
1868
btr_search_disable();
1872
static void innodb_old_blocks_pct_update(Session *, sql_var_t)
1874
innobase_old_blocks_pct= buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(), TRUE);
1877
static void innodb_thread_concurrency_update(Session *, sql_var_t)
1879
srv_thread_concurrency= innobase_thread_concurrency.get();
1882
static void innodb_sync_spin_loops_update(Session *, sql_var_t)
1884
srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
1887
static void innodb_spin_wait_delay_update(Session *, sql_var_t)
1889
srv_spin_wait_delay= innodb_spin_wait_delay.get();
1892
static void innodb_thread_sleep_delay_update(Session *, sql_var_t)
1894
srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
1897
static void innodb_read_ahead_threshold_update(Session *, sql_var_t)
1899
srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
1903
static int innodb_commit_concurrency_validate(Session *session, set_var *var)
1905
uint32_t new_value= var->save_result.uint32_t_value;
1907
if ((innobase_commit_concurrency.get() == 0 && new_value != 0) ||
1908
(innobase_commit_concurrency.get() != 0 && new_value == 0))
1910
push_warning_printf(session,
1911
DRIZZLE_ERROR::WARN_LEVEL_WARN,
1913
_("Once InnoDB is running, innodb_commit_concurrency "
1914
"must not change between zero and nonzero."));
1920
/*************************************************************//**
1921
Check if it is a valid file format. This function is registered as
1922
a callback with MySQL.
1923
@return 0 for valid file format */
1926
innodb_file_format_name_validate(
1927
/*=============================*/
1928
Session* , /*!< in: thread handle */
1931
const char *file_format_input = var->value->str_value.ptr();
1932
if (file_format_input == NULL)
1935
if (file_format_input != NULL) {
1938
format_id = innobase_file_format_name_lookup(
1941
if (format_id <= DICT_TF_FORMAT_MAX) {
1942
innobase_file_format_name =
1943
trx_sys_file_format_id_to_name(format_id);
1952
/*************************************************************//**
1953
Check if it is a valid value of innodb_change_buffering. This function is
1954
registered as a callback with MySQL.
1955
@return 0 for valid innodb_change_buffering */
1958
innodb_change_buffering_validate(
1959
/*=============================*/
1960
Session* , /*!< in: thread handle */
1963
const char *change_buffering_input = var->value->str_value.ptr();
1965
if (change_buffering_input == NULL)
1971
use < UT_ARR_SIZE(innobase_change_buffering_values);
1973
if (!innobase_strcasecmp(change_buffering_input,
1974
innobase_change_buffering_values[use]))
1976
ibuf_use= static_cast<ibuf_use_t>(use);
1985
/*************************************************************//**
1986
Check if valid argument to innodb_file_format_max. This function
1987
is registered as a callback with MySQL.
1988
@return 0 for valid file format */
1991
innodb_file_format_max_validate(
1992
/*==============================*/
1993
Session* session, /*!< in: thread handle */
1996
const char *file_format_input = var->value->str_value.ptr();
1997
if (file_format_input == NULL)
2000
if (file_format_input != NULL) {
2001
int format_id = innobase_file_format_validate_and_set(file_format_input);
2003
if (format_id > DICT_TF_FORMAT_MAX) {
2004
/* DEFAULT is "on", which is invalid at runtime. */
2008
if (format_id >= 0) {
2009
innobase_file_format_max=
2010
trx_sys_file_format_id_to_name((uint)format_id);
2012
/* Update the max format id in the system tablespace. */
2013
char name_buff[100];
2014
strcpy(name_buff, innobase_file_format_max.c_str());
2015
if (trx_sys_file_format_max_set(format_id, (const char **)&name_buff))
2017
errmsg_printf(ERRMSG_LVL_WARN,
2018
" [Info] InnoDB: the file format in the system "
2019
"tablespace is now set to %s.\n", name_buff);
2020
innobase_file_format_max= name_buff;
2025
push_warning_printf(session,
2026
DRIZZLE_ERROR::WARN_LEVEL_WARN,
2028
"InnoDB: invalid innodb_file_format_max "
2029
"value; can be any format up to %s "
2030
"or equivalent id of %d",
2031
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX),
2032
DICT_TF_FORMAT_MAX);
2040
/*********************************************************************//**
2041
Opens an InnoDB database.
2042
@return 0 on success, error code on failure */
2047
module::Context &context) /*!< in: Drizzle Plugin Context */
2052
InnobaseEngine *actuall_engine_ptr;
2053
const module::option_map &vm= context.getOptions();
2055
srv_auto_extend_increment= innodb_auto_extend_increment.get();
2056
srv_io_capacity= innodb_io_capacity.get();
2057
srv_purge_batch_size= innodb_purge_batch_size.get();
2058
srv_n_purge_threads= innodb_n_purge_threads.get();
2059
srv_flush_log_at_trx_commit= innodb_flush_log_at_trx_commit.get();
2060
srv_max_buf_pool_modified_pct= innodb_max_dirty_pages_pct.get();
2061
srv_max_purge_lag= innodb_max_purge_lag.get();
2062
srv_stats_sample_pages= innodb_stats_sample_pages.get();
2063
srv_n_free_tickets_to_enter= innodb_concurrency_tickets.get();
2064
srv_replication_delay= innodb_replication_delay.get();
2065
srv_thread_concurrency= innobase_thread_concurrency.get();
2066
srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
2067
srv_spin_wait_delay= innodb_spin_wait_delay.get();
2068
srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
2069
srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
2071
/* Inverted Booleans */
2073
innobase_use_checksums= (vm.count("disable-checksums")) ? false : true;
2074
innobase_use_doublewrite= (vm.count("disable-doublewrite")) ? false : true;
2075
srv_adaptive_flushing= (vm.count("disable-adaptive-flushing")) ? false : true;
2076
srv_use_sys_malloc= (vm.count("use-internal-malloc")) ? false : true;
2077
support_xa= (vm.count("disable-xa")) ? false : true;
2078
btr_search_enabled= (vm.count("disable-adaptive-hash-index")) ? false : true;
2081
/* Hafta do this here because we need to late-bind the default value */
2082
if (vm.count("data-home-dir"))
2084
innobase_data_home_dir= vm["data-home-dir"].as<string>();
2088
innobase_data_home_dir= getDataHome().file_string();
2092
if (vm.count("data-file-path"))
2094
innobase_data_file_path= vm["data-file-path"].as<string>();
2098
innodb_engine_ptr= actuall_engine_ptr= new InnobaseEngine(innobase_engine_name);
2100
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
2103
static const char test_filename[] = "-@";
2104
char test_tablename[sizeof test_filename
2105
+ sizeof srv_mysql50_table_name_prefix];
2106
if ((sizeof test_tablename) - 1
2107
!= filename_to_tablename(test_filename, test_tablename,
2108
sizeof test_tablename)
2109
|| strncmp(test_tablename,
2110
srv_mysql50_table_name_prefix,
2111
sizeof srv_mysql50_table_name_prefix)
2112
|| strcmp(test_tablename
2113
+ sizeof srv_mysql50_table_name_prefix,
2115
errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
2118
#endif /* UNIV_DEBUG */
2120
os_innodb_umask = (ulint)internal::my_umask;
2123
/* Set InnoDB initialization parameters according to the values
2124
read from MySQL .cnf file */
2126
/*--------------- Data files -------------------------*/
2128
/* The default dir for data files is the datadir of MySQL */
2130
srv_data_home = (char *)innobase_data_home_dir.c_str();
2132
/* Set default InnoDB data file size to 10 MB and let it be
2133
auto-extending. Thus users can use InnoDB in >= 4.0 without having
2134
to specify any startup options. */
2136
if (innobase_data_file_path.empty())
2138
innobase_data_file_path= std::string("ibdata1:10M:autoextend");
2141
/* Since InnoDB edits the argument in the next call, we make another
2144
internal_innobase_data_file_path = strdup(innobase_data_file_path.c_str());
2146
ret = (bool) srv_parse_data_file_paths_and_sizes(
2147
internal_innobase_data_file_path);
2149
errmsg_printf(ERRMSG_LVL_ERROR,
2150
"InnoDB: syntax error in innodb_data_file_path");
2152
srv_free_paths_and_sizes();
2153
if (internal_innobase_data_file_path)
2154
free(internal_innobase_data_file_path);
2158
/* -------------- Log files ---------------------------*/
2160
/* The default dir for log files is the datadir of MySQL */
2162
if (vm.count("log-group-home-dir"))
2164
innobase_log_group_home_dir= vm["log-group-home-dir"].as<string>();
2168
innobase_log_group_home_dir= getDataHome().file_string();
2172
srv_parse_log_group_home_dirs((char *)innobase_log_group_home_dir.c_str());
2174
if (ret == FALSE || innobase_mirrored_log_groups.get() != 1) {
2175
errmsg_printf(ERRMSG_LVL_ERROR,
2176
_("syntax error in innodb_log_group_home_dir, or a "
2177
"wrong number of mirrored log groups"));
2179
goto mem_free_and_error;
2183
/* Validate the file format by animal name */
2184
if (vm.count("file-format"))
2186
format_id = innobase_file_format_name_lookup(
2187
vm["file-format"].as<string>().c_str());
2189
if (format_id > DICT_TF_FORMAT_MAX) {
2191
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
2193
goto mem_free_and_error;
2196
/* Set it to the default file format id.*/
2200
srv_file_format = format_id;
2202
innobase_file_format_name =
2203
trx_sys_file_format_id_to_name(format_id);
2205
/* Check innobase_file_format_check variable */
2206
if (!innobase_file_format_check)
2208
/* Set the value to disable checking. */
2209
srv_max_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
2211
/* Set the value to the lowest supported format. */
2212
srv_max_file_format_at_startup = DICT_TF_FORMAT_MIN;
2215
/* Did the user specify a format name that we support?
2216
As a side effect it will update the variable
2217
srv_max_file_format_at_startup */
2218
if (innobase_file_format_validate_and_set(innobase_file_format_max.c_str()) < 0)
2220
errmsg_printf(ERRMSG_LVL_ERROR, _("InnoDB: invalid "
2221
"innodb_file_format_max value: "
2222
"should be any value up to %s or its "
2223
"equivalent numeric id"),
2224
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
2225
goto mem_free_and_error;
2228
if (vm.count("change-buffering"))
2233
use < UT_ARR_SIZE(innobase_change_buffering_values);
2235
if (!innobase_strcasecmp(
2236
innobase_change_buffering.c_str(),
2237
innobase_change_buffering_values[use])) {
2238
ibuf_use = static_cast<ibuf_use_t>(use);
2239
goto innobase_change_buffering_inited_ok;
2243
errmsg_printf(ERRMSG_LVL_ERROR,
2244
"InnoDB: invalid value "
2245
"innodb_change_buffering=%s",
2246
vm["change-buffering"].as<string>().c_str());
2247
goto mem_free_and_error;
2250
innobase_change_buffering_inited_ok:
2251
ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
2252
innobase_change_buffering = innobase_change_buffering_values[ibuf_use];
2254
/* --------------------------------------------------*/
2256
if (vm.count("flush-method") != 0)
2258
srv_file_flush_method_str = (char *)vm["flush-method"].as<string>().c_str();
2261
srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
2262
srv_n_log_files = (ulint) innobase_log_files_in_group;
2263
srv_log_file_size = (ulint) innobase_log_file_size;
2265
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
2267
srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
2268
srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances;
2270
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
2272
srv_n_read_io_threads = (ulint) innobase_read_io_threads;
2273
srv_n_write_io_threads = (ulint) innobase_write_io_threads;
2275
srv_force_recovery = (ulint) innobase_force_recovery;
2277
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
2278
srv_use_checksums = (ibool) innobase_use_checksums;
2280
#ifdef HAVE_LARGE_PAGES
2281
if ((os_use_large_pages = (ibool) my_use_large_pages))
2282
os_large_page_size = (ulint) opt_large_page_size;
2285
row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
2287
srv_locks_unsafe_for_binlog = (ibool) TRUE;
2289
srv_max_n_open_files = (ulint) innobase_open_files;
2290
srv_innodb_status = (ibool) innobase_create_status_file;
2292
srv_print_verbose_log = true;
2294
/* Store the default charset-collation number of this MySQL
2297
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
2299
/* Since we in this module access directly the fields of a trx
2300
struct, and due to different headers and flags it might happen that
2301
mutex_t has a different size in this module and in InnoDB
2302
modules, we check at run time that the size is the same in
2303
these compilation modules. */
2305
err = innobase_start_or_create_for_mysql();
2307
if (err != DB_SUCCESS)
2309
goto mem_free_and_error;
2312
err = dict_create_sys_replication_log();
2314
if (err != DB_SUCCESS) {
2315
goto mem_free_and_error;
2319
innobase_old_blocks_pct = buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(),
2322
innobase_open_tables = hash_create(200);
2323
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
2324
pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
2325
pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
2326
pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
2327
pthread_cond_init(&commit_cond, NULL);
2330
actuall_engine_ptr->dropTemporarySchema();
2332
status_table_function_ptr= new InnodbStatusTool;
2334
context.add(innodb_engine_ptr);
2336
context.add(status_table_function_ptr);
2338
cmp_tool= new(std::nothrow)CmpTool(false);
2339
context.add(cmp_tool);
2341
cmp_reset_tool= new(std::nothrow)CmpTool(true);
2342
context.add(cmp_reset_tool);
2344
cmp_mem_tool= new(std::nothrow)CmpmemTool(false);
2345
context.add(cmp_mem_tool);
2347
cmp_mem_reset_tool= new(std::nothrow)CmpmemTool(true);
2348
context.add(cmp_mem_reset_tool);
2350
innodb_trx_tool= new(std::nothrow)InnodbTrxTool("INNODB_TRX");
2351
context.add(innodb_trx_tool);
2353
innodb_locks_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCKS");
2354
context.add(innodb_locks_tool);
2356
innodb_lock_waits_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS");
2357
context.add(innodb_lock_waits_tool);
2359
innodb_sys_tables_tool= new(std::nothrow)InnodbSysTablesTool();
2360
context.add(innodb_sys_tables_tool);
2362
innodb_sys_tablestats_tool= new(std::nothrow)InnodbSysTableStatsTool();
2363
context.add(innodb_sys_tablestats_tool);
2365
innodb_sys_indexes_tool= new(std::nothrow)InnodbSysIndexesTool();
2366
context.add(innodb_sys_indexes_tool);
2368
innodb_sys_columns_tool= new(std::nothrow)InnodbSysColumnsTool();
2369
context.add(innodb_sys_columns_tool);
2371
innodb_sys_fields_tool= new(std::nothrow)InnodbSysFieldsTool();
2372
context.add(innodb_sys_fields_tool);
2374
innodb_sys_foreign_tool= new(std::nothrow)InnodbSysForeignTool();
2375
context.add(innodb_sys_foreign_tool);
2377
innodb_sys_foreign_cols_tool= new(std::nothrow)InnodbSysForeignColsTool();
2378
context.add(innodb_sys_foreign_cols_tool);
2380
context.add(new(std::nothrow)InnodbInternalTables());
2381
context.add(new(std::nothrow)InnodbReplicationTable());
2383
if (innobase_use_replication_log)
2385
replication_logger= new(std::nothrow)ReplicationLog();
2386
context.add(replication_logger);
2387
ReplicationLog::setup(replication_logger);
2390
context.registerVariable(new sys_var_const_string_val("data-home-dir", innobase_data_home_dir));
2391
context.registerVariable(new sys_var_const_string_val("flush-method",
2392
vm.count("flush-method") ? vm["flush-method"].as<string>() : ""));
2393
context.registerVariable(new sys_var_const_string_val("log-group-home-dir", innobase_log_group_home_dir));
2394
context.registerVariable(new sys_var_const_string_val("data-file-path", innobase_data_file_path));
2395
context.registerVariable(new sys_var_const_string_val("version", vm["version"].as<string>()));
2398
context.registerVariable(new sys_var_bool_ptr_readonly("replication_log", &innobase_use_replication_log));
2399
context.registerVariable(new sys_var_bool_ptr_readonly("checksums", &innobase_use_checksums));
2400
context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite", &innobase_use_doublewrite));
2401
context.registerVariable(new sys_var_bool_ptr("file-per-table", &srv_file_per_table));
2402
context.registerVariable(new sys_var_bool_ptr_readonly("file-format-check", &innobase_file_format_check));
2403
context.registerVariable(new sys_var_bool_ptr("adaptive-flushing", &srv_adaptive_flushing));
2404
context.registerVariable(new sys_var_bool_ptr("status-file", &innobase_create_status_file));
2405
context.registerVariable(new sys_var_bool_ptr_readonly("use-sys-malloc", &srv_use_sys_malloc));
2406
context.registerVariable(new sys_var_bool_ptr_readonly("use-native-aio", &srv_use_native_aio));
2408
context.registerVariable(new sys_var_bool_ptr("support-xa", &support_xa));
2409
context.registerVariable(new sys_var_bool_ptr("strict_mode", &strict_mode));
2410
context.registerVariable(new sys_var_constrained_value<uint32_t>("lock_wait_timeout", lock_wait_timeout));
2412
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
2413
context.registerVariable(new sys_var_constrained_value<uint32_t>("autoextend_increment",
2414
innodb_auto_extend_increment,
2415
auto_extend_update));
2416
context.registerVariable(new sys_var_constrained_value<uint32_t>("io_capacity",
2418
io_capacity_update));
2419
context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_batch_size",
2420
innodb_purge_batch_size,
2421
purge_batch_update));
2422
context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_threads",
2423
innodb_n_purge_threads,
2424
purge_threads_update));
2425
context.registerVariable(new sys_var_constrained_value<uint16_t>("fast_shutdown", innobase_fast_shutdown));
2426
context.registerVariable(new sys_var_std_string("file_format",
2427
innobase_file_format_name,
2428
innodb_file_format_name_validate));
2429
context.registerVariable(new sys_var_std_string("change_buffering",
2430
innobase_change_buffering,
2431
innodb_change_buffering_validate));
2432
context.registerVariable(new sys_var_std_string("file_format_max",
2433
innobase_file_format_max,
2434
innodb_file_format_max_validate));
2435
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
2436
context.registerVariable(new sys_var_constrained_value_readonly<int64_t>("log_file_size", innobase_log_file_size));
2437
context.registerVariable(new sys_var_constrained_value_readonly<uint16_t>("flush_log_at_trx_commit",
2438
innodb_flush_log_at_trx_commit));
2439
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("max_dirty_pages_pct",
2440
innodb_max_dirty_pages_pct));
2441
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", innodb_max_purge_lag));
2442
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("stats_sample_pages", innodb_stats_sample_pages));
2443
context.registerVariable(new sys_var_bool_ptr("adaptive_hash_index", &btr_search_enabled, innodb_adaptive_hash_index_update));
2445
context.registerVariable(new sys_var_constrained_value<uint32_t>("commit_concurrency",
2446
innobase_commit_concurrency,
2447
innodb_commit_concurrency_validate));
2448
context.registerVariable(new sys_var_constrained_value<uint32_t>("concurrency_tickets",
2449
innodb_concurrency_tickets));
2450
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_io_threads", innobase_read_io_threads));
2451
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_io_threads", innobase_write_io_threads));
2452
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("replication_delay", innodb_replication_delay));
2453
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("force_recovery", innobase_force_recovery));
2454
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("log_buffer_size", innobase_log_buffer_size));
2455
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("log_files_in_group", innobase_log_files_in_group));
2456
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("mirrored_log_groups", innobase_mirrored_log_groups));
2457
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("open_files", innobase_open_files));
2458
context.registerVariable(new sys_var_constrained_value<uint32_t>("old_blocks_pct",
2459
innobase_old_blocks_pct,
2460
innodb_old_blocks_pct_update));
2461
context.registerVariable(new sys_var_uint32_t_ptr("old_blocks_time", &buf_LRU_old_threshold_ms));
2462
context.registerVariable(new sys_var_constrained_value<uint32_t>("sync_spin_loops", innodb_sync_spin_loops, innodb_sync_spin_loops_update));
2463
context.registerVariable(new sys_var_constrained_value<uint32_t>("spin_wait_delay", innodb_spin_wait_delay, innodb_spin_wait_delay_update));
2464
context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_sleep_delay", innodb_thread_sleep_delay, innodb_thread_sleep_delay_update));
2465
context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_concurrency",
2466
innobase_thread_concurrency,
2467
innodb_thread_concurrency_update));
2468
context.registerVariable(new sys_var_constrained_value<uint32_t>("read_ahead_threshold",
2469
innodb_read_ahead_threshold,
2470
innodb_read_ahead_threshold_update));
2471
/* Get the current high water mark format. */
2472
innobase_file_format_max = trx_sys_file_format_max_get();
2473
btr_search_fully_disabled = (!btr_search_enabled);
2481
/****************************************************************//**
2482
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2483
the logs, and the name of this function should be innobase_checkpoint.
2484
@return TRUE if error */
2486
InnobaseEngine::flush_logs()
2487
/*=====================*/
2491
assert(this == innodb_engine_ptr);
2493
log_buffer_flush_to_disk();
2498
/*****************************************************************//**
2499
Commits a transaction in an InnoDB database. */
2502
innobase_commit_low(
2503
/*================*/
2504
trx_t* trx) /*!< in: transaction handle */
2506
if (trx->conc_state == TRX_NOT_STARTED) {
2511
trx_commit_for_mysql(trx);
2514
/*****************************************************************//**
2515
Creates an InnoDB transaction struct for the thd if it does not yet have one.
2516
Starts a new InnoDB transaction if a transaction is not yet started. And
2517
assigns a new snapshot for a consistent read if the transaction does not yet
2521
InnobaseEngine::doStartTransaction(
2522
/*====================================*/
2523
Session* session, /*!< in: MySQL thread handle of the user for whom
2524
the transaction should be committed */
2525
start_transaction_option_t options)
2527
assert(this == innodb_engine_ptr);
2529
/* Create a new trx struct for session, if it does not yet have one */
2530
trx_t *trx = check_trx_exists(session);
2532
/* This is just to play safe: release a possible FIFO ticket and
2533
search latch. Since we will reserve the kernel mutex, we have to
2534
release the search system latch first to obey the latching order. */
2535
innobase_release_stat_resources(trx);
2537
/* If the transaction is not started yet, start it */
2538
trx_start_if_not_started(trx);
2540
/* Assign a read view if the transaction does not have it yet */
2541
if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2542
trx_assign_read_view(trx);
2547
/*****************************************************************//**
2548
Commits a transaction in an InnoDB database or marks an SQL statement
2552
InnobaseEngine::doCommit(
2554
Session* session, /*!< in: MySQL thread handle of the user for whom
2555
the transaction should be committed */
2556
bool all) /*!< in: TRUE - commit transaction
2557
FALSE - the current SQL statement ended */
2561
assert(this == innodb_engine_ptr);
2563
trx = check_trx_exists(session);
2565
/* Since we will reserve the kernel mutex, we have to release
2566
the search system latch first to obey the latching order. */
2568
if (trx->has_search_latch) {
2569
trx_search_latch_release_if_reserved(trx);
2573
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
2575
/* We were instructed to commit the whole transaction, or
2576
this is an SQL statement end and autocommit is on */
2578
/* We need current binlog position for ibbackup to work.
2579
Note, the position is current because of
2580
prepare_commit_mutex */
2582
if (innobase_commit_concurrency.get() > 0) {
2583
pthread_mutex_lock(&commit_cond_m);
2586
if (commit_threads > innobase_commit_concurrency.get()) {
2588
pthread_cond_wait(&commit_cond,
2590
pthread_mutex_unlock(&commit_cond_m);
2594
pthread_mutex_unlock(&commit_cond_m);
2598
/* Store transaction point for binlog
2599
Later logic tests that this is set to _something_. We need
2600
that logic to fire, even though we do not have a real name. */
2601
trx->mysql_log_file_name = "UNUSED";
2602
trx->mysql_log_offset = 0;
2604
/* Don't do write + flush right now. For group commit
2605
to work we want to do the flush after releasing the
2606
prepare_commit_mutex. */
2607
trx->flush_log_later = TRUE;
2608
innobase_commit_low(trx);
2609
trx->flush_log_later = FALSE;
2611
if (innobase_commit_concurrency.get() > 0) {
2612
pthread_mutex_lock(&commit_cond_m);
2614
pthread_cond_signal(&commit_cond);
2615
pthread_mutex_unlock(&commit_cond_m);
2618
/* Now do a write + flush of logs. */
2619
trx_commit_complete_for_mysql(trx);
2622
/* We just mark the SQL statement ended and do not do a
2623
transaction commit */
2625
/* If we had reserved the auto-inc lock for some
2626
table in this SQL statement we release it now */
2628
row_unlock_table_autoinc_for_mysql(trx);
2630
/* Store the current undo_no of the transaction so that we
2631
know where to roll back if we have to roll back the next
2634
trx_mark_sql_stat_end(trx);
2636
if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
2638
if (trx->conc_state != TRX_NOT_STARTED)
2640
commit(session, TRUE);
2645
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2647
if (trx->declared_to_be_inside_innodb) {
2648
/* Release our possible ticket in the FIFO */
2650
srv_conc_force_exit_innodb(trx);
2653
/* Tell the InnoDB server that there might be work for utility
2655
srv_active_wake_master_thread();
2657
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2658
trx->global_read_view)
2660
/* At low transaction isolation levels we let
2661
each consistent read set its own snapshot */
2662
read_view_close_for_mysql(trx);
2668
/*****************************************************************//**
2669
Rolls back a transaction or the latest SQL statement.
2670
@return 0 or error number */
2672
InnobaseEngine::doRollback(
2674
Session* session,/*!< in: handle to the MySQL thread of the user
2675
whose transaction should be rolled back */
2676
bool all) /*!< in: TRUE - commit transaction
2677
FALSE - the current SQL statement ended */
2682
assert(this == innodb_engine_ptr);
2684
trx = check_trx_exists(session);
2686
/* Release a possible FIFO ticket and search latch. Since we will
2687
reserve the kernel mutex, we have to release the search system latch
2688
first to obey the latching order. */
2690
innobase_release_stat_resources(trx);
2692
trx->n_autoinc_rows = 0;
2694
/* If we had reserved the auto-inc lock for some table (if
2695
we come here to roll back the latest SQL statement) we
2696
release it now before a possibly lengthy rollback */
2698
row_unlock_table_autoinc_for_mysql(trx);
2701
|| !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
2703
error = trx_rollback_for_mysql(trx);
2705
error = trx_rollback_last_sql_stat_for_mysql(trx);
2708
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2709
trx->global_read_view)
2711
/* At low transaction isolation levels we let
2712
each consistent read set its own snapshot */
2713
read_view_close_for_mysql(trx);
2716
return(convert_error_code_to_mysql(error, 0, NULL));
2719
/*****************************************************************//**
2720
Rolls back a transaction
2721
@return 0 or error number */
2724
innobase_rollback_trx(
2725
/*==================*/
2726
trx_t* trx) /*!< in: transaction */
2730
/* Release a possible FIFO ticket and search latch. Since we will
2731
reserve the kernel mutex, we have to release the search system latch
2732
first to obey the latching order. */
2734
innobase_release_stat_resources(trx);
2736
/* If we had reserved the auto-inc lock for some table (if
2737
we come here to roll back the latest SQL statement) we
2738
release it now before a possibly lengthy rollback */
2740
row_unlock_table_autoinc_for_mysql(trx);
2742
error = trx_rollback_for_mysql(trx);
2744
return(convert_error_code_to_mysql(error, 0, NULL));
2747
/*****************************************************************//**
2748
Rolls back a transaction to a savepoint.
2749
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2752
InnobaseEngine::doRollbackToSavepoint(
2753
/*===========================*/
2754
Session* session, /*!< in: handle to the MySQL thread of the user
2755
whose transaction should be rolled back */
2756
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2758
ib_int64_t mysql_binlog_cache_pos;
2762
assert(this == innodb_engine_ptr);
2764
trx = check_trx_exists(session);
2766
/* Release a possible FIFO ticket and search latch. Since we will
2767
reserve the kernel mutex, we have to release the search system latch
2768
first to obey the latching order. */
2770
innobase_release_stat_resources(trx);
2772
error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2773
&mysql_binlog_cache_pos);
2774
return(convert_error_code_to_mysql(error, 0, NULL));
2777
/*****************************************************************//**
2778
Release transaction savepoint name.
2779
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2782
InnobaseEngine::doReleaseSavepoint(
2783
/*=======================*/
2784
Session* session, /*!< in: handle to the MySQL thread of the user
2785
whose transaction should be rolled back */
2786
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2791
assert(this == innodb_engine_ptr);
2793
trx = check_trx_exists(session);
2795
error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2797
return(convert_error_code_to_mysql(error, 0, NULL));
2800
/*****************************************************************//**
2801
Sets a transaction savepoint.
2802
@return always 0, that is, always succeeds */
2804
InnobaseEngine::doSetSavepoint(
2806
Session* session,/*!< in: handle to the MySQL thread */
2807
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2812
assert(this == innodb_engine_ptr);
2815
In the autocommit mode there is no sense to set a savepoint
2816
(unless we are in sub-statement), so SQL layer ensures that
2817
this method is never called in such situation.
2820
trx = check_trx_exists(session);
2822
/* Release a possible FIFO ticket and search latch. Since we will
2823
reserve the kernel mutex, we have to release the search system latch
2824
first to obey the latching order. */
2826
innobase_release_stat_resources(trx);
2828
/* cannot happen outside of transaction */
2829
assert(trx->conc_state != TRX_NOT_STARTED);
2831
error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2833
return(convert_error_code_to_mysql(error, 0, NULL));
2836
/*****************************************************************//**
2837
Frees a possible InnoDB trx object associated with the current Session.
2838
@return 0 or error number */
2840
InnobaseEngine::close_connection(
2841
/*======================*/
2842
Session* session)/*!< in: handle to the MySQL thread of the user
2843
whose resources should be free'd */
2847
assert(this == innodb_engine_ptr);
2848
trx = session_to_trx(session);
2852
assert(session->getKilled() != Session::NOT_KILLED ||
2853
trx->conc_state == TRX_NOT_STARTED);
2855
/* Warn if rolling back some things... */
2856
if (session->getKilled() != Session::NOT_KILLED &&
2857
trx->conc_state != TRX_NOT_STARTED &&
2859
global_system_variables.log_warnings)
2861
errmsg_printf(ERRMSG_LVL_WARN,
2862
"Drizzle is closing a connection during a KILL operation\n"
2863
"that has an active InnoDB transaction. %llu row modifications will "
2865
(ullint) trx->undo_no);
2868
innobase_rollback_trx(trx);
2870
thr_local_free(trx->mysql_thread_id);
2871
trx_free_for_mysql(trx);
2877
/*************************************************************************//**
2878
** InnoDB database tables
2879
*****************************************************************************/
2881
/****************************************************************//**
2882
Returns the index type. */
2885
ha_innobase::index_type(
2886
/*====================*/
2888
/*!< out: index type */
2893
/****************************************************************//**
2894
Returns the maximum number of keys.
2898
InnobaseEngine::max_supported_keys() const
2899
/*===================================*/
2904
/****************************************************************//**
2905
Returns the maximum key length.
2906
@return maximum supported key length, in bytes */
2909
InnobaseEngine::max_supported_key_length() const
2910
/*=========================================*/
2912
/* An InnoDB page must store >= 2 keys; a secondary key record
2913
must also contain the primary key value: max key length is
2914
therefore set to slightly less than 1 / 4 of page size which
2915
is 16 kB; but currently MySQL does not work with keys whose
2916
size is > MAX_KEY_LENGTH */
2920
/****************************************************************//**
2921
Returns the key map of keys that are usable for scanning.
2922
@return key_map_full */
2925
ha_innobase::keys_to_use_for_scanning()
2927
return(&key_map_full);
2931
/****************************************************************//**
2932
Determines if the primary key is clustered index.
2936
ha_innobase::primary_key_is_clustered()
2941
/*****************************************************************//**
2942
Normalizes a table name string. A normalized name consists of the
2943
database name catenated to '/' and table name. An example:
2944
test/mytable. On Windows normalization puts both the database name and the
2945
table name always to lower case. */
2948
normalize_table_name(
2949
/*=================*/
2950
char* norm_name, /*!< out: normalized name as a
2951
null-terminated string */
2952
const char* name) /*!< in: table name string */
2954
const char* name_ptr;
2958
/* Scan name from the end */
2960
ptr = strchr(name, '\0')-1;
2962
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2972
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2978
memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
2980
norm_name[name_ptr - db_ptr - 1] = '/';
2983
innobase_casedn_str(norm_name);
2987
/********************************************************************//**
2988
Get the upper limit of the MySQL integral and floating-point type.
2989
@return maximum allowed value for the field */
2992
innobase_get_int_col_max_value(
2993
/*===========================*/
2994
const Field* field) /*!< in: MySQL field */
2996
uint64_t max_value = 0;
2998
switch(field->key_type()) {
3000
case HA_KEYTYPE_BINARY:
3001
max_value = 0xFFULL;
3004
case HA_KEYTYPE_ULONG_INT:
3005
max_value = 0xFFFFFFFFULL;
3007
case HA_KEYTYPE_LONG_INT:
3008
max_value = 0x7FFFFFFFULL;
3011
case HA_KEYTYPE_ULONGLONG:
3012
max_value = 0xFFFFFFFFFFFFFFFFULL;
3014
case HA_KEYTYPE_LONGLONG:
3015
max_value = 0x7FFFFFFFFFFFFFFFULL;
3017
case HA_KEYTYPE_DOUBLE:
3018
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
3019
max_value = 0x20000000000000ULL;
3028
/*******************************************************************//**
3029
This function checks whether the index column information
3030
is consistent between KEY info from mysql and that from innodb index.
3031
@return TRUE if all column types match. */
3034
innobase_match_index_columns(
3035
/*=========================*/
3036
const KeyInfo* key_info, /*!< in: Index info
3038
const dict_index_t* index_info) /*!< in: Index info
3041
const KeyPartInfo* key_part;
3042
const KeyPartInfo* key_end;
3043
const dict_field_t* innodb_idx_fld;
3044
const dict_field_t* innodb_idx_fld_end;
3046
/* Check whether user defined index column count matches */
3047
if (key_info->key_parts != index_info->n_user_defined_cols) {
3051
key_part = key_info->key_part;
3052
key_end = key_part + key_info->key_parts;
3053
innodb_idx_fld = index_info->fields;
3054
innodb_idx_fld_end = index_info->fields + index_info->n_fields;
3056
/* Check each index column's datatype. We do not check
3057
column name because there exists case that index
3058
column name got modified in mysql but such change does not
3059
propagate to InnoDB.
3060
One hidden assumption here is that the index column sequences
3061
are matched up between those in mysql and Innodb. */
3062
for (; key_part != key_end; ++key_part) {
3065
ulint mtype = innodb_idx_fld->col->mtype;
3067
/* Need to translate to InnoDB column type before
3069
col_type = get_innobase_type_from_mysql_type(&is_unsigned,
3072
/* Ignore Innodb specific system columns. */
3073
while (mtype == DATA_SYS) {
3076
if (innodb_idx_fld >= innodb_idx_fld_end) {
3081
if (col_type != mtype) {
3082
/* Column Type mismatches */
3092
/*******************************************************************//**
3093
This function builds a translation table in INNOBASE_SHARE
3094
structure for fast index location with mysql array number from its
3095
table->key_info structure. This also provides the necessary translation
3096
between the key order in mysql key_info and Innodb ib_table->indexes if
3097
they are not fully matched with each other.
3098
Note we do not have any mutex protecting the translation table
3099
building based on the assumption that there is no concurrent
3100
index creation/drop and DMLs that requires index lookup. All table
3101
handle will be closed before the index creation/drop.
3102
@return TRUE if index translation table built successfully */
3105
innobase_build_index_translation(
3106
/*=============================*/
3107
const Table* table, /*!< in: table in MySQL data
3109
dict_table_t* ib_table, /*!< in: table in Innodb data
3111
INNOBASE_SHARE* share) /*!< in/out: share structure
3112
where index translation table
3113
will be constructed in. */
3115
ulint mysql_num_index;
3117
dict_index_t** index_mapping;
3120
mutex_enter(&dict_sys->mutex);
3122
mysql_num_index = table->getShare()->keys;
3123
ib_num_index = UT_LIST_GET_LEN(ib_table->indexes);
3125
index_mapping = share->idx_trans_tbl.index_mapping;
3127
/* If there exists inconsistency between MySQL and InnoDB dictionary
3128
(metadata) information, the number of index defined in MySQL
3129
could exceed that in InnoDB, do not build index translation
3130
table in such case */
3131
if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) {
3136
/* If index entry count is non-zero, nothing has
3137
changed since last update, directly return TRUE */
3138
if (share->idx_trans_tbl.index_count) {
3139
/* Index entry count should still match mysql_num_index */
3140
ut_a(share->idx_trans_tbl.index_count == mysql_num_index);
3144
/* The number of index increased, rebuild the mapping table */
3145
if (mysql_num_index > share->idx_trans_tbl.array_size) {
3146
index_mapping = (dict_index_t**) realloc(index_mapping,
3148
sizeof(*index_mapping));
3150
if (!index_mapping) {
3151
/* Report an error if index_mapping continues to be
3152
NULL and mysql_num_index is a non-zero value */
3153
errmsg_printf(ERRMSG_LVL_ERROR,
3154
"InnoDB: fail to allocate memory for "
3155
"index translation table. Number of "
3156
"Index:%lu, array size:%lu",
3158
share->idx_trans_tbl.array_size);
3163
share->idx_trans_tbl.array_size = mysql_num_index;
3166
/* For each index in the mysql key_info array, fetch its
3167
corresponding InnoDB index pointer into index_mapping
3169
for (ulint count = 0; count < mysql_num_index; count++) {
3171
/* Fetch index pointers into index_mapping according to mysql
3173
index_mapping[count] = dict_table_get_index_on_name(
3174
ib_table, table->key_info[count].name);
3176
if (!index_mapping[count]) {
3177
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find index %s in InnoDB "
3178
"index dictionary.",
3179
table->key_info[count].name);
3184
/* Double check fetched index has the same
3185
column info as those in mysql key_info. */
3186
if (!innobase_match_index_columns(&table->key_info[count],
3187
index_mapping[count])) {
3188
errmsg_printf(ERRMSG_LVL_ERROR, "Found index %s whose column info "
3189
"does not match that of MySQL.",
3190
table->key_info[count].name);
3196
/* Successfully built the translation table */
3197
share->idx_trans_tbl.index_count = mysql_num_index;
3201
/* Build translation table failed. */
3202
free(index_mapping);
3204
share->idx_trans_tbl.array_size = 0;
3205
share->idx_trans_tbl.index_count = 0;
3206
index_mapping = NULL;
3209
share->idx_trans_tbl.index_mapping = index_mapping;
3211
mutex_exit(&dict_sys->mutex);
3216
/*******************************************************************//**
3217
This function uses index translation table to quickly locate the
3218
requested index structure.
3219
Note we do not have mutex protection for the index translatoin table
3220
access, it is based on the assumption that there is no concurrent
3221
translation table rebuild (fter create/drop index) and DMLs that
3222
require index lookup.
3223
@return dict_index_t structure for requested index. NULL if
3224
fail to locate the index structure. */
3227
innobase_index_lookup(
3228
/*==================*/
3229
INNOBASE_SHARE* share, /*!< in: share structure for index
3230
translation table. */
3231
uint keynr) /*!< in: index number for the requested
3234
if (!share->idx_trans_tbl.index_mapping
3235
|| keynr >= share->idx_trans_tbl.index_count) {
3239
return(share->idx_trans_tbl.index_mapping[keynr]);
3242
/********************************************************************//**
3243
Set the autoinc column max value. This should only be called once from
3244
ha_innobase::open(). Therefore there's no need for a covering lock. */
3247
ha_innobase::innobase_initialize_autoinc()
3248
/*======================================*/
3251
const Field* field = getTable()->found_next_number_field;
3253
if (field != NULL) {
3254
auto_inc = innobase_get_int_col_max_value(field);
3256
/* We have no idea what's been passed in to us as the
3257
autoinc column. We set it to the 0, effectively disabling
3258
updates to the table. */
3261
ut_print_timestamp(stderr);
3262
fprintf(stderr, " InnoDB: Unable to determine the AUTOINC "
3266
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3267
/* If the recovery level is set so high that writes
3268
are disabled we force the AUTOINC counter to 0
3269
value effectively disabling writes to the table.
3270
Secondly, we avoid reading the table in case the read
3271
results in failure due to a corrupted table/index.
3273
We will not return an error to the client, so that the
3274
tables can be dumped with minimal hassle. If an error
3275
were returned in this case, the first attempt to read
3276
the table would fail and subsequent SELECTs would succeed. */
3278
} else if (field == NULL) {
3279
/* This is a far more serious error, best to avoid
3280
opening the table and return failure. */
3281
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
3283
dict_index_t* index;
3284
const char* col_name;
3285
uint64_t read_auto_inc;
3288
update_session(getTable()->in_use);
3289
col_name = field->field_name;
3291
ut_a(prebuilt->trx == session_to_trx(user_session));
3293
index = innobase_get_index(getTable()->getShare()->next_number_index);
3295
/* Execute SELECT MAX(col_name) FROM TABLE; */
3296
err = row_search_max_autoinc(index, col_name, &read_auto_inc);
3300
uint64_t col_max_value;
3302
col_max_value = innobase_get_int_col_max_value(field);
3304
/* At the this stage we do not know the increment
3305
nor the offset, so use a default increment of 1. */
3307
auto_inc = innobase_next_autoinc(read_auto_inc, 1, 1, col_max_value);
3311
case DB_RECORD_NOT_FOUND:
3312
ut_print_timestamp(stderr);
3313
fprintf(stderr, " InnoDB: MySQL and InnoDB data "
3314
"dictionaries are out of sync.\n"
3315
"InnoDB: Unable to find the AUTOINC column "
3316
"%s in the InnoDB table %s.\n"
3317
"InnoDB: We set the next AUTOINC column "
3319
"InnoDB: in effect disabling the AUTOINC "
3320
"next value generation.\n"
3321
"InnoDB: You can either set the next "
3322
"AUTOINC value explicitly using ALTER TABLE\n"
3323
"InnoDB: or fix the data dictionary by "
3324
"recreating the table.\n",
3325
col_name, index->table->name);
3327
/* This will disable the AUTOINC generation. */
3330
/* We want the open to succeed, so that the user can
3331
take corrective action. ie. reads should succeed but
3332
updates should fail. */
3336
/* row_search_max_autoinc() should only return
3337
one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
3342
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
3345
/*****************************************************************//**
3346
Creates and opens a handle to a table which already exists in an InnoDB
3348
@return 1 if error, 0 if success */
3351
ha_innobase::doOpen(const TableIdentifier &identifier,
3352
int mode, /*!< in: not used */
3353
uint test_if_locked) /*!< in: not used */
3355
dict_table_t* ib_table;
3356
char norm_name[FN_REFLEN];
3360
UT_NOT_USED(test_if_locked);
3362
session= getTable()->in_use;
3364
/* Under some cases Drizzle seems to call this function while
3365
holding btr_search_latch. This breaks the latching order as
3366
we acquire dict_sys->mutex below and leads to a deadlock. */
3367
if (session != NULL) {
3368
getTransactionalEngine()->releaseTemporaryLatches(session);
3371
normalize_table_name(norm_name, identifier.getPath().c_str());
3373
user_session = NULL;
3375
if (!(share=get_share(identifier.getPath().c_str()))) {
3380
/* Create buffers for packing the fields of a record. Why
3381
table->stored_rec_length did not work here? Obviously, because char
3382
fields when packed actually became 1 byte longer, when we also
3383
stored the string length as the first byte. */
3385
upd_and_key_val_buff_len =
3386
getTable()->getShare()->stored_rec_length
3387
+ getTable()->getShare()->max_key_length
3388
+ MAX_REF_PARTS * 3;
3390
upd_buff.resize(upd_and_key_val_buff_len);
3392
if (upd_buff.size() < upd_and_key_val_buff_len)
3397
key_val_buff.resize(upd_and_key_val_buff_len);
3398
if (key_val_buff.size() < upd_and_key_val_buff_len)
3403
/* Get pointer to a table object in InnoDB dictionary cache */
3404
ib_table = dict_table_get(norm_name, TRUE);
3406
if (NULL == ib_table) {
3407
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
3408
"the internal data dictionary of InnoDB "
3409
"though the .frm file for the\n"
3410
"table exists. Maybe you have deleted and "
3411
"recreated InnoDB data\n"
3412
"files but have forgotten to delete the "
3413
"corresponding .frm files\n"
3414
"of InnoDB tables, or you have moved .frm "
3415
"files to another database?\n"
3416
"or, the table contains indexes that this "
3417
"version of the engine\n"
3418
"doesn't support.\n"
3419
"See " REFMAN "innodb-troubleshooting.html\n"
3420
"how you can resolve the problem.\n",
3424
key_val_buff.resize(0);
3427
return(HA_ERR_NO_SUCH_TABLE);
3430
if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
3431
errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
3432
"the .ibd file for\ntable %s does not exist.\n"
3433
"Have you deleted the .ibd file from the "
3434
"database directory under\nthe MySQL datadir, "
3435
"or have you used DISCARD TABLESPACE?\n"
3436
"See " REFMAN "innodb-troubleshooting.html\n"
3437
"how you can resolve the problem.\n",
3441
key_val_buff.resize(0);
3444
dict_table_decrement_handle_count(ib_table, FALSE);
3445
return(HA_ERR_NO_SUCH_TABLE);
3448
prebuilt = row_create_prebuilt(ib_table);
3450
prebuilt->mysql_row_len = getTable()->getShare()->stored_rec_length;
3451
prebuilt->default_rec = getTable()->getDefaultValues();
3452
ut_ad(prebuilt->default_rec);
3454
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
3456
primary_key = getTable()->getShare()->getPrimaryKey();
3457
key_used_on_scan = primary_key;
3459
if (!innobase_build_index_translation(getTable(), ib_table, share)) {
3460
errmsg_printf(ERRMSG_LVL_ERROR, "Build InnoDB index translation table for"
3461
" Table %s failed", identifier.getPath().c_str());
3464
/* Allocate a buffer for a 'row reference'. A row reference is
3465
a string of bytes of length ref_length which uniquely specifies
3466
a row in our table. Note that MySQL may also compare two row
3467
references for equality by doing a simple memcmp on the strings
3468
of length ref_length! */
3470
if (!row_table_got_default_clust_index(ib_table)) {
3472
prebuilt->clust_index_was_generated = FALSE;
3474
if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
3475
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in "
3476
"InnoDB data dictionary, but not "
3477
"in MySQL!", identifier.getTableName().c_str());
3479
/* This mismatch could cause further problems
3480
if not attended, bring this to the user's attention
3481
by printing a warning in addition to log a message
3483
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3485
"InnoDB: Table %s has a "
3486
"primary key in InnoDB data "
3487
"dictionary, but not in "
3488
"MySQL!", identifier.getTableName().c_str());
3490
/* If primary_key >= MAX_KEY, its (primary_key)
3491
value could be out of bound if continue to index
3492
into key_info[] array. Find InnoDB primary index,
3493
and assign its key_length to ref_length.
3494
In addition, since MySQL indexes are sorted starting
3495
with primary index, unique index etc., initialize
3496
ref_length to the first index key length in
3497
case we fail to find InnoDB cluster index.
3499
Please note, this will not resolve the primary
3500
index mismatch problem, other side effects are
3501
possible if users continue to use the table.
3502
However, we allow this table to be opened so
3503
that user can adopt necessary measures for the
3504
mismatch while still being accessible to the table
3506
ref_length = getTable()->key_info[0].key_length;
3508
/* Find correspoinding cluster index
3509
key length in MySQL's key_info[] array */
3510
for (ulint i = 0; i < getTable()->getShare()->keys; i++) {
3511
dict_index_t* index;
3512
index = innobase_get_index(i);
3513
if (dict_index_is_clust(index)) {
3515
getTable()->key_info[i].key_length;
3519
/* MySQL allocates the buffer for ref.
3520
key_info->key_length includes space for all key
3521
columns + one byte for each column that may be
3522
NULL. ref_length must be as exact as possible to
3523
save space, because all row reference buffers are
3524
allocated based on ref_length. */
3526
ref_length = getTable()->key_info[primary_key].key_length;
3529
if (primary_key != MAX_KEY) {
3530
errmsg_printf(ERRMSG_LVL_ERROR,
3531
"Table %s has no primary key in InnoDB data "
3532
"dictionary, but has one in MySQL! If you "
3533
"created the table with a MySQL version < "
3534
"3.23.54 and did not define a primary key, "
3535
"but defined a unique key with all non-NULL "
3536
"columns, then MySQL internally treats that "
3537
"key as the primary key. You can fix this "
3538
"error by dump + DROP + CREATE + reimport "
3539
"of the table.", identifier.getTableName().c_str());
3541
/* This mismatch could cause further problems
3542
if not attended, bring this to the user attention
3543
by printing a warning in addition to log a message
3545
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3547
"InnoDB: Table %s has no "
3548
"primary key in InnoDB data "
3549
"dictionary, but has one in "
3550
"MySQL!", identifier.getTableName().c_str());
3553
prebuilt->clust_index_was_generated = TRUE;
3555
ref_length = DATA_ROW_ID_LEN;
3557
/* If we automatically created the clustered index, then
3558
MySQL does not know about it, and MySQL must NOT be aware
3559
of the index used on scan, to make it avoid checking if we
3560
update the column of the index. That is why we assert below
3561
that key_used_on_scan is the undefined value MAX_KEY.
3562
The column is the row id in the automatical generation case,
3563
and it will never be updated anyway. */
3565
if (key_used_on_scan != MAX_KEY) {
3566
errmsg_printf(ERRMSG_LVL_WARN,
3567
"Table %s key_used_on_scan is %lu even "
3568
"though there is no primary key inside "
3569
"InnoDB.", identifier.getTableName().c_str(), (ulong) key_used_on_scan);
3573
/* Index block size in InnoDB: used by MySQL in query optimization */
3574
stats.block_size = 16 * 1024;
3576
/* Init table lock structure */
3577
lock.init(&share->lock);
3579
if (prebuilt->table) {
3580
/* We update the highest file format in the system table
3581
space, if this table has higher file format setting. */
3583
char changed_file_format_max[100];
3584
strcpy(changed_file_format_max, innobase_file_format_max.c_str());
3585
trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
3586
dict_table_get_format(prebuilt->table));
3587
innobase_file_format_max= changed_file_format_max;
3590
/* Only if the table has an AUTOINC column. */
3591
if (prebuilt->table != NULL && getTable()->found_next_number_field != NULL) {
3593
dict_table_autoinc_lock(prebuilt->table);
3595
/* Since a table can already be "open" in InnoDB's internal
3596
data dictionary, we only init the autoinc counter once, the
3597
first time the table is loaded. We can safely reuse the
3598
autoinc value from a previous Drizzle open. */
3599
if (dict_table_autoinc_read(prebuilt->table) == 0) {
3601
innobase_initialize_autoinc();
3604
dict_table_autoinc_unlock(prebuilt->table);
3607
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
3614
InnobaseEngine::max_supported_key_part_length() const
3616
return(DICT_MAX_INDEX_COL_LEN - 1);
3619
/******************************************************************//**
3620
Closes a handle to an InnoDB table.
3624
ha_innobase::close(void)
3625
/*====================*/
3629
session= getTable()->in_use;
3630
if (session != NULL) {
3631
getTransactionalEngine()->releaseTemporaryLatches(session);
3634
row_prebuilt_free(prebuilt, FALSE);
3637
key_val_buff.clear();
3640
/* Tell InnoDB server that there might be work for
3643
srv_active_wake_master_thread();
3648
/* The following accessor functions should really be inside MySQL code! */
3650
/**************************************************************//**
3651
Gets field offset for a field in a table.
3657
Table* table, /*!< in: MySQL table object */
3658
Field* field) /*!< in: MySQL field object */
3660
return((uint) (field->ptr - table->getInsertRecord()));
3663
/**************************************************************//**
3664
Checks if a field in a record is SQL NULL. Uses the record format
3665
information in table to track the null bit in record.
3666
@return 1 if NULL, 0 otherwise */
3669
field_in_record_is_null(
3670
/*====================*/
3671
Table* table, /*!< in: MySQL table object */
3672
Field* field, /*!< in: MySQL field object */
3673
char* record) /*!< in: a row in MySQL format */
3677
if (!field->null_ptr) {
3682
null_offset = (uint) ((char*) field->null_ptr
3683
- (char*) table->getInsertRecord());
3685
if (record[null_offset] & field->null_bit) {
3693
/**************************************************************//**
3694
Sets a field in a record to SQL NULL. Uses the record format
3695
information in table to track the null bit in record. */
3698
set_field_in_record_to_null(
3699
/*========================*/
3700
Table* table, /*!< in: MySQL table object */
3701
Field* field, /*!< in: MySQL field object */
3702
char* record) /*!< in: a row in MySQL format */
3706
null_offset = (uint) ((char*) field->null_ptr
3707
- (char*) table->getInsertRecord());
3709
record[null_offset] = record[null_offset] | field->null_bit;
3712
/*************************************************************//**
3713
InnoDB uses this function to compare two data fields for which the data type
3714
is such that we must use MySQL code to compare them. NOTE that the prototype
3715
of this function is in rem0cmp.c in InnoDB source code! If you change this
3716
function, remember to update the prototype there!
3717
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
3718
extern "C" UNIV_INTERN
3722
int mysql_type, /*!< in: MySQL type */
3723
uint charset_number, /*!< in: number of the charset */
3724
const unsigned char* a, /*!< in: data field */
3725
unsigned int a_length, /*!< in: data field length,
3726
not UNIV_SQL_NULL */
3727
const unsigned char* b, /* in: data field */
3728
unsigned int b_length); /* in: data field length,
3729
not UNIV_SQL_NULL */
3734
/* out: 1, 0, -1, if a is greater, equal, less than b, respectively */
3735
int mysql_type, /* in: MySQL type */
3736
uint charset_number, /* in: number of the charset */
3737
const unsigned char* a, /* in: data field */
3738
unsigned int a_length, /* in: data field length, not UNIV_SQL_NULL */
3739
const unsigned char* b, /* in: data field */
3740
unsigned int b_length) /* in: data field length, not UNIV_SQL_NULL */
3742
const CHARSET_INFO* charset;
3743
enum_field_types mysql_tp;
3746
assert(a_length != UNIV_SQL_NULL);
3747
assert(b_length != UNIV_SQL_NULL);
3749
mysql_tp = (enum_field_types) mysql_type;
3753
case DRIZZLE_TYPE_BLOB:
3754
case DRIZZLE_TYPE_VARCHAR:
3755
/* Use the charset number to pick the right charset struct for
3756
the comparison. Since the MySQL function get_charset may be
3757
slow before Bar removes the mutex operation there, we first
3758
look at 2 common charsets directly. */
3760
if (charset_number == default_charset_info->number) {
3761
charset = default_charset_info;
3763
charset = get_charset(charset_number);
3765
if (charset == NULL) {
3766
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
3767
"a comparison, but MySQL cannot "
3768
"find that charset.",
3769
(ulong) charset_number);
3774
/* Starting from 4.1.3, we use strnncollsp() in comparisons of
3775
non-latin1_swedish_ci strings. NOTE that the collation order
3776
changes then: 'b\0\0...' is ordered BEFORE 'b ...'. Users
3777
having indexes on such data need to rebuild their tables! */
3779
ret = charset->coll->strnncollsp(charset,
3784
} else if (ret > 0) {
3796
/**************************************************************//**
3797
Converts a MySQL type to an InnoDB type. Note that this function returns
3798
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3799
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3800
@return DATA_BINARY, DATA_VARCHAR, ... */
3801
extern "C" UNIV_INTERN
3803
get_innobase_type_from_mysql_type(
3804
/*==============================*/
3805
ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
3807
at least ENUM and SET,
3808
and unsigned integer
3809
types are 'unsigned types' */
3810
const void* f) /*!< in: MySQL Field */
3812
const class Field* field = reinterpret_cast<const class Field*>(f);
3814
/* The following asserts try to check that the MySQL type code fits in
3815
8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3818
assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3820
if (field->flags & UNSIGNED_FLAG) {
3822
*unsigned_flag = DATA_UNSIGNED;
3827
if (field->real_type() == DRIZZLE_TYPE_ENUM)
3829
/* MySQL has field->type() a string type for these, but the
3830
data is actually internally stored as an unsigned integer
3833
*unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3834
flag set to zero, even though
3835
internally this is an unsigned
3840
switch (field->type()) {
3841
/* NOTE that we only allow string types in DATA_DRIZZLE and
3843
case DRIZZLE_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
3844
if (field->binary()) {
3845
return(DATA_BINARY);
3847
return(DATA_VARMYSQL);
3849
case DRIZZLE_TYPE_DECIMAL:
3850
return(DATA_FIXBINARY);
3851
case DRIZZLE_TYPE_LONG:
3852
case DRIZZLE_TYPE_LONGLONG:
3853
case DRIZZLE_TYPE_DATETIME:
3854
case DRIZZLE_TYPE_DATE:
3855
case DRIZZLE_TYPE_TIMESTAMP:
3856
case DRIZZLE_TYPE_ENUM:
3858
case DRIZZLE_TYPE_DOUBLE:
3859
return(DATA_DOUBLE);
3860
case DRIZZLE_TYPE_BLOB:
3862
case DRIZZLE_TYPE_UUID:
3863
return(DATA_FIXBINARY);
3864
case DRIZZLE_TYPE_NULL:
3871
/*******************************************************************//**
3872
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
3876
innobase_write_to_2_little_endian(
3877
/*==============================*/
3878
byte* buf, /*!< in: where to store */
3879
ulint val) /*!< in: value to write, must be < 64k */
3881
ut_a(val < 256 * 256);
3883
buf[0] = (byte)(val & 0xFF);
3884
buf[1] = (byte)(val / 256);
3887
/*******************************************************************//**
3888
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
3893
innobase_read_from_2_little_endian(
3894
/*===============================*/
3895
const unsigned char* buf) /*!< in: from where to read */
3897
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
3900
/*******************************************************************//**
3901
Stores a key value for a row to a buffer.
3902
@return key value length as stored in buff */
3905
ha_innobase::store_key_val_for_row(
3906
/*===============================*/
3907
uint keynr, /*!< in: key number */
3908
char* buff, /*!< in/out: buffer for the key value (in MySQL
3910
uint buff_len,/*!< in: buffer length */
3911
const unsigned char* record)/*!< in: row in MySQL format */
3913
KeyInfo* key_info = &getTable()->key_info[keynr];
3914
KeyPartInfo* key_part = key_info->key_part;
3915
KeyPartInfo* end = key_part + key_info->key_parts;
3916
char* buff_start = buff;
3917
enum_field_types mysql_type;
3921
/* The format for storing a key field in MySQL is the following:
3923
1. If the column can be NULL, then in the first byte we put 1 if the
3924
field value is NULL, 0 otherwise.
3926
2. If the column is of a BLOB type (it must be a column prefix field
3927
in this case), then we put the length of the data in the field to the
3928
next 2 bytes, in the little-endian format. If the field is SQL NULL,
3929
then these 2 bytes are set to 0. Note that the length of data in the
3930
field is <= column prefix length.
3932
3. In a column prefix field, prefix_len next bytes are reserved for
3933
data. In a normal field the max field length next bytes are reserved
3934
for data. For a VARCHAR(n) the max field length is n. If the stored
3935
value is the SQL NULL then these data bytes are set to 0.
3937
4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
3938
in the MySQL row format, the length is stored in 1 or 2 bytes,
3939
depending on the maximum allowed length. But in the MySQL key value
3940
format, the length always takes 2 bytes.
3942
We have to zero-fill the buffer so that MySQL is able to use a
3943
simple memcmp to compare two key values to determine if they are
3944
equal. MySQL does this to compare contents of two 'ref' values. */
3946
bzero(buff, buff_len);
3948
for (; key_part != end; key_part++) {
3951
if (key_part->null_bit) {
3952
if (record[key_part->null_offset]
3953
& key_part->null_bit) {
3962
field = key_part->field;
3963
mysql_type = field->type();
3965
if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
3966
/* >= 5.0.3 true VARCHAR */
3972
const CHARSET_INFO* cs;
3975
key_len = key_part->length;
3978
buff += key_len + 2;
3982
cs = field->charset();
3985
(((Field_varstring*)field)->pack_length_no_ptr());
3987
data = row_mysql_read_true_varchar(&len,
3989
+ (ulint)get_field_offset(getTable(), field)),
3994
/* For multi byte character sets we need to calculate
3995
the true length of the key */
3997
if (len > 0 && cs->mbmaxlen > 1) {
3998
true_len = (ulint) cs->cset->well_formed_len(cs,
3999
(const char *) data,
4000
(const char *) data + len,
4006
/* In a column prefix index, we may need to truncate
4007
the stored value: */
4009
if (true_len > key_len) {
4013
/* The length in a key value is always stored in 2
4016
row_mysql_store_true_var_len((byte*)buff, true_len, 2);
4019
memcpy(buff, data, true_len);
4021
/* Note that we always reserve the maximum possible
4022
length of the true VARCHAR in the key value, though
4023
only len first bytes after the 2 length bytes contain
4024
actual data. The rest of the space was reset to zero
4025
in the bzero() call above. */
4029
} else if (mysql_type == DRIZZLE_TYPE_BLOB) {
4031
const CHARSET_INFO* cs;
4036
const byte* blob_data;
4038
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
4040
key_len = key_part->length;
4043
buff += key_len + 2;
4048
cs = field->charset();
4050
blob_data = row_mysql_read_blob_ref(&blob_len,
4052
+ (ulint)get_field_offset(getTable(), field)),
4053
(ulint) field->pack_length());
4055
true_len = blob_len;
4057
ut_a(get_field_offset(getTable(), field)
4058
== key_part->offset);
4060
/* For multi byte character sets we need to calculate
4061
the true length of the key */
4063
if (blob_len > 0 && cs->mbmaxlen > 1) {
4064
true_len = (ulint) cs->cset->well_formed_len(cs,
4065
(const char *) blob_data,
4066
(const char *) blob_data
4073
/* All indexes on BLOB and TEXT are column prefix
4074
indexes, and we may need to truncate the data to be
4075
stored in the key value: */
4077
if (true_len > key_len) {
4081
/* MySQL reserves 2 bytes for the length and the
4082
storage of the number is little-endian */
4084
innobase_write_to_2_little_endian(
4085
(byte*)buff, true_len);
4088
memcpy(buff, blob_data, true_len);
4090
/* Note that we always reserve the maximum possible
4091
length of the BLOB prefix in the key value. */
4095
/* Here we handle all other data types except the
4096
true VARCHAR, BLOB and TEXT. Note that the column
4097
value we store may be also in a column prefix
4102
const unsigned char* src_start;
4103
enum_field_types real_type;
4104
const CHARSET_INFO* cs= field->charset();
4106
key_len = key_part->length;
4114
src_start = record + key_part->offset;
4115
real_type = field->real_type();
4118
/* Character set for the field is defined only
4119
to fields whose type is string and real field
4120
type is not enum or set. For these fields check
4121
if character set is multi byte. */
4123
memcpy(buff, src_start, true_len);
4126
/* Pad the unused space with spaces. */
4128
if (true_len < key_len) {
4129
ulint pad_len = key_len - true_len;
4130
ut_a(!(pad_len % cs->mbminlen));
4132
cs->cset->fill(cs, buff, pad_len,
4139
ut_a(buff <= buff_start + buff_len);
4141
return((uint)(buff - buff_start));
4144
/**************************************************************//**
4145
Builds a 'template' to the prebuilt struct. The template is used in fast
4146
retrieval of just those column values MySQL needs in its processing. */
4151
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
4152
Session* , /*!< in: current user thread, used
4153
only if templ_type is
4154
ROW_DRIZZLE_REC_FIELDS */
4155
Table* table, /*!< in: MySQL table */
4156
uint templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
4157
ROW_DRIZZLE_REC_FIELDS */
4159
dict_index_t* index;
4160
dict_index_t* clust_index;
4161
mysql_row_templ_t* templ;
4164
ulint n_requested_fields = 0;
4165
ibool fetch_all_in_key = FALSE;
4166
ibool fetch_primary_key_cols = FALSE;
4168
/* byte offset of the end of last requested column */
4169
ulint mysql_prefix_len = 0;
4171
if (prebuilt->select_lock_type == LOCK_X) {
4172
/* We always retrieve the whole clustered index record if we
4173
use exclusive row level locks, for example, if the read is
4174
done in an UPDATE statement. */
4176
templ_type = ROW_MYSQL_WHOLE_ROW;
4179
if (templ_type == ROW_MYSQL_REC_FIELDS) {
4180
if (prebuilt->hint_need_to_fetch_extra_cols
4181
== ROW_RETRIEVE_ALL_COLS) {
4183
/* We know we must at least fetch all columns in the
4184
key, or all columns in the table */
4186
if (prebuilt->read_just_key) {
4187
/* MySQL has instructed us that it is enough
4188
to fetch the columns in the key; looks like
4189
MySQL can set this flag also when there is
4190
only a prefix of the column in the key: in
4191
that case we retrieve the whole column from
4192
the clustered index */
4194
fetch_all_in_key = TRUE;
4196
templ_type = ROW_MYSQL_WHOLE_ROW;
4198
} else if (prebuilt->hint_need_to_fetch_extra_cols
4199
== ROW_RETRIEVE_PRIMARY_KEY) {
4200
/* We must at least fetch all primary key cols. Note
4201
that if the clustered index was internally generated
4202
by InnoDB on the row id (no primary key was
4203
defined), then row_search_for_mysql() will always
4204
retrieve the row id to a special buffer in the
4207
fetch_primary_key_cols = TRUE;
4211
clust_index = dict_table_get_first_index(prebuilt->table);
4213
if (templ_type == ROW_MYSQL_REC_FIELDS) {
4214
index = prebuilt->index;
4216
index = clust_index;
4219
if (index == clust_index) {
4220
prebuilt->need_to_access_clustered = TRUE;
4222
prebuilt->need_to_access_clustered = FALSE;
4223
/* Below we check column by column if we need to access
4224
the clustered index */
4227
n_fields = (ulint)table->getShare()->sizeFields(); /* number of columns */
4229
if (!prebuilt->mysql_template) {
4230
prebuilt->mysql_template = (mysql_row_templ_t*)
4231
mem_alloc(n_fields * sizeof(mysql_row_templ_t));
4234
prebuilt->template_type = templ_type;
4235
prebuilt->null_bitmap_len = table->getShare()->null_bytes;
4237
prebuilt->templ_contains_blob = FALSE;
4239
/* Note that in InnoDB, i is the column number. MySQL calls columns
4241
for (i = 0; i < n_fields; i++)
4243
const dict_col_t *col= &index->table->cols[i];
4244
templ = prebuilt->mysql_template + n_requested_fields;
4245
field = table->getField(i);
4247
if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
4248
/* Decide which columns we should fetch
4249
and which we can skip. */
4250
register const ibool index_contains_field =
4251
dict_index_contains_col_or_prefix(index, i);
4253
if (!index_contains_field && prebuilt->read_just_key) {
4254
/* If this is a 'key read', we do not need
4255
columns that are not in the key */
4260
if (index_contains_field && fetch_all_in_key) {
4261
/* This field is needed in the query */
4266
if (field->isReadSet() || field->isWriteSet())
4267
/* This field is needed in the query */
4270
assert(table->isReadSet(i) == field->isReadSet());
4271
assert(table->isWriteSet(i) == field->isWriteSet());
4273
if (fetch_primary_key_cols
4274
&& dict_table_col_in_clustered_key(
4276
/* This field is needed in the query */
4281
/* This field is not needed in the query, skip it */
4286
n_requested_fields++;
4290
if (index == clust_index) {
4291
templ->rec_field_no = dict_col_get_clust_pos(col, index);
4293
templ->rec_field_no = dict_index_get_nth_col_pos(
4297
if (templ->rec_field_no == ULINT_UNDEFINED) {
4298
prebuilt->need_to_access_clustered = TRUE;
4301
if (field->null_ptr) {
4302
templ->mysql_null_byte_offset =
4303
(ulint) ((char*) field->null_ptr
4304
- (char*) table->getInsertRecord());
4306
templ->mysql_null_bit_mask = (ulint) field->null_bit;
4308
templ->mysql_null_bit_mask = 0;
4311
templ->mysql_col_offset = (ulint)
4312
get_field_offset(table, field);
4314
templ->mysql_col_len = (ulint) field->pack_length();
4315
if (mysql_prefix_len < templ->mysql_col_offset
4316
+ templ->mysql_col_len) {
4317
mysql_prefix_len = templ->mysql_col_offset
4318
+ templ->mysql_col_len;
4320
templ->type = col->mtype;
4321
templ->mysql_type = (ulint)field->type();
4323
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
4324
templ->mysql_length_bytes = (ulint)
4325
(((Field_varstring*)field)->pack_length_no_ptr());
4328
templ->charset = dtype_get_charset_coll(col->prtype);
4329
templ->mbminlen = dict_col_get_mbminlen(col);
4330
templ->mbmaxlen = dict_col_get_mbmaxlen(col);
4331
templ->is_unsigned = col->prtype & DATA_UNSIGNED;
4332
if (templ->type == DATA_BLOB) {
4333
prebuilt->templ_contains_blob = TRUE;
4339
prebuilt->n_template = n_requested_fields;
4340
prebuilt->mysql_prefix_len = mysql_prefix_len;
4342
if (index != clust_index && prebuilt->need_to_access_clustered) {
4343
/* Change rec_field_no's to correspond to the clustered index
4345
for (i = 0; i < n_requested_fields; i++) {
4346
templ = prebuilt->mysql_template + i;
4348
templ->rec_field_no = dict_col_get_clust_pos(
4349
&index->table->cols[templ->col_no],
4355
/********************************************************************//**
4356
This special handling is really to overcome the limitations of MySQL's
4357
binlogging. We need to eliminate the non-determinism that will arise in
4358
INSERT ... SELECT type of statements, since MySQL binlog only stores the
4359
min value of the autoinc interval. Once that is fixed we can get rid of
4360
the special lock handling.
4361
@return DB_SUCCESS if all OK else error code */
4364
ha_innobase::innobase_lock_autoinc(void)
4365
/*====================================*/
4367
ulint error = DB_SUCCESS;
4369
dict_table_autoinc_lock(prebuilt->table);
4371
return(ulong(error));
4374
/********************************************************************//**
4375
Reset the autoinc value in the table.
4376
@return DB_SUCCESS if all went well else error code */
4379
ha_innobase::innobase_reset_autoinc(
4380
/*================================*/
4381
uint64_t autoinc) /*!< in: value to store */
4383
dict_table_autoinc_lock(prebuilt->table);
4384
dict_table_autoinc_initialize(prebuilt->table, autoinc);
4385
dict_table_autoinc_unlock(prebuilt->table);
4387
return(ulong(DB_SUCCESS));
4390
/********************************************************************//**
4391
Store the autoinc value in the table. The autoinc value is only set if
4392
it's greater than the existing autoinc value in the table.
4393
@return DB_SUCCESS if all went well else error code */
4396
ha_innobase::innobase_set_max_autoinc(
4397
/*==================================*/
4398
uint64_t auto_inc) /*!< in: value to store */
4400
dict_table_autoinc_lock(prebuilt->table);
4401
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4402
dict_table_autoinc_unlock(prebuilt->table);
4404
return(ulong(DB_SUCCESS));
4407
/********************************************************************//**
4408
Stores a row in an InnoDB database, to the table specified in this
4410
@return error code */
4413
ha_innobase::doInsertRecord(
4414
/*===================*/
4415
unsigned char* record) /*!< in: a row in MySQL format */
4418
int error_result= 0;
4419
ibool auto_inc_used= FALSE;
4421
trx_t* trx = session_to_trx(user_session);
4423
if (prebuilt->trx != trx) {
4424
errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
4425
"%p, but for the current thread it is at %p",
4426
(const void*) prebuilt->trx, (const void*) trx);
4428
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
4429
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
4431
"InnoDB: Dump of 200 bytes around ha_data: ",
4433
ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
4438
sql_command = session_sql_command(user_session);
4440
if ((sql_command == SQLCOM_ALTER_TABLE
4441
|| sql_command == SQLCOM_CREATE_INDEX
4442
|| sql_command == SQLCOM_DROP_INDEX)
4443
&& num_write_row >= 10000) {
4444
/* ALTER TABLE is COMMITted at every 10000 copied rows.
4445
The IX table lock for the original table has to be re-issued.
4446
As this method will be called on a temporary table where the
4447
contents of the original table is being copied to, it is
4448
a bit tricky to determine the source table. The cursor
4449
position in the source table need not be adjusted after the
4450
intermediate COMMIT, since writes by other transactions are
4451
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
4453
dict_table_t* src_table;
4454
enum lock_mode mode;
4458
/* Commit the transaction. This will release the table
4459
locks, so they have to be acquired again. */
4461
/* Altering an InnoDB table */
4462
/* Get the source table. */
4463
src_table = lock_get_src_table(
4464
prebuilt->trx, prebuilt->table, &mode);
4467
/* Unknown situation: do not commit */
4469
ut_print_timestamp(stderr);
4471
" InnoDB: ALTER TABLE is holding lock"
4472
" on %lu tables!\n",
4473
prebuilt->trx->mysql_n_tables_locked);
4476
} else if (src_table == prebuilt->table) {
4477
/* Source table is not in InnoDB format:
4478
no need to re-acquire locks on it. */
4480
/* Altering to InnoDB format */
4481
getTransactionalEngine()->commit(user_session, 1);
4482
/* We will need an IX lock on the destination table. */
4483
prebuilt->sql_stat_start = TRUE;
4485
/* Ensure that there are no other table locks than
4486
LOCK_IX and LOCK_AUTO_INC on the destination table. */
4488
if (!lock_is_table_exclusive(prebuilt->table,
4493
/* Commit the transaction. This will release the table
4494
locks, so they have to be acquired again. */
4495
getTransactionalEngine()->commit(user_session, 1);
4496
/* Re-acquire the table lock on the source table. */
4497
row_lock_table_for_mysql(prebuilt, src_table, mode);
4498
/* We will need an IX lock on the destination table. */
4499
prebuilt->sql_stat_start = TRUE;
4505
/* This is the case where the table has an auto-increment column */
4506
if (getTable()->next_number_field && record == getTable()->getInsertRecord()) {
4508
/* Reset the error code before calling
4509
innobase_get_auto_increment(). */
4510
prebuilt->autoinc_error = DB_SUCCESS;
4512
if ((error = update_auto_increment())) {
4513
/* We don't want to mask autoinc overflow errors. */
4515
/* Handle the case where the AUTOINC sub-system
4516
failed during initialization. */
4517
if (prebuilt->autoinc_error == DB_UNSUPPORTED) {
4518
error_result = ER_AUTOINC_READ_FAILED;
4519
/* Set the error message to report too. */
4520
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
4522
} else if (prebuilt->autoinc_error != DB_SUCCESS) {
4523
error = (int) prebuilt->autoinc_error;
4528
/* MySQL errors are passed straight back. */
4529
error_result = (int) error;
4533
auto_inc_used = TRUE;
4536
if (prebuilt->mysql_template == NULL
4537
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
4539
/* Build the template used in converting quickly between
4540
the two database formats */
4542
build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
4545
innodb_srv_conc_enter_innodb(prebuilt->trx);
4547
error = row_insert_for_mysql((byte*) record, prebuilt);
4549
user_session->setXaId(trx->id);
4551
/* Handle duplicate key errors */
4552
if (auto_inc_used) {
4555
uint64_t col_max_value;
4557
/* Note the number of rows processed for this statement, used
4558
by get_auto_increment() to determine the number of AUTO-INC
4559
values to reserve. This is only useful for a mult-value INSERT
4560
and is a statement level counter.*/
4561
if (trx->n_autoinc_rows > 0) {
4562
--trx->n_autoinc_rows;
4565
/* We need the upper limit of the col type to check for
4566
whether we update the table autoinc counter or not. */
4567
col_max_value = innobase_get_int_col_max_value(
4568
getTable()->next_number_field);
4569
/* Get the value that MySQL attempted to store in the table.*/
4570
auto_inc = getTable()->next_number_field->val_int();
4573
case DB_DUPLICATE_KEY:
4575
/* A REPLACE command and LOAD DATA INFILE REPLACE
4576
handle a duplicate key error themselves, but we
4577
must update the autoinc counter if we are performing
4578
those statements. */
4580
switch (sql_command) {
4582
if ((trx->duplicates
4583
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
4585
goto set_max_autoinc;
4589
case SQLCOM_REPLACE:
4590
case SQLCOM_INSERT_SELECT:
4591
case SQLCOM_REPLACE_SELECT:
4592
goto set_max_autoinc;
4601
/* If the actual value inserted is greater than
4602
the upper limit of the interval, then we try and
4603
update the table upper limit. Note: last_value
4604
will be 0 if get_auto_increment() was not called.*/
4606
if (auto_inc >= prebuilt->autoinc_last_value) {
4608
/* This should filter out the negative
4609
values set explicitly by the user. */
4610
if (auto_inc <= col_max_value) {
4611
ut_a(prebuilt->autoinc_increment > 0);
4616
offset = prebuilt->autoinc_offset;
4617
need = prebuilt->autoinc_increment;
4619
auto_inc = innobase_next_autoinc(
4621
need, offset, col_max_value);
4623
err = innobase_set_max_autoinc(
4626
if (err != DB_SUCCESS) {
4635
innodb_srv_conc_exit_innodb(prebuilt->trx);
4638
error_result = convert_error_code_to_mysql((int) error,
4639
prebuilt->table->flags,
4643
innobase_active_small();
4645
return(error_result);
4648
/**********************************************************************//**
4649
Checks which fields have changed in a row and stores information
4650
of them to an update vector.
4651
@return error number or 0 */
4654
calc_row_difference(
4655
/*================*/
4656
upd_t* uvect, /*!< in/out: update vector */
4657
unsigned char* old_row, /*!< in: old row in MySQL format */
4658
unsigned char* new_row, /*!< in: new row in MySQL format */
4659
Table* table, /*!< in: table in MySQL data
4661
unsigned char* upd_buff, /*!< in: buffer to use */
4662
ulint buff_len, /*!< in: buffer length */
4663
row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
4664
Session* ) /*!< in: user thread */
4666
unsigned char* original_upd_buff = upd_buff;
4667
enum_field_types field_mysql_type;
4672
const byte* new_mysql_row_col;
4676
upd_field_t* ufield;
4678
ulint n_changed = 0;
4680
dict_index_t* clust_index;
4683
n_fields = table->getShare()->sizeFields();
4684
clust_index = dict_table_get_first_index(prebuilt->table);
4686
/* We use upd_buff to convert changed fields */
4687
buf = (byte*) upd_buff;
4689
for (i = 0; i < n_fields; i++) {
4690
Field *field= table->getField(i);
4692
o_ptr = (const byte*) old_row + get_field_offset(table, field);
4693
n_ptr = (const byte*) new_row + get_field_offset(table, field);
4695
/* Use new_mysql_row_col and col_pack_len save the values */
4697
new_mysql_row_col = n_ptr;
4698
col_pack_len = field->pack_length();
4700
o_len = col_pack_len;
4701
n_len = col_pack_len;
4703
/* We use o_ptr and n_ptr to dig up the actual data for
4706
field_mysql_type = field->type();
4708
col_type = prebuilt->table->cols[i].mtype;
4713
o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4714
n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4721
if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4722
/* This is a >= 5.0.3 type true VARCHAR where
4723
the real payload data length is stored in
4726
o_ptr = row_mysql_read_true_varchar(
4729
(((Field_varstring*)field)->pack_length_no_ptr()));
4731
n_ptr = row_mysql_read_true_varchar(
4734
(((Field_varstring*)field)->pack_length_no_ptr()));
4742
if (field->null_ptr) {
4743
if (field_in_record_is_null(table, field,
4745
o_len = UNIV_SQL_NULL;
4748
if (field_in_record_is_null(table, field,
4750
n_len = UNIV_SQL_NULL;
4754
if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4755
0 != memcmp(o_ptr, n_ptr, o_len))) {
4756
/* The field has changed */
4758
ufield = uvect->fields + n_changed;
4760
/* Let us use a dummy dfield to make the conversion
4761
from the MySQL column format to the InnoDB format */
4763
dict_col_copy_type(prebuilt->table->cols + i,
4766
if (n_len != UNIV_SQL_NULL) {
4767
buf = row_mysql_store_col_in_innobase_format(
4773
dict_table_is_comp(prebuilt->table));
4774
dfield_copy_data(&ufield->new_val, &dfield);
4776
dfield_set_null(&ufield->new_val);
4780
ufield->orig_len = 0;
4781
ufield->field_no = dict_col_get_clust_pos(
4782
&prebuilt->table->cols[i], clust_index);
4787
uvect->n_fields = n_changed;
4788
uvect->info_bits = 0;
4790
ut_a(buf <= (byte*)original_upd_buff + buff_len);
4795
/**********************************************************************//**
4796
Updates a row given as a parameter to a new value. Note that we are given
4797
whole rows, not just the fields which are updated: this incurs some
4798
overhead for CPU when we check which fields are actually updated.
4799
TODO: currently InnoDB does not prevent the 'Halloween problem':
4800
in a searched update a single row can get updated several times
4801
if its index columns are updated!
4802
@return error number or 0 */
4805
ha_innobase::doUpdateRecord(
4806
/*====================*/
4807
const unsigned char* old_row,/*!< in: old row in MySQL format */
4808
unsigned char* new_row)/*!< in: new row in MySQL format */
4812
trx_t* trx = session_to_trx(user_session);
4814
ut_a(prebuilt->trx == trx);
4816
if (prebuilt->upd_node) {
4817
uvect = prebuilt->upd_node->update;
4819
uvect = row_get_prebuilt_update_vector(prebuilt);
4822
/* Build an update vector from the modified fields in the rows
4823
(uses upd_buff of the handle) */
4825
calc_row_difference(uvect, (unsigned char*) old_row, new_row, getTable(),
4826
&upd_buff[0], (ulint)upd_and_key_val_buff_len,
4827
prebuilt, user_session);
4829
/* This is not a delete */
4830
prebuilt->upd_node->is_delete = FALSE;
4832
ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4834
if (getTable()->found_next_number_field)
4837
uint64_t col_max_value;
4839
auto_inc = getTable()->found_next_number_field->val_int();
4841
/* We need the upper limit of the col type to check for
4842
whether we update the table autoinc counter or not. */
4843
col_max_value = innobase_get_int_col_max_value(
4844
getTable()->found_next_number_field);
4846
uint64_t current_autoinc;
4847
ulint autoinc_error= innobase_get_autoinc(¤t_autoinc);
4848
if (autoinc_error == DB_SUCCESS
4849
&& auto_inc <= col_max_value && auto_inc != 0
4850
&& auto_inc >= current_autoinc)
4856
offset = prebuilt->autoinc_offset;
4857
need = prebuilt->autoinc_increment;
4859
auto_inc = innobase_next_autoinc(
4860
auto_inc, need, offset, col_max_value);
4862
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4865
dict_table_autoinc_unlock(prebuilt->table);
4868
innodb_srv_conc_enter_innodb(trx);
4870
error = row_update_for_mysql((byte*) old_row, prebuilt);
4872
user_session->setXaId(trx->id);
4874
/* We need to do some special AUTOINC handling for the following case:
4876
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4878
We need to use the AUTOINC counter that was actually used by
4879
MySQL in the UPDATE statement, which can be different from the
4880
value used in the INSERT statement.*/
4882
if (error == DB_SUCCESS
4883
&& getTable()->next_number_field
4884
&& new_row == getTable()->getInsertRecord()
4885
&& session_sql_command(user_session) == SQLCOM_INSERT
4886
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
4887
== TRX_DUP_IGNORE) {
4890
uint64_t col_max_value;
4892
auto_inc = getTable()->next_number_field->val_int();
4894
/* We need the upper limit of the col type to check for
4895
whether we update the table autoinc counter or not. */
4896
col_max_value = innobase_get_int_col_max_value(
4897
getTable()->next_number_field);
4899
if (auto_inc <= col_max_value && auto_inc != 0) {
4904
offset = prebuilt->autoinc_offset;
4905
need = prebuilt->autoinc_increment;
4907
auto_inc = innobase_next_autoinc(
4908
auto_inc, need, offset, col_max_value);
4910
error = innobase_set_max_autoinc(auto_inc);
4914
innodb_srv_conc_exit_innodb(trx);
4916
error = convert_error_code_to_mysql(error,
4917
prebuilt->table->flags,
4920
if (error == 0 /* success */
4921
&& uvect->n_fields == 0 /* no columns were updated */) {
4923
/* This is the same as success, but instructs
4924
MySQL that the row is not really updated and it
4925
should not increase the count of updated rows.
4926
This is fix for http://bugs.mysql.com/29157 */
4927
error = HA_ERR_RECORD_IS_THE_SAME;
4930
/* Tell InnoDB server that there might be work for
4933
innobase_active_small();
4938
/**********************************************************************//**
4939
Deletes a row given as the parameter.
4940
@return error number or 0 */
4943
ha_innobase::doDeleteRecord(
4944
/*====================*/
4945
const unsigned char* record) /*!< in: a row in MySQL format */
4948
trx_t* trx = session_to_trx(user_session);
4950
ut_a(prebuilt->trx == trx);
4952
if (!prebuilt->upd_node) {
4953
row_get_prebuilt_update_vector(prebuilt);
4956
/* This is a delete */
4958
prebuilt->upd_node->is_delete = TRUE;
4960
innodb_srv_conc_enter_innodb(trx);
4962
error = row_update_for_mysql((byte*) record, prebuilt);
4964
user_session->setXaId(trx->id);
4966
innodb_srv_conc_exit_innodb(trx);
4968
error = convert_error_code_to_mysql(
4969
error, prebuilt->table->flags, user_session);
4971
/* Tell the InnoDB server that there might be work for
4974
innobase_active_small();
4979
/**********************************************************************//**
4980
Removes a new lock set on a row, if it was not read optimistically. This can
4981
be called after a row has been read in the processing of an UPDATE or a DELETE
4982
query, if the option innodb_locks_unsafe_for_binlog is set. */
4985
ha_innobase::unlock_row(void)
4986
/*=========================*/
4988
/* Consistent read does not take any locks, thus there is
4989
nothing to unlock. */
4991
if (prebuilt->select_lock_type == LOCK_NONE) {
4995
switch (prebuilt->row_read_type) {
4996
case ROW_READ_WITH_LOCKS:
4997
if (!srv_locks_unsafe_for_binlog
4998
&& prebuilt->trx->isolation_level
4999
> TRX_ISO_READ_COMMITTED) {
5003
case ROW_READ_TRY_SEMI_CONSISTENT:
5004
row_unlock_for_mysql(prebuilt, FALSE);
5006
case ROW_READ_DID_SEMI_CONSISTENT:
5007
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
5014
/* See Cursor.h and row0mysql.h for docs on this function. */
5017
ha_innobase::was_semi_consistent_read(void)
5018
/*=======================================*/
5020
return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
5023
/* See Cursor.h and row0mysql.h for docs on this function. */
5026
ha_innobase::try_semi_consistent_read(bool yes)
5027
/*===========================================*/
5029
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5031
/* Row read type is set to semi consistent read if this was
5032
requested by the MySQL and either innodb_locks_unsafe_for_binlog
5033
option is used or this session is using READ COMMITTED isolation
5037
&& (srv_locks_unsafe_for_binlog
5038
|| prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED)) {
5039
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
5041
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
5045
/******************************************************************//**
5046
Initializes a handle to use an index.
5047
@return 0 or error number */
5050
ha_innobase::doStartIndexScan(
5051
/*====================*/
5052
uint keynr, /*!< in: key (index) number */
5053
bool ) /*!< in: 1 if result MUST be sorted according to index */
5055
return(change_active_index(keynr));
5058
/******************************************************************//**
5059
Currently does nothing.
5063
ha_innobase::doEndIndexScan(void)
5064
/*========================*/
5067
active_index=MAX_KEY;
5071
/*********************************************************************//**
5072
Converts a search mode flag understood by MySQL to a flag understood
5076
convert_search_mode_to_innobase(
5077
/*============================*/
5078
enum ha_rkey_function find_flag)
5080
switch (find_flag) {
5081
case HA_READ_KEY_EXACT:
5082
/* this does not require the index to be UNIQUE */
5083
return(PAGE_CUR_GE);
5084
case HA_READ_KEY_OR_NEXT:
5085
return(PAGE_CUR_GE);
5086
case HA_READ_KEY_OR_PREV:
5087
return(PAGE_CUR_LE);
5088
case HA_READ_AFTER_KEY:
5090
case HA_READ_BEFORE_KEY:
5092
case HA_READ_PREFIX:
5093
return(PAGE_CUR_GE);
5094
case HA_READ_PREFIX_LAST:
5095
return(PAGE_CUR_LE);
5096
case HA_READ_PREFIX_LAST_OR_PREV:
5097
return(PAGE_CUR_LE);
5098
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
5099
pass a complete-field prefix of a key value as the search
5100
tuple. I.e., it is not allowed that the last field would
5101
just contain n first bytes of the full field value.
5102
MySQL uses a 'padding' trick to convert LIKE 'abc%'
5103
type queries so that it can use as a search tuple
5104
a complete-field-prefix of a key value. Thus, the InnoDB
5105
search mode PAGE_CUR_LE_OR_EXTENDS is never used.
5106
TODO: when/if MySQL starts to use also partial-field
5107
prefixes, we have to deal with stripping of spaces
5108
and comparison of non-latin1 char type fields in
5109
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
5111
case HA_READ_MBR_CONTAIN:
5112
case HA_READ_MBR_INTERSECT:
5113
case HA_READ_MBR_WITHIN:
5114
case HA_READ_MBR_DISJOINT:
5115
case HA_READ_MBR_EQUAL:
5116
return(PAGE_CUR_UNSUPP);
5117
/* do not use "default:" in order to produce a gcc warning:
5118
enumeration value '...' not handled in switch
5119
(if -Wswitch or -Wall is used) */
5122
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
5124
return(PAGE_CUR_UNSUPP);
5128
BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
5129
---------------------------------------------------
5130
The following does not cover all the details, but explains how we determine
5131
the start of a new SQL statement, and what is associated with it.
5133
For each table in the database the MySQL interpreter may have several
5134
table handle instances in use, also in a single SQL query. For each table
5135
handle instance there is an InnoDB 'prebuilt' struct which contains most
5136
of the InnoDB data associated with this table handle instance.
5138
A) if the user has not explicitly set any MySQL table level locks:
5140
1) Drizzle calls StorageEngine::doStartStatement(), indicating to
5141
InnoDB that a new SQL statement has begun.
5143
2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
5144
to set an 'intention' table level lock on the table of the Cursor instance.
5145
There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should
5146
be set true if we are taking this table handle instance to use in a new SQL
5147
statement issued by the user.
5149
2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
5150
instructions to prebuilt->template of the table handle instance in
5151
::index_read. The template is used to save CPU time in large joins.
5153
3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
5154
allocate a new consistent read view for the trx if it does not yet have one,
5155
or in the case of a locking read, set an InnoDB 'intention' table level
5158
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
5159
same table handle instance, if it is a join.
5161
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
5163
(a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter
5164
does NOT execute autocommit for pure read transactions, though it should.
5165
That is why we must execute the COMMIT in ::doEndStatement().
5166
(b) we also release possible 'SQL statement level resources' InnoDB may
5167
have for this SQL statement.
5171
Remove need for InnoDB to call autocommit for read-only trx
5173
@todo Check the below is still valid (I don't think it is...)
5175
B) If the user has explicitly set MySQL table level locks, then MySQL
5176
does NOT call ::external_lock at the start of the statement. To determine
5177
when we are at the start of a new SQL statement we at the start of
5178
::index_read also compare the query id to the latest query id where the
5179
table handle instance was used. If it has changed, we know we are at the
5180
start of a new SQL statement. Since the query id can theoretically
5181
overwrap, we use this test only as a secondary way of determining the
5182
start of a new SQL statement. */
5185
/**********************************************************************//**
5186
Positions an index cursor to the index specified in the handle. Fetches the
5188
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
5191
ha_innobase::index_read(
5192
/*====================*/
5193
unsigned char* buf, /*!< in/out: buffer for the returned
5195
const unsigned char* key_ptr,/*!< in: key value; if this is NULL
5196
we position the cursor at the
5197
start or end of index; this can
5198
also contain an InnoDB row id, in
5199
which case key_len is the InnoDB
5200
row id length; the key value can
5201
also be a prefix of a full key value,
5202
and the last column can be a prefix
5204
uint key_len,/*!< in: key value length */
5205
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5208
dict_index_t* index;
5209
ulint match_mode = 0;
5213
ut_a(prebuilt->trx == session_to_trx(user_session));
5215
ha_statistic_increment(&system_status_var::ha_read_key_count);
5217
index = prebuilt->index;
5219
if (UNIV_UNLIKELY(index == NULL)) {
5220
prebuilt->index_usable = FALSE;
5221
return(HA_ERR_CRASHED);
5224
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5225
return(HA_ERR_TABLE_DEF_CHANGED);
5228
/* Note that if the index for which the search template is built is not
5229
necessarily prebuilt->index, but can also be the clustered index */
5231
if (prebuilt->sql_stat_start) {
5232
build_template(prebuilt, user_session, getTable(),
5233
ROW_MYSQL_REC_FIELDS);
5237
/* Convert the search key value to InnoDB format into
5238
prebuilt->search_tuple */
5240
row_sel_convert_mysql_key_to_innobase(
5241
prebuilt->search_tuple,
5242
(byte*) &key_val_buff[0],
5243
(ulint)upd_and_key_val_buff_len,
5249
/* We position the cursor to the last or the first entry
5252
dtuple_set_n_fields(prebuilt->search_tuple, 0);
5255
mode = convert_search_mode_to_innobase(find_flag);
5259
if (find_flag == HA_READ_KEY_EXACT) {
5261
match_mode = ROW_SEL_EXACT;
5263
} else if (find_flag == HA_READ_PREFIX
5264
|| find_flag == HA_READ_PREFIX_LAST) {
5266
match_mode = ROW_SEL_EXACT_PREFIX;
5269
last_match_mode = (uint) match_mode;
5271
if (mode != PAGE_CUR_UNSUPP) {
5273
innodb_srv_conc_enter_innodb(prebuilt->trx);
5275
ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
5278
innodb_srv_conc_exit_innodb(prebuilt->trx);
5281
ret = DB_UNSUPPORTED;
5287
getTable()->status = 0;
5289
case DB_RECORD_NOT_FOUND:
5290
error = HA_ERR_KEY_NOT_FOUND;
5291
getTable()->status = STATUS_NOT_FOUND;
5293
case DB_END_OF_INDEX:
5294
error = HA_ERR_KEY_NOT_FOUND;
5295
getTable()->status = STATUS_NOT_FOUND;
5298
error = convert_error_code_to_mysql((int) ret,
5299
prebuilt->table->flags,
5301
getTable()->status = STATUS_NOT_FOUND;
5308
/*******************************************************************//**
5309
The following functions works like index_read, but it find the last
5310
row with the current key value or prefix.
5311
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
5314
ha_innobase::index_read_last(
5315
/*=========================*/
5316
unsigned char* buf, /*!< out: fetched row */
5317
const unsigned char* key_ptr,/*!< in: key value, or a prefix of a full
5319
uint key_len)/*!< in: length of the key val or prefix
5322
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
5325
/********************************************************************//**
5326
Get the index for a handle. Does not change active index.
5327
@return NULL or index instance. */
5330
ha_innobase::innobase_get_index(
5331
/*============================*/
5332
uint keynr) /*!< in: use this index; MAX_KEY means always
5333
clustered index, even if it was internally
5334
generated by InnoDB */
5336
dict_index_t* index = 0;
5338
ha_statistic_increment(&system_status_var::ha_read_key_count);
5340
if (keynr != MAX_KEY && getTable()->getShare()->sizeKeys() > 0)
5342
KeyInfo *key = getTable()->key_info + keynr;
5343
index = innobase_index_lookup(share, keynr);
5346
ut_a(ut_strcmp(index->name, key->name) == 0);
5348
/* Can't find index with keynr in the translation
5349
table. Only print message if the index translation
5351
if (share->idx_trans_tbl.index_mapping) {
5352
errmsg_printf(ERRMSG_LVL_ERROR,
5353
"InnoDB could not find "
5354
"index %s key no %u for "
5355
"table %s through its "
5356
"index translation table",
5357
key ? key->name : "NULL",
5359
prebuilt->table->name);
5362
index = dict_table_get_index_on_name(prebuilt->table,
5366
index = dict_table_get_first_index(prebuilt->table);
5370
errmsg_printf(ERRMSG_LVL_ERROR,
5371
"Innodb could not find key n:o %u with name %s "
5372
"from dict cache for table %s",
5373
keynr, getTable()->getShare()->getTableProto()->indexes(keynr).name().c_str(),
5374
prebuilt->table->name);
5380
/********************************************************************//**
5381
Changes the active index of a handle.
5382
@return 0 or error code */
5385
ha_innobase::change_active_index(
5386
/*=============================*/
5387
uint keynr) /*!< in: use this index; MAX_KEY means always clustered
5388
index, even if it was internally generated by
5391
ut_ad(user_session == table->in_use);
5392
ut_a(prebuilt->trx == session_to_trx(user_session));
5394
active_index = keynr;
5396
prebuilt->index = innobase_get_index(keynr);
5398
if (UNIV_UNLIKELY(!prebuilt->index)) {
5399
errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
5401
prebuilt->index_usable = FALSE;
5405
prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
5408
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5409
push_warning_printf(user_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5410
HA_ERR_TABLE_DEF_CHANGED,
5411
"InnoDB: insufficient history for index %u",
5413
/* The caller seems to ignore this. Thus, we must check
5414
this again in row_search_for_mysql(). */
5418
ut_a(prebuilt->search_tuple != 0);
5420
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
5422
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
5423
prebuilt->index->n_fields);
5425
/* MySQL changes the active index for a handle also during some
5426
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
5427
and then calculates the sum. Previously we played safe and used
5428
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
5429
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
5431
build_template(prebuilt, user_session, getTable(), ROW_MYSQL_REC_FIELDS);
5436
/**********************************************************************//**
5437
Positions an index cursor to the index specified in keynr. Fetches the
5439
??? This is only used to read whole keys ???
5440
@return error number or 0 */
5443
ha_innobase::index_read_idx(
5444
/*========================*/
5445
unsigned char* buf, /*!< in/out: buffer for the returned
5447
uint keynr, /*!< in: use this index */
5448
const unsigned char* key, /*!< in: key value; if this is NULL
5449
we position the cursor at the
5450
start or end of index */
5451
uint key_len, /*!< in: key value length */
5452
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5454
if (change_active_index(keynr)) {
5459
return(index_read(buf, key, key_len, find_flag));
5462
/***********************************************************************//**
5463
Reads the next or previous row from a cursor, which must have previously been
5464
positioned using index_read.
5465
@return 0, HA_ERR_END_OF_FILE, or error number */
5468
ha_innobase::general_fetch(
5469
/*=======================*/
5470
unsigned char* buf, /*!< in/out: buffer for next row in MySQL
5472
uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
5473
uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
5474
ROW_SEL_EXACT_PREFIX */
5479
ut_a(prebuilt->trx == session_to_trx(user_session));
5481
innodb_srv_conc_enter_innodb(prebuilt->trx);
5483
ret = row_search_for_mysql(
5484
(byte*)buf, 0, prebuilt, match_mode, direction);
5486
innodb_srv_conc_exit_innodb(prebuilt->trx);
5491
getTable()->status = 0;
5493
case DB_RECORD_NOT_FOUND:
5494
error = HA_ERR_END_OF_FILE;
5495
getTable()->status = STATUS_NOT_FOUND;
5497
case DB_END_OF_INDEX:
5498
error = HA_ERR_END_OF_FILE;
5499
getTable()->status = STATUS_NOT_FOUND;
5502
error = convert_error_code_to_mysql(
5503
(int) ret, prebuilt->table->flags, user_session);
5504
getTable()->status = STATUS_NOT_FOUND;
5511
/***********************************************************************//**
5512
Reads the next row from a cursor, which must have previously been
5513
positioned using index_read.
5514
@return 0, HA_ERR_END_OF_FILE, or error number */
5517
ha_innobase::index_next(
5518
/*====================*/
5519
unsigned char* buf) /*!< in/out: buffer for next row in MySQL
5522
ha_statistic_increment(&system_status_var::ha_read_next_count);
5524
return(general_fetch(buf, ROW_SEL_NEXT, 0));
5527
/*******************************************************************//**
5528
Reads the next row matching to the key value given as the parameter.
5529
@return 0, HA_ERR_END_OF_FILE, or error number */
5532
ha_innobase::index_next_same(
5533
/*=========================*/
5534
unsigned char* buf, /*!< in/out: buffer for the row */
5535
const unsigned char* , /*!< in: key value */
5536
uint ) /*!< in: key value length */
5538
ha_statistic_increment(&system_status_var::ha_read_next_count);
5540
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
5543
/***********************************************************************//**
5544
Reads the previous row from a cursor, which must have previously been
5545
positioned using index_read.
5546
@return 0, HA_ERR_END_OF_FILE, or error number */
5549
ha_innobase::index_prev(
5550
/*====================*/
5551
unsigned char* buf) /*!< in/out: buffer for previous row in MySQL format */
5553
ha_statistic_increment(&system_status_var::ha_read_prev_count);
5555
return(general_fetch(buf, ROW_SEL_PREV, 0));
5558
/********************************************************************//**
5559
Positions a cursor on the first record in an index and reads the
5560
corresponding row to buf.
5561
@return 0, HA_ERR_END_OF_FILE, or error code */
5564
ha_innobase::index_first(
5565
/*=====================*/
5566
unsigned char* buf) /*!< in/out: buffer for the row */
5570
ha_statistic_increment(&system_status_var::ha_read_first_count);
5572
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
5574
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5576
if (error == HA_ERR_KEY_NOT_FOUND) {
5577
error = HA_ERR_END_OF_FILE;
5583
/********************************************************************//**
5584
Positions a cursor on the last record in an index and reads the
5585
corresponding row to buf.
5586
@return 0, HA_ERR_END_OF_FILE, or error code */
5589
ha_innobase::index_last(
5590
/*====================*/
5591
unsigned char* buf) /*!< in/out: buffer for the row */
5595
ha_statistic_increment(&system_status_var::ha_read_last_count);
5597
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
5599
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5601
if (error == HA_ERR_KEY_NOT_FOUND) {
5602
error = HA_ERR_END_OF_FILE;
5608
/****************************************************************//**
5609
Initialize a table scan.
5610
@return 0 or error number */
5613
ha_innobase::doStartTableScan(
5614
/*==================*/
5615
bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
5619
/* Store the active index value so that we can restore the original
5620
value after a scan */
5622
if (prebuilt->clust_index_was_generated) {
5623
err = change_active_index(MAX_KEY);
5625
err = change_active_index(primary_key);
5628
/* Don't use semi-consistent read in random row reads (by position).
5629
This means we must disable semi_consistent_read if scan is false */
5632
try_semi_consistent_read(0);
5640
/*****************************************************************//**
5642
@return 0 or error number */
5645
ha_innobase::doEndTableScan(void)
5646
/*======================*/
5648
return(doEndIndexScan());
5651
/*****************************************************************//**
5652
Reads the next row in a table scan (also used to read the FIRST row
5654
@return 0, HA_ERR_END_OF_FILE, or error number */
5657
ha_innobase::rnd_next(
5658
/*==================*/
5659
unsigned char* buf) /*!< in/out: returns the row in this buffer,
5664
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
5666
if (start_of_scan) {
5667
error = index_first(buf);
5669
if (error == HA_ERR_KEY_NOT_FOUND) {
5670
error = HA_ERR_END_OF_FILE;
5675
error = general_fetch(buf, ROW_SEL_NEXT, 0);
5681
/**********************************************************************//**
5682
Fetches a row from the table based on a row reference.
5683
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
5686
ha_innobase::rnd_pos(
5687
/*=================*/
5688
unsigned char* buf, /*!< in/out: buffer for the row */
5689
unsigned char* pos) /*!< in: primary key value of the row in the
5690
MySQL format, or the row id if the clustered
5691
index was internally generated by InnoDB; the
5692
length of data in pos has to be ref_length */
5695
uint keynr = active_index;
5697
ha_statistic_increment(&system_status_var::ha_read_rnd_count);
5699
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5701
if (prebuilt->clust_index_was_generated) {
5702
/* No primary key was defined for the table and we
5703
generated the clustered index from the row id: the
5704
row reference is the row id, not any key value
5705
that MySQL knows of */
5707
error = change_active_index(MAX_KEY);
5709
error = change_active_index(primary_key);
5716
/* Note that we assume the length of the row reference is fixed
5717
for the table, and it is == ref_length */
5719
error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5724
change_active_index(keynr);
5729
/*********************************************************************//**
5730
Stores a reference to the current row to 'ref' field of the handle. Note
5731
that in the case where we have generated the clustered index for the
5732
table, the function parameter is illogical: we MUST ASSUME that 'record'
5733
is the current 'position' of the handle, because if row ref is actually
5734
the row id internally generated in InnoDB, then 'record' does not contain
5735
it. We just guess that the row id must be for the record where the handle
5736
was positioned the last time. */
5739
ha_innobase::position(
5740
/*==================*/
5741
const unsigned char* record) /*!< in: row in MySQL format */
5745
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5747
if (prebuilt->clust_index_was_generated) {
5748
/* No primary key was defined for the table and we
5749
generated the clustered index from row id: the
5750
row reference will be the row id, not any key value
5751
that MySQL knows of */
5753
len = DATA_ROW_ID_LEN;
5755
memcpy(ref, prebuilt->row_id, len);
5757
len = store_key_val_for_row(primary_key, (char*)ref,
5758
ref_length, record);
5761
/* We assume that the 'ref' value len is always fixed for the same
5764
if (len != ref_length) {
5765
errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
5766
(ulong) len, (ulong) ref_length);
5771
/*****************************************************************//**
5772
Creates a table definition to an InnoDB database. */
5777
trx_t* trx, /*!< in: InnoDB transaction handle */
5778
Table* form, /*!< in: information on table
5779
columns and indexes */
5780
const char* table_name, /*!< in: table name */
5781
const char* path_of_temp_table,/*!< in: if this is a table explicitly
5782
created by the user with the
5783
TEMPORARY keyword, then this
5784
parameter is the dir path where the
5785
table should be placed if we create
5786
an .ibd file for it (no .ibd extension
5787
in the path, though); otherwise this
5789
ulint flags) /*!< in: table flags */
5792
dict_table_t* table;
5797
ulint nulls_allowed;
5798
ulint unsigned_type;
5800
ulint long_true_varchar;
5804
n_cols = form->getShare()->sizeFields();
5806
/* We pass 0 as the space id, and determine at a lower level the space
5807
id where to store the table */
5809
table = dict_mem_table_create(table_name, 0, n_cols, flags);
5811
if (path_of_temp_table) {
5812
table->dir_path_of_temp_table =
5813
mem_heap_strdup(table->heap, path_of_temp_table);
5816
for (i = 0; i < n_cols; i++) {
5817
field = form->getField(i);
5819
col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5823
push_warning_printf(
5824
(Session*) trx->mysql_thd,
5825
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5826
ER_CANT_CREATE_TABLE,
5827
"Error creating table '%s' with "
5828
"column '%s'. Please check its "
5829
"column type and try to re-create "
5830
"the table with an appropriate "
5832
table->name, (char*) field->field_name);
5836
if (field->null_ptr) {
5839
nulls_allowed = DATA_NOT_NULL;
5842
if (field->binary()) {
5843
binary_type = DATA_BINARY_TYPE;
5850
if (dtype_is_string_type(col_type)) {
5852
charset_no = (ulint)field->charset()->number;
5854
if (UNIV_UNLIKELY(charset_no >= 256)) {
5855
/* in data0type.h we assume that the
5856
number fits in one byte in prtype */
5857
push_warning_printf(
5858
(Session*) trx->mysql_thd,
5859
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5860
ER_CANT_CREATE_TABLE,
5861
"In InnoDB, charset-collation codes"
5862
" must be below 256."
5863
" Unsupported code %lu.",
5864
(ulong) charset_no);
5865
return(ER_CANT_CREATE_TABLE);
5869
ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5870
that this fits in one byte */
5871
col_len = field->pack_length();
5873
/* The MySQL pack length contains 1 or 2 bytes length field
5874
for a true VARCHAR. Let us subtract that, so that the InnoDB
5875
column length in the InnoDB data dictionary is the real
5876
maximum byte length of the actual data. */
5878
long_true_varchar = 0;
5880
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5881
col_len -= ((Field_varstring*)field)->pack_length_no_ptr();
5883
if (((Field_varstring*)field)->pack_length_no_ptr() == 2) {
5884
long_true_varchar = DATA_LONG_TRUE_VARCHAR;
5888
/* First check whether the column to be added has a
5889
system reserved name. */
5890
if (dict_col_name_is_reserved(field->field_name)){
5891
my_error(ER_WRONG_COLUMN_NAME, MYF(0), field->field_name);
5894
dict_mem_table_free(table);
5895
trx_commit_for_mysql(trx);
5901
dict_mem_table_add_col(table, table->heap,
5902
(char*) field->field_name,
5905
(ulint)field->type()
5906
| nulls_allowed | unsigned_type
5907
| binary_type | long_true_varchar,
5912
error = row_create_table_for_mysql(table, trx);
5914
if (error == DB_DUPLICATE_KEY) {
5916
char* buf_end = innobase_convert_identifier(
5917
buf, sizeof buf - 1, table_name, strlen(table_name),
5918
trx->mysql_thd, TRUE);
5921
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf);
5925
error = convert_error_code_to_mysql(error, flags, NULL);
5930
/*****************************************************************//**
5931
Creates an index in an InnoDB database. */
5936
trx_t* trx, /*!< in: InnoDB transaction handle */
5937
Table* form, /*!< in: information on table
5938
columns and indexes */
5939
ulint flags, /*!< in: InnoDB table flags */
5940
const char* table_name, /*!< in: table name */
5941
uint key_num) /*!< in: index number */
5944
dict_index_t* index;
5948
KeyPartInfo* key_part;
5955
ulint* field_lengths;
5957
key = &form->key_info[key_num];
5959
n_fields = key->key_parts;
5961
/* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */
5962
ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0);
5966
if (key_num == form->getShare()->getPrimaryKey()) {
5967
ind_type = ind_type | DICT_CLUSTERED;
5970
if (key->flags & HA_NOSAME ) {
5971
ind_type = ind_type | DICT_UNIQUE;
5974
/* We pass 0 as the space id, and determine at a lower level the space
5975
id where to store the table */
5977
index = dict_mem_index_create(table_name, key->name, 0,
5978
ind_type, n_fields);
5980
field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
5982
for (i = 0; i < n_fields; i++) {
5983
key_part = key->key_part + i;
5985
/* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
5986
field in an index: we only store a specified number of first
5987
bytes of the column to the index field.) The flag does not
5988
seem to be properly set by MySQL. Let us fall back on testing
5989
the length of the key part versus the column. */
5992
for (j = 0; j < form->getShare()->sizeFields(); j++)
5995
field = form->getField(j);
5997
if (0 == innobase_strcasecmp(
5999
key_part->field->field_name)) {
6000
/* Found the corresponding column */
6006
ut_a(j < form->getShare()->sizeFields());
6008
col_type = get_innobase_type_from_mysql_type(
6009
&is_unsigned, key_part->field);
6011
if (DATA_BLOB == col_type
6012
|| (key_part->length < field->pack_length()
6013
&& field->type() != DRIZZLE_TYPE_VARCHAR)
6014
|| (field->type() == DRIZZLE_TYPE_VARCHAR
6015
&& key_part->length < field->pack_length()
6016
- ((Field_varstring*)field)->pack_length_no_ptr())) {
6018
prefix_len = key_part->length;
6020
if (col_type == DATA_INT
6021
|| col_type == DATA_FLOAT
6022
|| col_type == DATA_DOUBLE
6023
|| col_type == DATA_DECIMAL) {
6024
errmsg_printf(ERRMSG_LVL_ERROR,
6025
"MySQL is trying to create a column "
6026
"prefix index field, on an "
6027
"inappropriate data type. Table "
6028
"name %s, column name %s.",
6030
key_part->field->field_name);
6038
field_lengths[i] = key_part->length;
6040
dict_mem_index_add_field(index,
6041
(char*) key_part->field->field_name, prefix_len);
6044
/* Even though we've defined max_supported_key_part_length, we
6045
still do our own checking using field_lengths to be absolutely
6046
sure we don't create too long indexes. */
6047
error = row_create_index_for_mysql(index, trx, field_lengths);
6049
error = convert_error_code_to_mysql(error, flags, NULL);
6051
free(field_lengths);
6056
/*****************************************************************//**
6057
Creates an index to an InnoDB table when the user has defined no
6061
create_clustered_index_when_no_primary(
6062
/*===================================*/
6063
trx_t* trx, /*!< in: InnoDB transaction handle */
6064
ulint flags, /*!< in: InnoDB table flags */
6065
const char* table_name) /*!< in: table name */
6067
dict_index_t* index;
6070
/* We pass 0 as the space id, and determine at a lower level the space
6071
id where to store the table */
6073
index = dict_mem_index_create(table_name,
6074
innobase_index_reserve_name,
6075
0, DICT_CLUSTERED, 0);
6077
error = row_create_index_for_mysql(index, trx, NULL);
6079
error = convert_error_code_to_mysql(error, flags, NULL);
6084
/*****************************************************************//**
6085
Validates the create options. We may build on this function
6086
in future. For now, it checks two specifiers:
6087
KEY_BLOCK_SIZE and ROW_FORMAT
6088
If innodb_strict_mode is not set then this function is a no-op
6089
@return TRUE if valid. */
6093
create_options_are_valid(
6094
/*=====================*/
6095
Session* session, /*!< in: connection thread. */
6096
Table& form, /*!< in: information on table
6097
columns and indexes */
6098
message::Table& create_proto)
6100
ibool kbs_specified = FALSE;
6104
ut_ad(session != NULL);
6106
/* If innodb_strict_mode is not set don't do any validation. */
6107
if (!(SessionVAR(session, strict_mode))) {
6111
/* Now check for ROW_FORMAT specifier. */
6116
/*********************************************************************
6117
Creates a new table to an InnoDB database. */
6120
InnobaseEngine::doCreateTable(
6121
/*================*/
6122
Session &session, /*!< in: Session */
6123
Table& form, /*!< in: information on table columns and indexes */
6124
const TableIdentifier &identifier,
6125
message::Table& create_proto)
6128
dict_table_t* innobase_table;
6133
char name2[FN_REFLEN];
6134
char norm_name[FN_REFLEN];
6135
ib_int64_t auto_inc_value;
6137
/* Cache the value of innodb_file_format, in case it is
6138
modified by another thread while the table is being created. */
6139
const ulint file_format = srv_file_format;
6140
bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
6144
const char *table_name= identifier.getPath().c_str();
6146
if (form.getShare()->sizeFields() > 1000) {
6147
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
6148
but we play safe here */
6150
return(HA_ERR_TO_BIG_ROW);
6153
/* Get the transaction associated with the current session, or create one
6154
if not yet created */
6156
parent_trx = check_trx_exists(&session);
6158
/* In case MySQL calls this in the middle of a SELECT query, release
6159
possible adaptive hash latch to avoid deadlocks of threads */
6161
trx_search_latch_release_if_reserved(parent_trx);
6163
trx = innobase_trx_allocate(&session);
6165
srv_lower_case_table_names = TRUE;
6167
strcpy(name2, table_name);
6169
normalize_table_name(norm_name, name2);
6171
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
6172
or lock waits can happen in it during a table create operation.
6173
Drop table etc. do this latching in row0mysql.c. */
6175
row_mysql_lock_data_dictionary(trx);
6177
/* Create the table definition in InnoDB */
6181
#if 0 // Since we validate the options before this stage, we no longer need to do this.
6182
/* Validate create options if innodb_strict_mode is set. */
6183
if (! create_options_are_valid(&session, form, create_proto)) {
6184
error = ER_ILLEGAL_HA_CREATE_OPTION;
6189
// We assume compact format by default
6190
iflags= DICT_TF_COMPACT;
6192
size_t num_engine_options= create_proto.engine().options_size();
6193
for (size_t x= 0; x < num_engine_options; ++x)
6195
if (boost::iequals(create_proto.engine().options(x).name(), "ROW_FORMAT"))
6197
if (boost::iequals(create_proto.engine().options(x).state(), "COMPRESSED"))
6199
iflags= DICT_TF_FORMAT_ZIP;
6201
else if (boost::iequals(create_proto.engine().options(x).state(), "COMPACT"))
6203
iflags= DICT_TF_FORMAT_ZIP;
6205
else if (boost::iequals(create_proto.engine().options(x).state(), "DYNAMIC"))
6207
iflags= DICT_TF_COMPACT;
6209
else if (boost::iequals(create_proto.engine().options(x).state(), "REDUNDANT"))
6211
iflags= DICT_TF_COMPACT;
6216
assert(0); // This should never happen since we have already validated the options.
6220
if (iflags == DICT_TF_FORMAT_ZIP)
6223
ROW_FORMAT=COMPRESSED without KEY_BLOCK_SIZE implies half the maximum KEY_BLOCK_SIZE.
6224
@todo implement KEY_BLOCK_SIZE
6226
iflags= (DICT_TF_ZSSIZE_MAX - 1)
6227
<< DICT_TF_ZSSIZE_SHIFT
6229
| DICT_TF_FORMAT_ZIP
6230
<< DICT_TF_FORMAT_SHIFT;
6231
#if DICT_TF_ZSSIZE_MAX < 1
6232
# error "DICT_TF_ZSSIZE_MAX < 1"
6237
if (! srv_file_per_table)
6239
push_warning_printf(
6241
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6242
ER_ILLEGAL_HA_CREATE_OPTION,
6243
"InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.");
6245
else if (file_format < DICT_TF_FORMAT_ZIP)
6247
push_warning_printf(
6249
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6250
ER_ILLEGAL_HA_CREATE_OPTION,
6251
"InnoDB: ROW_FORMAT=compressed requires innodb_file_format > Antelope.");
6256
/* Look for a primary key */
6258
primary_key_no= (form.getShare()->hasPrimaryKey() ?
6259
(int) form.getShare()->getPrimaryKey() :
6262
/* Our function innobase_get_mysql_key_number_for_index assumes
6263
the primary key is always number 0, if it exists */
6265
assert(primary_key_no == -1 || primary_key_no == 0);
6267
/* Check for name conflicts (with reserved name) for
6268
any user indices to be created. */
6269
if (innobase_index_name_is_reserved(trx, form.key_info,
6270
form.getShare()->keys)) {
6275
if (lex_identified_temp_table)
6276
iflags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
6278
error= create_table_def(trx, &form, norm_name,
6279
lex_identified_temp_table ? name2 : NULL,
6282
session.setXaId(trx->id);
6288
/* Create the keys */
6290
if (form.getShare()->sizeKeys() == 0 || primary_key_no == -1) {
6291
/* Create an index which is used as the clustered index;
6292
order the rows by their row id which is internally generated
6295
error = create_clustered_index_when_no_primary(trx, iflags, norm_name);
6301
if (primary_key_no != -1) {
6302
/* In InnoDB the clustered index must always be created first */
6303
if ((error = create_index(trx, &form, iflags, norm_name,
6304
(uint) primary_key_no))) {
6309
for (i = 0; i < form.getShare()->sizeKeys(); i++) {
6310
if (i != (uint) primary_key_no) {
6312
if ((error = create_index(trx, &form, iflags, norm_name,
6319
stmt = innobase_get_stmt(&session, &stmt_len);
6322
string generated_create_table;
6323
const char *query= stmt;
6325
if (session_sql_command(&session) == SQLCOM_CREATE_TABLE)
6327
message::transformTableDefinitionToSql(create_proto,
6328
generated_create_table,
6329
message::DRIZZLE, true);
6330
query= generated_create_table.c_str();
6333
error = row_table_add_foreign_constraints(trx,
6334
query, strlen(query),
6336
lex_identified_temp_table);
6338
error = convert_error_code_to_mysql(error, iflags, NULL);
6345
innobase_commit_low(trx);
6347
row_mysql_unlock_data_dictionary(trx);
6349
/* Flush the log to reduce probability that the .frm files and
6350
the InnoDB data dictionary get out-of-sync if the user runs
6351
with innodb_flush_log_at_trx_commit = 0 */
6353
log_buffer_flush_to_disk();
6355
innobase_table = dict_table_get(norm_name, FALSE);
6357
assert(innobase_table != 0);
6359
if (innobase_table) {
6360
/* We update the highest file format in the system table
6361
space, if this table has higher file format setting. */
6363
char changed_file_format_max[100];
6364
strcpy(changed_file_format_max, innobase_file_format_max.c_str());
6365
trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
6366
dict_table_get_format(innobase_table));
6367
innobase_file_format_max= changed_file_format_max;
6370
/* Note: We can't call update_session() as prebuilt will not be
6371
setup at this stage and so we use session. */
6373
/* We need to copy the AUTOINC value from the old table if
6374
this is an ALTER TABLE or CREATE INDEX because CREATE INDEX
6375
does a table copy too. */
6377
if ((create_proto.options().has_auto_increment_value()
6378
|| session_sql_command(&session) == SQLCOM_ALTER_TABLE
6379
|| session_sql_command(&session) == SQLCOM_CREATE_INDEX)
6380
&& create_proto.options().auto_increment_value() != 0) {
6382
/* Query was one of :
6383
CREATE TABLE ...AUTO_INCREMENT = x; or
6384
ALTER TABLE...AUTO_INCREMENT = x; or
6385
CREATE INDEX x on t(...);
6386
Find out a table definition from the dictionary and get
6387
the current value of the auto increment field. Set a new
6388
value to the auto increment field if the value is greater
6389
than the maximum value in the column. */
6391
auto_inc_value = create_proto.options().auto_increment_value();
6393
dict_table_autoinc_lock(innobase_table);
6394
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
6395
dict_table_autoinc_unlock(innobase_table);
6398
/* Tell the InnoDB server that there might be work for
6401
srv_active_wake_master_thread();
6403
trx_free_for_mysql(trx);
6405
if (lex_identified_temp_table)
6407
session.getMessageCache().storeTableMessage(identifier, create_proto);
6411
StorageEngine::writeDefinitionFromPath(identifier, create_proto);
6417
innobase_commit_low(trx);
6419
row_mysql_unlock_data_dictionary(trx);
6421
trx_free_for_mysql(trx);
6426
/*****************************************************************//**
6427
Discards or imports an InnoDB tablespace.
6428
@return 0 == success, -1 == error */
6431
ha_innobase::discard_or_import_tablespace(
6432
/*======================================*/
6433
my_bool discard) /*!< in: TRUE if discard, else import */
6435
dict_table_t* dict_table;
6439
ut_a(prebuilt->trx);
6440
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6441
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6443
dict_table = prebuilt->table;
6444
trx = prebuilt->trx;
6447
err = row_discard_tablespace_for_mysql(dict_table->name, trx);
6449
err = row_import_tablespace_for_mysql(dict_table->name, trx);
6452
err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
6457
/*****************************************************************//**
6458
Deletes all rows of an InnoDB table.
6459
@return error number */
6462
ha_innobase::delete_all_rows(void)
6463
/*==============================*/
6467
/* Get the transaction associated with the current session, or create one
6468
if not yet created, and update prebuilt->trx */
6470
update_session(getTable()->in_use);
6472
if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
6474
/* We only handle TRUNCATE TABLE t as a special case.
6475
DELETE FROM t will have to use ha_innobase::doDeleteRecord(),
6476
because DELETE is transactional while TRUNCATE is not. */
6477
return(errno=HA_ERR_WRONG_COMMAND);
6480
/* Truncate the table in InnoDB */
6482
error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
6483
if (error == DB_ERROR) {
6484
/* Cannot truncate; resort to ha_innobase::doDeleteRecord() */
6488
error = convert_error_code_to_mysql(error, prebuilt->table->flags,
6494
/*****************************************************************//**
6495
Drops a table from an InnoDB database. Before calling this function,
6496
MySQL calls innobase_commit to commit the transaction of the current user.
6497
Then the current user cannot have locks set on the table. Drop table
6498
operation inside InnoDB will remove all locks any user has on the table
6500
@return error number */
6503
InnobaseEngine::doDropTable(
6504
/*======================*/
6506
const TableIdentifier &identifier)
6511
char norm_name[1000];
6513
ut_a(identifier.getPath().length() < 1000);
6515
/* Strangely, MySQL passes the table name without the '.frm'
6516
extension, in contrast to ::create */
6517
normalize_table_name(norm_name, identifier.getPath().c_str());
6519
/* Get the transaction associated with the current session, or create one
6520
if not yet created */
6522
parent_trx = check_trx_exists(&session);
6524
/* In case MySQL calls this in the middle of a SELECT query, release
6525
possible adaptive hash latch to avoid deadlocks of threads */
6527
trx_search_latch_release_if_reserved(parent_trx);
6529
trx = innobase_trx_allocate(&session);
6531
srv_lower_case_table_names = TRUE;
6533
/* Drop the table in InnoDB */
6535
error = row_drop_table_for_mysql(norm_name, trx,
6536
session_sql_command(&session)
6539
session.setXaId(trx->id);
6541
/* Flush the log to reduce probability that the .frm files and
6542
the InnoDB data dictionary get out-of-sync if the user runs
6543
with innodb_flush_log_at_trx_commit = 0 */
6545
log_buffer_flush_to_disk();
6547
/* Tell the InnoDB server that there might be work for
6550
srv_active_wake_master_thread();
6552
innobase_commit_low(trx);
6554
trx_free_for_mysql(trx);
6556
if (error != ENOENT)
6557
error = convert_error_code_to_mysql(error, 0, NULL);
6559
if (error == 0 || error == ENOENT)
6561
if (identifier.getType() == message::Table::TEMPORARY)
6563
session.getMessageCache().removeTableMessage(identifier);
6564
ulint sql_command = session_sql_command(&session);
6566
// If this was the final removal to an alter table then we will need
6567
// to remove the .dfe that was left behind.
6568
if ((sql_command == SQLCOM_ALTER_TABLE
6569
|| sql_command == SQLCOM_CREATE_INDEX
6570
|| sql_command == SQLCOM_DROP_INDEX))
6572
string path(identifier.getPath());
6574
path.append(DEFAULT_FILE_EXTENSION);
6576
(void)internal::my_delete(path.c_str(), MYF(0));
6581
string path(identifier.getPath());
6583
path.append(DEFAULT_FILE_EXTENSION);
6585
(void)internal::my_delete(path.c_str(), MYF(0));
6592
/*****************************************************************//**
6593
Removes all tables in the named database inside InnoDB. */
6595
InnobaseEngine::doDropSchema(
6596
/*===================*/
6597
const SchemaIdentifier &identifier)
6598
/*!< in: database path; inside InnoDB the name
6599
of the last directory in the path is used as
6600
the database name: for example, in 'mysql/data/test'
6601
the database name is 'test' */
6605
string schema_path(identifier.getPath());
6606
Session* session = current_session;
6608
/* Get the transaction associated with the current session, or create one
6609
if not yet created */
6611
assert(this == innodb_engine_ptr);
6613
/* In the Windows plugin, session = current_session is always NULL */
6615
trx_t* parent_trx = check_trx_exists(session);
6617
/* In case Drizzle calls this in the middle of a SELECT
6618
query, release possible adaptive hash latch to avoid
6619
deadlocks of threads */
6621
trx_search_latch_release_if_reserved(parent_trx);
6624
schema_path.append("/");
6625
trx = innobase_trx_allocate(session);
6626
error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6628
/* Flush the log to reduce probability that the .frm files and
6629
the InnoDB data dictionary get out-of-sync if the user runs
6630
with innodb_flush_log_at_trx_commit = 0 */
6632
log_buffer_flush_to_disk();
6634
/* Tell the InnoDB server that there might be work for
6637
srv_active_wake_master_thread();
6639
innobase_commit_low(trx);
6640
trx_free_for_mysql(trx);
6642
return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement.
6645
void InnobaseEngine::dropTemporarySchema()
6647
SchemaIdentifier schema_identifier(GLOBAL_TEMPORARY_EXT);
6649
string schema_path(GLOBAL_TEMPORARY_EXT);
6651
schema_path.append("/");
6653
trx = trx_allocate_for_mysql();
6655
trx->mysql_thd = NULL;
6657
trx->check_foreigns = false;
6658
trx->check_unique_secondary = false;
6660
(void)row_drop_database_for_mysql(schema_path.c_str(), trx);
6662
/* Flush the log to reduce probability that the .frm files and
6663
the InnoDB data dictionary get out-of-sync if the user runs
6664
with innodb_flush_log_at_trx_commit = 0 */
6666
log_buffer_flush_to_disk();
6668
/* Tell the InnoDB server that there might be work for
6671
srv_active_wake_master_thread();
6673
innobase_commit_low(trx);
6674
trx_free_for_mysql(trx);
6676
/*********************************************************************//**
6677
Renames an InnoDB table.
6678
@return 0 or error code */
6681
innobase_rename_table(
6682
/*==================*/
6683
trx_t* trx, /*!< in: transaction */
6684
const char* from, /*!< in: old name of the table */
6685
const char* to, /*!< in: new name of the table */
6686
ibool lock_and_commit)
6687
/*!< in: TRUE=lock data dictionary and commit */
6690
char norm_to[FN_REFLEN];
6691
char norm_from[FN_REFLEN];
6693
srv_lower_case_table_names = TRUE;
6695
normalize_table_name(norm_to, to);
6696
normalize_table_name(norm_from, from);
6698
/* Serialize data dictionary operations with dictionary mutex:
6699
no deadlocks can occur then in these operations */
6701
if (lock_and_commit) {
6702
row_mysql_lock_data_dictionary(trx);
6705
error = row_rename_table_for_mysql(
6706
norm_from, norm_to, trx, lock_and_commit);
6708
if (error != DB_SUCCESS) {
6709
FILE* ef = dict_foreign_err_file;
6711
fputs("InnoDB: Renaming table ", ef);
6712
ut_print_name(ef, trx, TRUE, norm_from);
6714
ut_print_name(ef, trx, TRUE, norm_to);
6715
fputs(" failed!\n", ef);
6718
if (lock_and_commit) {
6719
row_mysql_unlock_data_dictionary(trx);
6721
/* Flush the log to reduce probability that the .frm
6722
files and the InnoDB data dictionary get out-of-sync
6723
if the user runs with innodb_flush_log_at_trx_commit = 0 */
6725
log_buffer_flush_to_disk();
6730
/*********************************************************************//**
6731
Renames an InnoDB table.
6732
@return 0 or error code */
6733
UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
6735
// A temp table alter table/rename is a shallow rename and only the
6736
// definition needs to be updated.
6737
if (to.getType() == message::Table::TEMPORARY && from.getType() == message::Table::TEMPORARY)
6739
session.getMessageCache().renameTableMessage(from, to);
6747
/* Get the transaction associated with the current session, or create one
6748
if not yet created */
6750
parent_trx = check_trx_exists(&session);
6752
/* In case MySQL calls this in the middle of a SELECT query, release
6753
possible adaptive hash latch to avoid deadlocks of threads */
6755
trx_search_latch_release_if_reserved(parent_trx);
6757
trx = innobase_trx_allocate(&session);
6759
error = innobase_rename_table(trx, from.getPath().c_str(), to.getPath().c_str(), TRUE);
6761
session.setXaId(trx->id);
6763
/* Tell the InnoDB server that there might be work for
6766
srv_active_wake_master_thread();
6768
innobase_commit_low(trx);
6769
trx_free_for_mysql(trx);
6771
/* Add a special case to handle the Duplicated Key error
6772
and return DB_ERROR instead.
6773
This is to avoid a possible SIGSEGV error from mysql error
6774
handling code. Currently, mysql handles the Duplicated Key
6775
error by re-entering the storage layer and getting dup key
6776
info by calling get_dup_key(). This operation requires a valid
6777
table handle ('row_prebuilt_t' structure) which could no
6778
longer be available in the error handling stage. The suggested
6779
solution is to report a 'table exists' error message (since
6780
the dup key error here is due to an existing table whose name
6781
is the one we are trying to rename to) and return the generic
6783
if (error == (int) DB_DUPLICATE_KEY) {
6784
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to.getPath().c_str());
6788
error = convert_error_code_to_mysql(error, 0, NULL);
6792
// If this fails, we are in trouble
6793
plugin::StorageEngine::renameDefinitionFromPath(to, from);
6799
/*********************************************************************//**
6800
Estimates the number of index records in a range.
6801
@return estimated number of rows */
6804
ha_innobase::records_in_range(
6805
/*==========================*/
6806
uint keynr, /*!< in: index number */
6807
key_range *min_key, /*!< in: start key value of the
6808
range, may also be 0 */
6809
key_range *max_key) /*!< in: range end key val, may
6813
dict_index_t* index;
6814
unsigned char* key_val_buff2 = (unsigned char*) malloc(
6815
getTable()->getShare()->stored_rec_length
6816
+ getTable()->getShare()->max_key_length + 100);
6817
ulint buff2_len = getTable()->getShare()->stored_rec_length
6818
+ getTable()->getShare()->max_key_length + 100;
6819
dtuple_t* range_start;
6820
dtuple_t* range_end;
6826
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6828
prebuilt->trx->op_info = (char*)"estimating records in index range";
6830
/* In case MySQL calls this in the middle of a SELECT query, release
6831
possible adaptive hash latch to avoid deadlocks of threads */
6833
trx_search_latch_release_if_reserved(prebuilt->trx);
6835
active_index = keynr;
6837
key = &getTable()->key_info[active_index];
6839
index = innobase_get_index(keynr);
6841
/* There exists possibility of not being able to find requested
6842
index due to inconsistency between MySQL and InoDB dictionary info.
6843
Necessary message should have been printed in innobase_get_index() */
6844
if (UNIV_UNLIKELY(!index)) {
6845
n_rows = HA_POS_ERROR;
6849
if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) {
6850
n_rows = HA_ERR_TABLE_DEF_CHANGED;
6854
heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6855
+ sizeof(dtuple_t)));
6857
range_start = dtuple_create(heap, key->key_parts);
6858
dict_index_copy_types(range_start, index, key->key_parts);
6860
range_end = dtuple_create(heap, key->key_parts);
6861
dict_index_copy_types(range_end, index, key->key_parts);
6863
row_sel_convert_mysql_key_to_innobase(
6864
range_start, (byte*) &key_val_buff[0],
6865
(ulint)upd_and_key_val_buff_len,
6867
(byte*) (min_key ? min_key->key :
6868
(const unsigned char*) 0),
6869
(ulint) (min_key ? min_key->length : 0),
6872
row_sel_convert_mysql_key_to_innobase(
6873
range_end, (byte*) key_val_buff2,
6875
(byte*) (max_key ? max_key->key :
6876
(const unsigned char*) 0),
6877
(ulint) (max_key ? max_key->length : 0),
6880
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
6882
mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
6885
if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
6887
n_rows = btr_estimate_n_rows_in_range(index, range_start,
6892
n_rows = HA_POS_ERROR;
6895
mem_heap_free(heap);
6898
free(key_val_buff2);
6900
prebuilt->trx->op_info = (char*)"";
6902
/* The MySQL optimizer seems to believe an estimate of 0 rows is
6903
always accurate and may return the result 'Empty set' based on that.
6904
The accuracy is not guaranteed, and even if it were, for a locking
6905
read we should anyway perform the search to set the next-key lock.
6906
Add 1 to the value to make sure MySQL does not make the assumption! */
6912
return((ha_rows) n_rows);
6915
/*********************************************************************//**
6916
Gives an UPPER BOUND to the number of rows in a table. This is used in
6918
@return upper bound of rows */
6921
ha_innobase::estimate_rows_upper_bound(void)
6922
/*======================================*/
6924
dict_index_t* index;
6926
uint64_t local_data_file_length;
6928
/* We do not know if MySQL can call this function before calling
6929
external_lock(). To be safe, update the session of the current table
6932
update_session(getTable()->in_use);
6934
prebuilt->trx->op_info = (char*)
6935
"calculating upper bound for table rows";
6937
/* In case MySQL calls this in the middle of a SELECT query, release
6938
possible adaptive hash latch to avoid deadlocks of threads */
6940
trx_search_latch_release_if_reserved(prebuilt->trx);
6942
index = dict_table_get_first_index(prebuilt->table);
6944
ut_a(index->stat_n_leaf_pages > 0);
6946
local_data_file_length =
6947
((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
6950
/* Calculate a minimum length for a clustered index record and from
6951
that an upper bound for the number of rows. Since we only calculate
6952
new statistics in row0mysql.c when a table has grown by a threshold
6953
factor, we must add a safety factor 2 in front of the formula below. */
6955
estimate = 2 * local_data_file_length /
6956
dict_index_calc_min_rec_len(index);
6958
prebuilt->trx->op_info = (char*)"";
6960
return((ha_rows) estimate);
6963
/*********************************************************************//**
6964
How many seeks it will take to read through the table. This is to be
6965
comparable to the number returned by records_in_range so that we can
6966
decide if we should scan the table or use keys.
6967
@return estimated time measured in disk seeks */
6970
ha_innobase::scan_time()
6971
/*====================*/
6973
/* Since MySQL seems to favor table scans too much over index
6974
searches, we pretend that a sequential read takes the same time
6975
as a random disk read, that is, we do not divide the following
6976
by 10, which would be physically realistic. */
6978
return((double) (prebuilt->table->stat_clustered_index_size));
6981
/******************************************************************//**
6982
Calculate the time it takes to read a set of ranges through an index
6983
This enables us to optimise reads for clustered indexes.
6984
@return estimated time measured in disk seeks */
6987
ha_innobase::read_time(
6988
/*===================*/
6989
uint index, /*!< in: key number */
6990
uint ranges, /*!< in: how many ranges */
6991
ha_rows rows) /*!< in: estimated number of rows in the ranges */
6994
double time_for_scan;
6996
if (index != getTable()->getShare()->getPrimaryKey()) {
6998
return(Cursor::read_time(index, ranges, rows));
7003
return((double) rows);
7006
/* Assume that the read time is proportional to the scan time for all
7007
rows + at most one seek per range. */
7009
time_for_scan = scan_time();
7011
if ((total_rows = estimate_rows_upper_bound()) < rows) {
7013
return(time_for_scan);
7016
return(ranges + (double) rows / (double) total_rows * time_for_scan);
7019
/*********************************************************************//**
7020
Calculates the key number used inside MySQL for an Innobase index. We will
7021
first check the "index translation table" for a match of the index to get
7022
the index number. If there does not exist an "index translation table",
7023
or not able to find the index in the translation table, then we will fall back
7024
to the traditional way of looping through dict_index_t list to find a
7025
match. In this case, we have to take into account if we generated a
7026
default clustered index for the table
7027
@return the key number used inside MySQL */
7030
innobase_get_mysql_key_number_for_index(
7031
/*====================================*/
7032
INNOBASE_SHARE* share, /*!< in: share structure for index
7033
translation table. */
7034
const drizzled::Table* table, /*!< in: table in MySQL data
7036
dict_table_t* ib_table,/*!< in: table in Innodb data
7038
const dict_index_t* index) /*!< in: index */
7040
const dict_index_t* ind;
7048
/* If index does not belong to the table of share structure. Search
7049
index->table instead */
7050
if (index->table != ib_table) {
7052
ind = dict_table_get_first_index(index->table);
7054
while (index != ind) {
7055
ind = dict_table_get_next_index(ind);
7059
if (row_table_got_default_clust_index(index->table)) {
7067
/* If index does not belong to the table of share structure. Search
7068
index->table instead */
7069
if (index->table != ib_table) {
7071
ind = dict_table_get_first_index(index->table);
7073
while (index != ind) {
7074
ind = dict_table_get_next_index(ind);
7078
if (row_table_got_default_clust_index(index->table)) {
7086
/* If index translation table exists, we will first check
7087
the index through index translation table for a match. */
7088
if (share->idx_trans_tbl.index_mapping) {
7089
for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
7090
if (share->idx_trans_tbl.index_mapping[i] == index) {
7095
/* Print an error message if we cannot find the index
7096
** in the "index translation table". */
7097
errmsg_printf(ERRMSG_LVL_ERROR,
7098
"Cannot find index %s in InnoDB index "
7099
"translation table.", index->name);
7102
/* If we do not have an "index translation table", or not able
7103
to find the index in the translation table, we'll directly find
7104
matching index in the dict_index_t list */
7105
for (i = 0; i < table->getShare()->keys; i++) {
7106
ind = dict_table_get_index_on_name(
7107
ib_table, table->key_info[i].name);
7114
errmsg_printf(ERRMSG_LVL_ERROR,
7115
"Cannot find matching index number for index %s "
7116
"in InnoDB index list.", index->name);
7120
/*********************************************************************//**
7121
Returns statistics information of the table to the MySQL interpreter,
7122
in various fields of the handle object. */
7127
uint flag) /*!< in: what information MySQL requests */
7129
dict_table_t* ib_table;
7130
dict_index_t* index;
7131
ha_rows rec_per_key;
7133
os_file_stat_t stat_info;
7135
/* If we are forcing recovery at a high level, we will suppress
7136
statistics calculation on tables, because that may crash the
7137
server if an index is badly corrupted. */
7139
/* We do not know if MySQL can call this function before calling
7140
external_lock(). To be safe, update the session of the current table
7143
update_session(getTable()->in_use);
7145
/* In case MySQL calls this in the middle of a SELECT query, release
7146
possible adaptive hash latch to avoid deadlocks of threads */
7148
prebuilt->trx->op_info = (char*)"returning various info to MySQL";
7150
trx_search_latch_release_if_reserved(prebuilt->trx);
7152
ib_table = prebuilt->table;
7154
if (flag & HA_STATUS_TIME) {
7155
/* In Analyze we call with this flag: update
7156
then statistics so that they are up-to-date */
7158
prebuilt->trx->op_info = "updating table statistics";
7160
dict_update_statistics(ib_table);
7162
prebuilt->trx->op_info = "returning various info to MySQL";
7164
fs::path get_status_path(getDataHomeCatalog());
7165
get_status_path /= ib_table->name;
7166
fs::change_extension(get_status_path, "dfe");
7168
/* Note that we do not know the access time of the table,
7169
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
7171
if (os_file_get_status(get_status_path.file_string().c_str(), &stat_info)) {
7172
stats.create_time = (ulong) stat_info.ctime;
7176
if (flag & HA_STATUS_VARIABLE) {
7177
n_rows = ib_table->stat_n_rows;
7179
/* Because we do not protect stat_n_rows by any mutex in a
7180
delete, it is theoretically possible that the value can be
7181
smaller than zero! TODO: fix this race.
7183
The MySQL optimizer seems to assume in a left join that n_rows
7184
is an accurate estimate if it is zero. Of course, it is not,
7185
since we do not have any locks on the rows yet at this phase.
7186
Since SHOW TABLE STATUS seems to call this function with the
7187
HA_STATUS_TIME flag set, while the left join optimizer does not
7188
set that flag, we add one to a zero value if the flag is not
7189
set. That way SHOW TABLE STATUS will show the best estimate,
7190
while the optimizer never sees the table empty. */
7196
if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
7200
/* Fix bug#40386: Not flushing query cache after truncate.
7201
n_rows can not be 0 unless the table is empty, set to 1
7202
instead. The original problem of bug#29507 is actually
7203
fixed in the server code. */
7204
if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
7208
/* We need to reset the prebuilt value too, otherwise
7209
checks for values greater than the last value written
7210
to the table will fail and the autoinc counter will
7211
not be updated. This will force doInsertRecord() into
7212
attempting an update of the table's AUTOINC counter. */
7214
prebuilt->autoinc_last_value = 0;
7217
stats.records = (ha_rows)n_rows;
7219
stats.data_file_length = ((uint64_t)
7220
ib_table->stat_clustered_index_size)
7222
stats.index_file_length = ((uint64_t)
7223
ib_table->stat_sum_of_other_index_sizes)
7226
/* Since fsp_get_available_space_in_free_extents() is
7227
acquiring latches inside InnoDB, we do not call it if we
7228
are asked by MySQL to avoid locking. Another reason to
7229
avoid the call is that it uses quite a lot of CPU.
7231
if (flag & HA_STATUS_NO_LOCK) {
7232
/* We do not update delete_length if no
7233
locking is requested so the "old" value can
7234
remain. delete_length is initialized to 0 in
7235
the ha_statistics' constructor. */
7236
} else if (UNIV_UNLIKELY
7237
(srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) {
7238
/* Avoid accessing the tablespace if
7239
innodb_crash_recovery is set to a high value. */
7240
stats.delete_length = 0;
7242
/* lock the data dictionary to avoid races with
7243
ibd_file_missing and tablespace_discarded */
7244
row_mysql_lock_data_dictionary(prebuilt->trx);
7246
/* ib_table->space must be an existent tablespace */
7247
if (!ib_table->ibd_file_missing
7248
&& !ib_table->tablespace_discarded) {
7250
stats.delete_length =
7251
fsp_get_available_space_in_free_extents(
7252
ib_table->space) * 1024;
7257
session= getTable()->in_use;
7260
push_warning_printf(
7262
DRIZZLE_ERROR::WARN_LEVEL_WARN,
7264
"InnoDB: Trying to get the free "
7265
"space for table %s but its "
7266
"tablespace has been discarded or "
7267
"the .ibd file is missing. Setting "
7268
"the free space to zero.",
7271
stats.delete_length = 0;
7274
row_mysql_unlock_data_dictionary(prebuilt->trx);
7277
stats.check_time = 0;
7279
if (stats.records == 0) {
7280
stats.mean_rec_length = 0;
7282
stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
7286
if (flag & HA_STATUS_CONST) {
7288
/* Verify the number of index in InnoDB and MySQL
7289
matches up. If prebuilt->clust_index_was_generated
7290
holds, InnoDB defines GEN_CLUST_INDEX internally */
7291
ulint num_innodb_index = UT_LIST_GET_LEN(ib_table->indexes) - prebuilt->clust_index_was_generated;
7293
if (getTable()->getShare()->keys != num_innodb_index) {
7294
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains %lu "
7295
"indexes inside InnoDB, which "
7296
"is different from the number of "
7297
"indexes %u defined in the MySQL ",
7298
ib_table->name, num_innodb_index,
7299
getTable()->getShare()->keys);
7302
for (i = 0; i < getTable()->getShare()->sizeKeys(); i++) {
7304
/* We could get index quickly through internal
7305
index mapping with the index translation table.
7306
The identity of index (match up index name with
7307
that of table->key_info[i]) is already verified in
7308
innobase_get_index(). */
7309
index = innobase_get_index(i);
7311
if (index == NULL) {
7312
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
7313
"indexes inside InnoDB than "
7314
"are defined in the MySQL "
7315
".frm file. Have you mixed up "
7316
".frm files from different "
7317
"installations? See "
7319
"innodb-troubleshooting.html\n",
7324
for (j = 0; j < getTable()->key_info[i].key_parts; j++) {
7326
if (j + 1 > index->n_uniq) {
7327
errmsg_printf(ERRMSG_LVL_ERROR,
7328
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
7329
"statistics for %lu columns. Have you mixed up .frm files from different "
7331
"See " REFMAN "innodb-troubleshooting.html\n",
7335
index->n_uniq, j + 1);
7339
dict_index_stat_mutex_enter(index);
7341
if (index->stat_n_diff_key_vals[j + 1] == 0) {
7343
rec_per_key = stats.records;
7345
rec_per_key = (ha_rows)(stats.records /
7346
index->stat_n_diff_key_vals[j + 1]);
7349
dict_index_stat_mutex_exit(index);
7351
/* Since MySQL seems to favor table scans
7352
too much over index searches, we pretend
7353
index selectivity is 2 times better than
7356
rec_per_key = rec_per_key / 2;
7358
if (rec_per_key == 0) {
7362
getTable()->key_info[i].rec_per_key[j]=
7363
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
7364
(ulong) rec_per_key;
7369
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
7373
if (flag & HA_STATUS_ERRKEY) {
7374
const dict_index_t* err_index;
7376
ut_a(prebuilt->trx);
7377
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7379
err_index = trx_get_error_info(prebuilt->trx);
7382
errkey = (unsigned int)
7383
innobase_get_mysql_key_number_for_index(share, getTable(), ib_table,
7386
errkey = (unsigned int) prebuilt->trx->error_key_num;
7390
if ((flag & HA_STATUS_AUTO) && getTable()->found_next_number_field) {
7391
stats.auto_increment_value = innobase_peek_autoinc();
7395
prebuilt->trx->op_info = (char*)"";
7400
/**********************************************************************//**
7401
Updates index cardinalities of the table, based on 8 random dives into
7402
each index tree. This does NOT calculate exact statistics on the table.
7403
@return returns always 0 (success) */
7406
ha_innobase::analyze(
7407
/*=================*/
7408
Session*) /*!< in: connection thread handle */
7410
/* Simply call ::info() with all the flags */
7411
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
7416
/*******************************************************************//**
7417
Tries to check that an InnoDB table is not corrupted. If corruption is
7418
noticed, prints to stderr information about it. In case of corruption
7419
may also assert a failure and crash the server.
7420
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
7425
Session* session) /*!< in: user thread handle */
7427
dict_index_t* index;
7429
ulint n_rows_in_table = ULINT_UNDEFINED;
7431
ulint old_isolation_level;
7433
assert(session == getTable()->in_use);
7434
ut_a(prebuilt->trx);
7435
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7436
ut_a(prebuilt->trx == session_to_trx(session));
7438
if (prebuilt->mysql_template == NULL) {
7439
/* Build the template; we will use a dummy template
7440
in index scans done in checking */
7442
build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
7445
if (prebuilt->table->ibd_file_missing) {
7446
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: Error:\n"
7447
"InnoDB: MySQL is trying to use a table handle"
7448
" but the .ibd file for\n"
7449
"InnoDB: table %s does not exist.\n"
7450
"InnoDB: Have you deleted the .ibd file"
7451
" from the database directory under\n"
7452
"InnoDB: the MySQL datadir, or have you"
7453
" used DISCARD TABLESPACE?\n"
7454
"InnoDB: Please refer to\n"
7455
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
7456
"InnoDB: how you can resolve the problem.\n",
7457
prebuilt->table->name);
7458
return(HA_ADMIN_CORRUPT);
7461
prebuilt->trx->op_info = "checking table";
7463
old_isolation_level = prebuilt->trx->isolation_level;
7465
/* We must run the index record counts at an isolation level
7466
>= READ COMMITTED, because a dirty read can see a wrong number
7467
of records in some index; to play safe, we use always
7468
REPEATABLE READ here */
7470
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
7472
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
7473
mutex_enter(&kernel_mutex);
7474
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
7475
mutex_exit(&kernel_mutex);
7477
for (index = dict_table_get_first_index(prebuilt->table);
7479
index = dict_table_get_next_index(index)) {
7481
fputs("Validating index ", stderr);
7482
ut_print_name(stderr, trx, FALSE, index->name);
7486
if (!btr_validate_index(index, prebuilt->trx)) {
7488
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7490
"InnoDB: The B-tree of"
7491
" index '%-.200s' is corrupted.",
7496
/* Instead of invoking change_active_index(), set up
7497
a dummy template for non-locking reads, disabling
7498
access to the clustered index. */
7499
prebuilt->index = index;
7501
prebuilt->index_usable = row_merge_is_index_usable(
7502
prebuilt->trx, prebuilt->index);
7504
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
7505
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7506
HA_ERR_TABLE_DEF_CHANGED,
7507
"InnoDB: Insufficient history for"
7513
prebuilt->sql_stat_start = TRUE;
7514
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
7515
prebuilt->n_template = 0;
7516
prebuilt->need_to_access_clustered = FALSE;
7518
dtuple_set_n_fields(prebuilt->search_tuple, 0);
7520
prebuilt->select_lock_type = LOCK_NONE;
7522
if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) {
7523
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7525
"InnoDB: The B-tree of"
7526
" index '%-.200s' is corrupted.",
7531
if (user_session->getKilled()) {
7536
fprintf(stderr, "%lu entries in index %s\n", n_rows,
7540
if (index == dict_table_get_first_index(prebuilt->table)) {
7541
n_rows_in_table = n_rows;
7542
} else if (n_rows != n_rows_in_table) {
7543
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7545
"InnoDB: Index '%-.200s'"
7546
" contains %lu entries,"
7550
(ulong) n_rows_in_table);
7555
/* Restore the original isolation level */
7556
prebuilt->trx->isolation_level = old_isolation_level;
7558
/* We validate also the whole adaptive hash index for all tables
7559
at every CHECK TABLE */
7561
if (!btr_search_validate()) {
7562
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7564
"InnoDB: The adaptive hash index is corrupted.");
7568
/* Restore the fatal lock wait timeout after CHECK TABLE. */
7569
mutex_enter(&kernel_mutex);
7570
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
7571
mutex_exit(&kernel_mutex);
7573
prebuilt->trx->op_info = "";
7574
if (user_session->getKilled()) {
7575
my_error(ER_QUERY_INTERRUPTED, MYF(0));
7578
return(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
7581
/*************************************************************//**
7582
Adds information about free space in the InnoDB tablespace to a table comment
7583
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
7585
@return table comment + InnoDB free space + info on foreign keys */
7588
ha_innobase::update_table_comment(
7589
/*==============================*/
7590
const char* comment)/*!< in: table comment defined by user */
7592
uint length = (uint) strlen(comment);
7596
/* We do not know if MySQL can call this function before calling
7597
external_lock(). To be safe, update the session of the current table
7600
if (length > 64000 - 3) {
7601
return((char*)comment); /* string too long */
7604
update_session(getTable()->in_use);
7606
prebuilt->trx->op_info = (char*)"returning table comment";
7608
/* In case MySQL calls this in the middle of a SELECT query, release
7609
possible adaptive hash latch to avoid deadlocks of threads */
7611
trx_search_latch_release_if_reserved(prebuilt->trx);
7614
/* output the data to a temporary file */
7616
mutex_enter(&srv_dict_tmpfile_mutex);
7617
rewind(srv_dict_tmpfile);
7619
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
7620
fsp_get_available_space_in_free_extents(
7621
prebuilt->table->space));
7623
dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
7624
prebuilt->trx, prebuilt->table);
7625
flen = ftell(srv_dict_tmpfile);
7628
} else if (length + flen + 3 > 64000) {
7629
flen = 64000 - 3 - length;
7632
/* allocate buffer for the full string, and
7633
read the contents of the temporary file */
7635
str = (char*) malloc(length + flen + 3);
7638
char* pos = str + length;
7640
memcpy(str, comment, length);
7644
rewind(srv_dict_tmpfile);
7645
flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
7649
mutex_exit(&srv_dict_tmpfile_mutex);
7651
prebuilt->trx->op_info = (char*)"";
7653
return(str ? str : (char*) comment);
7656
/*******************************************************************//**
7657
Gets the foreign key create info for a table stored in InnoDB.
7658
@return own: character string in the form which can be inserted to the
7659
CREATE TABLE statement, MUST be freed with
7660
ha_innobase::free_foreign_key_create_info */
7663
ha_innobase::get_foreign_key_create_info(void)
7664
/*==========================================*/
7669
ut_a(prebuilt != NULL);
7671
/* We do not know if MySQL can call this function before calling
7672
external_lock(). To be safe, update the session of the current table
7675
update_session(getTable()->in_use);
7677
prebuilt->trx->op_info = (char*)"getting info on foreign keys";
7679
/* In case MySQL calls this in the middle of a SELECT query,
7680
release possible adaptive hash latch to avoid
7681
deadlocks of threads */
7683
trx_search_latch_release_if_reserved(prebuilt->trx);
7685
mutex_enter(&srv_dict_tmpfile_mutex);
7686
rewind(srv_dict_tmpfile);
7688
/* output the data to a temporary file */
7689
dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
7690
prebuilt->trx, prebuilt->table);
7691
prebuilt->trx->op_info = (char*)"";
7693
flen = ftell(srv_dict_tmpfile);
7696
} else if (flen > 64000 - 1) {
7700
/* allocate buffer for the string, and
7701
read the contents of the temporary file */
7703
str = (char*) malloc(flen + 1);
7706
rewind(srv_dict_tmpfile);
7707
flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
7711
mutex_exit(&srv_dict_tmpfile_mutex);
7719
ha_innobase::get_foreign_key_list(Session *session, List<ForeignKeyInfo> *f_key_list)
7721
dict_foreign_t* foreign;
7723
ut_a(prebuilt != NULL);
7724
update_session(getTable()->in_use);
7725
prebuilt->trx->op_info = (char*)"getting list of foreign keys";
7726
trx_search_latch_release_if_reserved(prebuilt->trx);
7727
mutex_enter(&(dict_sys->mutex));
7728
foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7730
while (foreign != NULL) {
7733
LEX_STRING *name = 0;
7735
char uname[NAME_LEN + 1]; /* Unencoded name */
7736
char db_name[NAME_LEN + 1];
7737
const char *tmp_buff;
7740
tmp_buff = foreign->id;
7742
while (tmp_buff[i] != '/')
7745
LEX_STRING *tmp_foreign_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
7748
tmp_buff = foreign->referenced_table_name;
7751
while (tmp_buff[i] != '/')
7753
db_name[i]= tmp_buff[i];
7757
ulen= TableIdentifier::filename_to_tablename(db_name, uname, sizeof(uname));
7758
LEX_STRING *tmp_referenced_db = session->make_lex_string(NULL, uname, ulen, true);
7762
ulen= TableIdentifier::filename_to_tablename(tmp_buff, uname, sizeof(uname));
7763
LEX_STRING *tmp_referenced_table = session->make_lex_string(NULL, uname, ulen, true);
7765
/** Foreign Fields **/
7766
List<LEX_STRING> tmp_foreign_fields;
7767
List<LEX_STRING> tmp_referenced_fields;
7769
tmp_buff= foreign->foreign_col_names[i];
7770
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
7771
tmp_foreign_fields.push_back(name);
7772
tmp_buff= foreign->referenced_col_names[i];
7773
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
7774
tmp_referenced_fields.push_back(name);
7775
if (++i >= foreign->n_fields)
7780
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
7783
tmp_buff= "CASCADE";
7785
else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
7788
tmp_buff= "SET NULL";
7790
else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
7793
tmp_buff= "NO ACTION";
7798
tmp_buff= "RESTRICT";
7800
LEX_STRING *tmp_delete_method = session->make_lex_string(NULL, tmp_buff, length, true);
7803
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
7806
tmp_buff= "CASCADE";
7808
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
7811
tmp_buff= "SET NULL";
7813
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
7816
tmp_buff= "NO ACTION";
7821
tmp_buff= "RESTRICT";
7823
LEX_STRING *tmp_update_method = session->make_lex_string(NULL, tmp_buff, length, true);
7825
LEX_STRING *tmp_referenced_key_name = NULL;
7827
if (foreign->referenced_index &&
7828
foreign->referenced_index->name)
7830
tmp_referenced_key_name = session->make_lex_string(NULL,
7831
foreign->referenced_index->name, strlen(foreign->referenced_index->name), true);
7834
ForeignKeyInfo f_key_info(
7835
tmp_foreign_id, tmp_referenced_db, tmp_referenced_table,
7836
tmp_update_method, tmp_delete_method, tmp_referenced_key_name,
7837
tmp_foreign_fields, tmp_referenced_fields);
7839
ForeignKeyInfo *pf_key_info = (ForeignKeyInfo *)
7840
session->memdup(&f_key_info, sizeof(ForeignKeyInfo));
7841
f_key_list->push_back(pf_key_info);
7842
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
7844
mutex_exit(&(dict_sys->mutex));
7845
prebuilt->trx->op_info = (char*)"";
7850
/*****************************************************************//**
7851
Checks if ALTER TABLE may change the storage engine of the table.
7852
Changing storage engines is not allowed for tables for which there
7853
are foreign key constraints (parent or child tables).
7854
@return TRUE if can switch engines */
7857
ha_innobase::can_switch_engines(void)
7858
/*=================================*/
7862
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
7864
prebuilt->trx->op_info =
7865
"determining if there are foreign key constraints";
7866
row_mysql_lock_data_dictionary(prebuilt->trx);
7868
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
7869
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7871
row_mysql_unlock_data_dictionary(prebuilt->trx);
7872
prebuilt->trx->op_info = "";
7877
/*******************************************************************//**
7878
Checks if a table is referenced by a foreign key. The MySQL manual states that
7879
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
7880
delete is then allowed internally to resolve a duplicate key conflict in
7881
REPLACE, not an update.
7882
@return > 0 if referenced by a FOREIGN KEY */
7885
ha_innobase::referenced_by_foreign_key(void)
7886
/*========================================*/
7888
if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
7896
/*******************************************************************//**
7897
Frees the foreign key create info for a table stored in InnoDB, if it is
7901
ha_innobase::free_foreign_key_create_info(
7902
/*======================================*/
7903
char* str) /*!< in, own: create info string to free */
7910
/*******************************************************************//**
7911
Tells something additional to the Cursor about how to do things.
7912
@return 0 or error number */
7917
enum ha_extra_function operation)
7918
/*!< in: HA_EXTRA_FLUSH or some other flag */
7920
/* Warning: since it is not sure that MySQL calls external_lock
7921
before calling this function, the trx field in prebuilt can be
7924
switch (operation) {
7925
case HA_EXTRA_FLUSH:
7926
if (prebuilt->blob_heap) {
7927
row_mysql_prebuilt_free_blob_heap(prebuilt);
7930
case HA_EXTRA_RESET_STATE:
7931
reset_template(prebuilt);
7933
case HA_EXTRA_NO_KEYREAD:
7934
prebuilt->read_just_key = 0;
7936
case HA_EXTRA_KEYREAD:
7937
prebuilt->read_just_key = 1;
7939
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
7940
prebuilt->keep_other_fields_on_keyread = 1;
7943
/* IMPORTANT: prebuilt->trx can be obsolete in
7944
this method, because it is not sure that MySQL
7945
calls external_lock before this method with the
7946
parameters below. We must not invoke update_session()
7947
either, because the calling threads may change.
7948
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
7949
case HA_EXTRA_IGNORE_DUP_KEY:
7950
session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_IGNORE;
7952
case HA_EXTRA_WRITE_CAN_REPLACE:
7953
session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_REPLACE;
7955
case HA_EXTRA_WRITE_CANNOT_REPLACE:
7956
session_to_trx(getTable()->in_use)->duplicates &= ~TRX_DUP_REPLACE;
7958
case HA_EXTRA_NO_IGNORE_DUP_KEY:
7959
session_to_trx(getTable()->in_use)->duplicates &=
7960
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
7962
default:/* Do nothing */
7971
ha_innobase::reset()
7973
if (prebuilt->blob_heap) {
7974
row_mysql_prebuilt_free_blob_heap(prebuilt);
7977
reset_template(prebuilt);
7979
/* TODO: This should really be reset in reset_template() but for now
7980
it's safer to do it explicitly here. */
7982
/* This is a statement level counter. */
7983
prebuilt->autoinc_last_value = 0;
7988
/******************************************************************//**
7989
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7990
@return InnoDB isolation level */
7993
innobase_map_isolation_level(
7994
/*=========================*/
7995
enum_tx_isolation iso) /*!< in: MySQL isolation level code */
7998
case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
7999
case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
8000
case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
8001
case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
8002
default: ut_a(0); return(0);
8006
/******************************************************************//**
8007
As MySQL will execute an external lock for every new table it uses when it
8008
starts to process an SQL statement. We can use this function to store the pointer to
8009
the Session in the handle.
8013
ha_innobase::external_lock(
8014
/*=======================*/
8015
Session* session, /*!< in: handle to the user thread */
8016
int lock_type) /*!< in: lock type */
8018
update_session(session);
8020
trx_t *trx= prebuilt->trx;
8022
prebuilt->sql_stat_start = TRUE;
8023
prebuilt->hint_need_to_fetch_extra_cols = 0;
8025
reset_template(prebuilt);
8027
if (lock_type == F_WRLCK) {
8029
/* If this is a SELECT, then it is in UPDATE TABLE ...
8030
or SELECT ... FOR UPDATE */
8031
prebuilt->select_lock_type = LOCK_X;
8032
prebuilt->stored_select_lock_type = LOCK_X;
8035
if (lock_type != F_UNLCK) {
8036
/* MySQL is setting a new table lock */
8038
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
8039
&& prebuilt->select_lock_type == LOCK_NONE
8040
&& session_test_options(session,
8041
OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
8043
/* To get serializable execution, we let InnoDB
8044
conceptually add 'LOCK IN SHARE MODE' to all SELECTs
8045
which otherwise would have been consistent reads. An
8046
exception is consistent reads in the AUTOCOMMIT=1 mode:
8047
we know that they are read-only transactions, and they
8048
can be serialized also if performed as consistent
8051
prebuilt->select_lock_type = LOCK_S;
8052
prebuilt->stored_select_lock_type = LOCK_S;
8055
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
8056
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
8057
an InnoDB table lock if it is released immediately at the end
8058
of LOCK TABLES, and InnoDB's table locks in that case cause
8059
VERY easily deadlocks.
8061
We do not set InnoDB table locks if user has not explicitly
8062
requested a table lock. Note that session_in_lock_tables(session)
8063
can hold in some cases, e.g., at the start of a stored
8064
procedure call (SQLCOM_CALL). */
8066
if (prebuilt->select_lock_type != LOCK_NONE) {
8067
trx->mysql_n_tables_locked++;
8070
prebuilt->mysql_has_locked = TRUE;
8075
/* MySQL is releasing a table lock */
8076
prebuilt->mysql_has_locked = FALSE;
8077
trx->mysql_n_tables_locked= 0;
8082
/************************************************************************//**
8083
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
8084
Monitor to the client. */
8089
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
8090
Session* session,/*!< in: the MySQL query thread of the caller */
8091
stat_print_fn *stat_print)
8094
static const char truncated_msg[] = "... truncated...\n";
8095
const long MAX_STATUS_SIZE = 1048576;
8096
ulint trx_list_start = ULINT_UNDEFINED;
8097
ulint trx_list_end = ULINT_UNDEFINED;
8099
assert(engine == innodb_engine_ptr);
8101
trx = check_trx_exists(session);
8103
innobase_release_stat_resources(trx);
8105
/* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
8108
long flen, usable_len;
8111
mutex_enter(&srv_monitor_file_mutex);
8112
rewind(srv_monitor_file);
8113
srv_printf_innodb_monitor(srv_monitor_file, FALSE,
8114
&trx_list_start, &trx_list_end);
8115
flen = ftell(srv_monitor_file);
8116
os_file_set_eof(srv_monitor_file);
8122
if (flen > MAX_STATUS_SIZE) {
8123
usable_len = MAX_STATUS_SIZE;
8124
srv_truncated_status_writes++;
8129
/* allocate buffer for the string, and
8130
read the contents of the temporary file */
8132
if (!(str = (char*) malloc(usable_len + 1))) {
8133
mutex_exit(&srv_monitor_file_mutex);
8137
rewind(srv_monitor_file);
8138
if (flen < MAX_STATUS_SIZE) {
8139
/* Display the entire output. */
8140
flen = (long) fread(str, 1, flen, srv_monitor_file);
8141
} else if (trx_list_end < (ulint) flen
8142
&& trx_list_start < trx_list_end
8143
&& trx_list_start + (flen - trx_list_end)
8144
< MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
8145
/* Omit the beginning of the list of active transactions. */
8146
long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
8147
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
8148
len += sizeof truncated_msg - 1;
8149
usable_len = (MAX_STATUS_SIZE - 1) - len;
8150
fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
8151
len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
8154
/* Omit the end of the output. */
8155
flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
8158
mutex_exit(&srv_monitor_file_mutex);
8160
stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
8161
STRING_WITH_LEN(""), str, flen);
8168
/************************************************************************//**
8169
Implements the SHOW MUTEX STATUS command.
8170
@return true on failure false on success*/
8173
innodb_mutex_show_status(
8174
/*=====================*/
8175
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
8176
Session* session, /*!< in: the MySQL query thread of the
8178
stat_print_fn* stat_print) /*!< in: function for printing
8181
char buf1[IO_SIZE], buf2[IO_SIZE];
8184
ulint block_mutex_oswait_count = 0;
8185
ulint block_lock_oswait_count = 0;
8186
mutex_t* block_mutex = NULL;
8187
rw_lock_t* block_lock = NULL;
8189
ulint rw_lock_count= 0;
8190
ulint rw_lock_count_spin_loop= 0;
8191
ulint rw_lock_count_spin_rounds= 0;
8192
ulint rw_lock_count_os_wait= 0;
8193
ulint rw_lock_count_os_yield= 0;
8194
uint64_t rw_lock_wait_time= 0;
8195
#endif /* UNIV_DEBUG */
8196
uint engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
8197
assert(engine == innodb_engine_ptr);
8199
mutex_enter(&mutex_list_mutex);
8201
for (mutex = UT_LIST_GET_FIRST(mutex_list); mutex != NULL;
8202
mutex = UT_LIST_GET_NEXT(list, mutex)) {
8203
if (mutex->count_os_wait == 0) {
8208
if (buf_pool_is_block_mutex(mutex)) {
8209
block_mutex = mutex;
8210
block_mutex_oswait_count += mutex->count_os_wait;
8214
if (mutex->mutex_type != 1) {
8215
if (mutex->count_using > 0) {
8216
buf1len= my_snprintf(buf1, sizeof(buf1),
8218
mutex->cmutex_name, mutex->cfile_name);
8219
buf2len= my_snprintf(buf2, sizeof(buf2),
8220
"count=%lu, spin_waits=%lu,"
8221
" spin_rounds=%lu, "
8222
"os_waits=%lu, os_yields=%lu,"
8223
" os_wait_times=%lu",
8225
mutex->count_spin_loop,
8226
mutex->count_spin_rounds,
8227
mutex->count_os_wait,
8228
mutex->count_os_yield,
8229
(ulong) (mutex->lspent_time/1000));
8231
if (stat_print(session, innobase_engine_name,
8232
engine_name_len, buf1, buf1len,
8234
mutex_exit(&mutex_list_mutex);
8239
rw_lock_count += mutex->count_using;
8240
rw_lock_count_spin_loop += mutex->count_spin_loop;
8241
rw_lock_count_spin_rounds += mutex->count_spin_rounds;
8242
rw_lock_count_os_wait += mutex->count_os_wait;
8243
rw_lock_count_os_yield += mutex->count_os_yield;
8244
rw_lock_wait_time += mutex->lspent_time;
8246
#else /* UNIV_DEBUG */
8247
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
8248
mutex->cfile_name, (ulong) mutex->cline);
8249
buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
8250
(ulong) mutex->count_os_wait);
8252
if (stat_print(session, innobase_engine_name,
8253
engine_name_len, buf1, buf1len,
8255
mutex_exit(&mutex_list_mutex);
8258
#endif /* UNIV_DEBUG */
8262
buf1len = snprintf(buf1, sizeof buf1,
8264
block_mutex->cfile_name,
8265
(ulong) block_mutex->cline);
8266
buf2len = snprintf(buf2, sizeof buf2,
8268
(ulong) block_mutex_oswait_count);
8270
if (stat_print(session, innobase_engine_name,
8271
strlen(innobase_engine_name), buf1, buf1len,
8273
mutex_exit(&mutex_list_mutex);
8278
mutex_exit(&mutex_list_mutex);
8280
mutex_enter(&rw_lock_list_mutex);
8282
for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL;
8283
lock = UT_LIST_GET_NEXT(list, lock)) {
8284
if (lock->count_os_wait == 0) {
8288
if (buf_pool_is_block_lock(lock)) {
8290
block_lock_oswait_count += lock->count_os_wait;
8294
buf1len = snprintf(buf1, sizeof buf1, "%s:%lu",
8295
lock->cfile_name, (ulong) lock->cline);
8296
buf2len = snprintf(buf2, sizeof buf2, "os_waits=%lu",
8297
(ulong) lock->count_os_wait);
8299
if (stat_print(session, innobase_engine_name,
8300
strlen(innobase_engine_name), buf1, buf1len,
8302
mutex_exit(&rw_lock_list_mutex);
8308
buf1len = snprintf(buf1, sizeof buf1,
8310
block_lock->cfile_name,
8311
(ulong) block_lock->cline);
8312
buf2len = snprintf(buf2, sizeof buf2,
8314
(ulong) block_lock_oswait_count);
8316
if (stat_print(session, innobase_engine_name,
8317
strlen(innobase_engine_name), buf1, buf1len,
8319
mutex_exit(&rw_lock_list_mutex);
8324
mutex_exit(&rw_lock_list_mutex);
8327
buf2len = snprintf(buf2, sizeof buf2,
8328
"count=%lu, spin_waits=%lu, spin_rounds=%lu, "
8329
"os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
8330
(ulong) rw_lock_count,
8331
(ulong) rw_lock_count_spin_loop,
8332
(ulong) rw_lock_count_spin_rounds,
8333
(ulong) rw_lock_count_os_wait,
8334
(ulong) rw_lock_count_os_yield,
8335
(ulong) (rw_lock_wait_time / 1000));
8337
if (stat_print(session, innobase_engine_name, engine_name_len,
8338
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
8341
#endif /* UNIV_DEBUG */
8346
bool InnobaseEngine::show_status(Session* session,
8347
stat_print_fn* stat_print,
8348
enum ha_stat_type stat_type)
8350
assert(this == innodb_engine_ptr);
8352
switch (stat_type) {
8353
case HA_ENGINE_STATUS:
8354
return innodb_show_status(this, session, stat_print);
8355
case HA_ENGINE_MUTEX:
8356
return innodb_mutex_show_status(this, session, stat_print);
8362
/************************************************************************//**
8363
Handling the shared INNOBASE_SHARE structure that is needed to provide table
8365
****************************************************************************/
8367
static INNOBASE_SHARE* get_share(const char* table_name)
8369
INNOBASE_SHARE *share;
8370
pthread_mutex_lock(&innobase_share_mutex);
8372
ulint fold = ut_fold_string(table_name);
8374
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8375
INNOBASE_SHARE*, share,
8376
ut_ad(share->use_count > 0),
8377
!strcmp(share->table_name, table_name));
8380
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
8383
share= new INNOBASE_SHARE(table_name);
8385
HASH_INSERT(INNOBASE_SHARE, table_name_hash,
8386
innobase_open_tables, fold, share);
8388
thr_lock_init(&share->lock);
8390
/* Index translation table initialization */
8391
share->idx_trans_tbl.index_mapping = NULL;
8392
share->idx_trans_tbl.index_count = 0;
8393
share->idx_trans_tbl.array_size = 0;
8397
pthread_mutex_unlock(&innobase_share_mutex);
8402
static void free_share(INNOBASE_SHARE* share)
8404
pthread_mutex_lock(&innobase_share_mutex);
8407
INNOBASE_SHARE* share2;
8408
ulint fold = ut_fold_string(share->table_name);
8410
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8411
INNOBASE_SHARE*, share2,
8412
ut_ad(share->use_count > 0),
8413
!strcmp(share->table_name, share2->table_name));
8415
ut_a(share2 == share);
8416
#endif /* UNIV_DEBUG */
8418
if (!--share->use_count) {
8419
ulint fold = ut_fold_string(share->table_name);
8421
HASH_DELETE(INNOBASE_SHARE, table_name_hash,
8422
innobase_open_tables, fold, share);
8423
share->lock.deinit();
8425
/* Free any memory from index translation table */
8426
free(share->idx_trans_tbl.index_mapping);
8430
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
8434
pthread_mutex_unlock(&innobase_share_mutex);
8437
/*****************************************************************//**
8438
Converts a MySQL table lock stored in the 'lock' field of the handle to
8439
a proper type before storing pointer to the lock into an array of pointers.
8440
MySQL also calls this if it wants to reset some table locks to a not-locked
8441
state during the processing of an SQL query. An example is that during a
8442
SELECT the read lock is released early on the 'const' tables where we only
8443
fetch one row. MySQL does not call this when it releases all locks at the
8444
end of an SQL statement.
8445
@return pointer to the next element in the 'to' array */
8448
ha_innobase::store_lock(
8449
/*====================*/
8450
Session* session, /*!< in: user thread handle */
8451
THR_LOCK_DATA** to, /*!< in: pointer to an array
8452
of pointers to lock structs;
8453
pointer to the 'lock' field
8454
of current handle is stored
8455
next to this array */
8456
enum thr_lock_type lock_type) /*!< in: lock type to store in
8457
'lock'; this may also be
8462
/* Note that trx in this function is NOT necessarily prebuilt->trx
8463
because we call update_session() later, in ::external_lock()! Failure to
8464
understand this caused a serious memory corruption bug in 5.1.11. */
8466
trx = check_trx_exists(session);
8468
assert(EQ_CURRENT_SESSION(session));
8469
const uint32_t sql_command = session_sql_command(session);
8471
if (sql_command == SQLCOM_DROP_TABLE) {
8473
/* MySQL calls this function in DROP Table though this table
8474
handle may belong to another session that is running a query.
8475
Let us in that case skip any changes to the prebuilt struct. */
8477
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
8478
|| lock_type == TL_READ_NO_INSERT
8479
|| (lock_type != TL_IGNORE
8480
&& sql_command != SQLCOM_SELECT)) {
8482
/* The OR cases above are in this order:
8483
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
8484
are processing a stored procedure or function, or
8485
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
8486
3) this is a SELECT ... IN SHARE MODE, or
8487
4) we are doing a complex SQL statement like
8488
INSERT INTO ... SELECT ... and the logical logging (MySQL
8489
binlog) requires the use of a locking read, or
8490
MySQL is doing LOCK TABLES ... READ.
8491
5) we let InnoDB do locking reads for all SQL statements that
8492
are not simple SELECTs; note that select_lock_type in this
8493
case may get strengthened in ::external_lock() to LOCK_X.
8494
Note that we MUST use a locking read in all data modifying
8495
SQL statements, because otherwise the execution would not be
8496
serializable, and also the results from the update could be
8497
unexpected if an obsolete consistent read view would be
8500
ulint isolation_level;
8502
isolation_level = trx->isolation_level;
8504
if ((srv_locks_unsafe_for_binlog
8505
|| isolation_level <= TRX_ISO_READ_COMMITTED)
8506
&& isolation_level != TRX_ISO_SERIALIZABLE
8507
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
8508
&& (sql_command == SQLCOM_INSERT_SELECT
8509
|| sql_command == SQLCOM_REPLACE_SELECT
8510
|| sql_command == SQLCOM_UPDATE
8511
|| sql_command == SQLCOM_CREATE_TABLE
8512
|| sql_command == SQLCOM_SET_OPTION)) {
8514
/* If we either have innobase_locks_unsafe_for_binlog
8515
option set or this session is using READ COMMITTED
8516
isolation level and isolation level of the transaction
8517
is not set to serializable and MySQL is doing
8518
INSERT INTO...SELECT or REPLACE INTO...SELECT
8519
or UPDATE ... = (SELECT ...) or CREATE ...
8520
SELECT... or SET ... = (SELECT ...) without
8521
FOR UPDATE or IN SHARE MODE in select,
8522
then we use consistent read for select. */
8524
prebuilt->select_lock_type = LOCK_NONE;
8525
prebuilt->stored_select_lock_type = LOCK_NONE;
8526
} else if (sql_command == SQLCOM_CHECKSUM) {
8527
/* Use consistent read for checksum table */
8529
prebuilt->select_lock_type = LOCK_NONE;
8530
prebuilt->stored_select_lock_type = LOCK_NONE;
8532
prebuilt->select_lock_type = LOCK_S;
8533
prebuilt->stored_select_lock_type = LOCK_S;
8536
} else if (lock_type != TL_IGNORE) {
8538
/* We set possible LOCK_X value in external_lock, not yet
8539
here even if this would be SELECT ... FOR UPDATE */
8541
prebuilt->select_lock_type = LOCK_NONE;
8542
prebuilt->stored_select_lock_type = LOCK_NONE;
8545
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
8547
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
8548
TABLESPACE or TRUNCATE TABLE then allow multiple
8549
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
8550
< TL_WRITE_CONCURRENT_INSERT.
8553
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
8554
&& lock_type <= TL_WRITE)
8555
&& !session_tablespace_op(session)
8556
&& sql_command != SQLCOM_TRUNCATE
8557
&& sql_command != SQLCOM_CREATE_TABLE) {
8559
lock_type = TL_WRITE_ALLOW_WRITE;
8562
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
8563
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
8564
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
8565
to t2. Convert the lock to a normal read lock to allow
8566
concurrent inserts to t2.
8569
if (lock_type == TL_READ_NO_INSERT) {
8571
lock_type = TL_READ;
8574
lock.type = lock_type;
8582
/*********************************************************************//**
8583
Read the next autoinc value. Acquire the relevant locks before reading
8584
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
8585
on return and all relevant locks acquired.
8586
@return DB_SUCCESS or error code */
8589
ha_innobase::innobase_get_autoinc(
8590
/*==============================*/
8591
uint64_t* value) /*!< out: autoinc value */
8595
dict_table_autoinc_lock(prebuilt->table);
8596
prebuilt->autoinc_error= DB_SUCCESS;
8597
/* Determine the first value of the interval */
8598
*value = dict_table_autoinc_read(prebuilt->table);
8600
/* It should have been initialized during open. */
8602
prebuilt->autoinc_error = DB_UNSUPPORTED;
8603
dict_table_autoinc_unlock(prebuilt->table);
8609
/*******************************************************************//**
8610
This function reads the global auto-inc counter. It doesn't use the
8611
AUTOINC lock even if the lock mode is set to TRADITIONAL.
8612
@return the autoinc value */
8615
ha_innobase::innobase_peek_autoinc(void)
8616
/*====================================*/
8619
dict_table_t* innodb_table;
8621
ut_a(prebuilt != NULL);
8622
ut_a(prebuilt->table != NULL);
8624
innodb_table = prebuilt->table;
8626
dict_table_autoinc_lock(innodb_table);
8628
auto_inc = dict_table_autoinc_read(innodb_table);
8630
if (auto_inc == 0) {
8631
ut_print_timestamp(stderr);
8632
fprintf(stderr, " InnoDB: AUTOINC next value generation "
8633
"is disabled for '%s'\n", innodb_table->name);
8636
dict_table_autoinc_unlock(innodb_table);
8641
/*********************************************************************//**
8642
This function initializes the auto-inc counter if it has not been
8643
initialized yet. This function does not change the value of the auto-inc
8644
counter if it already has been initialized. Returns the value of the
8645
auto-inc counter in *first_value, and UINT64_T_MAX in *nb_reserved_values (as
8646
we have a table-level lock). offset, increment, nb_desired_values are ignored.
8647
*first_value is set to -1 if error (deadlock or lock wait timeout) */
8650
ha_innobase::get_auto_increment(
8651
/*============================*/
8652
uint64_t offset, /*!< in: table autoinc offset */
8653
uint64_t increment, /*!< in: table autoinc increment */
8654
uint64_t nb_desired_values, /*!< in: number of values reqd */
8655
uint64_t *first_value, /*!< out: the autoinc value */
8656
uint64_t *nb_reserved_values) /*!< out: count of reserved values */
8660
uint64_t autoinc = 0;
8662
/* Prepare prebuilt->trx in the table handle */
8663
update_session(getTable()->in_use);
8665
error = innobase_get_autoinc(&autoinc);
8667
if (error != DB_SUCCESS) {
8668
*first_value = (~(uint64_t) 0);
8672
/* This is a hack, since nb_desired_values seems to be accurate only
8673
for the first call to get_auto_increment() for multi-row INSERT and
8674
meaningless for other statements e.g, LOAD etc. Subsequent calls to
8675
this method for the same statement results in different values which
8676
don't make sense. Therefore we store the value the first time we are
8677
called and count down from that as rows are written (see doInsertRecord()).
8680
trx = prebuilt->trx;
8682
/* Note: We can't rely on *first_value since some MySQL engines,
8683
in particular the partition engine, don't initialize it to 0 when
8684
invoking this method. So we are not sure if it's guaranteed to
8687
/* We need the upper limit of the col type to check for
8688
whether we update the table autoinc counter or not. */
8689
uint64_t col_max_value = innobase_get_int_col_max_value(getTable()->next_number_field);
8691
/* Called for the first time ? */
8692
if (trx->n_autoinc_rows == 0) {
8694
trx->n_autoinc_rows = (ulint) nb_desired_values;
8696
/* It's possible for nb_desired_values to be 0:
8697
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
8698
if (nb_desired_values == 0) {
8700
trx->n_autoinc_rows = 1;
8703
set_if_bigger(*first_value, autoinc);
8704
/* Not in the middle of a mult-row INSERT. */
8705
} else if (prebuilt->autoinc_last_value == 0) {
8706
set_if_bigger(*first_value, autoinc);
8707
/* Check for -ve values. */
8708
} else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
8709
/* Set to next logical value. */
8710
ut_a(autoinc > trx->n_autoinc_rows);
8711
*first_value = (autoinc - trx->n_autoinc_rows) - 1;
8714
*nb_reserved_values = trx->n_autoinc_rows;
8716
/* This all current style autoinc. */
8720
uint64_t next_value;
8722
current = *first_value > col_max_value ? autoinc : *first_value;
8723
need = *nb_reserved_values * increment;
8725
/* Compute the last value in the interval */
8726
next_value = innobase_next_autoinc(current, need, offset, col_max_value);
8728
prebuilt->autoinc_last_value = next_value;
8730
if (prebuilt->autoinc_last_value < *first_value) {
8731
*first_value = (~(unsigned long long) 0);
8733
/* Update the table autoinc variable */
8734
dict_table_autoinc_update_if_greater(
8735
prebuilt->table, prebuilt->autoinc_last_value);
8739
/* The increment to be used to increase the AUTOINC value, we use
8740
this in doInsertRecord() and doUpdateRecord() to increase the autoinc counter
8741
for columns that are filled by the user. We need the offset and
8743
prebuilt->autoinc_offset = offset;
8744
prebuilt->autoinc_increment = increment;
8746
dict_table_autoinc_unlock(prebuilt->table);
8749
/*******************************************************************//**
8750
Reset the auto-increment counter to the given value, i.e. the next row
8751
inserted will get the given value. This is called e.g. after TRUNCATE
8752
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
8753
returned by storage engines that don't support this operation.
8754
@return 0 or error code */
8757
ha_innobase::reset_auto_increment(
8758
/*==============================*/
8759
uint64_t value) /*!< in: new value for table autoinc */
8763
update_session(getTable()->in_use);
8765
error = row_lock_table_autoinc_for_mysql(prebuilt);
8767
if (error != DB_SUCCESS) {
8768
error = convert_error_code_to_mysql(error,
8769
prebuilt->table->flags,
8775
/* The next value can never be 0. */
8780
innobase_reset_autoinc(value);
8785
/* See comment in Cursor.cc */
8788
InnobaseEngine::get_error_message(int, String *buf)
8790
trx_t* trx = check_trx_exists(current_session);
8792
buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
8793
system_charset_info);
8798
/*******************************************************************//**
8799
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
8800
If there is no explicitly declared non-null unique key or a primary key, then
8801
InnoDB internally uses the row id as the primary key.
8802
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
8805
ha_innobase::cmp_ref(
8806
/*=================*/
8807
const unsigned char* ref1, /*!< in: an (internal) primary key value in the
8808
MySQL key value format */
8809
const unsigned char* ref2) /*!< in: an (internal) primary key value in the
8810
MySQL key value format */
8812
enum_field_types mysql_type;
8814
KeyPartInfo* key_part;
8815
KeyPartInfo* key_part_end;
8820
if (prebuilt->clust_index_was_generated) {
8821
/* The 'ref' is an InnoDB row id */
8823
return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
8826
/* Do a type-aware comparison of primary key fields. PK fields
8827
are always NOT NULL, so no checks for NULL are performed. */
8829
key_part = getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_part;
8831
key_part_end = key_part
8832
+ getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_parts;
8834
for (; key_part != key_part_end; ++key_part) {
8835
field = key_part->field;
8836
mysql_type = field->type();
8838
if (mysql_type == DRIZZLE_TYPE_BLOB) {
8840
/* In the MySQL key value format, a column prefix of
8841
a BLOB is preceded by a 2-byte length field */
8843
len1 = innobase_read_from_2_little_endian(ref1);
8844
len2 = innobase_read_from_2_little_endian(ref2);
8848
result = ((Field_blob*)field)->cmp( ref1, len1,
8851
result = field->key_cmp(ref1, ref2);
8859
ref1 += key_part->store_length;
8860
ref2 += key_part->store_length;
8866
/**********************************************************************
8867
This function is used to find the storage length in bytes of the first n
8868
characters for prefix indexes using a multibyte character set. The function
8869
finds charset information and returns length of prefix_len characters in the
8870
index field in bytes.
8871
@return number of bytes occupied by the first n characters */
8872
extern "C" UNIV_INTERN
8874
innobase_get_at_most_n_mbchars(
8875
/*===========================*/
8876
ulint charset_id, /*!< in: character set id */
8877
ulint prefix_len, /*!< in: prefix length in bytes of the index
8878
(this has to be divided by mbmaxlen to get the
8879
number of CHARACTERS n in the prefix) */
8880
ulint data_len, /*!< in: length of the string in bytes */
8881
const char* str); /*!< in: character string */
8884
innobase_get_at_most_n_mbchars(
8885
/*===========================*/
8886
ulint charset_id, /*!< in: character set id */
8887
ulint prefix_len, /*!< in: prefix length in bytes of the index
8888
(this has to be divided by mbmaxlen to get the
8889
number of CHARACTERS n in the prefix) */
8890
ulint data_len, /*!< in: length of the string in bytes */
8891
const char* str) /*!< in: character string */
8893
ulint char_length; /*!< character length in bytes */
8894
ulint n_chars; /*!< number of characters in prefix */
8895
const CHARSET_INFO* charset; /*!< charset used in the field */
8897
charset = get_charset((uint) charset_id);
8900
ut_ad(charset->mbmaxlen);
8902
/* Calculate how many characters at most the prefix index contains */
8904
n_chars = prefix_len / charset->mbmaxlen;
8906
/* If the charset is multi-byte, then we must find the length of the
8907
first at most n chars in the string. If the string contains less
8908
characters than n, then we return the length to the end of the last
8911
if (charset->mbmaxlen > 1) {
8912
/* my_charpos() returns the byte length of the first n_chars
8913
characters, or a value bigger than the length of str, if
8914
there were not enough full characters in str.
8916
Why does the code below work:
8917
Suppose that we are looking for n UTF-8 characters.
8919
1) If the string is long enough, then the prefix contains at
8920
least n complete UTF-8 characters + maybe some extra
8921
characters + an incomplete UTF-8 character. No problem in
8922
this case. The function returns the pointer to the
8923
end of the nth character.
8925
2) If the string is not long enough, then the string contains
8926
the complete value of a column, that is, only complete UTF-8
8927
characters, and we can store in the column prefix index the
8930
char_length = my_charpos(charset, str,
8931
str + data_len, (int) n_chars);
8932
if (char_length > data_len) {
8933
char_length = data_len;
8936
if (data_len < prefix_len) {
8937
char_length = data_len;
8939
char_length = prefix_len;
8943
return(char_length);
8946
* We will also use this function to communicate
8947
* to InnoDB that a new SQL statement has started and that we must store a
8948
* savepoint to our transaction handle, so that we are able to roll back
8949
* the SQL statement in case of an error.
8952
InnobaseEngine::doStartStatement(
8953
Session *session) /*!< in: handle to the Drizzle session */
8956
* Create the InnoDB transaction structure
8959
trx_t *trx= check_trx_exists(session);
8961
/* "reset" the error message for the transaction */
8962
trx->detailed_error[0]= '\0';
8964
/* Set the isolation level of the transaction. */
8965
trx->isolation_level= innobase_map_isolation_level(session_tx_isolation(session));
8969
InnobaseEngine::doEndStatement(
8972
trx_t *trx= check_trx_exists(session);
8974
/* Release a possible FIFO ticket and search latch. Since we
8975
may reserve the kernel mutex, we have to release the search
8976
system latch first to obey the latching order. */
8978
innobase_release_stat_resources(trx);
8982
/*******************************************************************//**
8983
This function is used to prepare an X/Open XA distributed transaction.
8984
@return 0 or error number */
8986
InnobaseEngine::doXaPrepare(
8987
/*================*/
8988
Session* session,/*!< in: handle to the MySQL thread of
8989
the user whose XA transaction should
8991
bool all) /*!< in: TRUE - commit transaction
8992
FALSE - the current SQL statement
8996
trx_t* trx = check_trx_exists(session);
8998
assert(this == innodb_engine_ptr);
9000
/* we use support_xa value as it was seen at transaction start
9001
time, not the current session variable value. Any possible changes
9002
to the session variable take effect only in the next transaction */
9003
if (!trx->support_xa) {
9008
session->get_xid(reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
9010
/* Release a possible FIFO ticket and search latch. Since we will
9011
reserve the kernel mutex, we have to release the search system latch
9012
first to obey the latching order. */
9014
innobase_release_stat_resources(trx);
9017
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
9019
/* We were instructed to prepare the whole transaction, or
9020
this is an SQL statement end and autocommit is on */
9022
ut_ad(trx->conc_state != TRX_NOT_STARTED);
9024
error = (int) trx_prepare_for_mysql(trx);
9026
/* We just mark the SQL statement ended and do not do a
9027
transaction prepare */
9029
/* If we had reserved the auto-inc lock for some
9030
table in this SQL statement we release it now */
9032
row_unlock_table_autoinc_for_mysql(trx);
9034
/* Store the current undo_no of the transaction so that we
9035
know where to roll back if we have to roll back the next
9038
trx_mark_sql_stat_end(trx);
9041
/* Tell the InnoDB server that there might be work for utility
9044
srv_active_wake_master_thread();
9049
uint64_t InnobaseEngine::doGetCurrentTransactionId(Session *session)
9051
trx_t *trx= session_to_trx(session);
9055
uint64_t InnobaseEngine::doGetNewTransactionId(Session *session)
9057
trx_t*& trx = session_to_trx(session);
9061
trx = innobase_trx_allocate(session);
9063
innobase_trx_init(session, trx);
9066
mutex_enter(&kernel_mutex);
9067
trx->id= trx_sys_get_new_trx_id();
9068
mutex_exit(&kernel_mutex);
9070
uint64_t transaction_id= trx->id;
9072
return transaction_id;
9075
/*******************************************************************//**
9076
This function is used to recover X/Open XA distributed transactions.
9077
@return number of prepared transactions stored in xid_list */
9079
InnobaseEngine::doXaRecover(
9080
/*================*/
9081
::drizzled::XID* xid_list,/*!< in/out: prepared transactions */
9082
size_t len) /*!< in: number of slots in xid_list */
9084
assert(this == innodb_engine_ptr);
9086
if (len == 0 || xid_list == NULL) {
9091
return(trx_recover_for_mysql((::XID *)xid_list, len));
9094
/*******************************************************************//**
9095
This function is used to commit one X/Open XA distributed transaction
9096
which is in the prepared state
9097
@return 0 or error number */
9099
InnobaseEngine::doXaCommitXid(
9100
/*===================*/
9101
::drizzled::XID* xid) /*!< in: X/Open XA transaction identification */
9105
assert(this == innodb_engine_ptr);
9107
trx = trx_get_trx_by_xid((::XID *)xid);
9110
innobase_commit_low(trx);
9118
/*******************************************************************//**
9119
This function is used to rollback one X/Open XA distributed transaction
9120
which is in the prepared state
9121
@return 0 or error number */
9123
InnobaseEngine::doXaRollbackXid(
9124
/*=====================*/
9125
::drizzled::XID* xid) /*!< in: X/Open XA transaction
9130
assert(this == innodb_engine_ptr);
9132
trx = trx_get_trx_by_xid((::XID *)xid);
9135
return(innobase_rollback_trx(trx));
9142
/************************************************************//**
9143
Validate the file format name and return its corresponding id.
9144
@return valid file format id */
9147
innobase_file_format_name_lookup(
9148
/*=============================*/
9149
const char* format_name) /*!< in: pointer to file format name */
9154
ut_a(format_name != NULL);
9156
/* The format name can contain the format id itself instead of
9157
the name and we check for that. */
9158
format_id = (uint) strtoul(format_name, &endp, 10);
9160
/* Check for valid parse. */
9161
if (*endp == '\0' && *format_name != '\0') {
9163
if (format_id <= DICT_TF_FORMAT_MAX) {
9169
for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
9173
name = trx_sys_file_format_id_to_name(format_id);
9175
if (!innobase_strcasecmp(format_name, name)) {
9182
return(DICT_TF_FORMAT_MAX + 1);
9185
/************************************************************//**
9186
Validate the file format check config parameters, as a side effect it
9187
sets the srv_max_file_format_at_startup variable.
9188
@return the format_id if valid config value, otherwise, return -1 */
9191
innobase_file_format_validate_and_set(
9192
/*================================*/
9193
const char* format_max) /*!< in: parameter value */
9197
format_id = innobase_file_format_name_lookup(format_max);
9199
if (format_id < DICT_TF_FORMAT_MAX + 1) {
9200
srv_max_file_format_at_startup = format_id;
9201
return((int) format_id);
9209
static void init_options(drizzled::module::option_context &context)
9211
context("disable-checksums",
9212
"Disable InnoDB checksums validation.");
9213
context("data-home-dir",
9214
po::value<string>(),
9215
"The common part for InnoDB table spaces.");
9216
context("disable-doublewrite",
9217
"Disable InnoDB doublewrite buffer.");
9218
context("io-capacity",
9219
po::value<io_capacity_constraint>(&innodb_io_capacity)->default_value(200),
9220
"Number of IOPs the server can do. Tunes the background IO rate");
9221
context("fast-shutdown",
9222
po::value<trinary_constraint>(&innobase_fast_shutdown)->default_value(1),
9223
"Speeds up the shutdown process of the InnoDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like).");
9224
context("purge-batch-size",
9225
po::value<purge_batch_constraint>(&innodb_purge_batch_size)->default_value(20),
9226
"Number of UNDO logs to purge in one batch from the history list. "
9228
context("purge-threads",
9229
po::value<purge_threads_constraint>(&innodb_n_purge_threads)->default_value(0),
9230
"Purge threads can be either 0 or 1. Defalut is 0.");
9231
context("file-per-table",
9232
po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
9233
"Stores each InnoDB table to an .ibd file in the database dir.");
9234
context("file-format",
9235
po::value<string>(&innobase_file_format_name)->default_value("Antelope"),
9236
"File format to use for new tables in .ibd files.");
9237
context("file-format-max",
9238
po::value<string>(&innobase_file_format_max)->default_value("Antelope"),
9239
"The highest file format in the tablespace.");
9240
context("file-format-check",
9241
po::value<bool>(&innobase_file_format_check)->default_value(true)->zero_tokens(),
9242
"Whether to perform system file format check.");
9243
context("flush-log-at-trx-commit",
9244
po::value<trinary_constraint>(&innodb_flush_log_at_trx_commit)->default_value(1),
9245
"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).");
9246
context("flush-method",
9247
po::value<string>(),
9248
"With which method to flush data.");
9249
context("log-group-home-dir",
9250
po::value<string>(),
9251
"Path to InnoDB log files.");
9252
context("max-dirty-pages-pct",
9253
po::value<max_dirty_pages_constraint>(&innodb_max_dirty_pages_pct)->default_value(75),
9254
"Percentage of dirty pages allowed in bufferpool.");
9255
context("disable-adaptive-flushing",
9256
"Do not attempt flushing dirty pages to avoid IO bursts at checkpoints.");
9257
context("max-purge-lag",
9258
po::value<uint64_constraint>(&innodb_max_purge_lag)->default_value(0),
9259
"Desired maximum length of the purge queue (0 = no limit)");
9260
context("status-file",
9261
po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
9262
"Enable SHOW INNODB STATUS output in the innodb_status.<pid> file");
9263
context("disable-stats-on-metadata",
9264
"Disable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)");
9265
context("stats-sample-pages",
9266
po::value<uint64_nonzero_constraint>(&innodb_stats_sample_pages)->default_value(8),
9267
"The number of index pages to sample when calculating statistics (default 8)");
9268
context("disable-adaptive-hash-index",
9269
"Enable InnoDB adaptive hash index (enabled by default)");
9270
context("replication-delay",
9271
po::value<uint64_constraint>(&innodb_replication_delay)->default_value(0),
9272
"Replication thread delay (ms) on the slave server if innodb_thread_concurrency is reached (0 by default)");
9273
context("additional-mem-pool-size",
9274
po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
9275
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.");
9276
context("autoextend-increment",
9277
po::value<autoextend_constraint>(&innodb_auto_extend_increment)->default_value(8L),
9278
"Data file autoextend increment in megabytes");
9279
context("buffer-pool-size",
9280
po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
9281
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.");
9282
context("buffer-pool-instances",
9283
po::value<buffer_pool_instances_constraint>(&innobase_buffer_pool_instances)->default_value(1),
9284
"Number of buffer pool instances, set to higher value on high-end machines to increase scalability");
9286
context("commit-concurrency",
9287
po::value<concurrency_constraint>(&innobase_commit_concurrency)->default_value(0),
9288
"Helps in performance tuning in heavily concurrent environments.");
9289
context("concurrency-tickets",
9290
po::value<uint32_nonzero_constraint>(&innodb_concurrency_tickets)->default_value(500L),
9291
"Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket");
9292
context("read-io-threads",
9293
po::value<io_threads_constraint>(&innobase_read_io_threads)->default_value(4),
9294
"Number of background read I/O threads in InnoDB.");
9295
context("write-io-threads",
9296
po::value<io_threads_constraint>(&innobase_write_io_threads)->default_value(4),
9297
"Number of background write I/O threads in InnoDB.");
9298
context("force-recovery",
9299
po::value<force_recovery_constraint>(&innobase_force_recovery)->default_value(0),
9300
"Helps to save your data in case the disk image of the database becomes corrupt.");
9301
context("log-buffer-size",
9302
po::value<log_buffer_constraint>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
9303
"The size of the buffer which InnoDB uses to write log to the log files on disk.");
9304
context("log-file-size",
9305
po::value<log_file_constraint>(&innobase_log_file_size)->default_value(20*1024*1024L),
9306
"The size of the buffer which InnoDB uses to write log to the log files on disk.");
9307
context("log-files-in-group",
9308
po::value<log_files_in_group_constraint>(&innobase_log_files_in_group)->default_value(2),
9309
"Number of log files in the log group. InnoDB writes to the files in a circular fashion.");
9310
context("mirrored-log-groups",
9311
po::value<mirrored_log_groups_constraint>(&innobase_mirrored_log_groups)->default_value(1),
9312
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.");
9313
context("open-files",
9314
po::value<open_files_constraint>(&innobase_open_files)->default_value(300L),
9315
"How many files at the maximum InnoDB keeps open at the same time.");
9316
context("sync-spin-loops",
9317
po::value<uint32_constraint>(&innodb_sync_spin_loops)->default_value(30L),
9318
"Count of spin-loop rounds in InnoDB mutexes (30 by default)");
9319
context("spin-wait-delay",
9320
po::value<uint32_constraint>(&innodb_spin_wait_delay)->default_value(6L),
9321
"Maximum delay between polling for a spin lock (6 by default)");
9322
context("thread-concurrency",
9323
po::value<concurrency_constraint>(&innobase_thread_concurrency)->default_value(0),
9324
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.");
9325
context("thread-sleep-delay",
9326
po::value<uint32_constraint>(&innodb_thread_sleep_delay)->default_value(10000L),
9327
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep");
9328
context("data-file-path",
9329
po::value<string>(),
9330
"Path to individual files and their sizes.");
9332
po::value<string>()->default_value(INNODB_VERSION_STR),
9334
context("use-internal-malloc",
9335
"Use InnoDB's internal memory allocator instal of the OS memory allocator.");
9336
context("change-buffering",
9337
po::value<string>(&innobase_change_buffering),
9338
"Buffer changes to reduce random access: OFF, ON, inserting, deleting, changing, or purging.");
9339
context("read-ahead-threshold",
9340
po::value<read_ahead_threshold_constraint>(&innodb_read_ahead_threshold)->default_value(56),
9341
"Number of pages that must be accessed sequentially for InnoDB to trigger a readahead.");
9342
context("disable-xa",
9343
"Disable InnoDB support for the XA two-phase commit");
9344
context("disable-table-locks",
9345
"Disable InnoDB locking in LOCK TABLES");
9346
context("strict-mode",
9347
po::value<bool>(&strict_mode)->default_value(false)->zero_tokens(),
9348
"Use strict mode when evaluating create options.");
9349
context("replication-log",
9350
po::value<bool>(&innobase_use_replication_log)->default_value(false),
9351
_("Enable internal replication log."));
9352
context("lock-wait-timeout",
9353
po::value<lock_wait_constraint>(&lock_wait_timeout)->default_value(50),
9354
_("Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
9355
context("old-blocks-pct",
9356
po::value<old_blocks_constraint>(&innobase_old_blocks_pct)->default_value(100 * 3 / 8),
9357
_("Percentage of the buffer pool to reserve for 'old' blocks."));
9358
context("old-blocks-time",
9359
po::value<uint32_t>(&buf_LRU_old_threshold_ms)->default_value(0),
9360
_("ove blocks to the 'new' end of the buffer pool if the first access"
9361
" was at least this many milliseconds ago."
9362
" The timeout is disabled if 0 (the default)."));
9367
DRIZZLE_DECLARE_PLUGIN
9370
innobase_engine_name,
9373
"Supports transactions, row-level locking, and foreign keys",
9375
innobase_init, /* Plugin Init */
9376
NULL, /* system variables */
9377
init_options /* reserved */
9379
DRIZZLE_DECLARE_PLUGIN_END;
9381
int ha_innobase::read_range_first(const key_range *start_key,
9382
const key_range *end_key,
9387
//if (!eq_range_arg)
9388
//in_range_read= TRUE;
9389
res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
9391
// in_range_read= FALSE;
9396
int ha_innobase::read_range_next()
9398
int res= Cursor::read_range_next();
9400
// in_range_read= FALSE;
9404
/***********************************************************************
9405
This function checks each index name for a table against reserved
9406
system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
9407
this function pushes an warning message to the client, and returns true. */
9408
extern "C" UNIV_INTERN
9410
innobase_index_name_is_reserved(
9411
/*============================*/
9412
/* out: true if an index name
9413
matches the reserved name */
9414
const trx_t* trx, /* in: InnoDB transaction handle */
9415
const KeyInfo* key_info, /* in: Indexes to be created */
9416
ulint num_of_keys) /* in: Number of indexes to
9420
uint key_num; /* index number */
9422
for (key_num = 0; key_num < num_of_keys; key_num++) {
9423
key = &key_info[key_num];
9425
if (innobase_strcasecmp(key->name,
9426
innobase_index_reserve_name) == 0) {
9427
/* Push warning to drizzle */
9428
push_warning_printf((Session*)trx->mysql_thd,
9429
DRIZZLE_ERROR::WARN_LEVEL_WARN,
9430
ER_WRONG_NAME_FOR_INDEX,
9431
"Cannot Create Index with name "
9432
"'%s'. The name is reserved "
9433
"for the system default primary "
9435
innobase_index_reserve_name);
9437
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
9438
innobase_index_reserve_name);
9447
#ifdef UNIV_COMPILE_TEST_FUNCS
9449
typedef struct innobase_convert_name_test_struct {
9457
const char* expected;
9458
} innobase_convert_name_test_t;
9461
test_innobase_convert_name()
9466
innobase_convert_name_test_t test_input[] = {
9467
{buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
9468
{buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
9469
{buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
9470
{buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
9471
{buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
9473
{buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9474
{buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9475
{buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9476
{buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9477
{buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
9478
{buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
9479
{buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
9481
{buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
9482
"\"#mysql50#ab\"\"cd\""},
9483
{buf, 17, "ab\"cd", 5, NULL, TRUE,
9484
"\"#mysql50#ab\"\"cd\""},
9485
{buf, 16, "ab\"cd", 5, NULL, TRUE,
9486
"\"#mysql50#ab\"\"c\""},
9487
{buf, 15, "ab\"cd", 5, NULL, TRUE,
9488
"\"#mysql50#ab\"\"\""},
9489
{buf, 14, "ab\"cd", 5, NULL, TRUE,
9491
{buf, 13, "ab\"cd", 5, NULL, TRUE,
9493
{buf, 12, "ab\"cd", 5, NULL, TRUE,
9495
{buf, 11, "ab\"cd", 5, NULL, TRUE,
9497
{buf, 10, "ab\"cd", 5, NULL, TRUE,
9500
{buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9501
{buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9502
{buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
9503
{buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
9504
{buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9505
{buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9506
{buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
9507
{buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
9508
{buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
9509
/* XXX probably "" is a better result in this case
9510
{buf, 1, "ab/cd", 5, NULL, TRUE, "."},
9512
{buf, 0, "ab/cd", 5, NULL, TRUE, ""},
9515
for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
9521
fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
9522
test_input[i].buflen,
9524
test_input[i].idlen,
9525
test_input[i].expected);
9527
end = innobase_convert_name(
9529
test_input[i].buflen,
9531
test_input[i].idlen,
9532
test_input[i].session,
9533
test_input[i].file_id);
9535
res_len = (size_t) (end - test_input[i].buf);
9537
if (res_len != strlen(test_input[i].expected)) {
9539
fprintf(stderr, "unexpected len of the result: %u, "
9540
"expected: %u\n", (unsigned) res_len,
9541
(unsigned) strlen(test_input[i].expected));
9545
if (memcmp(test_input[i].buf,
9546
test_input[i].expected,
9547
strlen(test_input[i].expected)) != 0
9550
fprintf(stderr, "unexpected result: %.*s, "
9551
"expected: %s\n", (int) res_len,
9553
test_input[i].expected);
9558
fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9561
fprintf(stderr, "FAILED\n\n");
9567
#endif /* UNIV_COMPILE_TEST_FUNCS */