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/plugin/xa_storage_engine.h>
64
#include <drizzled/plugin/daemon.h>
65
#include <drizzled/memory/multi_malloc.h>
66
#include <drizzled/pthread_globals.h>
67
#include <drizzled/named_savepoint.h>
69
#include <drizzled/transaction_services.h>
70
#include <drizzled/message/statement_transform.h>
72
#include <boost/algorithm/string.hpp>
73
#include <boost/program_options.hpp>
74
#include <boost/scoped_array.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 */
90
#include "os0thread.h"
91
#include "srv0start.h"
98
#include "row0mysql.h"
102
#include "lock0lock.h"
103
#include "dict0crea.h"
104
#include "create_replication.h"
108
#include "sync0sync.h"
111
#include "row0merge.h"
113
#include "dict0boot.h"
114
#include "ha_prototypes.h"
116
#include "ibuf0ibuf.h"
118
#include "ha_innodb.h"
119
#include "data_dictionary.h"
120
#include "replication_dictionary.h"
121
#include "internal_dictionary.h"
122
#include "handler0vars.h"
128
#include <plugin/innobase/handler/status_function.h>
129
#include <plugin/innobase/handler/replication_log.h>
131
#include <google/protobuf/io/zero_copy_stream.h>
132
#include <google/protobuf/io/zero_copy_stream_impl.h>
133
#include <google/protobuf/io/coded_stream.h>
134
#include <google/protobuf/text_format.h>
136
#include <boost/thread/mutex.hpp>
139
using namespace drizzled;
141
/** to protect innobase_open_files */
142
static boost::mutex innobase_share_mutex;
144
/** to force correct commit order in binlog */
145
static ulong commit_threads = 0;
146
static boost::condition_variable commit_cond;
147
static boost::mutex commit_cond_m;
148
static bool innodb_inited = 0;
150
#define INSIDE_HA_INNOBASE_CC
152
/* In the Windows plugin, the return value of current_session is
153
undefined. Map it to NULL. */
154
#if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
155
# undef current_session
156
# define current_session NULL
157
# define EQ_CURRENT_SESSION(session) TRUE
158
#else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
159
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
160
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
162
static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
164
typedef constrained_check<uint32_t, UINT32_MAX, 10> open_files_constraint;
165
static open_files_constraint innobase_open_files;
166
typedef constrained_check<uint32_t, 10, 1> mirrored_log_groups_constraint;
167
static mirrored_log_groups_constraint innobase_mirrored_log_groups;
168
typedef constrained_check<uint32_t, 100, 2> log_files_in_group_constraint;
169
static log_files_in_group_constraint innobase_log_files_in_group;
170
typedef constrained_check<uint32_t, 6, 0> force_recovery_constraint;
171
force_recovery_constraint innobase_force_recovery;
172
typedef constrained_check<size_t, SIZE_MAX, 256*1024, 1024> log_buffer_constraint;
173
static log_buffer_constraint innobase_log_buffer_size;
174
typedef constrained_check<size_t, SIZE_MAX, 512*1024, 1024> additional_mem_pool_constraint;
175
static additional_mem_pool_constraint innobase_additional_mem_pool_size;
176
typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
177
static autoextend_constraint innodb_auto_extend_increment;
178
typedef constrained_check<size_t, SIZE_MAX, 5242880, 1048576> buffer_pool_constraint;
179
static buffer_pool_constraint innobase_buffer_pool_size;
180
typedef constrained_check<uint32_t, MAX_BUFFER_POOLS, 1> buffer_pool_instances_constraint;
181
static buffer_pool_instances_constraint innobase_buffer_pool_instances;
182
typedef constrained_check<uint32_t, UINT32_MAX, 100> io_capacity_constraint;
183
static io_capacity_constraint innodb_io_capacity;
184
typedef constrained_check<uint32_t, 5000, 1> purge_batch_constraint;
185
static purge_batch_constraint innodb_purge_batch_size;
186
typedef constrained_check<uint32_t, 1, 0> purge_threads_constraint;
187
static purge_threads_constraint innodb_n_purge_threads;
188
typedef constrained_check<uint32_t, 2, 0> trinary_constraint;
189
static trinary_constraint innodb_flush_log_at_trx_commit;
190
typedef constrained_check<unsigned int, 99, 0> max_dirty_pages_constraint;
191
static max_dirty_pages_constraint innodb_max_dirty_pages_pct;
192
static uint64_constraint innodb_max_purge_lag;
193
static uint64_nonzero_constraint innodb_stats_sample_pages;
194
typedef constrained_check<uint32_t, 64, 1> io_threads_constraint;
195
static io_threads_constraint innobase_read_io_threads;
196
static io_threads_constraint innobase_write_io_threads;
198
typedef constrained_check<uint32_t, 1000, 0> concurrency_constraint;
199
static concurrency_constraint innobase_commit_concurrency;
200
static concurrency_constraint innobase_thread_concurrency;
201
static uint32_nonzero_constraint innodb_concurrency_tickets;
203
typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
204
static log_file_constraint innobase_log_file_size;
206
static uint64_constraint innodb_replication_delay;
208
/** Percentage of the buffer pool to reserve for 'old' blocks.
209
Connected to buf_LRU_old_ratio. */
210
typedef constrained_check<uint32_t, 95, 5> old_blocks_constraint;
211
static old_blocks_constraint innobase_old_blocks_pct;
213
static uint32_constraint innodb_sync_spin_loops;
214
static uint32_constraint innodb_spin_wait_delay;
215
static uint32_constraint innodb_thread_sleep_delay;
217
typedef constrained_check<uint32_t, 64, 0> read_ahead_threshold_constraint;
218
static read_ahead_threshold_constraint innodb_read_ahead_threshold;
220
/* The default values for the following char* start-up parameters
221
are determined in innobase_init below: */
223
std::string innobase_data_home_dir;
224
std::string innobase_data_file_path;
225
std::string innobase_log_group_home_dir;
226
static string innobase_file_format_name;
227
static string innobase_change_buffering;
229
/* The highest file format being used in the database. The value can be
230
set by user, however, it will be adjusted to the newer file format if
231
a table of such format is created/opened. */
232
static string innobase_file_format_max;
234
/* Below we have boolean-valued start-up parameters, and their default
237
typedef constrained_check<uint32_t, 2, 0> trinary_constraint;
238
static trinary_constraint innobase_fast_shutdown;
240
/* "innobase_file_format_check" decides whether we would continue
241
booting the server if the file format stamped on the system
242
table space exceeds the maximum file format supported
243
by the server. Can be set during server startup at command
244
line or configure file, and a read only variable after
247
/* If a new file format is introduced, the file format
248
name needs to be updated accordingly. Please refer to
249
file_format_name_map[] defined in trx0sys.c for the next
252
static my_bool innobase_file_format_check = TRUE;
253
static my_bool innobase_use_doublewrite = TRUE;
254
static my_bool innobase_use_checksums = TRUE;
255
static my_bool innobase_rollback_on_timeout = FALSE;
256
static my_bool innobase_create_status_file = FALSE;
257
static bool innobase_use_replication_log;
258
static bool support_xa;
259
static bool strict_mode;
260
typedef constrained_check<uint32_t, 1024*1024*1024, 1> lock_wait_constraint;
261
static lock_wait_constraint lock_wait_timeout;
263
static char* internal_innobase_data_file_path = NULL;
265
/* The following counter is used to convey information to InnoDB
266
about server activity: in selects it is not sensible to call
267
srv_active_wake_master_thread after each fetch or search, we only do
268
it every INNOBASE_WAKE_INTERVAL'th step. */
270
#define INNOBASE_WAKE_INTERVAL 32
271
static ulong innobase_active_counter = 0;
273
static hash_table_t* innobase_open_tables;
275
#ifdef __NETWARE__ /* some special cleanup for NetWare */
276
bool nw_panic = FALSE;
279
/** Allowed values of innodb_change_buffering */
280
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
281
"none", /* IBUF_USE_NONE */
282
"inserts", /* IBUF_USE_INSERT */
283
"deletes", /* IBUF_USE_DELETE_MARK */
284
"changes", /* IBUF_USE_INSERT_DELETE_MARK */
285
"purges", /* IBUF_USE_DELETE */
286
"all" /* IBUF_USE_ALL */
289
/* "GEN_CLUST_INDEX" is the name reserved for Innodb default
290
system primary index. */
291
static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX";
293
/********************************************************************
294
Gives the file extension of an InnoDB single-table tablespace. */
295
static const char* ha_innobase_exts[] = {
300
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
302
static INNOBASE_SHARE *get_share(const char *table_name);
303
static void free_share(INNOBASE_SHARE *share);
305
class InnobaseEngine : public plugin::XaStorageEngine
308
explicit InnobaseEngine(string name_arg) :
309
plugin::XaStorageEngine(name_arg,
311
HTON_CAN_INDEX_BLOBS |
312
HTON_PRIMARY_KEY_IN_READ_INDEX |
313
HTON_PARTIAL_COLUMN_READ |
314
HTON_TABLE_SCAN_ON_INDEX |
315
HTON_HAS_FOREIGN_KEYS |
316
HTON_HAS_DOES_TRANSACTIONS)
318
table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
319
addAlias("INNOBASE");
322
virtual ~InnobaseEngine()
326
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
328
hash_table_free(innobase_open_tables);
329
innobase_open_tables = NULL;
330
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
333
srv_free_paths_and_sizes();
334
if (internal_innobase_data_file_path)
335
free(internal_innobase_data_file_path);
338
/* These get strdup'd from vm variables */
343
virtual int doStartTransaction(Session *session, start_transaction_option_t options);
344
virtual void doStartStatement(Session *session);
345
virtual void doEndStatement(Session *session);
350
/*======================*/
351
/* out: 0 or error number */
352
Session* session); /* in: handle to the MySQL thread of the user
353
whose resources should be free'd */
355
virtual int doSetSavepoint(Session* session,
356
drizzled::NamedSavepoint &savepoint);
357
virtual int doRollbackToSavepoint(Session* session,
358
drizzled::NamedSavepoint &savepoint);
359
virtual int doReleaseSavepoint(Session* session,
360
drizzled::NamedSavepoint &savepoint);
361
virtual int doXaCommit(Session* session, bool all)
363
return doCommit(session, all); /* XA commit just does a SQL COMMIT */
365
virtual int doXaRollback(Session *session, bool all)
367
return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
369
virtual uint64_t doGetCurrentTransactionId(Session *session);
370
virtual uint64_t doGetNewTransactionId(Session *session);
371
virtual int doCommit(Session* session, bool all);
372
virtual int doRollback(Session* session, bool all);
374
/***********************************************************************
375
This function is used to prepare X/Open XA distributed transaction */
380
/* out: 0 or error number */
381
Session* session, /* in: handle to the MySQL thread of the user
382
whose XA transaction should be prepared */
383
bool all); /* in: TRUE - commit transaction
384
FALSE - the current SQL statement ended */
385
/***********************************************************************
386
This function is used to recover X/Open XA distributed transactions */
391
/* out: number of prepared transactions
392
stored in xid_list */
393
::drizzled::XID* xid_list, /* in/out: prepared transactions */
394
size_t len); /* in: number of slots in xid_list */
395
/***********************************************************************
396
This function is used to commit one X/Open XA distributed transaction
397
which is in the prepared state */
401
/*===================*/
402
/* out: 0 or error number */
403
::drizzled::XID* xid); /* in: X/Open XA transaction identification */
404
/***********************************************************************
405
This function is used to rollback one X/Open XA distributed transaction
406
which is in the prepared state */
410
/*=====================*/
411
/* out: 0 or error number */
412
::drizzled::XID *xid); /* in: X/Open XA transaction identification */
414
virtual Cursor *create(Table &table)
416
return new ha_innobase(*this, table);
419
/*********************************************************************
420
Removes all tables in the named database inside InnoDB. */
423
/*===================*/
424
/* out: error number */
425
const identifier::Schema &identifier); /* in: database path; inside InnoDB the name
426
of the last directory in the path is used as
427
the database name: for example, in 'mysql/data/test'
428
the database name is 'test' */
430
/********************************************************************
431
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
432
the logs, and the name of this function should be innobase_checkpoint. */
437
/* out: TRUE if error */
439
/****************************************************************************
440
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
441
Monitor to the client. */
446
Session* session, /* in: the MySQL query thread of the caller */
447
stat_print_fn *stat_print,
448
enum ha_stat_type stat_type);
452
doReleaseTemporaryLatches(
453
/*===============================*/
455
Session* session); /* in: MySQL thread */
458
const char** bas_ext() const {
459
return(ha_innobase_exts);
462
UNIV_INTERN int doCreateTable(Session &session,
464
const identifier::Table &identifier,
466
UNIV_INTERN int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
467
UNIV_INTERN int doDropTable(Session &session, const identifier::Table &identifier);
469
UNIV_INTERN virtual bool get_error_message(int error, String *buf) const;
471
UNIV_INTERN uint32_t max_supported_keys() const;
472
UNIV_INTERN uint32_t max_supported_key_length() const;
473
UNIV_INTERN uint32_t max_supported_key_part_length() const;
476
UNIV_INTERN uint32_t index_flags(enum ha_key_alg) const
478
return (HA_READ_NEXT |
485
int doGetTableDefinition(drizzled::Session& session,
486
const identifier::Table &identifier,
487
drizzled::message::Table &table_proto);
489
bool doDoesTableExist(drizzled::Session& session, const identifier::Table &identifier);
491
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
492
const drizzled::identifier::Schema &schema_identifier,
493
drizzled::identifier::Table::vector &set_of_identifiers);
494
bool validateCreateTableOption(const std::string &key, const std::string &state);
495
void dropTemporarySchema();
500
bool InnobaseEngine::validateCreateTableOption(const std::string &key, const std::string &state)
502
if (boost::iequals(key, "ROW_FORMAT"))
504
if (boost::iequals(state, "COMPRESSED"))
507
if (boost::iequals(state, "COMPACT"))
510
if (boost::iequals(state, "DYNAMIC"))
513
if (boost::iequals(state, "REDUNDANT"))
520
void InnobaseEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
521
const drizzled::identifier::Schema &schema_identifier,
522
drizzled::identifier::Table::vector &set_of_identifiers)
524
CachedDirectory::Entries entries= directory.getEntries();
526
std::string search_string(schema_identifier.getSchemaName());
528
boost::algorithm::to_lower(search_string);
530
if (search_string.compare("data_dictionary") == 0)
532
set_of_identifiers.push_back(identifier::Table(schema_identifier.getSchemaName(), "SYS_REPLICATION_LOG"));
535
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
536
entry_iter != entries.end(); ++entry_iter)
538
CachedDirectory::Entry *entry= *entry_iter;
539
const string *filename= &entry->filename;
541
assert(filename->size());
543
const char *ext= strchr(filename->c_str(), '.');
545
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
546
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
551
path+= directory.getPath();
553
path+= entry->filename;
555
message::Table definition;
556
if (StorageEngine::readTableFile(path, definition))
559
Using schema_identifier here to stop unused warning, could use
560
definition.schema() instead
562
identifier::Table identifier(schema_identifier.getSchemaName(), definition.name());
563
set_of_identifiers.push_back(identifier);
569
bool InnobaseEngine::doDoesTableExist(Session &session, const identifier::Table &identifier)
571
string proto_path(identifier.getPath());
572
proto_path.append(DEFAULT_FILE_EXTENSION);
574
if (session.getMessageCache().doesTableMessageExist(identifier))
577
std::string search_string(identifier.getPath());
578
boost::algorithm::to_lower(search_string);
580
if (search_string.compare("data_dictionary/sys_replication_log") == 0)
583
if (access(proto_path.c_str(), F_OK))
591
int InnobaseEngine::doGetTableDefinition(Session &session,
592
const identifier::Table &identifier,
593
message::Table &table_proto)
595
string proto_path(identifier.getPath());
596
proto_path.append(DEFAULT_FILE_EXTENSION);
598
// First we check the temporary tables.
599
if (session.getMessageCache().getTableMessage(identifier, table_proto))
602
if (read_replication_log_table_message(identifier.getTableName().c_str(), &table_proto) == 0)
605
if (access(proto_path.c_str(), F_OK))
610
if (StorageEngine::readTableFile(proto_path, table_proto))
617
/************************************************************//**
618
Validate the file format name and return its corresponding id.
619
@return valid file format id */
622
innobase_file_format_name_lookup(
623
/*=============================*/
624
const char* format_name); /*!< in: pointer to file format
626
/************************************************************//**
627
Validate the file format check config parameters, as a side effect it
628
sets the srv_max_file_format_at_startup variable.
629
@return the format_id if valid config value, otherwise, return -1 */
632
innobase_file_format_validate_and_set(
633
/*================================*/
634
const char* format_max); /*!< in: parameter value */
636
static const char innobase_engine_name[]= "InnoDB";
639
/*****************************************************************//**
640
Commits a transaction in an InnoDB database. */
645
trx_t* trx); /*!< in: transaction handle */
647
static drizzle_show_var innodb_status_variables[]= {
648
{"buffer_pool_pages_data",
649
(char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
650
{"buffer_pool_pages_dirty",
651
(char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
652
{"buffer_pool_pages_flushed",
653
(char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
654
{"buffer_pool_pages_free",
655
(char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
657
{"buffer_pool_pages_latched",
658
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
659
#endif /* UNIV_DEBUG */
660
{"buffer_pool_pages_misc",
661
(char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
662
{"buffer_pool_pages_total",
663
(char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
664
{"buffer_pool_read_ahead",
665
(char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG},
666
{"buffer_pool_read_ahead_evicted",
667
(char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG},
668
{"buffer_pool_read_requests",
669
(char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
670
{"buffer_pool_reads",
671
(char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
672
{"buffer_pool_wait_free",
673
(char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
674
{"buffer_pool_write_requests",
675
(char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
677
(char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
678
{"data_pending_fsyncs",
679
(char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
680
{"data_pending_reads",
681
(char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
682
{"data_pending_writes",
683
(char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
685
(char*) &export_vars.innodb_data_read, SHOW_LONG},
687
(char*) &export_vars.innodb_data_reads, SHOW_LONG},
689
(char*) &export_vars.innodb_data_writes, SHOW_LONG},
691
(char*) &export_vars.innodb_data_written, SHOW_LONG},
692
{"dblwr_pages_written",
693
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
695
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
696
{"have_atomic_builtins",
697
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
699
(char*) &export_vars.innodb_log_waits, SHOW_LONG},
700
{"log_write_requests",
701
(char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
703
(char*) &export_vars.innodb_log_writes, SHOW_LONG},
705
(char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
706
{"os_log_pending_fsyncs",
707
(char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
708
{"os_log_pending_writes",
709
(char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
711
(char*) &export_vars.innodb_os_log_written, SHOW_LONG},
713
(char*) &export_vars.innodb_page_size, SHOW_LONG},
715
(char*) &export_vars.innodb_pages_created, SHOW_LONG},
717
(char*) &export_vars.innodb_pages_read, SHOW_LONG},
719
(char*) &export_vars.innodb_pages_written, SHOW_LONG},
720
{"row_lock_current_waits",
721
(char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
723
(char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
724
{"row_lock_time_avg",
725
(char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
726
{"row_lock_time_max",
727
(char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
729
(char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
731
(char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
733
(char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
735
(char*) &export_vars.innodb_rows_read, SHOW_LONG},
737
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
738
{NULL, NULL, SHOW_LONG}
741
InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
742
plugin::TableFunction::Generator(fields)
744
srv_export_innodb_status();
745
status_var_ptr= innodb_status_variables;
748
bool InnodbStatusTool::Generator::populate()
750
if (status_var_ptr->name)
752
std::ostringstream oss;
754
const char *value= status_var_ptr->value;
757
push(status_var_ptr->name);
759
switch (status_var_ptr->type)
762
oss << *(int64_t*) value;
763
return_value= oss.str();
766
oss << *(int64_t*) value;
767
return_value= oss.str();
770
return_value= *(bool*) value ? "ON" : "OFF";
777
if (return_value.length())
789
/* General functions */
791
/******************************************************************//**
792
Returns true if the thread is the replication thread on the slave
793
server. Used in srv_conc_enter_innodb() to determine if the thread
794
should be allowed to enter InnoDB - the replication thread is treated
795
differently than other threads. Also used in
796
srv_conc_force_exit_innodb().
798
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
800
@return true if session is the replication thread */
803
thd_is_replication_slave_thread(
804
/*============================*/
805
drizzled::Session* ) /*!< in: thread handle (Session*) */
810
/******************************************************************//**
811
Save some CPU by testing the value of srv_thread_concurrency in inline
815
innodb_srv_conc_enter_innodb(
816
/*=========================*/
817
trx_t* trx) /*!< in: transaction handle */
819
if (UNIV_LIKELY(!srv_thread_concurrency)) {
824
srv_conc_enter_innodb(trx);
827
/******************************************************************//**
828
Save some CPU by testing the value of srv_thread_concurrency in inline
832
innodb_srv_conc_exit_innodb(
833
/*========================*/
834
trx_t* trx) /*!< in: transaction handle */
836
if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
841
srv_conc_exit_innodb(trx);
844
/******************************************************************//**
845
Releases possible search latch and InnoDB thread FIFO ticket. These should
846
be released at each SQL statement end, and also when mysqld passes the
847
control to the client. It does no harm to release these also in the middle
848
of an SQL statement. */
851
innobase_release_stat_resources(
852
/*============================*/
853
trx_t* trx) /*!< in: transaction object */
855
if (trx->has_search_latch) {
856
trx_search_latch_release_if_reserved(trx);
859
if (trx->declared_to_be_inside_innodb) {
860
/* Release our possible ticket in the FIFO */
862
srv_conc_force_exit_innodb(trx);
866
/******************************************************************//**
867
Returns true if the transaction this thread is processing has edited
868
non-transactional tables. Used by the deadlock detector when deciding
869
which transaction to rollback in case of a deadlock - we try to avoid
870
rolling back transactions that have edited non-transactional tables.
872
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
874
@return true if non-transactional tables have been edited */
877
thd_has_edited_nontrans_tables(
878
/*===========================*/
879
drizzled::Session *session) /*!< in: thread handle (Session*) */
881
return((ibool)session->transaction.all.hasModifiedNonTransData());
884
/******************************************************************//**
885
Returns true if the thread is executing a SELECT statement.
886
@return true if session is executing SELECT */
891
const drizzled::Session *session) /*!< in: thread handle (Session*) */
893
return(session->getSqlCommand() == SQLCOM_SELECT);
896
/******************************************************************//**
897
Returns true if the thread supports XA,
898
global value of innodb_supports_xa if session is NULL.
899
@return true if session has XA support */
904
drizzled::Session* ) /*!< in: thread handle (Session*), or NULL to query
905
the global innodb_supports_xa */
907
/* TODO: Add support here for per-session value */
911
/******************************************************************//**
912
Returns the lock wait timeout for the current connection.
913
@return the lock wait timeout, in seconds */
916
thd_lock_wait_timeout(
917
/*==================*/
918
drizzled::Session*) /*!< in: thread handle (Session*), or NULL to query
919
the global innodb_lock_wait_timeout */
921
/* TODO: Add support here for per-session value */
922
/* According to <drizzle/plugin.h>, passing session == NULL
923
returns the global value of the session variable. */
924
return((ulong)lock_wait_timeout.get());
927
/******************************************************************//**
928
Set the time waited for the lock for the current query. */
931
thd_set_lock_wait_time(
932
/*===================*/
933
drizzled::Session* in_session, /*!< in: thread handle (THD*) */
934
ulint value) /*!< in: time waited for the lock */
937
in_session->utime_after_lock+= value;
940
/********************************************************************//**
941
Obtain the InnoDB transaction of a MySQL thread.
942
@return reference to transaction pointer */
947
Session* session) /*!< in: Drizzle Session */
949
return *(trx_t**) session->getEngineData(innodb_engine_ptr);
953
plugin::ReplicationReturnCode ReplicationLog::apply(Session &session,
954
const message::Transaction &message)
956
char *data= new char[message.ByteSize()];
958
message.SerializeToArray(data, message.ByteSize());
960
trx_t *trx= session_to_trx(&session);
962
uint64_t trx_id= message.transaction_context().transaction_id();
963
uint32_t seg_id= message.segment_id();
964
uint64_t end_timestamp= message.transaction_context().end_timestamp();
965
bool is_end_segment= message.end_segment();
966
trx->log_commit_id= TRUE;
967
ulint error= insert_replication_message(data, message.ByteSize(), trx, trx_id,
968
end_timestamp, is_end_segment, seg_id);
973
return plugin::SUCCESS;
976
/********************************************************************//**
977
Call this function when mysqld passes control to the client. That is to
978
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
979
documentation, see Cursor.cc.
982
InnobaseEngine::doReleaseTemporaryLatches(
983
/*===============================*/
984
Session* session) /*!< in: MySQL thread */
988
assert(this == innodb_engine_ptr);
990
if (!innodb_inited) {
995
trx = session_to_trx(session);
998
innobase_release_stat_resources(trx);
1003
/********************************************************************//**
1004
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
1005
time calls srv_active_wake_master_thread. This function should be used
1006
when a single database operation may introduce a small need for
1007
server utility activity, like checkpointing. */
1010
innobase_active_small(void)
1011
/*=======================*/
1013
innobase_active_counter++;
1015
if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
1016
srv_active_wake_master_thread();
1020
/********************************************************************//**
1021
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
1022
about a possible transaction rollback inside InnoDB caused by a lock wait
1023
timeout or a deadlock.
1024
@return MySQL error code */
1027
convert_error_code_to_mysql(
1028
/*========================*/
1029
int error, /*!< in: InnoDB error code */
1030
ulint flags, /*!< in: InnoDB table flags, or 0 */
1031
Session* session)/*!< in: user thread handle or NULL */
1037
case DB_INTERRUPTED:
1038
my_error(ER_QUERY_INTERRUPTED, MYF(0));
1041
case DB_FOREIGN_EXCEED_MAX_CASCADE:
1042
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1043
HA_ERR_ROW_IS_REFERENCED,
1044
"InnoDB: Cannot delete/update "
1045
"rows with cascading foreign key "
1046
"constraints that exceed max "
1047
"depth of %d. Please "
1048
"drop extra constraints and try "
1049
"again", DICT_FK_MAX_RECURSIVE_LOAD);
1054
return(-1); /* unspecified error */
1056
case DB_DUPLICATE_KEY:
1057
/* Be cautious with returning this error, since
1058
mysql could re-enter the storage layer to get
1059
duplicated key info, the operation requires a
1060
valid table handle and/or transaction information,
1061
which might not always be available in the error
1063
return(HA_ERR_FOUND_DUPP_KEY);
1065
case DB_FOREIGN_DUPLICATE_KEY:
1066
return(HA_ERR_FOREIGN_DUPLICATE_KEY);
1068
case DB_MISSING_HISTORY:
1069
return(HA_ERR_TABLE_DEF_CHANGED);
1071
case DB_RECORD_NOT_FOUND:
1072
return(HA_ERR_NO_ACTIVE_RECORD);
1075
/* Since we rolled back the whole transaction, we must
1076
tell it also to MySQL so that MySQL knows to empty the
1077
cached binlog for this transaction */
1079
session->markTransactionForRollback(TRUE);
1081
return(HA_ERR_LOCK_DEADLOCK);
1083
case DB_LOCK_WAIT_TIMEOUT:
1084
/* Starting from 5.0.13, we let MySQL just roll back the
1085
latest SQL statement in a lock wait timeout. Previously, we
1086
rolled back the whole transaction. */
1088
session->markTransactionForRollback((bool)row_rollback_on_timeout);
1090
return(HA_ERR_LOCK_WAIT_TIMEOUT);
1092
case DB_NO_REFERENCED_ROW:
1093
return(HA_ERR_NO_REFERENCED_ROW);
1095
case DB_ROW_IS_REFERENCED:
1096
return(HA_ERR_ROW_IS_REFERENCED);
1098
case DB_CANNOT_ADD_CONSTRAINT:
1099
case DB_CHILD_NO_INDEX:
1100
case DB_PARENT_NO_INDEX:
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 & DICT_TF_COMPACT) / 2);
1125
return(HA_ERR_TO_BIG_ROW);
1127
case DB_NO_SAVEPOINT:
1128
return(HA_ERR_NO_SAVEPOINT);
1130
case DB_LOCK_TABLE_FULL:
1131
/* Since we rolled back the whole transaction, we must
1132
tell it also to MySQL so that MySQL knows to empty the
1133
cached binlog for this transaction */
1135
session->markTransactionForRollback(TRUE);
1137
return(HA_ERR_LOCK_TABLE_FULL);
1139
case DB_PRIMARY_KEY_IS_NULL:
1140
return(ER_PRIMARY_CANT_HAVE_NULL);
1142
case DB_TOO_MANY_CONCURRENT_TRXS:
1144
/* Once MySQL add the appropriate code to errmsg.txt then
1145
we can get rid of this #ifdef. NOTE: The code checked by
1146
the #ifdef is the suggested name for the error condition
1147
and the actual error code name could very well be different.
1148
This will require some monitoring, ie. the status
1149
of this request on our part.*/
1151
/* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only
1152
available in 5.1.38 and later, but the plugin should still
1153
work with previous versions of MySQL.
1154
In Drizzle we seem to not have this yet.
1156
#ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS
1157
return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
1158
#else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1159
return(HA_ERR_RECORD_FILE_FULL);
1160
#endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1161
case DB_UNSUPPORTED:
1162
return(HA_ERR_UNSUPPORTED);
1167
/*************************************************************//**
1168
Prints info of a Session object (== user session thread) to the given file. */
1171
innobase_mysql_print_thd(
1172
/*=====================*/
1173
FILE* f, /*!< in: output stream */
1174
drizzled::Session *in_session, /*!< in: pointer to a Drizzle Session object */
1175
uint ) /*!< in: max query length to print, or 0 to
1176
use the default max length */
1178
drizzled::identifier::User::const_shared_ptr user_identifier(in_session->user());
1181
"Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
1182
static_cast<uint64_t>(in_session->getSessionId()),
1183
static_cast<uint64_t>(in_session->getQueryId()),
1184
getServerHostname().c_str(),
1185
user_identifier->address().c_str(),
1186
user_identifier->username().c_str()
1188
fprintf(f, "\n%s", in_session->getQueryString()->c_str());
1192
/******************************************************************//**
1193
Get the variable length bounds of the given character set. */
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. */
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. */
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 */
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. */
1264
innobase_casedn_str(
1265
/*================*/
1266
char* a) /*!< in/out: string to put in lower case */
1268
my_casedn_str(system_charset_info, a);
1277
return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
1280
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1281
/*******************************************************************//**
1282
Map an OS error to an errno value. The OS error number is stored in
1283
_doserrno and the mapped value is stored in errno) */
1286
unsigned long); /*!< in: OS error value */
1288
/*********************************************************************//**
1289
Creates a temporary file.
1290
@return temporary file descriptor, or < 0 on error */
1293
innobase_mysql_tmpfile(void)
1294
/*========================*/
1296
int fd; /* handle of opened file */
1297
HANDLE osfh; /* OS handle of opened file */
1298
char* tmpdir; /* point to the directory
1299
where to create file */
1300
TCHAR path_buf[MAX_PATH - 14]; /* buffer for tmp file path.
1301
The length cannot be longer
1302
than MAX_PATH - 14, or
1303
GetTempFileName will fail. */
1304
char filename[MAX_PATH]; /* name of the tmpfile */
1305
DWORD fileaccess = GENERIC_READ /* OS file access */
1308
DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
1310
| FILE_SHARE_DELETE;
1311
DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
1312
DWORD fileattrib = /* OS file attribute flags */
1313
FILE_ATTRIBUTE_NORMAL
1314
| FILE_FLAG_DELETE_ON_CLOSE
1315
| FILE_ATTRIBUTE_TEMPORARY
1316
| FILE_FLAG_SEQUENTIAL_SCAN;
1318
tmpdir = my_tmpdir(&mysql_tmpdir_list);
1320
/* The tmpdir parameter can not be NULL for GetTempFileName. */
1324
/* Use GetTempPath to determine path for temporary files. */
1325
ret = GetTempPath(sizeof(path_buf), path_buf);
1326
if (ret > sizeof(path_buf) || (ret == 0)) {
1328
_dosmaperr(GetLastError()); /* map error */
1335
/* Use GetTempFileName to generate a unique filename. */
1336
if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
1338
_dosmaperr(GetLastError()); /* map error */
1342
/* Open/Create the file. */
1343
osfh = CreateFile(filename, fileaccess, fileshare, NULL,
1344
filecreate, fileattrib, NULL);
1345
if (osfh == INVALID_HANDLE_VALUE) {
1347
/* open/create file failed! */
1348
_dosmaperr(GetLastError()); /* map error */
1353
/* Associates a CRT file descriptor with the OS file handle. */
1354
fd = _open_osfhandle((intptr_t) osfh, 0);
1355
} while (fd == -1 && errno == EINTR);
1358
/* Open failed, close the file handle. */
1360
_dosmaperr(GetLastError()); /* map error */
1361
CloseHandle(osfh); /* no need to check if
1362
CloseHandle fails */
1368
/*********************************************************************//**
1369
Creates a temporary file.
1370
@return temporary file descriptor, or < 0 on error */
1373
innobase_mysql_tmpfile(void)
1374
/*========================*/
1377
int fd = ::drizzled::tmpfile("ib");
1379
/* Copy the file descriptor, so that the additional resources
1380
allocated by create_temp_file() can be freed by invoking
1381
internal::my_close().
1383
Because the file descriptor returned by this function
1384
will be passed to fdopen(), it will be closed by invoking
1385
fclose(), which in turn will invoke close() instead of
1386
internal::my_close(). */
1390
my_error(EE_OUT_OF_FILERESOURCES,
1391
MYF(ME_BELL+ME_WAITTANG),
1394
internal::my_close(fd, MYF(MY_WME));
1398
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
1401
/*******************************************************************//**
1402
Formats the raw data in "data" (in InnoDB on-disk format) that is of
1403
type DATA_(CHAR|VARCHAR|DRIZZLE|VARDRIZZLE) using "charset_coll" and writes
1404
the result to "buf". The result is converted to "system_charset_info".
1405
Not more than "buf_size" bytes are written to "buf".
1406
The result is always NUL-terminated (provided buf_size > 0) and the
1407
number of bytes that were written to "buf" is returned (including the
1409
@return number of bytes that were written */
1412
innobase_raw_format(
1413
/*================*/
1414
const char* data, /*!< in: raw data */
1415
ulint data_len, /*!< in: raw data length
1417
ulint , /*!< in: charset collation */
1418
char* buf, /*!< out: output buffer */
1419
ulint buf_size) /*!< in: output buffer size
1422
return(ut_str_sql_format(data, data_len, buf, buf_size));
1425
/*********************************************************************//**
1426
Compute the next autoinc value.
1428
For MySQL replication the autoincrement values can be partitioned among
1429
the nodes. The offset is the start or origin of the autoincrement value
1430
for a particular node. For n nodes the increment will be n and the offset
1431
will be in the interval [1, n]. The formula tries to allocate the next
1432
value for a particular node.
1434
Note: This function is also called with increment set to the number of
1435
values we want to reserve for multi-value inserts e.g.,
1437
INSERT INTO T VALUES(), (), ();
1439
innobase_next_autoinc() will be called with increment set to
1440
to reserve 3 values for the multi-value INSERT above.
1441
@return the next value */
1444
innobase_next_autoinc(
1445
/*==================*/
1446
uint64_t current, /*!< in: Current value */
1447
uint64_t increment, /*!< in: increment current by */
1448
uint64_t offset, /*!< in: AUTOINC offset */
1449
uint64_t max_value) /*!< in: max value for type */
1451
uint64_t next_value;
1453
/* Should never be 0. */
1454
ut_a(increment > 0);
1456
/* According to MySQL documentation, if the offset is greater than
1457
the increment then the offset is ignored. */
1458
if (offset > increment) {
1462
if (max_value <= current) {
1463
next_value = max_value;
1464
} else if (offset <= 1) {
1465
/* Offset 0 and 1 are the same, because there must be at
1466
least one node in the system. */
1467
if (max_value - current <= increment) {
1468
next_value = max_value;
1470
next_value = current + increment;
1472
} else if (max_value > current) {
1473
if (current > offset) {
1474
next_value = ((current - offset) / increment) + 1;
1476
next_value = ((offset - current) / increment) + 1;
1479
ut_a(increment > 0);
1480
ut_a(next_value > 0);
1482
/* Check for multiplication overflow. */
1483
if (increment > (max_value / next_value)) {
1485
next_value = max_value;
1487
next_value *= increment;
1489
ut_a(max_value >= next_value);
1491
/* Check for overflow. */
1492
if (max_value - next_value <= offset) {
1493
next_value = max_value;
1495
next_value += offset;
1499
next_value = max_value;
1502
ut_a(next_value <= max_value);
1507
/*********************************************************************//**
1508
Initializes some fields in an InnoDB transaction object. */
1513
Session* session, /*!< in: user thread handle */
1514
trx_t* trx) /*!< in/out: InnoDB transaction handle */
1516
assert(session == trx->mysql_thd);
1518
trx->check_foreigns = !session_test_options(
1519
session, OPTION_NO_FOREIGN_KEY_CHECKS);
1521
trx->check_unique_secondary = !session_test_options(
1522
session, OPTION_RELAXED_UNIQUE_CHECKS);
1527
/*********************************************************************//**
1528
Allocates an InnoDB transaction for a MySQL Cursor object.
1529
@return InnoDB transaction handle */
1532
innobase_trx_allocate(
1533
/*==================*/
1534
Session* session) /*!< in: user thread handle */
1538
assert(session != NULL);
1539
assert(EQ_CURRENT_SESSION(session));
1541
trx = trx_allocate_for_mysql();
1543
trx->mysql_thd = session;
1545
innobase_trx_init(session, trx);
1550
/*********************************************************************//**
1551
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1552
an InnoDB transaction struct if the corresponding MySQL thread struct still
1554
@return InnoDB transaction handle */
1559
Session* session) /*!< in: user thread handle */
1561
trx_t*& trx = session_to_trx(session);
1563
ut_ad(EQ_CURRENT_SESSION(session));
1566
trx = innobase_trx_allocate(session);
1567
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1568
mem_analyze_corruption(trx);
1572
innobase_trx_init(session, trx);
1578
/*********************************************************************//**
1579
Construct ha_innobase Cursor. */
1581
ha_innobase::ha_innobase(plugin::StorageEngine &engine_arg,
1583
:Cursor(engine_arg, table_arg),
1584
primary_key(0), /* needs initialization because index_flags() may be called
1585
before this is set to the real value. It's ok to have any
1586
value here because it doesn't matter if we return the
1587
HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
1592
/*********************************************************************//**
1593
Destruct ha_innobase Cursor. */
1595
ha_innobase::~ha_innobase()
1599
/*********************************************************************//**
1600
Updates the user_thd field in a handle and also allocates a new InnoDB
1601
transaction handle if needed, and updates the transaction fields in the
1605
ha_innobase::update_session(
1606
/*====================*/
1607
Session* session) /*!< in: thd to use the handle */
1612
trx = check_trx_exists(session);
1614
if (prebuilt->trx != trx) {
1616
row_update_prebuilt_trx(prebuilt, trx);
1619
user_session = session;
1622
/*****************************************************************//**
1623
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1624
and quote it if needed.
1625
@return pointer to the end of buf */
1628
innobase_convert_identifier(
1629
/*========================*/
1630
char* buf, /*!< out: buffer for converted identifier */
1631
ulint buflen, /*!< in: length of buf, in bytes */
1632
const char* id, /*!< in: identifier to convert */
1633
ulint idlen, /*!< in: length of id, in bytes */
1634
drizzled::Session *session,/*!< in: MySQL connection thread, or NULL */
1635
ibool file_id)/*!< in: TRUE=id is a table or database name;
1636
FALSE=id is an UTF-8 string */
1638
char nz[NAME_LEN + 1];
1639
const size_t nz2_size= NAME_LEN + 1 + srv_mysql50_table_name_prefix.size();
1640
boost::scoped_array<char> nz2(new char[nz2_size]);
1646
/* Decode the table name. The filename_to_tablename()
1647
function expects a NUL-terminated string. The input and
1648
output strings buffers must not be shared. */
1650
if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1651
idlen = (sizeof nz) - 1;
1654
memcpy(nz, id, idlen);
1658
idlen = identifier::Table::filename_to_tablename(nz, nz2.get(), nz2_size);
1661
/* See if the identifier needs to be quoted. */
1662
if (UNIV_UNLIKELY(!session)) {
1665
q = get_quote_char_for_identifier();
1669
if (UNIV_UNLIKELY(idlen > buflen)) {
1672
memcpy(buf, s, idlen);
1673
return(buf + idlen);
1676
/* Quote the identifier. */
1684
for (; idlen; idlen--) {
1686
if (UNIV_UNLIKELY(c == q)) {
1687
if (UNIV_UNLIKELY(buflen < 3)) {
1695
if (UNIV_UNLIKELY(buflen < 2)) {
1708
/*****************************************************************//**
1709
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1710
and quote it if needed.
1711
@return pointer to the end of buf */
1714
innobase_convert_name(
1715
/*==================*/
1716
char* buf, /*!< out: buffer for converted identifier */
1717
ulint buflen, /*!< in: length of buf, in bytes */
1718
const char* id, /*!< in: identifier to convert */
1719
ulint idlen, /*!< in: length of id, in bytes */
1720
drizzled::Session *session,/*!< in: MySQL connection thread, or NULL */
1721
ibool table_id)/*!< in: TRUE=id is a table or database name;
1722
FALSE=id is an index name */
1725
const char* bufend = buf + buflen;
1728
const char* slash = (const char*) memchr(id, '/', idlen);
1734
/* Print the database name and table name separately. */
1735
s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1737
if (UNIV_LIKELY(s < bufend)) {
1739
s = innobase_convert_identifier(s, bufend - s,
1744
} else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1745
/* Temporary index name (smart ALTER TABLE) */
1746
const char temp_index_suffix[]= "--temporary--";
1748
s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1750
if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1751
memcpy(s, temp_index_suffix,
1752
sizeof temp_index_suffix - 1);
1753
s += sizeof temp_index_suffix - 1;
1757
s = innobase_convert_identifier(buf, buflen, id, idlen,
1765
/**********************************************************************//**
1766
Determines if the currently running transaction has been interrupted.
1767
@return TRUE if interrupted */
1772
trx_t* trx) /*!< in: transaction */
1774
return(trx && trx->mysql_thd && trx->mysql_thd->getKilled());
1777
/**********************************************************************//**
1778
Determines if the currently running transaction is in strict mode.
1779
@return TRUE if strict */
1784
trx_t* trx) /*!< in: transaction */
1786
return(trx && trx->mysql_thd
1790
/**************************************************************//**
1791
Resets some fields of a prebuilt struct. The template is used in fast
1792
retrieval of just those column values MySQL needs in its processing. */
1797
row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1799
prebuilt->keep_other_fields_on_keyread = 0;
1800
prebuilt->read_just_key = 0;
1804
void align_value(T& value, size_t align_val= 1024)
1806
value= value - (value % align_val);
1809
static void auto_extend_update(Session *, sql_var_t)
1811
srv_auto_extend_increment= innodb_auto_extend_increment.get();
1814
static void io_capacity_update(Session *, sql_var_t)
1816
srv_io_capacity= innodb_io_capacity.get();
1819
static void purge_batch_update(Session *, sql_var_t)
1821
srv_purge_batch_size= innodb_purge_batch_size.get();
1824
static void purge_threads_update(Session *, sql_var_t)
1826
srv_n_purge_threads= innodb_n_purge_threads.get();
1829
static void innodb_adaptive_hash_index_update(Session *, sql_var_t)
1831
if (btr_search_enabled)
1833
btr_search_enable();
1835
btr_search_disable();
1839
static void innodb_old_blocks_pct_update(Session *, sql_var_t)
1841
innobase_old_blocks_pct= buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(), TRUE);
1844
static void innodb_thread_concurrency_update(Session *, sql_var_t)
1846
srv_thread_concurrency= innobase_thread_concurrency.get();
1849
static void innodb_sync_spin_loops_update(Session *, sql_var_t)
1851
srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
1854
static void innodb_spin_wait_delay_update(Session *, sql_var_t)
1856
srv_spin_wait_delay= innodb_spin_wait_delay.get();
1859
static void innodb_thread_sleep_delay_update(Session *, sql_var_t)
1861
srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
1864
static void innodb_read_ahead_threshold_update(Session *, sql_var_t)
1866
srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
1870
static int innodb_commit_concurrency_validate(Session *session, set_var *var)
1872
uint64_t new_value= var->getInteger();
1874
if ((innobase_commit_concurrency.get() == 0 && new_value != 0) ||
1875
(innobase_commit_concurrency.get() != 0 && new_value == 0))
1877
push_warning_printf(session,
1878
DRIZZLE_ERROR::WARN_LEVEL_WARN,
1880
_("Once InnoDB is running, innodb_commit_concurrency "
1881
"must not change between zero and nonzero."));
1887
/*************************************************************//**
1888
Check if it is a valid file format. This function is registered as
1889
a callback with MySQL.
1890
@return 0 for valid file format */
1893
innodb_file_format_name_validate(
1894
/*=============================*/
1895
Session* , /*!< in: thread handle */
1898
const char *file_format_input = var->value->str_value.ptr();
1899
if (file_format_input == NULL)
1902
if (file_format_input != NULL) {
1905
format_id = innobase_file_format_name_lookup(
1908
if (format_id <= DICT_TF_FORMAT_MAX) {
1909
innobase_file_format_name =
1910
trx_sys_file_format_id_to_name(format_id);
1919
/*************************************************************//**
1920
Check if it is a valid value of innodb_change_buffering. This function is
1921
registered as a callback with MySQL.
1922
@return 0 for valid innodb_change_buffering */
1925
innodb_change_buffering_validate(
1926
/*=============================*/
1927
Session* , /*!< in: thread handle */
1930
const char *change_buffering_input = var->value->str_value.ptr();
1932
if (change_buffering_input == NULL)
1938
use < UT_ARR_SIZE(innobase_change_buffering_values);
1940
if (!innobase_strcasecmp(change_buffering_input,
1941
innobase_change_buffering_values[use]))
1943
ibuf_use= static_cast<ibuf_use_t>(use);
1952
/*************************************************************//**
1953
Check if valid argument to innodb_file_format_max. This function
1954
is registered as a callback with MySQL.
1955
@return 0 for valid file format */
1958
innodb_file_format_max_validate(
1959
/*==============================*/
1960
Session* session, /*!< in: thread handle */
1963
const char *file_format_input = var->value->str_value.ptr();
1964
if (file_format_input == NULL)
1967
if (file_format_input != NULL) {
1968
int format_id = innobase_file_format_validate_and_set(file_format_input);
1970
if (format_id > DICT_TF_FORMAT_MAX) {
1971
/* DEFAULT is "on", which is invalid at runtime. */
1975
if (format_id >= 0) {
1976
innobase_file_format_max.assign(
1977
trx_sys_file_format_id_to_name((uint)format_id));
1979
/* Update the max format id in the system tablespace. */
1980
const char *name_buff;
1982
if (trx_sys_file_format_max_set(format_id, &name_buff))
1984
errmsg_printf(error::WARN,
1985
" [Info] InnoDB: the file format in the system "
1986
"tablespace is now set to %s.\n", name_buff);
1987
innobase_file_format_max= name_buff;
1992
push_warning_printf(session,
1993
DRIZZLE_ERROR::WARN_LEVEL_WARN,
1995
"InnoDB: invalid innodb_file_format_max "
1996
"value; can be any format up to %s "
1997
"or equivalent id of %d",
1998
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX),
1999
DICT_TF_FORMAT_MAX);
2007
/*********************************************************************//**
2008
Opens an InnoDB database.
2009
@return 0 on success, error code on failure */
2014
module::Context &context) /*!< in: Drizzle Plugin Context */
2019
InnobaseEngine *actuall_engine_ptr;
2020
const module::option_map &vm= context.getOptions();
2022
srv_auto_extend_increment= innodb_auto_extend_increment.get();
2023
srv_io_capacity= innodb_io_capacity.get();
2024
srv_purge_batch_size= innodb_purge_batch_size.get();
2025
srv_n_purge_threads= innodb_n_purge_threads.get();
2026
srv_flush_log_at_trx_commit= innodb_flush_log_at_trx_commit.get();
2027
srv_max_buf_pool_modified_pct= innodb_max_dirty_pages_pct.get();
2028
srv_max_purge_lag= innodb_max_purge_lag.get();
2029
srv_stats_sample_pages= innodb_stats_sample_pages.get();
2030
srv_n_free_tickets_to_enter= innodb_concurrency_tickets.get();
2031
srv_replication_delay= innodb_replication_delay.get();
2032
srv_thread_concurrency= innobase_thread_concurrency.get();
2033
srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
2034
srv_spin_wait_delay= innodb_spin_wait_delay.get();
2035
srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
2036
srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
2038
/* Inverted Booleans */
2040
innobase_use_checksums= (vm.count("disable-checksums")) ? false : true;
2041
innobase_use_doublewrite= (vm.count("disable-doublewrite")) ? false : true;
2042
srv_adaptive_flushing= (vm.count("disable-adaptive-flushing")) ? false : true;
2043
srv_use_sys_malloc= (vm.count("use-internal-malloc")) ? false : true;
2044
srv_use_native_aio= (vm.count("disable-native-aio")) ? false : true;
2045
support_xa= (vm.count("disable-xa")) ? false : true;
2046
btr_search_enabled= (vm.count("disable-adaptive-hash-index")) ? false : true;
2049
/* Hafta do this here because we need to late-bind the default value */
2050
if (vm.count("data-home-dir"))
2052
innobase_data_home_dir= vm["data-home-dir"].as<string>();
2056
innobase_data_home_dir= getDataHome().file_string();
2060
if (vm.count("data-file-path"))
2062
innobase_data_file_path= vm["data-file-path"].as<string>();
2066
innodb_engine_ptr= actuall_engine_ptr= new InnobaseEngine(innobase_engine_name);
2068
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
2071
static const char test_filename[] = "-@";
2072
const size_t test_tablename_size= sizeof test_filename
2073
+ srv_mysql50_table_name_prefix.size();
2074
boost::scoped_array test_tablename(new char[test_tablename_size]);
2075
if ((test_tablename_size) - 1
2076
!= filename_to_tablename(test_filename, test_tablename.get(),
2077
test_tablename_size)
2078
|| strncmp(test_tablename.get(),
2079
srv_mysql50_table_name_prefix.c_str(),
2080
srv_mysql50_table_name_prefix.size())
2081
|| strcmp(test_tablename.get()
2082
+ srv_mysql50_table_name_prefix.size(),
2084
errmsg_printf(error::ERROR, "tablename encoding has been changed");
2087
#endif /* UNIV_DEBUG */
2089
os_innodb_umask = (ulint)internal::my_umask;
2092
/* Set InnoDB initialization parameters according to the values
2093
read from MySQL .cnf file */
2095
/*--------------- Data files -------------------------*/
2097
/* The default dir for data files is the datadir of MySQL */
2099
srv_data_home = (char *)innobase_data_home_dir.c_str();
2101
/* Set default InnoDB data file size to 10 MB and let it be
2102
auto-extending. Thus users can use InnoDB in >= 4.0 without having
2103
to specify any startup options. */
2105
if (innobase_data_file_path.empty())
2107
innobase_data_file_path= std::string("ibdata1:10M:autoextend");
2110
/* Since InnoDB edits the argument in the next call, we make another
2113
internal_innobase_data_file_path = strdup(innobase_data_file_path.c_str());
2115
ret = (bool) srv_parse_data_file_paths_and_sizes(
2116
internal_innobase_data_file_path);
2118
errmsg_printf(error::ERROR, "InnoDB: syntax error in innodb_data_file_path");
2121
srv_free_paths_and_sizes();
2122
if (internal_innobase_data_file_path)
2123
free(internal_innobase_data_file_path);
2127
/* -------------- Log files ---------------------------*/
2129
/* The default dir for log files is the datadir of MySQL */
2131
if (vm.count("log-group-home-dir"))
2133
innobase_log_group_home_dir= vm["log-group-home-dir"].as<string>();
2137
innobase_log_group_home_dir= getDataHome().file_string();
2141
srv_parse_log_group_home_dirs((char *)innobase_log_group_home_dir.c_str());
2143
if (ret == FALSE || innobase_mirrored_log_groups.get() != 1) {
2144
errmsg_printf(error::ERROR, _("syntax error in innodb_log_group_home_dir, or a "
2145
"wrong number of mirrored log groups"));
2147
goto mem_free_and_error;
2151
/* Validate the file format by animal name */
2152
if (vm.count("file-format"))
2154
format_id = innobase_file_format_name_lookup(
2155
vm["file-format"].as<string>().c_str());
2157
if (format_id > DICT_TF_FORMAT_MAX) {
2159
errmsg_printf(error::ERROR, "InnoDB: wrong innodb_file_format.");
2161
goto mem_free_and_error;
2164
/* Set it to the default file format id.*/
2168
srv_file_format = format_id;
2170
innobase_file_format_name =
2171
trx_sys_file_format_id_to_name(format_id);
2173
/* Check innobase_file_format_check variable */
2174
if (!innobase_file_format_check)
2176
/* Set the value to disable checking. */
2177
srv_max_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
2179
/* Set the value to the lowest supported format. */
2180
srv_max_file_format_at_startup = DICT_TF_FORMAT_MIN;
2183
/* Did the user specify a format name that we support?
2184
As a side effect it will update the variable
2185
srv_max_file_format_at_startup */
2186
if (innobase_file_format_validate_and_set(innobase_file_format_max.c_str()) < 0)
2188
errmsg_printf(error::ERROR, _("InnoDB: invalid innodb_file_format_max value: "
2189
"should be any value up to %s or its equivalent numeric id"),
2190
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
2191
goto mem_free_and_error;
2194
if (vm.count("change-buffering"))
2199
use < UT_ARR_SIZE(innobase_change_buffering_values);
2201
if (!innobase_strcasecmp(
2202
innobase_change_buffering.c_str(),
2203
innobase_change_buffering_values[use])) {
2204
ibuf_use = static_cast<ibuf_use_t>(use);
2205
goto innobase_change_buffering_inited_ok;
2209
errmsg_printf(error::ERROR, "InnoDB: invalid value innodb_change_buffering=%s",
2210
vm["change-buffering"].as<string>().c_str());
2211
goto mem_free_and_error;
2214
innobase_change_buffering_inited_ok:
2215
ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
2216
innobase_change_buffering = innobase_change_buffering_values[ibuf_use];
2218
/* --------------------------------------------------*/
2220
if (vm.count("flush-method") != 0)
2222
srv_file_flush_method_str = (char *)vm["flush-method"].as<string>().c_str();
2225
srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
2226
srv_n_log_files = (ulint) innobase_log_files_in_group;
2227
srv_log_file_size = (ulint) innobase_log_file_size;
2229
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
2231
srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
2232
srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances;
2234
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
2236
srv_n_read_io_threads = (ulint) innobase_read_io_threads;
2237
srv_n_write_io_threads = (ulint) innobase_write_io_threads;
2239
srv_force_recovery = (ulint) innobase_force_recovery;
2241
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
2242
srv_use_checksums = (ibool) innobase_use_checksums;
2244
#ifdef HAVE_LARGE_PAGES
2245
if ((os_use_large_pages = (ibool) my_use_large_pages))
2246
os_large_page_size = (ulint) opt_large_page_size;
2249
row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
2251
srv_locks_unsafe_for_binlog = (ibool) TRUE;
2253
srv_max_n_open_files = (ulint) innobase_open_files;
2254
srv_innodb_status = (ibool) innobase_create_status_file;
2256
srv_print_verbose_log = true;
2258
/* Store the default charset-collation number of this MySQL
2261
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
2263
/* Since we in this module access directly the fields of a trx
2264
struct, and due to different headers and flags it might happen that
2265
mutex_t has a different size in this module and in InnoDB
2266
modules, we check at run time that the size is the same in
2267
these compilation modules. */
2269
err = innobase_start_or_create_for_mysql();
2271
if (err != DB_SUCCESS)
2273
goto mem_free_and_error;
2276
err = dict_create_sys_replication_log();
2278
if (err != DB_SUCCESS) {
2279
goto mem_free_and_error;
2283
innobase_old_blocks_pct = buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(),
2286
innobase_open_tables = hash_create(200);
2289
actuall_engine_ptr->dropTemporarySchema();
2291
context.add(new InnodbStatusTool);
2293
context.add(innodb_engine_ptr);
2295
context.add(new(std::nothrow)CmpTool(false));
2297
context.add(new(std::nothrow)CmpTool(true));
2299
context.add(new(std::nothrow)CmpmemTool(false));
2301
context.add(new(std::nothrow)CmpmemTool(true));
2303
context.add(new(std::nothrow)InnodbTrxTool("INNODB_TRX"));
2305
context.add(new(std::nothrow)InnodbTrxTool("INNODB_LOCKS"));
2307
context.add(new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS"));
2309
context.add(new(std::nothrow)InnodbSysTablesTool());
2311
context.add(new(std::nothrow)InnodbSysTableStatsTool());
2313
context.add(new(std::nothrow)InnodbSysIndexesTool());
2315
context.add(new(std::nothrow)InnodbSysColumnsTool());
2317
context.add(new(std::nothrow)InnodbSysFieldsTool());
2319
context.add(new(std::nothrow)InnodbSysForeignTool());
2321
context.add(new(std::nothrow)InnodbSysForeignColsTool());
2323
context.add(new(std::nothrow)InnodbInternalTables());
2324
context.add(new(std::nothrow)InnodbReplicationTable());
2326
if (innobase_use_replication_log)
2328
ReplicationLog *replication_logger= new(std::nothrow)ReplicationLog();
2329
context.add(replication_logger);
2330
ReplicationLog::setup(replication_logger);
2333
context.registerVariable(new sys_var_const_string_val("data-home-dir", innobase_data_home_dir));
2334
context.registerVariable(new sys_var_const_string_val("flush-method",
2335
vm.count("flush-method") ? vm["flush-method"].as<string>() : ""));
2336
context.registerVariable(new sys_var_const_string_val("log-group-home-dir", innobase_log_group_home_dir));
2337
context.registerVariable(new sys_var_const_string_val("data-file-path", innobase_data_file_path));
2338
context.registerVariable(new sys_var_const_string_val("version", vm["version"].as<string>()));
2341
context.registerVariable(new sys_var_bool_ptr_readonly("replication_log", &innobase_use_replication_log));
2342
context.registerVariable(new sys_var_bool_ptr_readonly("checksums", &innobase_use_checksums));
2343
context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite", &innobase_use_doublewrite));
2344
context.registerVariable(new sys_var_bool_ptr("file-per-table", &srv_file_per_table));
2345
context.registerVariable(new sys_var_bool_ptr_readonly("file-format-check", &innobase_file_format_check));
2346
context.registerVariable(new sys_var_bool_ptr("adaptive-flushing", &srv_adaptive_flushing));
2347
context.registerVariable(new sys_var_bool_ptr("status-file", &innobase_create_status_file));
2348
context.registerVariable(new sys_var_bool_ptr_readonly("use-sys-malloc", &srv_use_sys_malloc));
2349
context.registerVariable(new sys_var_bool_ptr_readonly("use-native-aio", &srv_use_native_aio));
2351
context.registerVariable(new sys_var_bool_ptr("support-xa", &support_xa));
2352
context.registerVariable(new sys_var_bool_ptr("strict_mode", &strict_mode));
2353
context.registerVariable(new sys_var_constrained_value<uint32_t>("lock_wait_timeout", lock_wait_timeout));
2355
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
2356
context.registerVariable(new sys_var_constrained_value<uint32_t>("autoextend_increment",
2357
innodb_auto_extend_increment,
2358
auto_extend_update));
2359
context.registerVariable(new sys_var_constrained_value<uint32_t>("io_capacity",
2361
io_capacity_update));
2362
context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_batch_size",
2363
innodb_purge_batch_size,
2364
purge_batch_update));
2365
context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_threads",
2366
innodb_n_purge_threads,
2367
purge_threads_update));
2368
context.registerVariable(new sys_var_constrained_value<uint32_t>("fast_shutdown", innobase_fast_shutdown));
2369
context.registerVariable(new sys_var_std_string("file_format",
2370
innobase_file_format_name,
2371
innodb_file_format_name_validate));
2372
context.registerVariable(new sys_var_std_string("change_buffering",
2373
innobase_change_buffering,
2374
innodb_change_buffering_validate));
2375
context.registerVariable(new sys_var_std_string("file_format_max",
2376
innobase_file_format_max,
2377
innodb_file_format_max_validate));
2378
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
2379
context.registerVariable(new sys_var_constrained_value_readonly<int64_t>("log_file_size", innobase_log_file_size));
2380
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("flush_log_at_trx_commit",
2381
innodb_flush_log_at_trx_commit));
2382
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("max_dirty_pages_pct",
2383
innodb_max_dirty_pages_pct));
2384
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", innodb_max_purge_lag));
2385
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("stats_sample_pages", innodb_stats_sample_pages));
2386
context.registerVariable(new sys_var_bool_ptr("adaptive_hash_index", &btr_search_enabled, innodb_adaptive_hash_index_update));
2388
context.registerVariable(new sys_var_constrained_value<uint32_t>("commit_concurrency",
2389
innobase_commit_concurrency,
2390
innodb_commit_concurrency_validate));
2391
context.registerVariable(new sys_var_constrained_value<uint32_t>("concurrency_tickets",
2392
innodb_concurrency_tickets));
2393
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_io_threads", innobase_read_io_threads));
2394
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_io_threads", innobase_write_io_threads));
2395
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("replication_delay", innodb_replication_delay));
2396
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("force_recovery", innobase_force_recovery));
2397
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("log_buffer_size", innobase_log_buffer_size));
2398
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("log_files_in_group", innobase_log_files_in_group));
2399
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("mirrored_log_groups", innobase_mirrored_log_groups));
2400
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("open_files", innobase_open_files));
2401
context.registerVariable(new sys_var_constrained_value<uint32_t>("old_blocks_pct",
2402
innobase_old_blocks_pct,
2403
innodb_old_blocks_pct_update));
2404
context.registerVariable(new sys_var_uint32_t_ptr("old_blocks_time", &buf_LRU_old_threshold_ms));
2405
context.registerVariable(new sys_var_constrained_value<uint32_t>("sync_spin_loops", innodb_sync_spin_loops, innodb_sync_spin_loops_update));
2406
context.registerVariable(new sys_var_constrained_value<uint32_t>("spin_wait_delay", innodb_spin_wait_delay, innodb_spin_wait_delay_update));
2407
context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_sleep_delay", innodb_thread_sleep_delay, innodb_thread_sleep_delay_update));
2408
context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_concurrency",
2409
innobase_thread_concurrency,
2410
innodb_thread_concurrency_update));
2411
context.registerVariable(new sys_var_constrained_value<uint32_t>("read_ahead_threshold",
2412
innodb_read_ahead_threshold,
2413
innodb_read_ahead_threshold_update));
2414
/* Get the current high water mark format. */
2415
innobase_file_format_max = trx_sys_file_format_max_get();
2416
btr_search_fully_disabled = (!btr_search_enabled);
2425
/****************************************************************//**
2426
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2427
the logs, and the name of this function should be innobase_checkpoint.
2428
@return TRUE if error */
2430
InnobaseEngine::flush_logs()
2431
/*=====================*/
2435
assert(this == innodb_engine_ptr);
2437
log_buffer_flush_to_disk();
2442
/*****************************************************************//**
2443
Commits a transaction in an InnoDB database. */
2446
innobase_commit_low(
2447
/*================*/
2448
trx_t* trx) /*!< in: transaction handle */
2450
if (trx->conc_state == TRX_NOT_STARTED) {
2455
trx_commit_for_mysql(trx);
2458
/*****************************************************************//**
2459
Creates an InnoDB transaction struct for the thd if it does not yet have one.
2460
Starts a new InnoDB transaction if a transaction is not yet started. And
2461
assigns a new snapshot for a consistent read if the transaction does not yet
2465
InnobaseEngine::doStartTransaction(
2466
/*====================================*/
2467
Session* session, /*!< in: MySQL thread handle of the user for whom
2468
the transaction should be committed */
2469
start_transaction_option_t options)
2471
assert(this == innodb_engine_ptr);
2473
/* Create a new trx struct for session, if it does not yet have one */
2474
trx_t *trx = check_trx_exists(session);
2476
/* This is just to play safe: release a possible FIFO ticket and
2477
search latch. Since we will reserve the kernel mutex, we have to
2478
release the search system latch first to obey the latching order. */
2479
innobase_release_stat_resources(trx);
2481
/* If the transaction is not started yet, start it */
2482
trx_start_if_not_started(trx);
2484
/* Assign a read view if the transaction does not have it yet */
2485
if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2486
trx_assign_read_view(trx);
2491
/*****************************************************************//**
2492
Commits a transaction in an InnoDB database or marks an SQL statement
2496
InnobaseEngine::doCommit(
2498
Session* session, /*!< in: MySQL thread handle of the user for whom
2499
the transaction should be committed */
2500
bool all) /*!< in: TRUE - commit transaction
2501
FALSE - the current SQL statement ended */
2505
assert(this == innodb_engine_ptr);
2507
trx = check_trx_exists(session);
2509
/* Since we will reserve the kernel mutex, we have to release
2510
the search system latch first to obey the latching order. */
2512
if (trx->has_search_latch) {
2513
trx_search_latch_release_if_reserved(trx);
2518
/* We were instructed to commit the whole transaction, or
2519
this is an SQL statement end and autocommit is on */
2521
/* We need current binlog position for ibbackup to work.
2522
Note, the position is current because of
2523
prepare_commit_mutex */
2524
const uint32_t commit_concurrency= innobase_commit_concurrency.get();
2525
if (commit_concurrency)
2529
boost::mutex::scoped_lock scopedLock(commit_cond_m);
2532
if (commit_threads <= commit_concurrency)
2536
commit_cond.wait(scopedLock);
2540
trx->mysql_log_file_name = NULL;
2541
trx->mysql_log_offset = 0;
2543
/* Don't do write + flush right now. For group commit
2544
to work we want to do the flush after releasing the
2545
prepare_commit_mutex. */
2546
trx->flush_log_later = TRUE;
2547
innobase_commit_low(trx);
2548
trx->flush_log_later = FALSE;
2550
if (commit_concurrency)
2552
boost::mutex::scoped_lock scopedLock(commit_cond_m);
2554
commit_cond.notify_one();
2557
/* Now do a write + flush of logs. */
2558
trx_commit_complete_for_mysql(trx);
2561
/* We just mark the SQL statement ended and do not do a
2562
transaction commit */
2564
/* If we had reserved the auto-inc lock for some
2565
table in this SQL statement we release it now */
2567
row_unlock_table_autoinc_for_mysql(trx);
2569
/* Store the current undo_no of the transaction so that we
2570
know where to roll back if we have to roll back the next
2573
trx_mark_sql_stat_end(trx);
2575
if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
2577
if (trx->conc_state != TRX_NOT_STARTED)
2579
commit(session, TRUE);
2584
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2586
if (trx->declared_to_be_inside_innodb) {
2587
/* Release our possible ticket in the FIFO */
2589
srv_conc_force_exit_innodb(trx);
2592
/* Tell the InnoDB server that there might be work for utility
2594
srv_active_wake_master_thread();
2596
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2597
trx->global_read_view)
2599
/* At low transaction isolation levels we let
2600
each consistent read set its own snapshot */
2601
read_view_close_for_mysql(trx);
2607
/*****************************************************************//**
2608
Rolls back a transaction or the latest SQL statement.
2609
@return 0 or error number */
2611
InnobaseEngine::doRollback(
2613
Session* session,/*!< in: handle to the MySQL thread of the user
2614
whose transaction should be rolled back */
2615
bool all) /*!< in: TRUE - commit transaction
2616
FALSE - the current SQL statement ended */
2621
assert(this == innodb_engine_ptr);
2623
trx = check_trx_exists(session);
2625
/* Release a possible FIFO ticket and search latch. Since we will
2626
reserve the kernel mutex, we have to release the search system latch
2627
first to obey the latching order. */
2629
innobase_release_stat_resources(trx);
2631
trx->n_autoinc_rows = 0;
2633
/* If we had reserved the auto-inc lock for some table (if
2634
we come here to roll back the latest SQL statement) we
2635
release it now before a possibly lengthy rollback */
2637
row_unlock_table_autoinc_for_mysql(trx);
2641
error = trx_rollback_for_mysql(trx);
2643
error = trx_rollback_last_sql_stat_for_mysql(trx);
2646
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2647
trx->global_read_view)
2649
/* At low transaction isolation levels we let
2650
each consistent read set its own snapshot */
2651
read_view_close_for_mysql(trx);
2654
return(convert_error_code_to_mysql(error, 0, NULL));
2657
/*****************************************************************//**
2658
Rolls back a transaction
2659
@return 0 or error number */
2662
innobase_rollback_trx(
2663
/*==================*/
2664
trx_t* trx) /*!< in: transaction */
2668
/* Release a possible FIFO ticket and search latch. Since we will
2669
reserve the kernel mutex, we have to release the search system latch
2670
first to obey the latching order. */
2672
innobase_release_stat_resources(trx);
2674
/* If we had reserved the auto-inc lock for some table (if
2675
we come here to roll back the latest SQL statement) we
2676
release it now before a possibly lengthy rollback */
2678
row_unlock_table_autoinc_for_mysql(trx);
2680
error = trx_rollback_for_mysql(trx);
2682
return(convert_error_code_to_mysql(error, 0, NULL));
2685
/*****************************************************************//**
2686
Rolls back a transaction to a savepoint.
2687
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2690
InnobaseEngine::doRollbackToSavepoint(
2691
/*===========================*/
2692
Session* session, /*!< in: handle to the MySQL thread of the user
2693
whose transaction should be rolled back */
2694
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2696
ib_int64_t mysql_binlog_cache_pos;
2700
assert(this == innodb_engine_ptr);
2702
trx = check_trx_exists(session);
2704
/* Release a possible FIFO ticket and search latch. Since we will
2705
reserve the kernel mutex, we have to release the search system latch
2706
first to obey the latching order. */
2708
innobase_release_stat_resources(trx);
2710
error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2711
&mysql_binlog_cache_pos);
2712
return(convert_error_code_to_mysql(error, 0, NULL));
2715
/*****************************************************************//**
2716
Release transaction savepoint name.
2717
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2720
InnobaseEngine::doReleaseSavepoint(
2721
/*=======================*/
2722
Session* session, /*!< in: handle to the MySQL thread of the user
2723
whose transaction should be rolled back */
2724
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2729
assert(this == innodb_engine_ptr);
2731
trx = check_trx_exists(session);
2733
error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2735
return(convert_error_code_to_mysql(error, 0, NULL));
2738
/*****************************************************************//**
2739
Sets a transaction savepoint.
2740
@return always 0, that is, always succeeds */
2742
InnobaseEngine::doSetSavepoint(
2744
Session* session,/*!< in: handle to the MySQL thread */
2745
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2750
assert(this == innodb_engine_ptr);
2753
In the autocommit mode there is no sense to set a savepoint
2754
(unless we are in sub-statement), so SQL layer ensures that
2755
this method is never called in such situation.
2758
trx = check_trx_exists(session);
2760
/* Release a possible FIFO ticket and search latch. Since we will
2761
reserve the kernel mutex, we have to release the search system latch
2762
first to obey the latching order. */
2764
innobase_release_stat_resources(trx);
2766
/* cannot happen outside of transaction */
2767
assert(trx->conc_state != TRX_NOT_STARTED);
2769
error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2771
return(convert_error_code_to_mysql(error, 0, NULL));
2774
/*****************************************************************//**
2775
Frees a possible InnoDB trx object associated with the current Session.
2776
@return 0 or error number */
2778
InnobaseEngine::close_connection(
2779
/*======================*/
2780
Session* session)/*!< in: handle to the MySQL thread of the user
2781
whose resources should be free'd */
2785
assert(this == innodb_engine_ptr);
2786
trx = session_to_trx(session);
2790
assert(session->getKilled() != Session::NOT_KILLED ||
2791
trx->conc_state == TRX_NOT_STARTED);
2793
/* Warn if rolling back some things... */
2794
if (session->getKilled() != Session::NOT_KILLED &&
2795
trx->conc_state != TRX_NOT_STARTED &&
2797
global_system_variables.log_warnings)
2799
errmsg_printf(error::WARN,
2800
"Drizzle is closing a connection during a KILL operation\n"
2801
"that has an active InnoDB transaction. %llu row modifications will "
2803
(ullint) trx->undo_no);
2806
innobase_rollback_trx(trx);
2808
thr_local_free(trx->mysql_thread_id);
2809
trx_free_for_mysql(trx);
2815
/*************************************************************************//**
2816
** InnoDB database tables
2817
*****************************************************************************/
2819
/****************************************************************//**
2820
Returns the index type. */
2823
ha_innobase::index_type(
2824
/*====================*/
2826
/*!< out: index type */
2831
/****************************************************************//**
2832
Returns the maximum number of keys.
2836
InnobaseEngine::max_supported_keys() const
2837
/*===================================*/
2842
/****************************************************************//**
2843
Returns the maximum key length.
2844
@return maximum supported key length, in bytes */
2847
InnobaseEngine::max_supported_key_length() const
2848
/*=========================================*/
2850
/* An InnoDB page must store >= 2 keys; a secondary key record
2851
must also contain the primary key value: max key length is
2852
therefore set to slightly less than 1 / 4 of page size which
2853
is 16 kB; but currently MySQL does not work with keys whose
2854
size is > MAX_KEY_LENGTH */
2858
/****************************************************************//**
2859
Returns the key map of keys that are usable for scanning.
2860
@return key_map_full */
2863
ha_innobase::keys_to_use_for_scanning()
2865
return(&key_map_full);
2869
/****************************************************************//**
2870
Determines if the primary key is clustered index.
2874
ha_innobase::primary_key_is_clustered()
2879
/********************************************************************//**
2880
Get the upper limit of the MySQL integral and floating-point type.
2881
@return maximum allowed value for the field */
2884
innobase_get_int_col_max_value(
2885
/*===========================*/
2886
const Field* field) /*!< in: MySQL field */
2888
uint64_t max_value = 0;
2890
switch(field->key_type()) {
2892
case HA_KEYTYPE_BINARY:
2893
max_value = 0xFFULL;
2896
case HA_KEYTYPE_ULONG_INT:
2897
max_value = 0xFFFFFFFFULL;
2899
case HA_KEYTYPE_LONG_INT:
2900
max_value = 0x7FFFFFFFULL;
2903
case HA_KEYTYPE_ULONGLONG:
2904
max_value = 0xFFFFFFFFFFFFFFFFULL;
2906
case HA_KEYTYPE_LONGLONG:
2907
max_value = 0x7FFFFFFFFFFFFFFFULL;
2909
case HA_KEYTYPE_DOUBLE:
2910
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
2911
max_value = 0x20000000000000ULL;
2920
/*******************************************************************//**
2921
This function checks whether the index column information
2922
is consistent between KEY info from mysql and that from innodb index.
2923
@return TRUE if all column types match. */
2926
innobase_match_index_columns(
2927
/*=========================*/
2928
const KeyInfo* key_info, /*!< in: Index info
2930
const dict_index_t* index_info) /*!< in: Index info
2933
const KeyPartInfo* key_part;
2934
const KeyPartInfo* key_end;
2935
const dict_field_t* innodb_idx_fld;
2936
const dict_field_t* innodb_idx_fld_end;
2938
/* Check whether user defined index column count matches */
2939
if (key_info->key_parts != index_info->n_user_defined_cols) {
2943
key_part = key_info->key_part;
2944
key_end = key_part + key_info->key_parts;
2945
innodb_idx_fld = index_info->fields;
2946
innodb_idx_fld_end = index_info->fields + index_info->n_fields;
2948
/* Check each index column's datatype. We do not check
2949
column name because there exists case that index
2950
column name got modified in mysql but such change does not
2951
propagate to InnoDB.
2952
One hidden assumption here is that the index column sequences
2953
are matched up between those in mysql and Innodb. */
2954
for (; key_part != key_end; ++key_part) {
2957
ulint mtype = innodb_idx_fld->col->mtype;
2959
/* Need to translate to InnoDB column type before
2961
col_type = get_innobase_type_from_mysql_type(&is_unsigned,
2964
/* Ignore Innodb specific system columns. */
2965
while (mtype == DATA_SYS) {
2968
if (innodb_idx_fld >= innodb_idx_fld_end) {
2973
if (col_type != mtype) {
2974
/* Column Type mismatches */
2984
/*******************************************************************//**
2985
This function builds a translation table in INNOBASE_SHARE
2986
structure for fast index location with mysql array number from its
2987
table->key_info structure. This also provides the necessary translation
2988
between the key order in mysql key_info and Innodb ib_table->indexes if
2989
they are not fully matched with each other.
2990
Note we do not have any mutex protecting the translation table
2991
building based on the assumption that there is no concurrent
2992
index creation/drop and DMLs that requires index lookup. All table
2993
handle will be closed before the index creation/drop.
2994
@return TRUE if index translation table built successfully */
2997
innobase_build_index_translation(
2998
/*=============================*/
2999
const Table* table, /*!< in: table in MySQL data
3001
dict_table_t* ib_table, /*!< in: table in Innodb data
3003
INNOBASE_SHARE* share) /*!< in/out: share structure
3004
where index translation table
3005
will be constructed in. */
3007
ulint mysql_num_index;
3009
dict_index_t** index_mapping;
3012
mutex_enter(&dict_sys->mutex);
3014
mysql_num_index = table->getShare()->keys;
3015
ib_num_index = UT_LIST_GET_LEN(ib_table->indexes);
3017
index_mapping = share->idx_trans_tbl.index_mapping;
3019
/* If there exists inconsistency between MySQL and InnoDB dictionary
3020
(metadata) information, the number of index defined in MySQL
3021
could exceed that in InnoDB, do not build index translation
3022
table in such case */
3023
if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) {
3028
/* If index entry count is non-zero, nothing has
3029
changed since last update, directly return TRUE */
3030
if (share->idx_trans_tbl.index_count) {
3031
/* Index entry count should still match mysql_num_index */
3032
ut_a(share->idx_trans_tbl.index_count == mysql_num_index);
3036
/* The number of index increased, rebuild the mapping table */
3037
if (mysql_num_index > share->idx_trans_tbl.array_size) {
3038
index_mapping = (dict_index_t**) realloc(index_mapping,
3040
sizeof(*index_mapping));
3042
if (!index_mapping) {
3043
/* Report an error if index_mapping continues to be
3044
NULL and mysql_num_index is a non-zero value */
3045
errmsg_printf(error::ERROR, "InnoDB: fail to allocate memory for "
3046
"index translation table. Number of Index:%lu, array size:%lu",
3048
share->idx_trans_tbl.array_size);
3053
share->idx_trans_tbl.array_size = mysql_num_index;
3056
/* For each index in the mysql key_info array, fetch its
3057
corresponding InnoDB index pointer into index_mapping
3059
for (ulint count = 0; count < mysql_num_index; count++) {
3061
/* Fetch index pointers into index_mapping according to mysql
3063
index_mapping[count] = dict_table_get_index_on_name(
3064
ib_table, table->key_info[count].name);
3066
if (!index_mapping[count]) {
3067
errmsg_printf(error::ERROR, "Cannot find index %s in InnoDB index dictionary.",
3068
table->key_info[count].name);
3073
/* Double check fetched index has the same
3074
column info as those in mysql key_info. */
3075
if (!innobase_match_index_columns(&table->key_info[count], index_mapping[count])) {
3076
errmsg_printf(error::ERROR, "Found index %s whose column info does not match that of MySQL.",
3077
table->key_info[count].name);
3083
/* Successfully built the translation table */
3084
share->idx_trans_tbl.index_count = mysql_num_index;
3088
/* Build translation table failed. */
3089
free(index_mapping);
3091
share->idx_trans_tbl.array_size = 0;
3092
share->idx_trans_tbl.index_count = 0;
3093
index_mapping = NULL;
3096
share->idx_trans_tbl.index_mapping = index_mapping;
3098
mutex_exit(&dict_sys->mutex);
3103
/*******************************************************************//**
3104
This function uses index translation table to quickly locate the
3105
requested index structure.
3106
Note we do not have mutex protection for the index translatoin table
3107
access, it is based on the assumption that there is no concurrent
3108
translation table rebuild (fter create/drop index) and DMLs that
3109
require index lookup.
3110
@return dict_index_t structure for requested index. NULL if
3111
fail to locate the index structure. */
3114
innobase_index_lookup(
3115
/*==================*/
3116
INNOBASE_SHARE* share, /*!< in: share structure for index
3117
translation table. */
3118
uint keynr) /*!< in: index number for the requested
3121
if (!share->idx_trans_tbl.index_mapping
3122
|| keynr >= share->idx_trans_tbl.index_count) {
3126
return(share->idx_trans_tbl.index_mapping[keynr]);
3129
/********************************************************************//**
3130
Set the autoinc column max value. This should only be called once from
3131
ha_innobase::open(). Therefore there's no need for a covering lock. */
3134
ha_innobase::innobase_initialize_autoinc()
3135
/*======================================*/
3138
const Field* field = getTable()->found_next_number_field;
3140
if (field != NULL) {
3141
auto_inc = innobase_get_int_col_max_value(field);
3143
/* We have no idea what's been passed in to us as the
3144
autoinc column. We set it to the 0, effectively disabling
3145
updates to the table. */
3148
ut_print_timestamp(stderr);
3149
errmsg_printf(error::ERROR, "InnoDB: Unable to determine the AUTOINC column name");
3152
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3153
/* If the recovery level is set so high that writes
3154
are disabled we force the AUTOINC counter to 0
3155
value effectively disabling writes to the table.
3156
Secondly, we avoid reading the table in case the read
3157
results in failure due to a corrupted table/index.
3159
We will not return an error to the client, so that the
3160
tables can be dumped with minimal hassle. If an error
3161
were returned in this case, the first attempt to read
3162
the table would fail and subsequent SELECTs would succeed. */
3164
} else if (field == NULL) {
3165
/* This is a far more serious error, best to avoid
3166
opening the table and return failure. */
3167
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
3169
dict_index_t* index;
3170
const char* col_name;
3171
uint64_t read_auto_inc;
3174
update_session(getTable()->in_use);
3175
col_name = field->field_name;
3177
ut_a(prebuilt->trx == session_to_trx(user_session));
3179
index = innobase_get_index(getTable()->getShare()->next_number_index);
3181
/* Execute SELECT MAX(col_name) FROM TABLE; */
3182
err = row_search_max_autoinc(index, col_name, &read_auto_inc);
3186
uint64_t col_max_value;
3188
col_max_value = innobase_get_int_col_max_value(field);
3190
/* At the this stage we do not know the increment
3191
nor the offset, so use a default increment of 1. */
3193
auto_inc = innobase_next_autoinc(read_auto_inc, 1, 1, col_max_value);
3197
case DB_RECORD_NOT_FOUND:
3198
ut_print_timestamp(stderr);
3199
errmsg_printf(error::ERROR, "InnoDB: MySQL and InnoDB data dictionaries are out of sync.\n"
3200
"InnoDB: Unable to find the AUTOINC column %s in the InnoDB table %s.\n"
3201
"InnoDB: We set the next AUTOINC column value to 0,\n"
3202
"InnoDB: in effect disabling the AUTOINC next value generation.\n"
3203
"InnoDB: You can either set the next AUTOINC value explicitly using ALTER TABLE\n"
3204
"InnoDB: or fix the data dictionary by recreating the table.\n",
3205
col_name, index->table->name);
3207
/* This will disable the AUTOINC generation. */
3210
/* We want the open to succeed, so that the user can
3211
take corrective action. ie. reads should succeed but
3212
updates should fail. */
3216
/* row_search_max_autoinc() should only return
3217
one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
3222
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
3225
/*****************************************************************//**
3226
Creates and opens a handle to a table which already exists in an InnoDB
3228
@return 1 if error, 0 if success */
3231
ha_innobase::doOpen(const identifier::Table &identifier,
3232
int mode, /*!< in: not used */
3233
uint test_if_locked) /*!< in: not used */
3235
dict_table_t* ib_table;
3239
UT_NOT_USED(test_if_locked);
3241
session= getTable()->in_use;
3243
/* Under some cases Drizzle seems to call this function while
3244
holding btr_search_latch. This breaks the latching order as
3245
we acquire dict_sys->mutex below and leads to a deadlock. */
3246
if (session != NULL) {
3247
getTransactionalEngine()->releaseTemporaryLatches(session);
3250
user_session = NULL;
3252
std::string search_string(identifier.getSchemaName());
3253
boost::algorithm::to_lower(search_string);
3255
if (search_string.compare("data_dictionary") == 0)
3257
std::string table_name(identifier.getTableName());
3258
boost::algorithm::to_upper(table_name);
3259
if (!(share=get_share(table_name.c_str())))
3266
if (!(share=get_share(identifier.getKeyPath().c_str())))
3272
/* Create buffers for packing the fields of a record. Why
3273
table->stored_rec_length did not work here? Obviously, because char
3274
fields when packed actually became 1 byte longer, when we also
3275
stored the string length as the first byte. */
3277
upd_and_key_val_buff_len =
3278
getTable()->getShare()->sizeStoredRecord()
3279
+ getTable()->getShare()->max_key_length
3280
+ MAX_REF_PARTS * 3;
3282
upd_buff.resize(upd_and_key_val_buff_len);
3284
if (upd_buff.size() < upd_and_key_val_buff_len)
3289
key_val_buff.resize(upd_and_key_val_buff_len);
3290
if (key_val_buff.size() < upd_and_key_val_buff_len)
3295
/* Get pointer to a table object in InnoDB dictionary cache */
3296
if (search_string.compare("data_dictionary") == 0)
3298
std::string table_name(identifier.getTableName());
3299
boost::algorithm::to_upper(table_name);
3300
ib_table = dict_table_get(table_name.c_str(), TRUE);
3304
ib_table = dict_table_get(identifier.getKeyPath().c_str(), TRUE);
3307
if (NULL == ib_table) {
3308
errmsg_printf(error::ERROR, "Cannot find or open table %s from\n"
3309
"the internal data dictionary of InnoDB "
3310
"though the .frm file for the\n"
3311
"table exists. Maybe you have deleted and "
3312
"recreated InnoDB data\n"
3313
"files but have forgotten to delete the "
3314
"corresponding .frm files\n"
3315
"of InnoDB tables, or you have moved .frm "
3316
"files to another database?\n"
3317
"or, the table contains indexes that this "
3318
"version of the engine\n"
3319
"doesn't support.\n"
3320
"See " REFMAN "innodb-troubleshooting.html\n"
3321
"how you can resolve the problem.\n",
3322
identifier.getKeyPath().c_str());
3325
key_val_buff.resize(0);
3328
return(HA_ERR_NO_SUCH_TABLE);
3331
if (ib_table->ibd_file_missing && ! session->doing_tablespace_operation()) {
3332
errmsg_printf(error::ERROR, "MySQL is trying to open a table handle but "
3333
"the .ibd file for\ntable %s does not exist.\n"
3334
"Have you deleted the .ibd file from the "
3335
"database directory under\nthe MySQL datadir, "
3336
"or have you used DISCARD TABLESPACE?\n"
3337
"See " REFMAN "innodb-troubleshooting.html\n"
3338
"how you can resolve the problem.\n",
3339
identifier.getKeyPath().c_str());
3342
key_val_buff.resize(0);
3345
dict_table_decrement_handle_count(ib_table, FALSE);
3346
return(HA_ERR_NO_SUCH_TABLE);
3349
prebuilt = row_create_prebuilt(ib_table);
3351
prebuilt->mysql_row_len = getTable()->getShare()->sizeStoredRecord();
3352
prebuilt->default_rec = getTable()->getDefaultValues();
3353
ut_ad(prebuilt->default_rec);
3355
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
3357
primary_key = getTable()->getShare()->getPrimaryKey();
3358
key_used_on_scan = primary_key;
3360
if (!innobase_build_index_translation(getTable(), ib_table, share)) {
3361
errmsg_printf(error::ERROR, "Build InnoDB index translation table for"
3362
" Table %s failed", identifier.getKeyPath().c_str());
3365
/* Allocate a buffer for a 'row reference'. A row reference is
3366
a string of bytes of length ref_length which uniquely specifies
3367
a row in our table. Note that MySQL may also compare two row
3368
references for equality by doing a simple memcmp on the strings
3369
of length ref_length! */
3371
if (!row_table_got_default_clust_index(ib_table)) {
3373
prebuilt->clust_index_was_generated = FALSE;
3375
if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
3376
errmsg_printf(error::ERROR, "Table %s has a primary key in "
3377
"InnoDB data dictionary, but not "
3378
"in MySQL!", identifier.getTableName().c_str());
3380
/* This mismatch could cause further problems
3381
if not attended, bring this to the user's attention
3382
by printing a warning in addition to log a message
3384
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3386
"InnoDB: Table %s has a "
3387
"primary key in InnoDB data "
3388
"dictionary, but not in "
3389
"MySQL!", identifier.getTableName().c_str());
3391
/* If primary_key >= MAX_KEY, its (primary_key)
3392
value could be out of bound if continue to index
3393
into key_info[] array. Find InnoDB primary index,
3394
and assign its key_length to ref_length.
3395
In addition, since MySQL indexes are sorted starting
3396
with primary index, unique index etc., initialize
3397
ref_length to the first index key length in
3398
case we fail to find InnoDB cluster index.
3400
Please note, this will not resolve the primary
3401
index mismatch problem, other side effects are
3402
possible if users continue to use the table.
3403
However, we allow this table to be opened so
3404
that user can adopt necessary measures for the
3405
mismatch while still being accessible to the table
3407
ref_length = getTable()->key_info[0].key_length;
3409
/* Find correspoinding cluster index
3410
key length in MySQL's key_info[] array */
3411
for (ulint i = 0; i < getTable()->getShare()->keys; i++) {
3412
dict_index_t* index;
3413
index = innobase_get_index(i);
3414
if (dict_index_is_clust(index)) {
3416
getTable()->key_info[i].key_length;
3420
/* MySQL allocates the buffer for ref.
3421
key_info->key_length includes space for all key
3422
columns + one byte for each column that may be
3423
NULL. ref_length must be as exact as possible to
3424
save space, because all row reference buffers are
3425
allocated based on ref_length. */
3427
ref_length = getTable()->key_info[primary_key].key_length;
3430
if (primary_key != MAX_KEY) {
3431
errmsg_printf(error::ERROR,
3432
"Table %s has no primary key in InnoDB data "
3433
"dictionary, but has one in MySQL! If you "
3434
"created the table with a MySQL version < "
3435
"3.23.54 and did not define a primary key, "
3436
"but defined a unique key with all non-NULL "
3437
"columns, then MySQL internally treats that "
3438
"key as the primary key. You can fix this "
3439
"error by dump + DROP + CREATE + reimport "
3440
"of the table.", identifier.getTableName().c_str());
3442
/* This mismatch could cause further problems
3443
if not attended, bring this to the user attention
3444
by printing a warning in addition to log a message
3446
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3448
"InnoDB: Table %s has no "
3449
"primary key in InnoDB data "
3450
"dictionary, but has one in "
3451
"MySQL!", identifier.getTableName().c_str());
3454
prebuilt->clust_index_was_generated = TRUE;
3456
ref_length = DATA_ROW_ID_LEN;
3458
/* If we automatically created the clustered index, then
3459
MySQL does not know about it, and MySQL must NOT be aware
3460
of the index used on scan, to make it avoid checking if we
3461
update the column of the index. That is why we assert below
3462
that key_used_on_scan is the undefined value MAX_KEY.
3463
The column is the row id in the automatical generation case,
3464
and it will never be updated anyway. */
3466
if (key_used_on_scan != MAX_KEY) {
3467
errmsg_printf(error::WARN,
3468
"Table %s key_used_on_scan is %lu even "
3469
"though there is no primary key inside "
3470
"InnoDB.", identifier.getTableName().c_str(), (ulong) key_used_on_scan);
3474
/* Index block size in InnoDB: used by MySQL in query optimization */
3475
stats.block_size = 16 * 1024;
3477
/* Init table lock structure */
3478
lock.init(&share->lock);
3480
if (prebuilt->table) {
3481
/* We update the highest file format in the system table
3482
space, if this table has higher file format setting. */
3484
char changed_file_format_max[100];
3485
strcpy(changed_file_format_max, innobase_file_format_max.c_str());
3486
trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
3487
dict_table_get_format(prebuilt->table));
3488
innobase_file_format_max= changed_file_format_max;
3491
/* Only if the table has an AUTOINC column. */
3492
if (prebuilt->table != NULL && getTable()->found_next_number_field != NULL) {
3494
dict_table_autoinc_lock(prebuilt->table);
3496
/* Since a table can already be "open" in InnoDB's internal
3497
data dictionary, we only init the autoinc counter once, the
3498
first time the table is loaded. We can safely reuse the
3499
autoinc value from a previous Drizzle open. */
3500
if (dict_table_autoinc_read(prebuilt->table) == 0) {
3502
innobase_initialize_autoinc();
3505
dict_table_autoinc_unlock(prebuilt->table);
3508
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
3515
InnobaseEngine::max_supported_key_part_length() const
3517
return(DICT_MAX_INDEX_COL_LEN - 1);
3520
/******************************************************************//**
3521
Closes a handle to an InnoDB table.
3525
ha_innobase::close(void)
3526
/*====================*/
3530
session= getTable()->in_use;
3531
if (session != NULL) {
3532
getTransactionalEngine()->releaseTemporaryLatches(session);
3535
row_prebuilt_free(prebuilt, FALSE);
3538
key_val_buff.clear();
3541
/* Tell InnoDB server that there might be work for
3544
srv_active_wake_master_thread();
3549
/* The following accessor functions should really be inside MySQL code! */
3551
/**************************************************************//**
3552
Gets field offset for a field in a table.
3558
Table* table, /*!< in: MySQL table object */
3559
Field* field) /*!< in: MySQL field object */
3561
return((uint) (field->ptr - table->getInsertRecord()));
3564
/**************************************************************//**
3565
Checks if a field in a record is SQL NULL. Uses the record format
3566
information in table to track the null bit in record.
3567
@return 1 if NULL, 0 otherwise */
3570
field_in_record_is_null(
3571
/*====================*/
3572
Table* table, /*!< in: MySQL table object */
3573
Field* field, /*!< in: MySQL field object */
3574
char* record) /*!< in: a row in MySQL format */
3578
if (!field->null_ptr) {
3583
null_offset = (uint) ((char*) field->null_ptr
3584
- (char*) table->getInsertRecord());
3586
if (record[null_offset] & field->null_bit) {
3594
/**************************************************************//**
3595
Sets a field in a record to SQL NULL. Uses the record format
3596
information in table to track the null bit in record. */
3599
set_field_in_record_to_null(
3600
/*========================*/
3601
Table* table, /*!< in: MySQL table object */
3602
Field* field, /*!< in: MySQL field object */
3603
char* record) /*!< in: a row in MySQL format */
3607
null_offset = (uint) ((char*) field->null_ptr
3608
- (char*) table->getInsertRecord());
3610
record[null_offset] = record[null_offset] | field->null_bit;
3613
/*************************************************************//**
3614
InnoDB uses this function to compare two data fields for which the data type
3615
is such that we must use MySQL code to compare them. NOTE that the prototype
3616
of this function is in rem0cmp.c in InnoDB source code! If you change this
3617
function, remember to update the prototype there!
3618
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
3622
int mysql_type, /*!< in: MySQL type */
3623
uint charset_number, /*!< in: number of the charset */
3624
const unsigned char* a, /*!< in: data field */
3625
unsigned int a_length, /*!< in: data field length,
3626
not UNIV_SQL_NULL */
3627
const unsigned char* b, /* in: data field */
3628
unsigned int b_length); /* in: data field length,
3629
not UNIV_SQL_NULL */
3634
/* out: 1, 0, -1, if a is greater, equal, less than b, respectively */
3635
int mysql_type, /* in: MySQL type */
3636
uint charset_number, /* in: number of the charset */
3637
const unsigned char* a, /* in: data field */
3638
unsigned int a_length, /* in: data field length, not UNIV_SQL_NULL */
3639
const unsigned char* b, /* in: data field */
3640
unsigned int b_length) /* in: data field length, not UNIV_SQL_NULL */
3642
const CHARSET_INFO* charset;
3643
enum_field_types mysql_tp;
3646
assert(a_length != UNIV_SQL_NULL);
3647
assert(b_length != UNIV_SQL_NULL);
3649
mysql_tp = (enum_field_types) mysql_type;
3653
case DRIZZLE_TYPE_BLOB:
3654
case DRIZZLE_TYPE_VARCHAR:
3655
/* Use the charset number to pick the right charset struct for
3656
the comparison. Since the MySQL function get_charset may be
3657
slow before Bar removes the mutex operation there, we first
3658
look at 2 common charsets directly. */
3660
if (charset_number == default_charset_info->number) {
3661
charset = default_charset_info;
3663
charset = get_charset(charset_number);
3665
if (charset == NULL) {
3666
errmsg_printf(error::ERROR, "InnoDB needs charset %lu for doing "
3667
"a comparison, but MySQL cannot "
3668
"find that charset.",
3669
(ulong) charset_number);
3674
/* Starting from 4.1.3, we use strnncollsp() in comparisons of
3675
non-latin1_swedish_ci strings. NOTE that the collation order
3676
changes then: 'b\0\0...' is ordered BEFORE 'b ...'. Users
3677
having indexes on such data need to rebuild their tables! */
3679
ret = charset->coll->strnncollsp(charset,
3684
} else if (ret > 0) {
3696
/**************************************************************//**
3697
Converts a MySQL type to an InnoDB type. Note that this function returns
3698
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3699
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3700
@return DATA_BINARY, DATA_VARCHAR, ... */
3703
get_innobase_type_from_mysql_type(
3704
/*==============================*/
3705
ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
3707
at least ENUM and SET,
3708
and unsigned integer
3709
types are 'unsigned types' */
3710
const void* f) /*!< in: MySQL Field */
3712
const class Field* field = reinterpret_cast<const class Field*>(f);
3714
/* The following asserts try to check that the MySQL type code fits in
3715
8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3718
assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3720
if (field->flags & UNSIGNED_FLAG) {
3722
*unsigned_flag = DATA_UNSIGNED;
3727
if (field->real_type() == DRIZZLE_TYPE_ENUM)
3729
/* MySQL has field->type() a string type for these, but the
3730
data is actually internally stored as an unsigned integer
3733
*unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3734
flag set to zero, even though
3735
internally this is an unsigned
3740
switch (field->type()) {
3741
/* NOTE that we only allow string types in DATA_DRIZZLE and
3743
case DRIZZLE_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
3744
if (field->binary()) {
3745
return(DATA_BINARY);
3747
return(DATA_VARMYSQL);
3749
case DRIZZLE_TYPE_DECIMAL:
3750
case DRIZZLE_TYPE_MICROTIME:
3751
return(DATA_FIXBINARY);
3752
case DRIZZLE_TYPE_LONG:
3753
case DRIZZLE_TYPE_LONGLONG:
3754
case DRIZZLE_TYPE_DATETIME:
3755
case DRIZZLE_TYPE_TIME:
3756
case DRIZZLE_TYPE_DATE:
3757
case DRIZZLE_TYPE_TIMESTAMP:
3758
case DRIZZLE_TYPE_ENUM:
3760
case DRIZZLE_TYPE_DOUBLE:
3761
return(DATA_DOUBLE);
3762
case DRIZZLE_TYPE_BLOB:
3764
case DRIZZLE_TYPE_BOOLEAN:
3765
case DRIZZLE_TYPE_UUID:
3766
return(DATA_FIXBINARY);
3767
case DRIZZLE_TYPE_NULL:
3774
/*******************************************************************//**
3775
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
3779
innobase_write_to_2_little_endian(
3780
/*==============================*/
3781
byte* buf, /*!< in: where to store */
3782
ulint val) /*!< in: value to write, must be < 64k */
3784
ut_a(val < 256 * 256);
3786
buf[0] = (byte)(val & 0xFF);
3787
buf[1] = (byte)(val / 256);
3790
/*******************************************************************//**
3791
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
3796
innobase_read_from_2_little_endian(
3797
/*===============================*/
3798
const unsigned char* buf) /*!< in: from where to read */
3800
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
3803
/*******************************************************************//**
3804
Stores a key value for a row to a buffer.
3805
@return key value length as stored in buff */
3808
ha_innobase::store_key_val_for_row(
3809
/*===============================*/
3810
uint keynr, /*!< in: key number */
3811
char* buff, /*!< in/out: buffer for the key value (in MySQL
3813
uint buff_len,/*!< in: buffer length */
3814
const unsigned char* record)/*!< in: row in MySQL format */
3816
KeyInfo* key_info = &getTable()->key_info[keynr];
3817
KeyPartInfo* key_part = key_info->key_part;
3818
KeyPartInfo* end = key_part + key_info->key_parts;
3819
char* buff_start = buff;
3820
enum_field_types mysql_type;
3824
/* The format for storing a key field in MySQL is the following:
3826
1. If the column can be NULL, then in the first byte we put 1 if the
3827
field value is NULL, 0 otherwise.
3829
2. If the column is of a BLOB type (it must be a column prefix field
3830
in this case), then we put the length of the data in the field to the
3831
next 2 bytes, in the little-endian format. If the field is SQL NULL,
3832
then these 2 bytes are set to 0. Note that the length of data in the
3833
field is <= column prefix length.
3835
3. In a column prefix field, prefix_len next bytes are reserved for
3836
data. In a normal field the max field length next bytes are reserved
3837
for data. For a VARCHAR(n) the max field length is n. If the stored
3838
value is the SQL NULL then these data bytes are set to 0.
3840
4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
3841
in the MySQL row format, the length is stored in 1 or 2 bytes,
3842
depending on the maximum allowed length. But in the MySQL key value
3843
format, the length always takes 2 bytes.
3845
We have to zero-fill the buffer so that MySQL is able to use a
3846
simple memcmp to compare two key values to determine if they are
3847
equal. MySQL does this to compare contents of two 'ref' values. */
3849
bzero(buff, buff_len);
3851
for (; key_part != end; key_part++) {
3854
if (key_part->null_bit) {
3855
if (record[key_part->null_offset]
3856
& key_part->null_bit) {
3865
field = key_part->field;
3866
mysql_type = field->type();
3868
if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
3869
/* >= 5.0.3 true VARCHAR */
3875
const CHARSET_INFO* cs;
3878
key_len = key_part->length;
3881
buff += key_len + 2;
3885
cs = field->charset();
3888
(((Field_varstring*)field)->pack_length_no_ptr());
3890
data = row_mysql_read_true_varchar(&len,
3892
+ (ulint)get_field_offset(getTable(), field)),
3897
/* For multi byte character sets we need to calculate
3898
the true length of the key */
3900
if (len > 0 && cs->mbmaxlen > 1) {
3901
true_len = (ulint) cs->cset->well_formed_len(cs,
3902
(const char *) data,
3903
(const char *) data + len,
3909
/* In a column prefix index, we may need to truncate
3910
the stored value: */
3912
if (true_len > key_len) {
3916
/* The length in a key value is always stored in 2
3919
row_mysql_store_true_var_len((byte*)buff, true_len, 2);
3922
memcpy(buff, data, true_len);
3924
/* Note that we always reserve the maximum possible
3925
length of the true VARCHAR in the key value, though
3926
only len first bytes after the 2 length bytes contain
3927
actual data. The rest of the space was reset to zero
3928
in the bzero() call above. */
3932
} else if (mysql_type == DRIZZLE_TYPE_BLOB) {
3934
const CHARSET_INFO* cs;
3939
const byte* blob_data;
3941
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
3943
key_len = key_part->length;
3946
buff += key_len + 2;
3951
cs = field->charset();
3953
blob_data = row_mysql_read_blob_ref(&blob_len,
3955
+ (ulint)get_field_offset(getTable(), field)),
3956
(ulint) field->pack_length());
3958
true_len = blob_len;
3960
ut_a(get_field_offset(getTable(), field)
3961
== key_part->offset);
3963
/* For multi byte character sets we need to calculate
3964
the true length of the key */
3966
if (blob_len > 0 && cs->mbmaxlen > 1) {
3967
true_len = (ulint) cs->cset->well_formed_len(cs,
3968
(const char *) blob_data,
3969
(const char *) blob_data
3976
/* All indexes on BLOB and TEXT are column prefix
3977
indexes, and we may need to truncate the data to be
3978
stored in the key value: */
3980
if (true_len > key_len) {
3984
/* MySQL reserves 2 bytes for the length and the
3985
storage of the number is little-endian */
3987
innobase_write_to_2_little_endian(
3988
(byte*)buff, true_len);
3991
memcpy(buff, blob_data, true_len);
3993
/* Note that we always reserve the maximum possible
3994
length of the BLOB prefix in the key value. */
3998
/* Here we handle all other data types except the
3999
true VARCHAR, BLOB and TEXT. Note that the column
4000
value we store may be also in a column prefix
4005
const unsigned char* src_start;
4006
enum_field_types real_type;
4007
const CHARSET_INFO* cs= field->charset();
4009
key_len = key_part->length;
4017
src_start = record + key_part->offset;
4018
real_type = field->real_type();
4021
/* Character set for the field is defined only
4022
to fields whose type is string and real field
4023
type is not enum or set. For these fields check
4024
if character set is multi byte. */
4026
memcpy(buff, src_start, true_len);
4029
/* Pad the unused space with spaces. */
4031
if (true_len < key_len) {
4032
ulint pad_len = key_len - true_len;
4033
ut_a(!(pad_len % cs->mbminlen));
4035
cs->cset->fill(cs, buff, pad_len,
4042
ut_a(buff <= buff_start + buff_len);
4044
return((uint)(buff - buff_start));
4047
/**************************************************************//**
4048
Builds a 'template' to the prebuilt struct. The template is used in fast
4049
retrieval of just those column values MySQL needs in its processing. */
4054
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
4055
Session* , /*!< in: current user thread, used
4056
only if templ_type is
4057
ROW_DRIZZLE_REC_FIELDS */
4058
Table* table, /*!< in: MySQL table */
4059
uint templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
4060
ROW_DRIZZLE_REC_FIELDS */
4062
dict_index_t* index;
4063
dict_index_t* clust_index;
4064
mysql_row_templ_t* templ;
4067
ulint n_requested_fields = 0;
4068
ibool fetch_all_in_key = FALSE;
4069
ibool fetch_primary_key_cols = FALSE;
4071
/* byte offset of the end of last requested column */
4072
ulint mysql_prefix_len = 0;
4074
if (prebuilt->select_lock_type == LOCK_X) {
4075
/* We always retrieve the whole clustered index record if we
4076
use exclusive row level locks, for example, if the read is
4077
done in an UPDATE statement. */
4079
templ_type = ROW_MYSQL_WHOLE_ROW;
4082
if (templ_type == ROW_MYSQL_REC_FIELDS) {
4083
if (prebuilt->hint_need_to_fetch_extra_cols
4084
== ROW_RETRIEVE_ALL_COLS) {
4086
/* We know we must at least fetch all columns in the
4087
key, or all columns in the table */
4089
if (prebuilt->read_just_key) {
4090
/* MySQL has instructed us that it is enough
4091
to fetch the columns in the key; looks like
4092
MySQL can set this flag also when there is
4093
only a prefix of the column in the key: in
4094
that case we retrieve the whole column from
4095
the clustered index */
4097
fetch_all_in_key = TRUE;
4099
templ_type = ROW_MYSQL_WHOLE_ROW;
4101
} else if (prebuilt->hint_need_to_fetch_extra_cols
4102
== ROW_RETRIEVE_PRIMARY_KEY) {
4103
/* We must at least fetch all primary key cols. Note
4104
that if the clustered index was internally generated
4105
by InnoDB on the row id (no primary key was
4106
defined), then row_search_for_mysql() will always
4107
retrieve the row id to a special buffer in the
4110
fetch_primary_key_cols = TRUE;
4114
clust_index = dict_table_get_first_index(prebuilt->table);
4116
if (templ_type == ROW_MYSQL_REC_FIELDS) {
4117
index = prebuilt->index;
4119
index = clust_index;
4122
if (index == clust_index) {
4123
prebuilt->need_to_access_clustered = TRUE;
4125
prebuilt->need_to_access_clustered = FALSE;
4126
/* Below we check column by column if we need to access
4127
the clustered index */
4130
n_fields = (ulint)table->getShare()->sizeFields(); /* number of columns */
4132
if (!prebuilt->mysql_template) {
4133
prebuilt->mysql_template = (mysql_row_templ_t*)
4134
mem_alloc(n_fields * sizeof(mysql_row_templ_t));
4137
prebuilt->template_type = templ_type;
4138
prebuilt->null_bitmap_len = table->getShare()->null_bytes;
4140
prebuilt->templ_contains_blob = FALSE;
4142
/* Note that in InnoDB, i is the column number. MySQL calls columns
4144
for (i = 0; i < n_fields; i++)
4146
const dict_col_t *col= &index->table->cols[i];
4147
templ = prebuilt->mysql_template + n_requested_fields;
4148
field = table->getField(i);
4150
if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
4151
/* Decide which columns we should fetch
4152
and which we can skip. */
4153
register const ibool index_contains_field =
4154
dict_index_contains_col_or_prefix(index, i);
4156
if (!index_contains_field && prebuilt->read_just_key) {
4157
/* If this is a 'key read', we do not need
4158
columns that are not in the key */
4163
if (index_contains_field && fetch_all_in_key) {
4164
/* This field is needed in the query */
4169
if (field->isReadSet() || field->isWriteSet())
4170
/* This field is needed in the query */
4173
assert(table->isReadSet(i) == field->isReadSet());
4174
assert(table->isWriteSet(i) == field->isWriteSet());
4176
if (fetch_primary_key_cols
4177
&& dict_table_col_in_clustered_key(
4179
/* This field is needed in the query */
4184
/* This field is not needed in the query, skip it */
4189
n_requested_fields++;
4192
templ->clust_rec_field_no = dict_col_get_clust_pos(col, clust_index);
4193
ut_ad(templ->clust_rec_field_no != ULINT_UNDEFINED);
4195
if (index == clust_index) {
4196
templ->rec_field_no = templ->clust_rec_field_no;
4198
templ->rec_field_no = dict_index_get_nth_col_pos(
4200
if (templ->rec_field_no == ULINT_UNDEFINED) {
4201
prebuilt->need_to_access_clustered = TRUE;
4205
if (field->null_ptr) {
4206
templ->mysql_null_byte_offset =
4207
(ulint) ((char*) field->null_ptr
4208
- (char*) table->getInsertRecord());
4210
templ->mysql_null_bit_mask = (ulint) field->null_bit;
4212
templ->mysql_null_bit_mask = 0;
4215
templ->mysql_col_offset = (ulint)
4216
get_field_offset(table, field);
4218
templ->mysql_col_len = (ulint) field->pack_length();
4219
if (mysql_prefix_len < templ->mysql_col_offset
4220
+ templ->mysql_col_len) {
4221
mysql_prefix_len = templ->mysql_col_offset
4222
+ templ->mysql_col_len;
4224
templ->type = col->mtype;
4225
templ->mysql_type = (ulint)field->type();
4227
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
4228
templ->mysql_length_bytes = (ulint)
4229
(((Field_varstring*)field)->pack_length_no_ptr());
4232
templ->charset = dtype_get_charset_coll(col->prtype);
4233
templ->mbminlen = dict_col_get_mbminlen(col);
4234
templ->mbmaxlen = dict_col_get_mbmaxlen(col);
4235
templ->is_unsigned = col->prtype & DATA_UNSIGNED;
4236
if (templ->type == DATA_BLOB) {
4237
prebuilt->templ_contains_blob = TRUE;
4243
prebuilt->n_template = n_requested_fields;
4244
prebuilt->mysql_prefix_len = mysql_prefix_len;
4246
if (index != clust_index && prebuilt->need_to_access_clustered) {
4247
/* Change rec_field_no's to correspond to the clustered index
4249
for (i = 0; i < n_requested_fields; i++) {
4250
templ = prebuilt->mysql_template + i;
4252
templ->rec_field_no = templ->clust_rec_field_no;
4257
/********************************************************************//**
4258
This special handling is really to overcome the limitations of MySQL's
4259
binlogging. We need to eliminate the non-determinism that will arise in
4260
INSERT ... SELECT type of statements, since MySQL binlog only stores the
4261
min value of the autoinc interval. Once that is fixed we can get rid of
4262
the special lock handling.
4263
@return DB_SUCCESS if all OK else error code */
4266
ha_innobase::innobase_lock_autoinc(void)
4267
/*====================================*/
4269
ulint error = DB_SUCCESS;
4271
dict_table_autoinc_lock(prebuilt->table);
4273
return(ulong(error));
4276
/********************************************************************//**
4277
Reset the autoinc value in the table.
4278
@return DB_SUCCESS if all went well else error code */
4281
ha_innobase::innobase_reset_autoinc(
4282
/*================================*/
4283
uint64_t autoinc) /*!< in: value to store */
4285
dict_table_autoinc_lock(prebuilt->table);
4286
dict_table_autoinc_initialize(prebuilt->table, autoinc);
4287
dict_table_autoinc_unlock(prebuilt->table);
4289
return(ulong(DB_SUCCESS));
4292
/********************************************************************//**
4293
Store the autoinc value in the table. The autoinc value is only set if
4294
it's greater than the existing autoinc value in the table.
4295
@return DB_SUCCESS if all went well else error code */
4298
ha_innobase::innobase_set_max_autoinc(
4299
/*==================================*/
4300
uint64_t auto_inc) /*!< in: value to store */
4302
dict_table_autoinc_lock(prebuilt->table);
4303
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4304
dict_table_autoinc_unlock(prebuilt->table);
4306
return(ulong(DB_SUCCESS));
4309
/********************************************************************//**
4310
Stores a row in an InnoDB database, to the table specified in this
4312
@return error code */
4315
ha_innobase::doInsertRecord(
4316
/*===================*/
4317
unsigned char* record) /*!< in: a row in MySQL format */
4320
int error_result= 0;
4321
ibool auto_inc_used= FALSE;
4323
trx_t* trx = session_to_trx(user_session);
4325
if (prebuilt->trx != trx) {
4326
errmsg_printf(error::ERROR, "The transaction object for the table handle is at "
4327
"%p, but for the current thread it is at %p",
4328
(const void*) prebuilt->trx, (const void*) trx);
4330
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
4331
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
4333
"InnoDB: Dump of 200 bytes around ha_data: ",
4335
ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
4340
sql_command = user_session->getSqlCommand();
4342
if ((sql_command == SQLCOM_ALTER_TABLE
4343
|| sql_command == SQLCOM_CREATE_INDEX
4344
|| sql_command == SQLCOM_DROP_INDEX)
4345
&& num_write_row >= 10000) {
4346
/* ALTER TABLE is COMMITted at every 10000 copied rows.
4347
The IX table lock for the original table has to be re-issued.
4348
As this method will be called on a temporary table where the
4349
contents of the original table is being copied to, it is
4350
a bit tricky to determine the source table. The cursor
4351
position in the source table need not be adjusted after the
4352
intermediate COMMIT, since writes by other transactions are
4353
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
4355
dict_table_t* src_table;
4356
enum lock_mode mode;
4360
/* Commit the transaction. This will release the table
4361
locks, so they have to be acquired again. */
4363
/* Altering an InnoDB table */
4364
/* Get the source table. */
4365
src_table = lock_get_src_table(
4366
prebuilt->trx, prebuilt->table, &mode);
4369
/* Unknown situation: do not commit */
4371
ut_print_timestamp(stderr);
4373
" InnoDB: ALTER TABLE is holding lock"
4374
" on %lu tables!\n",
4375
prebuilt->trx->mysql_n_tables_locked);
4378
} else if (src_table == prebuilt->table) {
4379
/* Source table is not in InnoDB format:
4380
no need to re-acquire locks on it. */
4382
/* Altering to InnoDB format */
4383
getTransactionalEngine()->commit(user_session, 1);
4384
/* We will need an IX lock on the destination table. */
4385
prebuilt->sql_stat_start = TRUE;
4387
/* Ensure that there are no other table locks than
4388
LOCK_IX and LOCK_AUTO_INC on the destination table. */
4390
if (!lock_is_table_exclusive(prebuilt->table,
4395
/* Commit the transaction. This will release the table
4396
locks, so they have to be acquired again. */
4397
getTransactionalEngine()->commit(user_session, 1);
4398
/* Re-acquire the table lock on the source table. */
4399
row_lock_table_for_mysql(prebuilt, src_table, mode);
4400
/* We will need an IX lock on the destination table. */
4401
prebuilt->sql_stat_start = TRUE;
4407
/* This is the case where the table has an auto-increment column */
4408
if (getTable()->next_number_field && record == getTable()->getInsertRecord()) {
4410
/* Reset the error code before calling
4411
innobase_get_auto_increment(). */
4412
prebuilt->autoinc_error = DB_SUCCESS;
4414
if ((error = update_auto_increment())) {
4415
/* We don't want to mask autoinc overflow errors. */
4417
/* Handle the case where the AUTOINC sub-system
4418
failed during initialization. */
4419
if (prebuilt->autoinc_error == DB_UNSUPPORTED) {
4420
error_result = ER_AUTOINC_READ_FAILED;
4421
/* Set the error message to report too. */
4422
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
4424
} else if (prebuilt->autoinc_error != DB_SUCCESS) {
4425
error = (int) prebuilt->autoinc_error;
4430
/* MySQL errors are passed straight back. */
4431
error_result = (int) error;
4435
auto_inc_used = TRUE;
4438
if (prebuilt->mysql_template == NULL
4439
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
4441
/* Build the template used in converting quickly between
4442
the two database formats */
4444
build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
4447
innodb_srv_conc_enter_innodb(prebuilt->trx);
4449
error = row_insert_for_mysql((byte*) record, prebuilt);
4451
user_session->setXaId(trx->id);
4453
/* Handle duplicate key errors */
4454
if (auto_inc_used) {
4457
uint64_t col_max_value;
4459
/* Note the number of rows processed for this statement, used
4460
by get_auto_increment() to determine the number of AUTO-INC
4461
values to reserve. This is only useful for a mult-value INSERT
4462
and is a statement level counter.*/
4463
if (trx->n_autoinc_rows > 0) {
4464
--trx->n_autoinc_rows;
4467
/* We need the upper limit of the col type to check for
4468
whether we update the table autoinc counter or not. */
4469
col_max_value = innobase_get_int_col_max_value(
4470
getTable()->next_number_field);
4471
/* Get the value that MySQL attempted to store in the table.*/
4472
auto_inc = getTable()->next_number_field->val_int();
4475
case DB_DUPLICATE_KEY:
4477
/* A REPLACE command and LOAD DATA INFILE REPLACE
4478
handle a duplicate key error themselves, but we
4479
must update the autoinc counter if we are performing
4480
those statements. */
4482
switch (sql_command) {
4484
if ((trx->duplicates
4485
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
4487
goto set_max_autoinc;
4491
case SQLCOM_REPLACE:
4492
case SQLCOM_INSERT_SELECT:
4493
case SQLCOM_REPLACE_SELECT:
4494
goto set_max_autoinc;
4503
/* If the actual value inserted is greater than
4504
the upper limit of the interval, then we try and
4505
update the table upper limit. Note: last_value
4506
will be 0 if get_auto_increment() was not called.*/
4508
if (auto_inc >= prebuilt->autoinc_last_value) {
4510
/* This should filter out the negative
4511
values set explicitly by the user. */
4512
if (auto_inc <= col_max_value) {
4513
ut_a(prebuilt->autoinc_increment > 0);
4518
offset = prebuilt->autoinc_offset;
4519
need = prebuilt->autoinc_increment;
4521
auto_inc = innobase_next_autoinc(
4523
need, offset, col_max_value);
4525
err = innobase_set_max_autoinc(
4528
if (err != DB_SUCCESS) {
4537
innodb_srv_conc_exit_innodb(prebuilt->trx);
4540
error_result = convert_error_code_to_mysql((int) error,
4541
prebuilt->table->flags,
4545
innobase_active_small();
4547
return(error_result);
4550
/**********************************************************************//**
4551
Checks which fields have changed in a row and stores information
4552
of them to an update vector.
4553
@return error number or 0 */
4556
calc_row_difference(
4557
/*================*/
4558
upd_t* uvect, /*!< in/out: update vector */
4559
unsigned char* old_row, /*!< in: old row in MySQL format */
4560
unsigned char* new_row, /*!< in: new row in MySQL format */
4561
Table* table, /*!< in: table in MySQL data
4563
unsigned char* upd_buff, /*!< in: buffer to use */
4564
ulint buff_len, /*!< in: buffer length */
4565
row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
4566
Session* ) /*!< in: user thread */
4568
unsigned char* original_upd_buff = upd_buff;
4569
enum_field_types field_mysql_type;
4574
const byte* new_mysql_row_col;
4578
upd_field_t* ufield;
4580
ulint n_changed = 0;
4582
dict_index_t* clust_index;
4585
n_fields = table->getShare()->sizeFields();
4586
clust_index = dict_table_get_first_index(prebuilt->table);
4588
/* We use upd_buff to convert changed fields */
4589
buf = (byte*) upd_buff;
4591
for (i = 0; i < n_fields; i++) {
4592
Field *field= table->getField(i);
4594
o_ptr = (const byte*) old_row + get_field_offset(table, field);
4595
n_ptr = (const byte*) new_row + get_field_offset(table, field);
4597
/* Use new_mysql_row_col and col_pack_len save the values */
4599
new_mysql_row_col = n_ptr;
4600
col_pack_len = field->pack_length();
4602
o_len = col_pack_len;
4603
n_len = col_pack_len;
4605
/* We use o_ptr and n_ptr to dig up the actual data for
4608
field_mysql_type = field->type();
4610
col_type = prebuilt->table->cols[i].mtype;
4615
o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4616
n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4623
if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4624
/* This is a >= 5.0.3 type true VARCHAR where
4625
the real payload data length is stored in
4628
o_ptr = row_mysql_read_true_varchar(
4631
(((Field_varstring*)field)->pack_length_no_ptr()));
4633
n_ptr = row_mysql_read_true_varchar(
4636
(((Field_varstring*)field)->pack_length_no_ptr()));
4644
if (field->null_ptr) {
4645
if (field_in_record_is_null(table, field,
4647
o_len = UNIV_SQL_NULL;
4650
if (field_in_record_is_null(table, field,
4652
n_len = UNIV_SQL_NULL;
4656
if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4657
0 != memcmp(o_ptr, n_ptr, o_len))) {
4658
/* The field has changed */
4660
ufield = uvect->fields + n_changed;
4662
/* Let us use a dummy dfield to make the conversion
4663
from the MySQL column format to the InnoDB format */
4665
dict_col_copy_type(prebuilt->table->cols + i,
4668
if (n_len != UNIV_SQL_NULL) {
4669
buf = row_mysql_store_col_in_innobase_format(
4675
dict_table_is_comp(prebuilt->table));
4676
dfield_copy_data(&ufield->new_val, &dfield);
4678
dfield_set_null(&ufield->new_val);
4682
ufield->orig_len = 0;
4683
ufield->field_no = dict_col_get_clust_pos(
4684
&prebuilt->table->cols[i], clust_index);
4689
uvect->n_fields = n_changed;
4690
uvect->info_bits = 0;
4692
ut_a(buf <= (byte*)original_upd_buff + buff_len);
4697
/**********************************************************************//**
4698
Updates a row given as a parameter to a new value. Note that we are given
4699
whole rows, not just the fields which are updated: this incurs some
4700
overhead for CPU when we check which fields are actually updated.
4701
TODO: currently InnoDB does not prevent the 'Halloween problem':
4702
in a searched update a single row can get updated several times
4703
if its index columns are updated!
4704
@return error number or 0 */
4707
ha_innobase::doUpdateRecord(
4708
/*====================*/
4709
const unsigned char* old_row,/*!< in: old row in MySQL format */
4710
unsigned char* new_row)/*!< in: new row in MySQL format */
4714
trx_t* trx = session_to_trx(user_session);
4716
ut_a(prebuilt->trx == trx);
4718
if (prebuilt->upd_node) {
4719
uvect = prebuilt->upd_node->update;
4721
uvect = row_get_prebuilt_update_vector(prebuilt);
4724
/* Build an update vector from the modified fields in the rows
4725
(uses upd_buff of the handle) */
4727
calc_row_difference(uvect, (unsigned char*) old_row, new_row, getTable(),
4728
&upd_buff[0], (ulint)upd_and_key_val_buff_len,
4729
prebuilt, user_session);
4731
/* This is not a delete */
4732
prebuilt->upd_node->is_delete = FALSE;
4734
ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4736
if (getTable()->found_next_number_field)
4739
uint64_t col_max_value;
4741
auto_inc = getTable()->found_next_number_field->val_int();
4743
/* We need the upper limit of the col type to check for
4744
whether we update the table autoinc counter or not. */
4745
col_max_value = innobase_get_int_col_max_value(
4746
getTable()->found_next_number_field);
4748
uint64_t current_autoinc;
4749
ulint autoinc_error= innobase_get_autoinc(¤t_autoinc);
4750
if (autoinc_error == DB_SUCCESS
4751
&& auto_inc <= col_max_value && auto_inc != 0
4752
&& auto_inc >= current_autoinc)
4758
offset = prebuilt->autoinc_offset;
4759
need = prebuilt->autoinc_increment;
4761
auto_inc = innobase_next_autoinc(
4762
auto_inc, need, offset, col_max_value);
4764
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4767
dict_table_autoinc_unlock(prebuilt->table);
4770
innodb_srv_conc_enter_innodb(trx);
4772
error = row_update_for_mysql((byte*) old_row, prebuilt);
4774
user_session->setXaId(trx->id);
4776
/* We need to do some special AUTOINC handling for the following case:
4778
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4780
We need to use the AUTOINC counter that was actually used by
4781
MySQL in the UPDATE statement, which can be different from the
4782
value used in the INSERT statement.*/
4784
if (error == DB_SUCCESS
4785
&& getTable()->next_number_field
4786
&& new_row == getTable()->getInsertRecord()
4787
&& user_session->getSqlCommand() == SQLCOM_INSERT
4788
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
4789
== TRX_DUP_IGNORE) {
4792
uint64_t col_max_value;
4794
auto_inc = getTable()->next_number_field->val_int();
4796
/* We need the upper limit of the col type to check for
4797
whether we update the table autoinc counter or not. */
4798
col_max_value = innobase_get_int_col_max_value(
4799
getTable()->next_number_field);
4801
if (auto_inc <= col_max_value && auto_inc != 0) {
4806
offset = prebuilt->autoinc_offset;
4807
need = prebuilt->autoinc_increment;
4809
auto_inc = innobase_next_autoinc(
4810
auto_inc, need, offset, col_max_value);
4812
error = innobase_set_max_autoinc(auto_inc);
4816
innodb_srv_conc_exit_innodb(trx);
4818
error = convert_error_code_to_mysql(error,
4819
prebuilt->table->flags,
4822
if (error == 0 /* success */
4823
&& uvect->n_fields == 0 /* no columns were updated */) {
4825
/* This is the same as success, but instructs
4826
MySQL that the row is not really updated and it
4827
should not increase the count of updated rows.
4828
This is fix for http://bugs.mysql.com/29157 */
4829
error = HA_ERR_RECORD_IS_THE_SAME;
4832
/* Tell InnoDB server that there might be work for
4835
innobase_active_small();
4840
/**********************************************************************//**
4841
Deletes a row given as the parameter.
4842
@return error number or 0 */
4845
ha_innobase::doDeleteRecord(
4846
/*====================*/
4847
const unsigned char* record) /*!< in: a row in MySQL format */
4850
trx_t* trx = session_to_trx(user_session);
4852
ut_a(prebuilt->trx == trx);
4854
if (!prebuilt->upd_node) {
4855
row_get_prebuilt_update_vector(prebuilt);
4858
/* This is a delete */
4860
prebuilt->upd_node->is_delete = TRUE;
4862
innodb_srv_conc_enter_innodb(trx);
4864
error = row_update_for_mysql((byte*) record, prebuilt);
4866
user_session->setXaId(trx->id);
4868
innodb_srv_conc_exit_innodb(trx);
4870
error = convert_error_code_to_mysql(
4871
error, prebuilt->table->flags, user_session);
4873
/* Tell the InnoDB server that there might be work for
4876
innobase_active_small();
4881
/**********************************************************************//**
4882
Removes a new lock set on a row, if it was not read optimistically. This can
4883
be called after a row has been read in the processing of an UPDATE or a DELETE
4884
query, if the option innodb_locks_unsafe_for_binlog is set. */
4887
ha_innobase::unlock_row(void)
4888
/*=========================*/
4890
/* Consistent read does not take any locks, thus there is
4891
nothing to unlock. */
4893
if (prebuilt->select_lock_type == LOCK_NONE) {
4897
switch (prebuilt->row_read_type) {
4898
case ROW_READ_WITH_LOCKS:
4899
if (!srv_locks_unsafe_for_binlog
4900
&& prebuilt->trx->isolation_level
4901
> TRX_ISO_READ_COMMITTED) {
4905
case ROW_READ_TRY_SEMI_CONSISTENT:
4906
row_unlock_for_mysql(prebuilt, FALSE);
4908
case ROW_READ_DID_SEMI_CONSISTENT:
4909
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4916
/* See Cursor.h and row0mysql.h for docs on this function. */
4919
ha_innobase::was_semi_consistent_read(void)
4920
/*=======================================*/
4922
return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
4925
/* See Cursor.h and row0mysql.h for docs on this function. */
4928
ha_innobase::try_semi_consistent_read(bool yes)
4929
/*===========================================*/
4931
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
4933
/* Row read type is set to semi consistent read if this was
4934
requested by the MySQL and either innodb_locks_unsafe_for_binlog
4935
option is used or this session is using READ COMMITTED isolation
4939
&& (srv_locks_unsafe_for_binlog
4940
|| prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED)) {
4941
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4943
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
4947
/******************************************************************//**
4948
Initializes a handle to use an index.
4949
@return 0 or error number */
4952
ha_innobase::doStartIndexScan(
4953
/*====================*/
4954
uint keynr, /*!< in: key (index) number */
4955
bool ) /*!< in: 1 if result MUST be sorted according to index */
4957
return(change_active_index(keynr));
4960
/******************************************************************//**
4961
Currently does nothing.
4965
ha_innobase::doEndIndexScan(void)
4966
/*========================*/
4969
active_index=MAX_KEY;
4973
/*********************************************************************//**
4974
Converts a search mode flag understood by MySQL to a flag understood
4978
convert_search_mode_to_innobase(
4979
/*============================*/
4980
enum ha_rkey_function find_flag)
4982
switch (find_flag) {
4983
case HA_READ_KEY_EXACT:
4984
/* this does not require the index to be UNIQUE */
4985
return(PAGE_CUR_GE);
4986
case HA_READ_KEY_OR_NEXT:
4987
return(PAGE_CUR_GE);
4988
case HA_READ_KEY_OR_PREV:
4989
return(PAGE_CUR_LE);
4990
case HA_READ_AFTER_KEY:
4992
case HA_READ_BEFORE_KEY:
4994
case HA_READ_PREFIX:
4995
return(PAGE_CUR_GE);
4996
case HA_READ_PREFIX_LAST:
4997
return(PAGE_CUR_LE);
4998
case HA_READ_PREFIX_LAST_OR_PREV:
4999
return(PAGE_CUR_LE);
5000
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
5001
pass a complete-field prefix of a key value as the search
5002
tuple. I.e., it is not allowed that the last field would
5003
just contain n first bytes of the full field value.
5004
MySQL uses a 'padding' trick to convert LIKE 'abc%'
5005
type queries so that it can use as a search tuple
5006
a complete-field-prefix of a key value. Thus, the InnoDB
5007
search mode PAGE_CUR_LE_OR_EXTENDS is never used.
5008
TODO: when/if MySQL starts to use also partial-field
5009
prefixes, we have to deal with stripping of spaces
5010
and comparison of non-latin1 char type fields in
5011
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
5013
case HA_READ_MBR_CONTAIN:
5014
case HA_READ_MBR_INTERSECT:
5015
case HA_READ_MBR_WITHIN:
5016
case HA_READ_MBR_DISJOINT:
5017
case HA_READ_MBR_EQUAL:
5018
return(PAGE_CUR_UNSUPP);
5019
/* do not use "default:" in order to produce a gcc warning:
5020
enumeration value '...' not handled in switch
5021
(if -Wswitch or -Wall is used) */
5024
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
5026
return(PAGE_CUR_UNSUPP);
5030
BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
5031
---------------------------------------------------
5032
The following does not cover all the details, but explains how we determine
5033
the start of a new SQL statement, and what is associated with it.
5035
For each table in the database the MySQL interpreter may have several
5036
table handle instances in use, also in a single SQL query. For each table
5037
handle instance there is an InnoDB 'prebuilt' struct which contains most
5038
of the InnoDB data associated with this table handle instance.
5040
A) if the user has not explicitly set any MySQL table level locks:
5042
1) Drizzle calls StorageEngine::doStartStatement(), indicating to
5043
InnoDB that a new SQL statement has begun.
5045
2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
5046
to set an 'intention' table level lock on the table of the Cursor instance.
5047
There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should
5048
be set true if we are taking this table handle instance to use in a new SQL
5049
statement issued by the user.
5051
2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
5052
instructions to prebuilt->template of the table handle instance in
5053
::index_read. The template is used to save CPU time in large joins.
5055
3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
5056
allocate a new consistent read view for the trx if it does not yet have one,
5057
or in the case of a locking read, set an InnoDB 'intention' table level
5060
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
5061
same table handle instance, if it is a join.
5063
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
5065
(a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter
5066
does NOT execute autocommit for pure read transactions, though it should.
5067
That is why we must execute the COMMIT in ::doEndStatement().
5068
(b) we also release possible 'SQL statement level resources' InnoDB may
5069
have for this SQL statement.
5073
Remove need for InnoDB to call autocommit for read-only trx
5075
@todo Check the below is still valid (I don't think it is...)
5077
B) If the user has explicitly set MySQL table level locks, then MySQL
5078
does NOT call ::external_lock at the start of the statement. To determine
5079
when we are at the start of a new SQL statement we at the start of
5080
::index_read also compare the query id to the latest query id where the
5081
table handle instance was used. If it has changed, we know we are at the
5082
start of a new SQL statement. Since the query id can theoretically
5083
overwrap, we use this test only as a secondary way of determining the
5084
start of a new SQL statement. */
5087
/**********************************************************************//**
5088
Positions an index cursor to the index specified in the handle. Fetches the
5090
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
5093
ha_innobase::index_read(
5094
/*====================*/
5095
unsigned char* buf, /*!< in/out: buffer for the returned
5097
const unsigned char* key_ptr,/*!< in: key value; if this is NULL
5098
we position the cursor at the
5099
start or end of index; this can
5100
also contain an InnoDB row id, in
5101
which case key_len is the InnoDB
5102
row id length; the key value can
5103
also be a prefix of a full key value,
5104
and the last column can be a prefix
5106
uint key_len,/*!< in: key value length */
5107
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5110
dict_index_t* index;
5111
ulint match_mode = 0;
5115
ut_a(prebuilt->trx == session_to_trx(user_session));
5117
ha_statistic_increment(&system_status_var::ha_read_key_count);
5119
index = prebuilt->index;
5121
if (UNIV_UNLIKELY(index == NULL)) {
5122
prebuilt->index_usable = FALSE;
5123
return(HA_ERR_CRASHED);
5126
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5127
return(HA_ERR_TABLE_DEF_CHANGED);
5130
/* Note that if the index for which the search template is built is not
5131
necessarily prebuilt->index, but can also be the clustered index */
5133
if (prebuilt->sql_stat_start) {
5134
build_template(prebuilt, user_session, getTable(),
5135
ROW_MYSQL_REC_FIELDS);
5139
/* Convert the search key value to InnoDB format into
5140
prebuilt->search_tuple */
5142
row_sel_convert_mysql_key_to_innobase(
5143
prebuilt->search_tuple,
5144
(byte*) &key_val_buff[0],
5145
(ulint)upd_and_key_val_buff_len,
5151
/* We position the cursor to the last or the first entry
5154
dtuple_set_n_fields(prebuilt->search_tuple, 0);
5157
mode = convert_search_mode_to_innobase(find_flag);
5161
if (find_flag == HA_READ_KEY_EXACT) {
5163
match_mode = ROW_SEL_EXACT;
5165
} else if (find_flag == HA_READ_PREFIX
5166
|| find_flag == HA_READ_PREFIX_LAST) {
5168
match_mode = ROW_SEL_EXACT_PREFIX;
5171
last_match_mode = (uint) match_mode;
5173
if (mode != PAGE_CUR_UNSUPP) {
5175
innodb_srv_conc_enter_innodb(prebuilt->trx);
5177
ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
5180
innodb_srv_conc_exit_innodb(prebuilt->trx);
5183
ret = DB_UNSUPPORTED;
5189
getTable()->status = 0;
5191
case DB_RECORD_NOT_FOUND:
5192
error = HA_ERR_KEY_NOT_FOUND;
5193
getTable()->status = STATUS_NOT_FOUND;
5195
case DB_END_OF_INDEX:
5196
error = HA_ERR_KEY_NOT_FOUND;
5197
getTable()->status = STATUS_NOT_FOUND;
5200
error = convert_error_code_to_mysql((int) ret,
5201
prebuilt->table->flags,
5203
getTable()->status = STATUS_NOT_FOUND;
5210
/*******************************************************************//**
5211
The following functions works like index_read, but it find the last
5212
row with the current key value or prefix.
5213
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
5216
ha_innobase::index_read_last(
5217
/*=========================*/
5218
unsigned char* buf, /*!< out: fetched row */
5219
const unsigned char* key_ptr,/*!< in: key value, or a prefix of a full
5221
uint key_len)/*!< in: length of the key val or prefix
5224
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
5227
/********************************************************************//**
5228
Get the index for a handle. Does not change active index.
5229
@return NULL or index instance. */
5232
ha_innobase::innobase_get_index(
5233
/*============================*/
5234
uint keynr) /*!< in: use this index; MAX_KEY means always
5235
clustered index, even if it was internally
5236
generated by InnoDB */
5238
dict_index_t* index = 0;
5240
ha_statistic_increment(&system_status_var::ha_read_key_count);
5242
if (keynr != MAX_KEY && getTable()->getShare()->sizeKeys() > 0)
5244
KeyInfo *key = getTable()->key_info + keynr;
5245
index = innobase_index_lookup(share, keynr);
5248
ut_a(ut_strcmp(index->name, key->name) == 0);
5250
/* Can't find index with keynr in the translation
5251
table. Only print message if the index translation
5253
if (share->idx_trans_tbl.index_mapping) {
5254
errmsg_printf(error::ERROR,
5255
"InnoDB could not find "
5256
"index %s key no %u for "
5257
"table %s through its "
5258
"index translation table",
5259
key ? key->name : "NULL",
5261
prebuilt->table->name);
5264
index = dict_table_get_index_on_name(prebuilt->table,
5268
index = dict_table_get_first_index(prebuilt->table);
5272
errmsg_printf(error::ERROR,
5273
"Innodb could not find key n:o %u with name %s "
5274
"from dict cache for table %s",
5275
keynr, getTable()->getShare()->getTableMessage()->indexes(keynr).name().c_str(),
5276
prebuilt->table->name);
5282
/********************************************************************//**
5283
Changes the active index of a handle.
5284
@return 0 or error code */
5287
ha_innobase::change_active_index(
5288
/*=============================*/
5289
uint keynr) /*!< in: use this index; MAX_KEY means always clustered
5290
index, even if it was internally generated by
5293
ut_ad(user_session == table->in_use);
5294
ut_a(prebuilt->trx == session_to_trx(user_session));
5296
active_index = keynr;
5298
prebuilt->index = innobase_get_index(keynr);
5300
if (UNIV_UNLIKELY(!prebuilt->index)) {
5301
errmsg_printf(error::WARN, "InnoDB: change_active_index(%u) failed",
5303
prebuilt->index_usable = FALSE;
5307
prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
5310
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5311
push_warning_printf(user_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5312
HA_ERR_TABLE_DEF_CHANGED,
5313
"InnoDB: insufficient history for index %u",
5315
/* The caller seems to ignore this. Thus, we must check
5316
this again in row_search_for_mysql(). */
5320
ut_a(prebuilt->search_tuple != 0);
5322
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
5324
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
5325
prebuilt->index->n_fields);
5327
/* MySQL changes the active index for a handle also during some
5328
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
5329
and then calculates the sum. Previously we played safe and used
5330
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
5331
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
5333
build_template(prebuilt, user_session, getTable(), ROW_MYSQL_REC_FIELDS);
5338
/**********************************************************************//**
5339
Positions an index cursor to the index specified in keynr. Fetches the
5341
??? This is only used to read whole keys ???
5342
@return error number or 0 */
5345
ha_innobase::index_read_idx(
5346
/*========================*/
5347
unsigned char* buf, /*!< in/out: buffer for the returned
5349
uint keynr, /*!< in: use this index */
5350
const unsigned char* key, /*!< in: key value; if this is NULL
5351
we position the cursor at the
5352
start or end of index */
5353
uint key_len, /*!< in: key value length */
5354
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5356
if (change_active_index(keynr)) {
5361
return(index_read(buf, key, key_len, find_flag));
5364
/***********************************************************************//**
5365
Reads the next or previous row from a cursor, which must have previously been
5366
positioned using index_read.
5367
@return 0, HA_ERR_END_OF_FILE, or error number */
5370
ha_innobase::general_fetch(
5371
/*=======================*/
5372
unsigned char* buf, /*!< in/out: buffer for next row in MySQL
5374
uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
5375
uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
5376
ROW_SEL_EXACT_PREFIX */
5381
ut_a(prebuilt->trx == session_to_trx(user_session));
5383
innodb_srv_conc_enter_innodb(prebuilt->trx);
5385
ret = row_search_for_mysql(
5386
(byte*)buf, 0, prebuilt, match_mode, direction);
5388
innodb_srv_conc_exit_innodb(prebuilt->trx);
5393
getTable()->status = 0;
5395
case DB_RECORD_NOT_FOUND:
5396
error = HA_ERR_END_OF_FILE;
5397
getTable()->status = STATUS_NOT_FOUND;
5399
case DB_END_OF_INDEX:
5400
error = HA_ERR_END_OF_FILE;
5401
getTable()->status = STATUS_NOT_FOUND;
5404
error = convert_error_code_to_mysql(
5405
(int) ret, prebuilt->table->flags, user_session);
5406
getTable()->status = STATUS_NOT_FOUND;
5413
/***********************************************************************//**
5414
Reads the next row from a cursor, which must have previously been
5415
positioned using index_read.
5416
@return 0, HA_ERR_END_OF_FILE, or error number */
5419
ha_innobase::index_next(
5420
/*====================*/
5421
unsigned char* buf) /*!< in/out: buffer for next row in MySQL
5424
ha_statistic_increment(&system_status_var::ha_read_next_count);
5426
return(general_fetch(buf, ROW_SEL_NEXT, 0));
5429
/*******************************************************************//**
5430
Reads the next row matching to the key value given as the parameter.
5431
@return 0, HA_ERR_END_OF_FILE, or error number */
5434
ha_innobase::index_next_same(
5435
/*=========================*/
5436
unsigned char* buf, /*!< in/out: buffer for the row */
5437
const unsigned char* , /*!< in: key value */
5438
uint ) /*!< in: key value length */
5440
ha_statistic_increment(&system_status_var::ha_read_next_count);
5442
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
5445
/***********************************************************************//**
5446
Reads the previous row from a cursor, which must have previously been
5447
positioned using index_read.
5448
@return 0, HA_ERR_END_OF_FILE, or error number */
5451
ha_innobase::index_prev(
5452
/*====================*/
5453
unsigned char* buf) /*!< in/out: buffer for previous row in MySQL format */
5455
ha_statistic_increment(&system_status_var::ha_read_prev_count);
5457
return(general_fetch(buf, ROW_SEL_PREV, 0));
5460
/********************************************************************//**
5461
Positions a cursor on the first record in an index and reads the
5462
corresponding row to buf.
5463
@return 0, HA_ERR_END_OF_FILE, or error code */
5466
ha_innobase::index_first(
5467
/*=====================*/
5468
unsigned char* buf) /*!< in/out: buffer for the row */
5472
ha_statistic_increment(&system_status_var::ha_read_first_count);
5474
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
5476
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5478
if (error == HA_ERR_KEY_NOT_FOUND) {
5479
error = HA_ERR_END_OF_FILE;
5485
/********************************************************************//**
5486
Positions a cursor on the last record in an index and reads the
5487
corresponding row to buf.
5488
@return 0, HA_ERR_END_OF_FILE, or error code */
5491
ha_innobase::index_last(
5492
/*====================*/
5493
unsigned char* buf) /*!< in/out: buffer for the row */
5497
ha_statistic_increment(&system_status_var::ha_read_last_count);
5499
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
5501
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5503
if (error == HA_ERR_KEY_NOT_FOUND) {
5504
error = HA_ERR_END_OF_FILE;
5510
/****************************************************************//**
5511
Initialize a table scan.
5512
@return 0 or error number */
5515
ha_innobase::doStartTableScan(
5516
/*==================*/
5517
bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
5521
/* Store the active index value so that we can restore the original
5522
value after a scan */
5524
if (prebuilt->clust_index_was_generated) {
5525
err = change_active_index(MAX_KEY);
5527
err = change_active_index(primary_key);
5530
/* Don't use semi-consistent read in random row reads (by position).
5531
This means we must disable semi_consistent_read if scan is false */
5534
try_semi_consistent_read(0);
5542
/*****************************************************************//**
5544
@return 0 or error number */
5547
ha_innobase::doEndTableScan(void)
5548
/*======================*/
5550
return(doEndIndexScan());
5553
/*****************************************************************//**
5554
Reads the next row in a table scan (also used to read the FIRST row
5556
@return 0, HA_ERR_END_OF_FILE, or error number */
5559
ha_innobase::rnd_next(
5560
/*==================*/
5561
unsigned char* buf) /*!< in/out: returns the row in this buffer,
5566
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
5568
if (start_of_scan) {
5569
error = index_first(buf);
5571
if (error == HA_ERR_KEY_NOT_FOUND) {
5572
error = HA_ERR_END_OF_FILE;
5577
error = general_fetch(buf, ROW_SEL_NEXT, 0);
5583
/**********************************************************************//**
5584
Fetches a row from the table based on a row reference.
5585
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
5588
ha_innobase::rnd_pos(
5589
/*=================*/
5590
unsigned char* buf, /*!< in/out: buffer for the row */
5591
unsigned char* pos) /*!< in: primary key value of the row in the
5592
MySQL format, or the row id if the clustered
5593
index was internally generated by InnoDB; the
5594
length of data in pos has to be ref_length */
5597
uint keynr = active_index;
5599
ha_statistic_increment(&system_status_var::ha_read_rnd_count);
5601
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5603
if (prebuilt->clust_index_was_generated) {
5604
/* No primary key was defined for the table and we
5605
generated the clustered index from the row id: the
5606
row reference is the row id, not any key value
5607
that MySQL knows of */
5609
error = change_active_index(MAX_KEY);
5611
error = change_active_index(primary_key);
5618
/* Note that we assume the length of the row reference is fixed
5619
for the table, and it is == ref_length */
5621
error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5626
change_active_index(keynr);
5631
/*********************************************************************//**
5632
Stores a reference to the current row to 'ref' field of the handle. Note
5633
that in the case where we have generated the clustered index for the
5634
table, the function parameter is illogical: we MUST ASSUME that 'record'
5635
is the current 'position' of the handle, because if row ref is actually
5636
the row id internally generated in InnoDB, then 'record' does not contain
5637
it. We just guess that the row id must be for the record where the handle
5638
was positioned the last time. */
5641
ha_innobase::position(
5642
/*==================*/
5643
const unsigned char* record) /*!< in: row in MySQL format */
5647
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5649
if (prebuilt->clust_index_was_generated) {
5650
/* No primary key was defined for the table and we
5651
generated the clustered index from row id: the
5652
row reference will be the row id, not any key value
5653
that MySQL knows of */
5655
len = DATA_ROW_ID_LEN;
5657
memcpy(ref, prebuilt->row_id, len);
5659
len = store_key_val_for_row(primary_key, (char*)ref,
5660
ref_length, record);
5663
/* We assume that the 'ref' value len is always fixed for the same
5666
if (len != ref_length) {
5667
errmsg_printf(error::ERROR, "Stored ref len is %lu, but table ref len is %lu",
5668
(ulong) len, (ulong) ref_length);
5673
/*****************************************************************//**
5674
Creates a table definition to an InnoDB database. */
5679
trx_t* trx, /*!< in: InnoDB transaction handle */
5680
Table* form, /*!< in: information on table
5681
columns and indexes */
5682
const char* table_name, /*!< in: table name */
5683
const char* path_of_temp_table,/*!< in: if this is a table explicitly
5684
created by the user with the
5685
TEMPORARY keyword, then this
5686
parameter is the dir path where the
5687
table should be placed if we create
5688
an .ibd file for it (no .ibd extension
5689
in the path, though); otherwise this
5691
ulint flags) /*!< in: table flags */
5694
dict_table_t* table;
5699
ulint nulls_allowed;
5700
ulint unsigned_type;
5702
ulint long_true_varchar;
5706
n_cols = form->getShare()->sizeFields();
5708
/* We pass 0 as the space id, and determine at a lower level the space
5709
id where to store the table */
5711
table = dict_mem_table_create(table_name, 0, n_cols, flags);
5713
if (path_of_temp_table) {
5714
table->dir_path_of_temp_table =
5715
mem_heap_strdup(table->heap, path_of_temp_table);
5718
for (i = 0; i < n_cols; i++) {
5719
field = form->getField(i);
5721
col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5725
push_warning_printf(
5727
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5728
ER_CANT_CREATE_TABLE,
5729
"Error creating table '%s' with "
5730
"column '%s'. Please check its "
5731
"column type and try to re-create "
5732
"the table with an appropriate "
5734
table->name, (char*) field->field_name);
5738
if (field->null_ptr) {
5741
nulls_allowed = DATA_NOT_NULL;
5744
if (field->binary()) {
5745
binary_type = DATA_BINARY_TYPE;
5752
if (dtype_is_string_type(col_type)) {
5754
charset_no = (ulint)field->charset()->number;
5756
if (UNIV_UNLIKELY(charset_no >= 256)) {
5757
/* in data0type.h we assume that the
5758
number fits in one byte in prtype */
5759
push_warning_printf(
5761
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5762
ER_CANT_CREATE_TABLE,
5763
"In InnoDB, charset-collation codes"
5764
" must be below 256."
5765
" Unsupported code %lu.",
5766
(ulong) charset_no);
5767
return(ER_CANT_CREATE_TABLE);
5771
ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5772
that this fits in one byte */
5773
col_len = field->pack_length();
5775
/* The MySQL pack length contains 1 or 2 bytes length field
5776
for a true VARCHAR. Let us subtract that, so that the InnoDB
5777
column length in the InnoDB data dictionary is the real
5778
maximum byte length of the actual data. */
5780
long_true_varchar = 0;
5782
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5783
col_len -= ((Field_varstring*)field)->pack_length_no_ptr();
5785
if (((Field_varstring*)field)->pack_length_no_ptr() == 2) {
5786
long_true_varchar = DATA_LONG_TRUE_VARCHAR;
5790
/* First check whether the column to be added has a
5791
system reserved name. */
5792
if (dict_col_name_is_reserved(field->field_name)){
5793
my_error(ER_WRONG_COLUMN_NAME, MYF(0), field->field_name);
5796
dict_mem_table_free(table);
5797
trx_commit_for_mysql(trx);
5803
dict_mem_table_add_col(table, table->heap,
5804
(char*) field->field_name,
5807
(ulint)field->type()
5808
| nulls_allowed | unsigned_type
5809
| binary_type | long_true_varchar,
5814
error = row_create_table_for_mysql(table, trx);
5816
if (error == DB_DUPLICATE_KEY) {
5818
char* buf_end = innobase_convert_identifier(
5819
buf, sizeof buf - 1, table_name, strlen(table_name),
5820
trx->mysql_thd, TRUE);
5823
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf);
5827
error = convert_error_code_to_mysql(error, flags, NULL);
5832
/*****************************************************************//**
5833
Creates an index in an InnoDB database. */
5838
trx_t* trx, /*!< in: InnoDB transaction handle */
5839
Table* form, /*!< in: information on table
5840
columns and indexes */
5841
ulint flags, /*!< in: InnoDB table flags */
5842
const char* table_name, /*!< in: table name */
5843
uint key_num) /*!< in: index number */
5846
dict_index_t* index;
5850
KeyPartInfo* key_part;
5857
ulint* field_lengths;
5859
key = &form->key_info[key_num];
5861
n_fields = key->key_parts;
5863
/* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */
5864
ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0);
5868
if (key_num == form->getShare()->getPrimaryKey()) {
5869
ind_type = ind_type | DICT_CLUSTERED;
5872
if (key->flags & HA_NOSAME ) {
5873
ind_type = ind_type | DICT_UNIQUE;
5876
/* We pass 0 as the space id, and determine at a lower level the space
5877
id where to store the table */
5879
index = dict_mem_index_create(table_name, key->name, 0,
5880
ind_type, n_fields);
5882
field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
5884
for (i = 0; i < n_fields; i++) {
5885
key_part = key->key_part + i;
5887
/* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
5888
field in an index: we only store a specified number of first
5889
bytes of the column to the index field.) The flag does not
5890
seem to be properly set by MySQL. Let us fall back on testing
5891
the length of the key part versus the column. */
5894
for (j = 0; j < form->getShare()->sizeFields(); j++)
5897
field = form->getField(j);
5899
if (0 == innobase_strcasecmp(
5901
key_part->field->field_name)) {
5902
/* Found the corresponding column */
5908
ut_a(j < form->getShare()->sizeFields());
5910
col_type = get_innobase_type_from_mysql_type(
5911
&is_unsigned, key_part->field);
5913
if (DATA_BLOB == col_type
5914
|| (key_part->length < field->pack_length()
5915
&& field->type() != DRIZZLE_TYPE_VARCHAR)
5916
|| (field->type() == DRIZZLE_TYPE_VARCHAR
5917
&& key_part->length < field->pack_length()
5918
- ((Field_varstring*)field)->pack_length_no_ptr())) {
5920
prefix_len = key_part->length;
5922
if (col_type == DATA_INT
5923
|| col_type == DATA_FLOAT
5924
|| col_type == DATA_DOUBLE
5925
|| col_type == DATA_DECIMAL) {
5926
errmsg_printf(error::ERROR,
5927
"MySQL is trying to create a column "
5928
"prefix index field, on an "
5929
"inappropriate data type. Table "
5930
"name %s, column name %s.",
5932
key_part->field->field_name);
5940
field_lengths[i] = key_part->length;
5942
dict_mem_index_add_field(index,
5943
(char*) key_part->field->field_name, prefix_len);
5946
/* Even though we've defined max_supported_key_part_length, we
5947
still do our own checking using field_lengths to be absolutely
5948
sure we don't create too long indexes. */
5949
error = row_create_index_for_mysql(index, trx, field_lengths);
5951
error = convert_error_code_to_mysql(error, flags, NULL);
5953
free(field_lengths);
5958
/*****************************************************************//**
5959
Creates an index to an InnoDB table when the user has defined no
5963
create_clustered_index_when_no_primary(
5964
/*===================================*/
5965
trx_t* trx, /*!< in: InnoDB transaction handle */
5966
ulint flags, /*!< in: InnoDB table flags */
5967
const char* table_name) /*!< in: table name */
5969
dict_index_t* index;
5972
/* We pass 0 as the space id, and determine at a lower level the space
5973
id where to store the table */
5975
index = dict_mem_index_create(table_name,
5976
innobase_index_reserve_name,
5977
0, DICT_CLUSTERED, 0);
5979
error = row_create_index_for_mysql(index, trx, NULL);
5981
error = convert_error_code_to_mysql(error, flags, NULL);
5986
/*****************************************************************//**
5987
Validates the create options. We may build on this function
5988
in future. For now, it checks two specifiers:
5989
KEY_BLOCK_SIZE and ROW_FORMAT
5990
If innodb_strict_mode is not set then this function is a no-op
5991
@return TRUE if valid. */
5995
create_options_are_valid(
5996
/*=====================*/
5997
Session* session, /*!< in: connection thread. */
5998
Table& form, /*!< in: information on table
5999
columns and indexes */
6000
message::Table& create_proto)
6002
ibool kbs_specified = FALSE;
6006
ut_ad(session != NULL);
6008
/* If innodb_strict_mode is not set don't do any validation. */
6009
if (!(SessionVAR(session, strict_mode))) {
6013
/* Now check for ROW_FORMAT specifier. */
6018
/*********************************************************************
6019
Creates a new table to an InnoDB database. */
6022
InnobaseEngine::doCreateTable(
6023
/*================*/
6024
Session &session, /*!< in: Session */
6025
Table& form, /*!< in: information on table columns and indexes */
6026
const identifier::Table &identifier,
6027
message::Table& create_proto)
6030
dict_table_t* innobase_table;
6035
ib_int64_t auto_inc_value;
6037
/* Cache the value of innodb_file_format, in case it is
6038
modified by another thread while the table is being created. */
6039
const ulint file_format = srv_file_format;
6040
bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
6044
std::string search_string(identifier.getSchemaName());
6045
boost::algorithm::to_lower(search_string);
6047
if (search_string.compare("data_dictionary") == 0)
6049
return HA_WRONG_CREATE_OPTION;
6052
if (form.getShare()->sizeFields() > 1000) {
6053
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
6054
but we play safe here */
6056
return(HA_ERR_TO_BIG_ROW);
6059
/* Get the transaction associated with the current session, or create one
6060
if not yet created */
6062
parent_trx = check_trx_exists(&session);
6064
/* In case MySQL calls this in the middle of a SELECT query, release
6065
possible adaptive hash latch to avoid deadlocks of threads */
6067
trx_search_latch_release_if_reserved(parent_trx);
6069
trx = innobase_trx_allocate(&session);
6071
srv_lower_case_table_names = TRUE;
6073
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
6074
or lock waits can happen in it during a table create operation.
6075
Drop table etc. do this latching in row0mysql.c. */
6077
row_mysql_lock_data_dictionary(trx);
6079
/* Create the table definition in InnoDB */
6083
#if 0 // Since we validate the options before this stage, we no longer need to do this.
6084
/* Validate create options if innodb_strict_mode is set. */
6085
if (! create_options_are_valid(&session, form, create_proto)) {
6086
error = ER_ILLEGAL_HA_CREATE_OPTION;
6091
// We assume compact format by default
6092
iflags= DICT_TF_COMPACT;
6094
size_t num_engine_options= create_proto.engine().options_size();
6095
for (size_t x= 0; x < num_engine_options; ++x)
6097
if (boost::iequals(create_proto.engine().options(x).name(), "ROW_FORMAT"))
6099
if (boost::iequals(create_proto.engine().options(x).state(), "COMPRESSED"))
6101
iflags= DICT_TF_FORMAT_ZIP;
6103
else if (boost::iequals(create_proto.engine().options(x).state(), "COMPACT"))
6105
iflags= DICT_TF_FORMAT_ZIP;
6107
else if (boost::iequals(create_proto.engine().options(x).state(), "DYNAMIC"))
6109
iflags= DICT_TF_COMPACT;
6111
else if (boost::iequals(create_proto.engine().options(x).state(), "REDUNDANT"))
6113
iflags= DICT_TF_COMPACT;
6118
assert(0); // This should never happen since we have already validated the options.
6122
if (iflags == DICT_TF_FORMAT_ZIP)
6125
ROW_FORMAT=COMPRESSED without KEY_BLOCK_SIZE implies half the maximum KEY_BLOCK_SIZE.
6126
@todo implement KEY_BLOCK_SIZE
6128
iflags= (DICT_TF_ZSSIZE_MAX - 1)
6129
<< DICT_TF_ZSSIZE_SHIFT
6131
| DICT_TF_FORMAT_ZIP
6132
<< DICT_TF_FORMAT_SHIFT;
6133
#if DICT_TF_ZSSIZE_MAX < 1
6134
# error "DICT_TF_ZSSIZE_MAX < 1"
6139
if (! srv_file_per_table)
6141
push_warning_printf(
6143
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6144
ER_ILLEGAL_HA_CREATE_OPTION,
6145
"InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.");
6147
else if (file_format < DICT_TF_FORMAT_ZIP)
6149
push_warning_printf(
6151
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6152
ER_ILLEGAL_HA_CREATE_OPTION,
6153
"InnoDB: ROW_FORMAT=compressed requires innodb_file_format > Antelope.");
6158
/* Look for a primary key */
6160
primary_key_no= (form.getShare()->hasPrimaryKey() ?
6161
(int) form.getShare()->getPrimaryKey() :
6164
/* Our function innobase_get_mysql_key_number_for_index assumes
6165
the primary key is always number 0, if it exists */
6167
assert(primary_key_no == -1 || primary_key_no == 0);
6169
/* Check for name conflicts (with reserved name) for
6170
any user indices to be created. */
6171
if (innobase_index_name_is_reserved(trx, form.key_info,
6172
form.getShare()->keys)) {
6177
if (lex_identified_temp_table)
6178
iflags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
6180
error= create_table_def(trx, &form, identifier.getKeyPath().c_str(),
6181
lex_identified_temp_table ? identifier.getKeyPath().c_str() : NULL,
6184
session.setXaId(trx->id);
6190
/* Create the keys */
6192
if (form.getShare()->sizeKeys() == 0 || primary_key_no == -1) {
6193
/* Create an index which is used as the clustered index;
6194
order the rows by their row id which is internally generated
6197
error = create_clustered_index_when_no_primary(trx, iflags, identifier.getKeyPath().c_str());
6203
if (primary_key_no != -1) {
6204
/* In InnoDB the clustered index must always be created first */
6205
if ((error = create_index(trx, &form, iflags, identifier.getKeyPath().c_str(),
6206
(uint) primary_key_no))) {
6211
for (i = 0; i < form.getShare()->sizeKeys(); i++) {
6212
if (i != (uint) primary_key_no) {
6214
if ((error = create_index(trx, &form, iflags, identifier.getKeyPath().c_str(),
6221
stmt= session.getQueryStringCopy(stmt_len);
6224
string generated_create_table;
6225
const char *query= stmt;
6227
if (session.getSqlCommand() == SQLCOM_CREATE_TABLE)
6229
message::transformTableDefinitionToSql(create_proto,
6230
generated_create_table,
6231
message::DRIZZLE, true);
6232
query= generated_create_table.c_str();
6235
error = row_table_add_foreign_constraints(trx,
6236
query, strlen(query),
6237
identifier.getKeyPath().c_str(),
6238
lex_identified_temp_table);
6241
case DB_PARENT_NO_INDEX:
6242
push_warning_printf(
6243
&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
6244
HA_ERR_CANNOT_ADD_FOREIGN,
6245
"Create table '%s' with foreign key constraint"
6246
" failed. There is no index in the referenced"
6247
" table where the referenced columns appear"
6248
" as the first columns.\n", identifier.getKeyPath().c_str());
6251
case DB_CHILD_NO_INDEX:
6252
push_warning_printf(
6253
&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
6254
HA_ERR_CANNOT_ADD_FOREIGN,
6255
"Create table '%s' with foreign key constraint"
6256
" failed. There is no index in the referencing"
6257
" table where referencing columns appear"
6258
" as the first columns.\n", identifier.getKeyPath().c_str());
6262
error = convert_error_code_to_mysql(error, iflags, NULL);
6269
innobase_commit_low(trx);
6271
row_mysql_unlock_data_dictionary(trx);
6273
/* Flush the log to reduce probability that the .frm files and
6274
the InnoDB data dictionary get out-of-sync if the user runs
6275
with innodb_flush_log_at_trx_commit = 0 */
6277
log_buffer_flush_to_disk();
6279
innobase_table = dict_table_get(identifier.getKeyPath().c_str(), FALSE);
6281
assert(innobase_table != 0);
6283
if (innobase_table) {
6284
/* We update the highest file format in the system table
6285
space, if this table has higher file format setting. */
6287
char changed_file_format_max[100];
6288
strcpy(changed_file_format_max, innobase_file_format_max.c_str());
6289
trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
6290
dict_table_get_format(innobase_table));
6291
innobase_file_format_max= changed_file_format_max;
6294
/* Note: We can't call update_session() as prebuilt will not be
6295
setup at this stage and so we use session. */
6297
/* We need to copy the AUTOINC value from the old table if
6298
this is an ALTER TABLE or CREATE INDEX because CREATE INDEX
6299
does a table copy too. */
6301
if ((create_proto.options().has_auto_increment_value()
6302
|| session.getSqlCommand() == SQLCOM_ALTER_TABLE
6303
|| session.getSqlCommand() == SQLCOM_CREATE_INDEX)
6304
&& create_proto.options().auto_increment_value() != 0) {
6306
/* Query was one of :
6307
CREATE TABLE ...AUTO_INCREMENT = x; or
6308
ALTER TABLE...AUTO_INCREMENT = x; or
6309
CREATE INDEX x on t(...);
6310
Find out a table definition from the dictionary and get
6311
the current value of the auto increment field. Set a new
6312
value to the auto increment field if the value is greater
6313
than the maximum value in the column. */
6315
auto_inc_value = create_proto.options().auto_increment_value();
6317
dict_table_autoinc_lock(innobase_table);
6318
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
6319
dict_table_autoinc_unlock(innobase_table);
6322
/* Tell the InnoDB server that there might be work for
6325
srv_active_wake_master_thread();
6327
trx_free_for_mysql(trx);
6329
if (lex_identified_temp_table)
6331
session.getMessageCache().storeTableMessage(identifier, create_proto);
6335
StorageEngine::writeDefinitionFromPath(identifier, create_proto);
6341
innobase_commit_low(trx);
6343
row_mysql_unlock_data_dictionary(trx);
6345
trx_free_for_mysql(trx);
6350
/*****************************************************************//**
6351
Discards or imports an InnoDB tablespace.
6352
@return 0 == success, -1 == error */
6355
ha_innobase::discard_or_import_tablespace(
6356
/*======================================*/
6357
my_bool discard) /*!< in: TRUE if discard, else import */
6359
dict_table_t* dict_table;
6363
ut_a(prebuilt->trx);
6364
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6365
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6367
dict_table = prebuilt->table;
6368
trx = prebuilt->trx;
6371
err = row_discard_tablespace_for_mysql(dict_table->name, trx);
6373
err = row_import_tablespace_for_mysql(dict_table->name, trx);
6376
err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
6381
/*****************************************************************//**
6382
Deletes all rows of an InnoDB table.
6383
@return error number */
6386
ha_innobase::delete_all_rows(void)
6387
/*==============================*/
6391
/* Get the transaction associated with the current session, or create one
6392
if not yet created, and update prebuilt->trx */
6394
update_session(getTable()->in_use);
6396
if (user_session->getSqlCommand() != SQLCOM_TRUNCATE) {
6398
/* We only handle TRUNCATE TABLE t as a special case.
6399
DELETE FROM t will have to use ha_innobase::doDeleteRecord(),
6400
because DELETE is transactional while TRUNCATE is not. */
6401
return(errno=HA_ERR_WRONG_COMMAND);
6404
/* Truncate the table in InnoDB */
6406
error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
6407
if (error == DB_ERROR) {
6408
/* Cannot truncate; resort to ha_innobase::doDeleteRecord() */
6412
error = convert_error_code_to_mysql(error, prebuilt->table->flags,
6418
/*****************************************************************//**
6419
Drops a table from an InnoDB database. Before calling this function,
6420
MySQL calls innobase_commit to commit the transaction of the current user.
6421
Then the current user cannot have locks set on the table. Drop table
6422
operation inside InnoDB will remove all locks any user has on the table
6424
@return error number */
6427
InnobaseEngine::doDropTable(
6428
/*======================*/
6430
const identifier::Table &identifier)
6436
ut_a(identifier.getPath().length() < 1000);
6438
std::string search_string(identifier.getSchemaName());
6439
boost::algorithm::to_lower(search_string);
6441
if (search_string.compare("data_dictionary") == 0)
6443
return HA_ERR_TABLE_READONLY;
6446
/* Get the transaction associated with the current session, or create one
6447
if not yet created */
6449
parent_trx = check_trx_exists(&session);
6451
/* In case MySQL calls this in the middle of a SELECT query, release
6452
possible adaptive hash latch to avoid deadlocks of threads */
6454
trx_search_latch_release_if_reserved(parent_trx);
6456
trx = innobase_trx_allocate(&session);
6458
srv_lower_case_table_names = TRUE;
6460
/* Drop the table in InnoDB */
6462
error = row_drop_table_for_mysql(identifier.getKeyPath().c_str(), trx,
6463
session.getSqlCommand()
6466
session.setXaId(trx->id);
6468
/* Flush the log to reduce probability that the .frm files and
6469
the InnoDB data dictionary get out-of-sync if the user runs
6470
with innodb_flush_log_at_trx_commit = 0 */
6472
log_buffer_flush_to_disk();
6474
/* Tell the InnoDB server that there might be work for
6477
srv_active_wake_master_thread();
6479
innobase_commit_low(trx);
6481
trx_free_for_mysql(trx);
6483
if (error != ENOENT)
6484
error = convert_error_code_to_mysql(error, 0, NULL);
6486
if (error == 0 || error == ENOENT)
6488
if (identifier.getType() == message::Table::TEMPORARY)
6490
session.getMessageCache().removeTableMessage(identifier);
6491
ulint sql_command = session.getSqlCommand();
6493
// If this was the final removal to an alter table then we will need
6494
// to remove the .dfe that was left behind.
6495
if ((sql_command == SQLCOM_ALTER_TABLE
6496
|| sql_command == SQLCOM_CREATE_INDEX
6497
|| sql_command == SQLCOM_DROP_INDEX))
6499
string path(identifier.getPath());
6501
path.append(DEFAULT_FILE_EXTENSION);
6503
(void)internal::my_delete(path.c_str(), MYF(0));
6508
string path(identifier.getPath());
6510
path.append(DEFAULT_FILE_EXTENSION);
6512
(void)internal::my_delete(path.c_str(), MYF(0));
6519
/*****************************************************************//**
6520
Removes all tables in the named database inside InnoDB. */
6522
InnobaseEngine::doDropSchema(
6523
/*===================*/
6524
const identifier::Schema &identifier)
6525
/*!< in: database path; inside InnoDB the name
6526
of the last directory in the path is used as
6527
the database name: for example, in 'mysql/data/test'
6528
the database name is 'test' */
6532
string schema_path(identifier.getPath());
6533
Session* session = current_session;
6535
/* Get the transaction associated with the current session, or create one
6536
if not yet created */
6538
assert(this == innodb_engine_ptr);
6540
/* In the Windows plugin, session = current_session is always NULL */
6542
trx_t* parent_trx = check_trx_exists(session);
6544
/* In case Drizzle calls this in the middle of a SELECT
6545
query, release possible adaptive hash latch to avoid
6546
deadlocks of threads */
6548
trx_search_latch_release_if_reserved(parent_trx);
6551
schema_path.append("/");
6552
trx = innobase_trx_allocate(session);
6553
error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6555
/* Flush the log to reduce probability that the .frm files and
6556
the InnoDB data dictionary get out-of-sync if the user runs
6557
with innodb_flush_log_at_trx_commit = 0 */
6559
log_buffer_flush_to_disk();
6561
/* Tell the InnoDB server that there might be work for
6564
srv_active_wake_master_thread();
6566
innobase_commit_low(trx);
6567
trx_free_for_mysql(trx);
6569
return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement.
6572
void InnobaseEngine::dropTemporarySchema()
6574
identifier::Schema schema_identifier(GLOBAL_TEMPORARY_EXT);
6576
string schema_path(GLOBAL_TEMPORARY_EXT);
6578
schema_path.append("/");
6580
trx = trx_allocate_for_mysql();
6582
trx->mysql_thd = NULL;
6584
trx->check_foreigns = false;
6585
trx->check_unique_secondary = false;
6587
(void)row_drop_database_for_mysql(schema_path.c_str(), trx);
6589
/* Flush the log to reduce probability that the .frm files and
6590
the InnoDB data dictionary get out-of-sync if the user runs
6591
with innodb_flush_log_at_trx_commit = 0 */
6593
log_buffer_flush_to_disk();
6595
/* Tell the InnoDB server that there might be work for
6598
srv_active_wake_master_thread();
6600
innobase_commit_low(trx);
6601
trx_free_for_mysql(trx);
6603
/*********************************************************************//**
6604
Renames an InnoDB table.
6605
@return 0 or error code */
6608
innobase_rename_table(
6609
/*==================*/
6610
trx_t* trx, /*!< in: transaction */
6611
const identifier::Table &from,
6612
const identifier::Table &to,
6613
ibool lock_and_commit)
6614
/*!< in: TRUE=lock data dictionary and commit */
6618
srv_lower_case_table_names = TRUE;
6620
/* Serialize data dictionary operations with dictionary mutex:
6621
no deadlocks can occur then in these operations */
6623
if (lock_and_commit) {
6624
row_mysql_lock_data_dictionary(trx);
6627
error = row_rename_table_for_mysql(from.getKeyPath().c_str(), to.getKeyPath().c_str(), trx, lock_and_commit);
6629
if (error != DB_SUCCESS) {
6630
FILE* ef = dict_foreign_err_file;
6632
fputs("InnoDB: Renaming table ", ef);
6633
ut_print_name(ef, trx, TRUE, from.getKeyPath().c_str());
6635
ut_print_name(ef, trx, TRUE, to.getKeyPath().c_str());
6636
fputs(" failed!\n", ef);
6639
if (lock_and_commit) {
6640
row_mysql_unlock_data_dictionary(trx);
6642
/* Flush the log to reduce probability that the .frm
6643
files and the InnoDB data dictionary get out-of-sync
6644
if the user runs with innodb_flush_log_at_trx_commit = 0 */
6646
log_buffer_flush_to_disk();
6651
/*********************************************************************//**
6652
Renames an InnoDB table.
6653
@return 0 or error code */
6654
UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
6656
// A temp table alter table/rename is a shallow rename and only the
6657
// definition needs to be updated.
6658
if (to.getType() == message::Table::TEMPORARY && from.getType() == message::Table::TEMPORARY)
6660
session.getMessageCache().renameTableMessage(from, to);
6668
/* Get the transaction associated with the current session, or create one
6669
if not yet created */
6671
parent_trx = check_trx_exists(&session);
6673
/* In case MySQL calls this in the middle of a SELECT query, release
6674
possible adaptive hash latch to avoid deadlocks of threads */
6676
trx_search_latch_release_if_reserved(parent_trx);
6678
trx = innobase_trx_allocate(&session);
6680
error = innobase_rename_table(trx, from, to, TRUE);
6682
session.setXaId(trx->id);
6684
/* Tell the InnoDB server that there might be work for
6687
srv_active_wake_master_thread();
6689
innobase_commit_low(trx);
6690
trx_free_for_mysql(trx);
6692
/* Add a special case to handle the Duplicated Key error
6693
and return DB_ERROR instead.
6694
This is to avoid a possible SIGSEGV error from mysql error
6695
handling code. Currently, mysql handles the Duplicated Key
6696
error by re-entering the storage layer and getting dup key
6697
info by calling get_dup_key(). This operation requires a valid
6698
table handle ('row_prebuilt_t' structure) which could no
6699
longer be available in the error handling stage. The suggested
6700
solution is to report a 'table exists' error message (since
6701
the dup key error here is due to an existing table whose name
6702
is the one we are trying to rename to) and return the generic
6704
if (error == (int) DB_DUPLICATE_KEY) {
6705
my_error(ER_TABLE_EXISTS_ERROR, to);
6709
error = convert_error_code_to_mysql(error, 0, NULL);
6713
// If this fails, we are in trouble
6714
plugin::StorageEngine::renameDefinitionFromPath(to, from);
6720
/*********************************************************************//**
6721
Estimates the number of index records in a range.
6722
@return estimated number of rows */
6725
ha_innobase::records_in_range(
6726
/*==========================*/
6727
uint keynr, /*!< in: index number */
6728
key_range *min_key, /*!< in: start key value of the
6729
range, may also be 0 */
6730
key_range *max_key) /*!< in: range end key val, may
6734
dict_index_t* index;
6735
unsigned char* key_val_buff2 = (unsigned char*) malloc(
6736
getTable()->getShare()->sizeStoredRecord()
6737
+ getTable()->getShare()->max_key_length + 100);
6738
ulint buff2_len = getTable()->getShare()->sizeStoredRecord()
6739
+ getTable()->getShare()->max_key_length + 100;
6740
dtuple_t* range_start;
6741
dtuple_t* range_end;
6747
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6749
prebuilt->trx->op_info = (char*)"estimating records in index range";
6751
/* In case MySQL calls this in the middle of a SELECT query, release
6752
possible adaptive hash latch to avoid deadlocks of threads */
6754
trx_search_latch_release_if_reserved(prebuilt->trx);
6756
active_index = keynr;
6758
key = &getTable()->key_info[active_index];
6760
index = innobase_get_index(keynr);
6762
/* There exists possibility of not being able to find requested
6763
index due to inconsistency between MySQL and InoDB dictionary info.
6764
Necessary message should have been printed in innobase_get_index() */
6765
if (UNIV_UNLIKELY(!index)) {
6766
n_rows = HA_POS_ERROR;
6770
if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) {
6771
n_rows = HA_ERR_TABLE_DEF_CHANGED;
6775
heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6776
+ sizeof(dtuple_t)));
6778
range_start = dtuple_create(heap, key->key_parts);
6779
dict_index_copy_types(range_start, index, key->key_parts);
6781
range_end = dtuple_create(heap, key->key_parts);
6782
dict_index_copy_types(range_end, index, key->key_parts);
6784
row_sel_convert_mysql_key_to_innobase(
6785
range_start, (byte*) &key_val_buff[0],
6786
(ulint)upd_and_key_val_buff_len,
6788
(byte*) (min_key ? min_key->key :
6789
(const unsigned char*) 0),
6790
(ulint) (min_key ? min_key->length : 0),
6793
row_sel_convert_mysql_key_to_innobase(
6794
range_end, (byte*) key_val_buff2,
6796
(byte*) (max_key ? max_key->key :
6797
(const unsigned char*) 0),
6798
(ulint) (max_key ? max_key->length : 0),
6801
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
6803
mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
6806
if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
6808
n_rows = btr_estimate_n_rows_in_range(index, range_start,
6813
n_rows = HA_POS_ERROR;
6816
mem_heap_free(heap);
6819
free(key_val_buff2);
6821
prebuilt->trx->op_info = (char*)"";
6823
/* The MySQL optimizer seems to believe an estimate of 0 rows is
6824
always accurate and may return the result 'Empty set' based on that.
6825
The accuracy is not guaranteed, and even if it were, for a locking
6826
read we should anyway perform the search to set the next-key lock.
6827
Add 1 to the value to make sure MySQL does not make the assumption! */
6833
return((ha_rows) n_rows);
6836
/*********************************************************************//**
6837
Gives an UPPER BOUND to the number of rows in a table. This is used in
6839
@return upper bound of rows */
6842
ha_innobase::estimate_rows_upper_bound(void)
6843
/*======================================*/
6845
dict_index_t* index;
6847
uint64_t local_data_file_length;
6848
ulint stat_n_leaf_pages;
6850
/* We do not know if MySQL can call this function before calling
6851
external_lock(). To be safe, update the session of the current table
6854
update_session(getTable()->in_use);
6856
prebuilt->trx->op_info = (char*)
6857
"calculating upper bound for table rows";
6859
/* In case MySQL calls this in the middle of a SELECT query, release
6860
possible adaptive hash latch to avoid deadlocks of threads */
6862
trx_search_latch_release_if_reserved(prebuilt->trx);
6864
index = dict_table_get_first_index(prebuilt->table);
6866
stat_n_leaf_pages = index->stat_n_leaf_pages;
6868
ut_a(stat_n_leaf_pages > 0);
6870
local_data_file_length =
6871
((uint64_t) stat_n_leaf_pages) * UNIV_PAGE_SIZE;
6874
/* Calculate a minimum length for a clustered index record and from
6875
that an upper bound for the number of rows. Since we only calculate
6876
new statistics in row0mysql.c when a table has grown by a threshold
6877
factor, we must add a safety factor 2 in front of the formula below. */
6879
estimate = 2 * local_data_file_length /
6880
dict_index_calc_min_rec_len(index);
6882
prebuilt->trx->op_info = (char*)"";
6884
return((ha_rows) estimate);
6887
/*********************************************************************//**
6888
How many seeks it will take to read through the table. This is to be
6889
comparable to the number returned by records_in_range so that we can
6890
decide if we should scan the table or use keys.
6891
@return estimated time measured in disk seeks */
6894
ha_innobase::scan_time()
6895
/*====================*/
6897
/* Since MySQL seems to favor table scans too much over index
6898
searches, we pretend that a sequential read takes the same time
6899
as a random disk read, that is, we do not divide the following
6900
by 10, which would be physically realistic. */
6902
return((double) (prebuilt->table->stat_clustered_index_size));
6905
/******************************************************************//**
6906
Calculate the time it takes to read a set of ranges through an index
6907
This enables us to optimise reads for clustered indexes.
6908
@return estimated time measured in disk seeks */
6911
ha_innobase::read_time(
6912
/*===================*/
6913
uint index, /*!< in: key number */
6914
uint ranges, /*!< in: how many ranges */
6915
ha_rows rows) /*!< in: estimated number of rows in the ranges */
6918
double time_for_scan;
6920
if (index != getTable()->getShare()->getPrimaryKey()) {
6922
return(Cursor::read_time(index, ranges, rows));
6927
return((double) rows);
6930
/* Assume that the read time is proportional to the scan time for all
6931
rows + at most one seek per range. */
6933
time_for_scan = scan_time();
6935
if ((total_rows = estimate_rows_upper_bound()) < rows) {
6937
return(time_for_scan);
6940
return(ranges + (double) rows / (double) total_rows * time_for_scan);
6943
/*********************************************************************//**
6944
Calculates the key number used inside MySQL for an Innobase index. We will
6945
first check the "index translation table" for a match of the index to get
6946
the index number. If there does not exist an "index translation table",
6947
or not able to find the index in the translation table, then we will fall back
6948
to the traditional way of looping through dict_index_t list to find a
6949
match. In this case, we have to take into account if we generated a
6950
default clustered index for the table
6951
@return the key number used inside MySQL */
6954
innobase_get_mysql_key_number_for_index(
6955
/*====================================*/
6956
INNOBASE_SHARE* share, /*!< in: share structure for index
6957
translation table. */
6958
const drizzled::Table* table, /*!< in: table in MySQL data
6960
dict_table_t* ib_table,/*!< in: table in Innodb data
6962
const dict_index_t* index) /*!< in: index */
6964
const dict_index_t* ind;
6972
/* If index does not belong to the table of share structure. Search
6973
index->table instead */
6974
if (index->table != ib_table) {
6976
ind = dict_table_get_first_index(index->table);
6978
while (index != ind) {
6979
ind = dict_table_get_next_index(ind);
6983
if (row_table_got_default_clust_index(index->table)) {
6991
/* If index does not belong to the table of share structure. Search
6992
index->table instead */
6993
if (index->table != ib_table) {
6995
ind = dict_table_get_first_index(index->table);
6997
while (index != ind) {
6998
ind = dict_table_get_next_index(ind);
7002
if (row_table_got_default_clust_index(index->table)) {
7010
/* If index translation table exists, we will first check
7011
the index through index translation table for a match. */
7012
if (share->idx_trans_tbl.index_mapping) {
7013
for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
7014
if (share->idx_trans_tbl.index_mapping[i] == index) {
7019
/* Print an error message if we cannot find the index
7020
** in the "index translation table". */
7021
errmsg_printf(error::ERROR,
7022
"Cannot find index %s in InnoDB index "
7023
"translation table.", index->name);
7026
/* If we do not have an "index translation table", or not able
7027
to find the index in the translation table, we'll directly find
7028
matching index in the dict_index_t list */
7029
for (i = 0; i < table->getShare()->keys; i++) {
7030
ind = dict_table_get_index_on_name(
7031
ib_table, table->key_info[i].name);
7038
errmsg_printf(error::ERROR,
7039
"Cannot find matching index number for index %s "
7040
"in InnoDB index list.", index->name);
7044
/*********************************************************************//**
7045
Returns statistics information of the table to the MySQL interpreter,
7046
in various fields of the handle object. */
7051
uint flag) /*!< in: what information MySQL requests */
7053
dict_table_t* ib_table;
7054
dict_index_t* index;
7055
ha_rows rec_per_key;
7057
os_file_stat_t stat_info;
7059
/* If we are forcing recovery at a high level, we will suppress
7060
statistics calculation on tables, because that may crash the
7061
server if an index is badly corrupted. */
7063
/* We do not know if MySQL can call this function before calling
7064
external_lock(). To be safe, update the session of the current table
7067
update_session(getTable()->in_use);
7069
/* In case MySQL calls this in the middle of a SELECT query, release
7070
possible adaptive hash latch to avoid deadlocks of threads */
7072
prebuilt->trx->op_info = (char*)"returning various info to MySQL";
7074
trx_search_latch_release_if_reserved(prebuilt->trx);
7076
ib_table = prebuilt->table;
7078
if (flag & HA_STATUS_TIME) {
7079
/* In Analyze we call with this flag: update
7080
then statistics so that they are up-to-date */
7082
prebuilt->trx->op_info = "updating table statistics";
7084
dict_update_statistics(ib_table,
7085
FALSE /* update even if stats
7086
are initialized */);
7089
prebuilt->trx->op_info = "returning various info to MySQL";
7091
fs::path get_status_path(getDataHomeCatalog());
7092
get_status_path /= ib_table->name;
7093
fs::change_extension(get_status_path, "dfe");
7095
/* Note that we do not know the access time of the table,
7096
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
7098
if (os_file_get_status(get_status_path.file_string().c_str(), &stat_info)) {
7099
stats.create_time = (ulong) stat_info.ctime;
7103
if (flag & HA_STATUS_VARIABLE) {
7105
dict_table_stats_lock(ib_table, RW_S_LATCH);
7107
n_rows = ib_table->stat_n_rows;
7109
/* Because we do not protect stat_n_rows by any mutex in a
7110
delete, it is theoretically possible that the value can be
7111
smaller than zero! TODO: fix this race.
7113
The MySQL optimizer seems to assume in a left join that n_rows
7114
is an accurate estimate if it is zero. Of course, it is not,
7115
since we do not have any locks on the rows yet at this phase.
7116
Since SHOW TABLE STATUS seems to call this function with the
7117
HA_STATUS_TIME flag set, while the left join optimizer does not
7118
set that flag, we add one to a zero value if the flag is not
7119
set. That way SHOW TABLE STATUS will show the best estimate,
7120
while the optimizer never sees the table empty. */
7126
if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
7130
/* Fix bug#40386: Not flushing query cache after truncate.
7131
n_rows can not be 0 unless the table is empty, set to 1
7132
instead. The original problem of bug#29507 is actually
7133
fixed in the server code. */
7134
if (user_session->getSqlCommand() == SQLCOM_TRUNCATE) {
7138
/* We need to reset the prebuilt value too, otherwise
7139
checks for values greater than the last value written
7140
to the table will fail and the autoinc counter will
7141
not be updated. This will force doInsertRecord() into
7142
attempting an update of the table's AUTOINC counter. */
7144
prebuilt->autoinc_last_value = 0;
7147
stats.records = (ha_rows)n_rows;
7149
stats.data_file_length = ((uint64_t)
7150
ib_table->stat_clustered_index_size)
7152
stats.index_file_length = ((uint64_t)
7153
ib_table->stat_sum_of_other_index_sizes)
7156
dict_table_stats_unlock(ib_table, RW_S_LATCH);
7158
/* Since fsp_get_available_space_in_free_extents() is
7159
acquiring latches inside InnoDB, we do not call it if we
7160
are asked by MySQL to avoid locking. Another reason to
7161
avoid the call is that it uses quite a lot of CPU.
7163
if (flag & HA_STATUS_NO_LOCK) {
7164
/* We do not update delete_length if no
7165
locking is requested so the "old" value can
7166
remain. delete_length is initialized to 0 in
7167
the ha_statistics' constructor. */
7168
} else if (UNIV_UNLIKELY
7169
(srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) {
7170
/* Avoid accessing the tablespace if
7171
innodb_crash_recovery is set to a high value. */
7172
stats.delete_length = 0;
7176
avail_space = fsp_get_available_space_in_free_extents(ib_table->space);
7178
if (avail_space == ULLINT_UNDEFINED) {
7181
session= getTable()->in_use;
7184
push_warning_printf(
7186
DRIZZLE_ERROR::WARN_LEVEL_WARN,
7188
"InnoDB: Trying to get the free "
7189
"space for table %s but its "
7190
"tablespace has been discarded or "
7191
"the .ibd file is missing. Setting "
7192
"the free space to zero.",
7195
stats.delete_length = 0;
7197
stats.delete_length = avail_space * 1024;
7201
stats.check_time = 0;
7203
if (stats.records == 0) {
7204
stats.mean_rec_length = 0;
7206
stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
7210
if (flag & HA_STATUS_CONST) {
7212
/* Verify the number of index in InnoDB and MySQL
7213
matches up. If prebuilt->clust_index_was_generated
7214
holds, InnoDB defines GEN_CLUST_INDEX internally */
7215
ulint num_innodb_index = UT_LIST_GET_LEN(ib_table->indexes) - prebuilt->clust_index_was_generated;
7217
if (getTable()->getShare()->keys != num_innodb_index) {
7218
errmsg_printf(error::ERROR, "Table %s contains %lu "
7219
"indexes inside InnoDB, which "
7220
"is different from the number of "
7221
"indexes %u defined in the MySQL ",
7222
ib_table->name, num_innodb_index,
7223
getTable()->getShare()->keys);
7226
dict_table_stats_lock(ib_table, RW_S_LATCH);
7228
for (i = 0; i < getTable()->getShare()->sizeKeys(); i++) {
7230
/* We could get index quickly through internal
7231
index mapping with the index translation table.
7232
The identity of index (match up index name with
7233
that of table->key_info[i]) is already verified in
7234
innobase_get_index(). */
7235
index = innobase_get_index(i);
7237
if (index == NULL) {
7238
errmsg_printf(error::ERROR, "Table %s contains fewer "
7239
"indexes inside InnoDB than "
7240
"are defined in the MySQL "
7241
".frm file. Have you mixed up "
7242
".frm files from different "
7243
"installations? See "
7245
"innodb-troubleshooting.html\n",
7250
for (j = 0; j < getTable()->key_info[i].key_parts; j++) {
7252
if (j + 1 > index->n_uniq) {
7253
errmsg_printf(error::ERROR,
7254
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
7255
"statistics for %lu columns. Have you mixed up .frm files from different "
7257
"See " REFMAN "innodb-troubleshooting.html\n",
7261
index->n_uniq, j + 1);
7265
if (index->stat_n_diff_key_vals[j + 1] == 0) {
7267
rec_per_key = stats.records;
7269
rec_per_key = (ha_rows)(stats.records /
7270
index->stat_n_diff_key_vals[j + 1]);
7273
/* Since MySQL seems to favor table scans
7274
too much over index searches, we pretend
7275
index selectivity is 2 times better than
7278
rec_per_key = rec_per_key / 2;
7280
if (rec_per_key == 0) {
7284
getTable()->key_info[i].rec_per_key[j]=
7285
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
7286
(ulong) rec_per_key;
7290
dict_table_stats_unlock(ib_table, RW_S_LATCH);
7293
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
7297
if (flag & HA_STATUS_ERRKEY) {
7298
const dict_index_t* err_index;
7300
ut_a(prebuilt->trx);
7301
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7303
err_index = trx_get_error_info(prebuilt->trx);
7306
errkey = (unsigned int)
7307
innobase_get_mysql_key_number_for_index(share, getTable(), ib_table,
7310
errkey = (unsigned int) prebuilt->trx->error_key_num;
7314
if ((flag & HA_STATUS_AUTO) && getTable()->found_next_number_field) {
7315
stats.auto_increment_value = innobase_peek_autoinc();
7319
prebuilt->trx->op_info = (char*)"";
7324
/**********************************************************************//**
7325
Updates index cardinalities of the table, based on 8 random dives into
7326
each index tree. This does NOT calculate exact statistics on the table.
7327
@return returns always 0 (success) */
7330
ha_innobase::analyze(
7331
/*=================*/
7332
Session*) /*!< in: connection thread handle */
7334
/* Simply call ::info() with all the flags */
7335
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
7340
/*******************************************************************//**
7341
Tries to check that an InnoDB table is not corrupted. If corruption is
7342
noticed, prints to stderr information about it. In case of corruption
7343
may also assert a failure and crash the server.
7344
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
7349
Session* session) /*!< in: user thread handle */
7351
dict_index_t* index;
7353
ulint n_rows_in_table = ULINT_UNDEFINED;
7355
ulint old_isolation_level;
7357
assert(session == getTable()->in_use);
7358
ut_a(prebuilt->trx);
7359
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7360
ut_a(prebuilt->trx == session_to_trx(session));
7362
if (prebuilt->mysql_template == NULL) {
7363
/* Build the template; we will use a dummy template
7364
in index scans done in checking */
7366
build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
7369
if (prebuilt->table->ibd_file_missing) {
7370
errmsg_printf(error::ERROR, "InnoDB: Error:\n"
7371
"InnoDB: MySQL is trying to use a table handle"
7372
" but the .ibd file for\n"
7373
"InnoDB: table %s does not exist.\n"
7374
"InnoDB: Have you deleted the .ibd file"
7375
" from the database directory under\n"
7376
"InnoDB: the MySQL datadir, or have you"
7377
" used DISCARD TABLESPACE?\n"
7378
"InnoDB: Please refer to\n"
7379
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
7380
"InnoDB: how you can resolve the problem.\n",
7381
prebuilt->table->name);
7382
return(HA_ADMIN_CORRUPT);
7385
prebuilt->trx->op_info = "checking table";
7387
old_isolation_level = prebuilt->trx->isolation_level;
7389
/* We must run the index record counts at an isolation level
7390
>= READ COMMITTED, because a dirty read can see a wrong number
7391
of records in some index; to play safe, we use always
7392
REPEATABLE READ here */
7394
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
7396
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
7397
mutex_enter(&kernel_mutex);
7398
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
7399
mutex_exit(&kernel_mutex);
7401
for (index = dict_table_get_first_index(prebuilt->table);
7403
index = dict_table_get_next_index(index)) {
7405
fputs("Validating index ", stderr);
7406
ut_print_name(stderr, trx, FALSE, index->name);
7410
if (!btr_validate_index(index, prebuilt->trx)) {
7412
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7414
"InnoDB: The B-tree of"
7415
" index '%-.200s' is corrupted.",
7420
/* Instead of invoking change_active_index(), set up
7421
a dummy template for non-locking reads, disabling
7422
access to the clustered index. */
7423
prebuilt->index = index;
7425
prebuilt->index_usable = row_merge_is_index_usable(
7426
prebuilt->trx, prebuilt->index);
7428
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
7429
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7430
HA_ERR_TABLE_DEF_CHANGED,
7431
"InnoDB: Insufficient history for"
7437
prebuilt->sql_stat_start = TRUE;
7438
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
7439
prebuilt->n_template = 0;
7440
prebuilt->need_to_access_clustered = FALSE;
7442
dtuple_set_n_fields(prebuilt->search_tuple, 0);
7444
prebuilt->select_lock_type = LOCK_NONE;
7446
if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) {
7447
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7449
"InnoDB: The B-tree of"
7450
" index '%-.200s' is corrupted.",
7455
if (user_session->getKilled()) {
7460
fprintf(stderr, "%lu entries in index %s\n", n_rows,
7464
if (index == dict_table_get_first_index(prebuilt->table)) {
7465
n_rows_in_table = n_rows;
7466
} else if (n_rows != n_rows_in_table) {
7467
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7469
"InnoDB: Index '%-.200s'"
7470
" contains %lu entries,"
7474
(ulong) n_rows_in_table);
7479
/* Restore the original isolation level */
7480
prebuilt->trx->isolation_level = old_isolation_level;
7482
/* We validate also the whole adaptive hash index for all tables
7483
at every CHECK TABLE */
7485
if (!btr_search_validate()) {
7486
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7488
"InnoDB: The adaptive hash index is corrupted.");
7492
/* Restore the fatal lock wait timeout after CHECK TABLE. */
7493
mutex_enter(&kernel_mutex);
7494
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
7495
mutex_exit(&kernel_mutex);
7497
prebuilt->trx->op_info = "";
7498
if (user_session->getKilled()) {
7499
my_error(ER_QUERY_INTERRUPTED, MYF(0));
7502
return(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
7505
/*************************************************************//**
7506
Adds information about free space in the InnoDB tablespace to a table comment
7507
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
7509
@return table comment + InnoDB free space + info on foreign keys */
7512
ha_innobase::update_table_comment(
7513
/*==============================*/
7514
const char* comment)/*!< in: table comment defined by user */
7516
uint length = (uint) strlen(comment);
7520
/* We do not know if MySQL can call this function before calling
7521
external_lock(). To be safe, update the session of the current table
7524
if (length > 64000 - 3) {
7525
return((char*)comment); /* string too long */
7528
update_session(getTable()->in_use);
7530
prebuilt->trx->op_info = (char*)"returning table comment";
7532
/* In case MySQL calls this in the middle of a SELECT query, release
7533
possible adaptive hash latch to avoid deadlocks of threads */
7535
trx_search_latch_release_if_reserved(prebuilt->trx);
7538
/* output the data to a temporary file */
7540
mutex_enter(&srv_dict_tmpfile_mutex);
7541
rewind(srv_dict_tmpfile);
7543
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
7544
fsp_get_available_space_in_free_extents(
7545
prebuilt->table->space));
7547
dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
7548
prebuilt->trx, prebuilt->table);
7549
flen = ftell(srv_dict_tmpfile);
7552
} else if (length + flen + 3 > 64000) {
7553
flen = 64000 - 3 - length;
7556
/* allocate buffer for the full string, and
7557
read the contents of the temporary file */
7559
str = (char*) malloc(length + flen + 3);
7562
char* pos = str + length;
7564
memcpy(str, comment, length);
7568
rewind(srv_dict_tmpfile);
7569
flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
7573
mutex_exit(&srv_dict_tmpfile_mutex);
7575
prebuilt->trx->op_info = (char*)"";
7577
return(str ? str : (char*) comment);
7580
/*******************************************************************//**
7581
Gets the foreign key create info for a table stored in InnoDB.
7582
@return own: character string in the form which can be inserted to the
7583
CREATE TABLE statement, MUST be freed with
7584
ha_innobase::free_foreign_key_create_info */
7587
ha_innobase::get_foreign_key_create_info(void)
7588
/*==========================================*/
7593
ut_a(prebuilt != NULL);
7595
/* We do not know if MySQL can call this function before calling
7596
external_lock(). To be safe, update the session of the current table
7599
update_session(getTable()->in_use);
7601
prebuilt->trx->op_info = (char*)"getting info on foreign keys";
7603
/* In case MySQL calls this in the middle of a SELECT query,
7604
release possible adaptive hash latch to avoid
7605
deadlocks of threads */
7607
trx_search_latch_release_if_reserved(prebuilt->trx);
7609
mutex_enter(&srv_dict_tmpfile_mutex);
7610
rewind(srv_dict_tmpfile);
7612
/* output the data to a temporary file */
7613
dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
7614
prebuilt->trx, prebuilt->table);
7615
prebuilt->trx->op_info = (char*)"";
7617
flen = ftell(srv_dict_tmpfile);
7622
/* allocate buffer for the string, and
7623
read the contents of the temporary file */
7625
str = (char*) malloc(flen + 1);
7628
rewind(srv_dict_tmpfile);
7629
flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
7633
mutex_exit(&srv_dict_tmpfile_mutex);
7641
ha_innobase::get_foreign_key_list(Session *session, List<ForeignKeyInfo> *f_key_list)
7643
dict_foreign_t* foreign;
7645
ut_a(prebuilt != NULL);
7646
update_session(getTable()->in_use);
7647
prebuilt->trx->op_info = (char*)"getting list of foreign keys";
7648
trx_search_latch_release_if_reserved(prebuilt->trx);
7649
mutex_enter(&(dict_sys->mutex));
7650
foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7652
while (foreign != NULL) {
7655
LEX_STRING *name = 0;
7657
char uname[NAME_LEN + 1]; /* Unencoded name */
7658
char db_name[NAME_LEN + 1];
7659
const char *tmp_buff;
7662
tmp_buff = foreign->id;
7664
while (tmp_buff[i] != '/')
7667
LEX_STRING *tmp_foreign_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
7670
tmp_buff = foreign->referenced_table_name;
7673
while (tmp_buff[i] != '/')
7675
db_name[i]= tmp_buff[i];
7679
ulen= identifier::Table::filename_to_tablename(db_name, uname, sizeof(uname));
7680
LEX_STRING *tmp_referenced_db = session->make_lex_string(NULL, uname, ulen, true);
7684
ulen= identifier::Table::filename_to_tablename(tmp_buff, uname, sizeof(uname));
7685
LEX_STRING *tmp_referenced_table = session->make_lex_string(NULL, uname, ulen, true);
7687
/** Foreign Fields **/
7688
List<LEX_STRING> tmp_foreign_fields;
7689
List<LEX_STRING> tmp_referenced_fields;
7691
tmp_buff= foreign->foreign_col_names[i];
7692
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
7693
tmp_foreign_fields.push_back(name);
7694
tmp_buff= foreign->referenced_col_names[i];
7695
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
7696
tmp_referenced_fields.push_back(name);
7697
if (++i >= foreign->n_fields)
7702
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
7705
tmp_buff= "CASCADE";
7707
else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
7710
tmp_buff= "SET NULL";
7712
else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
7715
tmp_buff= "NO ACTION";
7720
tmp_buff= "RESTRICT";
7722
LEX_STRING *tmp_delete_method = session->make_lex_string(NULL, tmp_buff, length, true);
7725
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
7728
tmp_buff= "CASCADE";
7730
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
7733
tmp_buff= "SET NULL";
7735
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
7738
tmp_buff= "NO ACTION";
7743
tmp_buff= "RESTRICT";
7745
LEX_STRING *tmp_update_method = session->make_lex_string(NULL, tmp_buff, length, true);
7747
LEX_STRING *tmp_referenced_key_name = NULL;
7749
if (foreign->referenced_index &&
7750
foreign->referenced_index->name)
7752
tmp_referenced_key_name = session->make_lex_string(NULL,
7753
foreign->referenced_index->name, strlen(foreign->referenced_index->name), true);
7756
ForeignKeyInfo f_key_info(
7757
tmp_foreign_id, tmp_referenced_db, tmp_referenced_table,
7758
tmp_update_method, tmp_delete_method, tmp_referenced_key_name,
7759
tmp_foreign_fields, tmp_referenced_fields);
7761
ForeignKeyInfo *pf_key_info = (ForeignKeyInfo *)
7762
session->getMemRoot()->duplicate(&f_key_info, sizeof(ForeignKeyInfo));
7763
f_key_list->push_back(pf_key_info);
7764
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
7766
mutex_exit(&(dict_sys->mutex));
7767
prebuilt->trx->op_info = (char*)"";
7772
/*****************************************************************//**
7773
Checks if ALTER TABLE may change the storage engine of the table.
7774
Changing storage engines is not allowed for tables for which there
7775
are foreign key constraints (parent or child tables).
7776
@return TRUE if can switch engines */
7779
ha_innobase::can_switch_engines(void)
7780
/*=================================*/
7784
ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
7786
prebuilt->trx->op_info =
7787
"determining if there are foreign key constraints";
7788
row_mysql_lock_data_dictionary(prebuilt->trx);
7790
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
7791
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7793
row_mysql_unlock_data_dictionary(prebuilt->trx);
7794
prebuilt->trx->op_info = "";
7799
/*******************************************************************//**
7800
Checks if a table is referenced by a foreign key. The MySQL manual states that
7801
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
7802
delete is then allowed internally to resolve a duplicate key conflict in
7803
REPLACE, not an update.
7804
@return > 0 if referenced by a FOREIGN KEY */
7807
ha_innobase::referenced_by_foreign_key(void)
7808
/*========================================*/
7810
if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
7818
/*******************************************************************//**
7819
Frees the foreign key create info for a table stored in InnoDB, if it is
7823
ha_innobase::free_foreign_key_create_info(
7824
/*======================================*/
7825
char* str) /*!< in, own: create info string to free */
7832
/*******************************************************************//**
7833
Tells something additional to the Cursor about how to do things.
7834
@return 0 or error number */
7839
enum ha_extra_function operation)
7840
/*!< in: HA_EXTRA_FLUSH or some other flag */
7842
/* Warning: since it is not sure that MySQL calls external_lock
7843
before calling this function, the trx field in prebuilt can be
7846
switch (operation) {
7847
case HA_EXTRA_FLUSH:
7848
if (prebuilt->blob_heap) {
7849
row_mysql_prebuilt_free_blob_heap(prebuilt);
7852
case HA_EXTRA_RESET_STATE:
7853
reset_template(prebuilt);
7855
case HA_EXTRA_NO_KEYREAD:
7856
prebuilt->read_just_key = 0;
7858
case HA_EXTRA_KEYREAD:
7859
prebuilt->read_just_key = 1;
7861
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
7862
prebuilt->keep_other_fields_on_keyread = 1;
7865
/* IMPORTANT: prebuilt->trx can be obsolete in
7866
this method, because it is not sure that MySQL
7867
calls external_lock before this method with the
7868
parameters below. We must not invoke update_session()
7869
either, because the calling threads may change.
7870
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
7871
case HA_EXTRA_IGNORE_DUP_KEY:
7872
session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_IGNORE;
7874
case HA_EXTRA_WRITE_CAN_REPLACE:
7875
session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_REPLACE;
7877
case HA_EXTRA_WRITE_CANNOT_REPLACE:
7878
session_to_trx(getTable()->in_use)->duplicates &= ~TRX_DUP_REPLACE;
7880
case HA_EXTRA_NO_IGNORE_DUP_KEY:
7881
session_to_trx(getTable()->in_use)->duplicates &=
7882
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
7884
default:/* Do nothing */
7893
ha_innobase::reset()
7895
if (prebuilt->blob_heap) {
7896
row_mysql_prebuilt_free_blob_heap(prebuilt);
7899
reset_template(prebuilt);
7901
/* TODO: This should really be reset in reset_template() but for now
7902
it's safer to do it explicitly here. */
7904
/* This is a statement level counter. */
7905
prebuilt->autoinc_last_value = 0;
7910
/******************************************************************//**
7911
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7912
@return InnoDB isolation level */
7915
innobase_map_isolation_level(
7916
/*=========================*/
7917
enum_tx_isolation iso) /*!< in: MySQL isolation level code */
7920
case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
7921
case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
7922
case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
7923
case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
7924
default: ut_a(0); return(0);
7928
/******************************************************************//**
7929
As MySQL will execute an external lock for every new table it uses when it
7930
starts to process an SQL statement. We can use this function to store the pointer to
7931
the Session in the handle.
7935
ha_innobase::external_lock(
7936
/*=======================*/
7937
Session* session, /*!< in: handle to the user thread */
7938
int lock_type) /*!< in: lock type */
7940
update_session(session);
7942
trx_t *trx= prebuilt->trx;
7944
prebuilt->sql_stat_start = TRUE;
7945
prebuilt->hint_need_to_fetch_extra_cols = 0;
7947
reset_template(prebuilt);
7949
if (lock_type == F_WRLCK) {
7951
/* If this is a SELECT, then it is in UPDATE TABLE ...
7952
or SELECT ... FOR UPDATE */
7953
prebuilt->select_lock_type = LOCK_X;
7954
prebuilt->stored_select_lock_type = LOCK_X;
7957
if (lock_type != F_UNLCK) {
7958
/* MySQL is setting a new table lock */
7960
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
7961
&& prebuilt->select_lock_type == LOCK_NONE
7962
&& session_test_options(session,
7963
OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7965
/* To get serializable execution, we let InnoDB
7966
conceptually add 'LOCK IN SHARE MODE' to all SELECTs
7967
which otherwise would have been consistent reads. An
7968
exception is consistent reads in the AUTOCOMMIT=1 mode:
7969
we know that they are read-only transactions, and they
7970
can be serialized also if performed as consistent
7973
prebuilt->select_lock_type = LOCK_S;
7974
prebuilt->stored_select_lock_type = LOCK_S;
7977
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
7978
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
7979
an InnoDB table lock if it is released immediately at the end
7980
of LOCK TABLES, and InnoDB's table locks in that case cause
7981
VERY easily deadlocks.
7983
We do not set InnoDB table locks if user has not explicitly
7984
requested a table lock. Note that session_in_lock_tables(session)
7985
can hold in some cases, e.g., at the start of a stored
7986
procedure call (SQLCOM_CALL). */
7988
if (prebuilt->select_lock_type != LOCK_NONE) {
7989
trx->mysql_n_tables_locked++;
7992
prebuilt->mysql_has_locked = TRUE;
7997
/* MySQL is releasing a table lock */
7998
prebuilt->mysql_has_locked = FALSE;
7999
trx->mysql_n_tables_locked= 0;
8004
/************************************************************************//**
8005
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
8006
Monitor to the client. */
8011
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
8012
Session* session,/*!< in: the MySQL query thread of the caller */
8013
stat_print_fn *stat_print)
8016
static const char truncated_msg[] = "... truncated...\n";
8017
const long MAX_STATUS_SIZE = 1048576;
8018
ulint trx_list_start = ULINT_UNDEFINED;
8019
ulint trx_list_end = ULINT_UNDEFINED;
8021
assert(engine == innodb_engine_ptr);
8023
trx = check_trx_exists(session);
8025
innobase_release_stat_resources(trx);
8027
/* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
8030
long flen, usable_len;
8033
mutex_enter(&srv_monitor_file_mutex);
8034
rewind(srv_monitor_file);
8035
srv_printf_innodb_monitor(srv_monitor_file, FALSE,
8036
&trx_list_start, &trx_list_end);
8037
flen = ftell(srv_monitor_file);
8038
os_file_set_eof(srv_monitor_file);
8044
if (flen > MAX_STATUS_SIZE) {
8045
usable_len = MAX_STATUS_SIZE;
8046
srv_truncated_status_writes++;
8051
/* allocate buffer for the string, and
8052
read the contents of the temporary file */
8054
if (!(str = (char*) malloc(usable_len + 1))) {
8055
mutex_exit(&srv_monitor_file_mutex);
8059
rewind(srv_monitor_file);
8060
if (flen < MAX_STATUS_SIZE) {
8061
/* Display the entire output. */
8062
flen = (long) fread(str, 1, flen, srv_monitor_file);
8063
} else if (trx_list_end < (ulint) flen
8064
&& trx_list_start < trx_list_end
8065
&& trx_list_start + (flen - trx_list_end)
8066
< MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
8067
/* Omit the beginning of the list of active transactions. */
8068
long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
8069
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
8070
len += sizeof truncated_msg - 1;
8071
usable_len = (MAX_STATUS_SIZE - 1) - len;
8072
fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
8073
len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
8076
/* Omit the end of the output. */
8077
flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
8080
mutex_exit(&srv_monitor_file_mutex);
8082
stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
8083
STRING_WITH_LEN(""), str, flen);
8090
/************************************************************************//**
8091
Implements the SHOW MUTEX STATUS command.
8092
@return true on failure false on success*/
8095
innodb_mutex_show_status(
8096
/*=====================*/
8097
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
8098
Session* session, /*!< in: the MySQL query thread of the
8100
stat_print_fn* stat_print) /*!< in: function for printing
8103
char buf1[IO_SIZE], buf2[IO_SIZE];
8106
ulint block_mutex_oswait_count = 0;
8107
ulint block_lock_oswait_count = 0;
8108
mutex_t* block_mutex = NULL;
8109
rw_lock_t* block_lock = NULL;
8111
ulint rw_lock_count= 0;
8112
ulint rw_lock_count_spin_loop= 0;
8113
ulint rw_lock_count_spin_rounds= 0;
8114
ulint rw_lock_count_os_wait= 0;
8115
ulint rw_lock_count_os_yield= 0;
8116
uint64_t rw_lock_wait_time= 0;
8117
#endif /* UNIV_DEBUG */
8118
uint engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
8119
assert(engine == innodb_engine_ptr);
8121
mutex_enter(&mutex_list_mutex);
8123
for (mutex = UT_LIST_GET_FIRST(mutex_list); mutex != NULL;
8124
mutex = UT_LIST_GET_NEXT(list, mutex)) {
8125
if (mutex->count_os_wait == 0) {
8130
if (buf_pool_is_block_mutex(mutex)) {
8131
block_mutex = mutex;
8132
block_mutex_oswait_count += mutex->count_os_wait;
8136
if (mutex->mutex_type != 1) {
8137
if (mutex->count_using > 0) {
8138
buf1len= my_snprintf(buf1, sizeof(buf1),
8140
mutex->cmutex_name, mutex->cfile_name);
8141
buf2len= my_snprintf(buf2, sizeof(buf2),
8142
"count=%lu, spin_waits=%lu,"
8143
" spin_rounds=%lu, "
8144
"os_waits=%lu, os_yields=%lu,"
8145
" os_wait_times=%lu",
8147
mutex->count_spin_loop,
8148
mutex->count_spin_rounds,
8149
mutex->count_os_wait,
8150
mutex->count_os_yield,
8151
(ulong) (mutex->lspent_time/1000));
8153
if (stat_print(session, innobase_engine_name,
8154
engine_name_len, buf1, buf1len,
8156
mutex_exit(&mutex_list_mutex);
8161
rw_lock_count += mutex->count_using;
8162
rw_lock_count_spin_loop += mutex->count_spin_loop;
8163
rw_lock_count_spin_rounds += mutex->count_spin_rounds;
8164
rw_lock_count_os_wait += mutex->count_os_wait;
8165
rw_lock_count_os_yield += mutex->count_os_yield;
8166
rw_lock_wait_time += mutex->lspent_time;
8168
#else /* UNIV_DEBUG */
8169
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
8170
mutex->cfile_name, (ulong) mutex->cline);
8171
buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
8172
(ulong) mutex->count_os_wait);
8174
if (stat_print(session, innobase_engine_name,
8175
engine_name_len, buf1, buf1len,
8177
mutex_exit(&mutex_list_mutex);
8180
#endif /* UNIV_DEBUG */
8184
buf1len = snprintf(buf1, sizeof buf1,
8186
block_mutex->cfile_name,
8187
(ulong) block_mutex->cline);
8188
buf2len = snprintf(buf2, sizeof buf2,
8190
(ulong) block_mutex_oswait_count);
8192
if (stat_print(session, innobase_engine_name,
8193
strlen(innobase_engine_name), buf1, buf1len,
8195
mutex_exit(&mutex_list_mutex);
8200
mutex_exit(&mutex_list_mutex);
8202
mutex_enter(&rw_lock_list_mutex);
8204
for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL;
8205
lock = UT_LIST_GET_NEXT(list, lock)) {
8206
if (lock->count_os_wait == 0) {
8210
if (buf_pool_is_block_lock(lock)) {
8212
block_lock_oswait_count += lock->count_os_wait;
8216
buf1len = snprintf(buf1, sizeof buf1, "%s:%lu",
8217
lock->cfile_name, (ulong) lock->cline);
8218
buf2len = snprintf(buf2, sizeof buf2, "os_waits=%lu",
8219
(ulong) lock->count_os_wait);
8221
if (stat_print(session, innobase_engine_name,
8222
strlen(innobase_engine_name), buf1, buf1len,
8224
mutex_exit(&rw_lock_list_mutex);
8230
buf1len = snprintf(buf1, sizeof buf1,
8232
block_lock->cfile_name,
8233
(ulong) block_lock->cline);
8234
buf2len = snprintf(buf2, sizeof buf2,
8236
(ulong) block_lock_oswait_count);
8238
if (stat_print(session, innobase_engine_name,
8239
strlen(innobase_engine_name), buf1, buf1len,
8241
mutex_exit(&rw_lock_list_mutex);
8246
mutex_exit(&rw_lock_list_mutex);
8249
buf2len = snprintf(buf2, sizeof buf2,
8250
"count=%lu, spin_waits=%lu, spin_rounds=%lu, "
8251
"os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
8252
(ulong) rw_lock_count,
8253
(ulong) rw_lock_count_spin_loop,
8254
(ulong) rw_lock_count_spin_rounds,
8255
(ulong) rw_lock_count_os_wait,
8256
(ulong) rw_lock_count_os_yield,
8257
(ulong) (rw_lock_wait_time / 1000));
8259
if (stat_print(session, innobase_engine_name, engine_name_len,
8260
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
8263
#endif /* UNIV_DEBUG */
8268
bool InnobaseEngine::show_status(Session* session,
8269
stat_print_fn* stat_print,
8270
enum ha_stat_type stat_type)
8272
assert(this == innodb_engine_ptr);
8274
switch (stat_type) {
8275
case HA_ENGINE_STATUS:
8276
return innodb_show_status(this, session, stat_print);
8277
case HA_ENGINE_MUTEX:
8278
return innodb_mutex_show_status(this, session, stat_print);
8284
/************************************************************************//**
8285
Handling the shared INNOBASE_SHARE structure that is needed to provide table
8287
****************************************************************************/
8289
static INNOBASE_SHARE* get_share(const char* table_name)
8291
INNOBASE_SHARE *share;
8292
boost::mutex::scoped_lock scopedLock(innobase_share_mutex);
8294
ulint fold = ut_fold_string(table_name);
8296
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8297
INNOBASE_SHARE*, share,
8298
ut_ad(share->use_count > 0),
8299
!strcmp(share->table_name, table_name));
8302
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
8305
share= new INNOBASE_SHARE(table_name);
8307
HASH_INSERT(INNOBASE_SHARE, table_name_hash,
8308
innobase_open_tables, fold, share);
8310
thr_lock_init(&share->lock);
8312
/* Index translation table initialization */
8313
share->idx_trans_tbl.index_mapping = NULL;
8314
share->idx_trans_tbl.index_count = 0;
8315
share->idx_trans_tbl.array_size = 0;
8323
static void free_share(INNOBASE_SHARE* share)
8325
boost::mutex::scoped_lock scopedLock(innobase_share_mutex);
8328
INNOBASE_SHARE* share2;
8329
ulint fold = ut_fold_string(share->table_name);
8331
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8332
INNOBASE_SHARE*, share2,
8333
ut_ad(share->use_count > 0),
8334
!strcmp(share->table_name, share2->table_name));
8336
ut_a(share2 == share);
8337
#endif /* UNIV_DEBUG */
8339
if (!--share->use_count) {
8340
ulint fold = ut_fold_string(share->table_name);
8342
HASH_DELETE(INNOBASE_SHARE, table_name_hash,
8343
innobase_open_tables, fold, share);
8344
share->lock.deinit();
8346
/* Free any memory from index translation table */
8347
free(share->idx_trans_tbl.index_mapping);
8351
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
8356
/*****************************************************************//**
8357
Converts a MySQL table lock stored in the 'lock' field of the handle to
8358
a proper type before storing pointer to the lock into an array of pointers.
8359
MySQL also calls this if it wants to reset some table locks to a not-locked
8360
state during the processing of an SQL query. An example is that during a
8361
SELECT the read lock is released early on the 'const' tables where we only
8362
fetch one row. MySQL does not call this when it releases all locks at the
8363
end of an SQL statement.
8364
@return pointer to the next element in the 'to' array */
8367
ha_innobase::store_lock(
8368
/*====================*/
8369
Session* session, /*!< in: user thread handle */
8370
THR_LOCK_DATA** to, /*!< in: pointer to an array
8371
of pointers to lock structs;
8372
pointer to the 'lock' field
8373
of current handle is stored
8374
next to this array */
8375
enum thr_lock_type lock_type) /*!< in: lock type to store in
8376
'lock'; this may also be
8381
/* Note that trx in this function is NOT necessarily prebuilt->trx
8382
because we call update_session() later, in ::external_lock()! Failure to
8383
understand this caused a serious memory corruption bug in 5.1.11. */
8385
trx = check_trx_exists(session);
8387
assert(EQ_CURRENT_SESSION(session));
8388
const uint32_t sql_command = session->getSqlCommand();
8390
if (sql_command == SQLCOM_DROP_TABLE) {
8392
/* MySQL calls this function in DROP Table though this table
8393
handle may belong to another session that is running a query.
8394
Let us in that case skip any changes to the prebuilt struct. */
8396
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
8397
|| lock_type == TL_READ_NO_INSERT
8398
|| (lock_type != TL_IGNORE
8399
&& sql_command != SQLCOM_SELECT)) {
8401
/* The OR cases above are in this order:
8402
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
8403
are processing a stored procedure or function, or
8404
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
8405
3) this is a SELECT ... IN SHARE MODE, or
8406
4) we are doing a complex SQL statement like
8407
INSERT INTO ... SELECT ... and the logical logging (MySQL
8408
binlog) requires the use of a locking read, or
8409
MySQL is doing LOCK TABLES ... READ.
8410
5) we let InnoDB do locking reads for all SQL statements that
8411
are not simple SELECTs; note that select_lock_type in this
8412
case may get strengthened in ::external_lock() to LOCK_X.
8413
Note that we MUST use a locking read in all data modifying
8414
SQL statements, because otherwise the execution would not be
8415
serializable, and also the results from the update could be
8416
unexpected if an obsolete consistent read view would be
8419
ulint isolation_level;
8421
isolation_level = trx->isolation_level;
8423
if ((srv_locks_unsafe_for_binlog
8424
|| isolation_level <= TRX_ISO_READ_COMMITTED)
8425
&& isolation_level != TRX_ISO_SERIALIZABLE
8426
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
8427
&& (sql_command == SQLCOM_INSERT_SELECT
8428
|| sql_command == SQLCOM_REPLACE_SELECT
8429
|| sql_command == SQLCOM_UPDATE
8430
|| sql_command == SQLCOM_CREATE_TABLE
8431
|| sql_command == SQLCOM_SET_OPTION)) {
8433
/* If we either have innobase_locks_unsafe_for_binlog
8434
option set or this session is using READ COMMITTED
8435
isolation level and isolation level of the transaction
8436
is not set to serializable and MySQL is doing
8437
INSERT INTO...SELECT or REPLACE INTO...SELECT
8438
or UPDATE ... = (SELECT ...) or CREATE ...
8439
SELECT... or SET ... = (SELECT ...) without
8440
FOR UPDATE or IN SHARE MODE in select,
8441
then we use consistent read for select. */
8443
prebuilt->select_lock_type = LOCK_NONE;
8444
prebuilt->stored_select_lock_type = LOCK_NONE;
8445
} else if (sql_command == SQLCOM_CHECKSUM) {
8446
/* Use consistent read for checksum table */
8448
prebuilt->select_lock_type = LOCK_NONE;
8449
prebuilt->stored_select_lock_type = LOCK_NONE;
8451
prebuilt->select_lock_type = LOCK_S;
8452
prebuilt->stored_select_lock_type = LOCK_S;
8455
} else if (lock_type != TL_IGNORE) {
8457
/* We set possible LOCK_X value in external_lock, not yet
8458
here even if this would be SELECT ... FOR UPDATE */
8460
prebuilt->select_lock_type = LOCK_NONE;
8461
prebuilt->stored_select_lock_type = LOCK_NONE;
8464
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
8466
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
8467
TABLESPACE or TRUNCATE TABLE then allow multiple
8468
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
8469
< TL_WRITE_CONCURRENT_INSERT.
8472
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
8473
&& lock_type <= TL_WRITE)
8474
&& ! session->doing_tablespace_operation()
8475
&& sql_command != SQLCOM_TRUNCATE
8476
&& sql_command != SQLCOM_CREATE_TABLE) {
8478
lock_type = TL_WRITE_ALLOW_WRITE;
8481
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
8482
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
8483
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
8484
to t2. Convert the lock to a normal read lock to allow
8485
concurrent inserts to t2.
8488
if (lock_type == TL_READ_NO_INSERT) {
8490
lock_type = TL_READ;
8493
lock.type = lock_type;
8501
/*********************************************************************//**
8502
Read the next autoinc value. Acquire the relevant locks before reading
8503
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
8504
on return and all relevant locks acquired.
8505
@return DB_SUCCESS or error code */
8508
ha_innobase::innobase_get_autoinc(
8509
/*==============================*/
8510
uint64_t* value) /*!< out: autoinc value */
8514
dict_table_autoinc_lock(prebuilt->table);
8515
prebuilt->autoinc_error= DB_SUCCESS;
8516
/* Determine the first value of the interval */
8517
*value = dict_table_autoinc_read(prebuilt->table);
8519
/* It should have been initialized during open. */
8521
prebuilt->autoinc_error = DB_UNSUPPORTED;
8522
dict_table_autoinc_unlock(prebuilt->table);
8528
/*******************************************************************//**
8529
This function reads the global auto-inc counter. It doesn't use the
8530
AUTOINC lock even if the lock mode is set to TRADITIONAL.
8531
@return the autoinc value */
8534
ha_innobase::innobase_peek_autoinc(void)
8535
/*====================================*/
8538
dict_table_t* innodb_table;
8540
ut_a(prebuilt != NULL);
8541
ut_a(prebuilt->table != NULL);
8543
innodb_table = prebuilt->table;
8545
dict_table_autoinc_lock(innodb_table);
8547
auto_inc = dict_table_autoinc_read(innodb_table);
8549
if (auto_inc == 0) {
8550
ut_print_timestamp(stderr);
8551
errmsg_printf(error::ERROR, " InnoDB: AUTOINC next value generation is disabled for '%s'\n", innodb_table->name);
8554
dict_table_autoinc_unlock(innodb_table);
8559
/*********************************************************************//**
8560
This function initializes the auto-inc counter if it has not been
8561
initialized yet. This function does not change the value of the auto-inc
8562
counter if it already has been initialized. Returns the value of the
8563
auto-inc counter in *first_value, and UINT64_T_MAX in *nb_reserved_values (as
8564
we have a table-level lock). offset, increment, nb_desired_values are ignored.
8565
*first_value is set to -1 if error (deadlock or lock wait timeout) */
8568
ha_innobase::get_auto_increment(
8569
/*============================*/
8570
uint64_t offset, /*!< in: table autoinc offset */
8571
uint64_t increment, /*!< in: table autoinc increment */
8572
uint64_t nb_desired_values, /*!< in: number of values reqd */
8573
uint64_t *first_value, /*!< out: the autoinc value */
8574
uint64_t *nb_reserved_values) /*!< out: count of reserved values */
8578
uint64_t autoinc = 0;
8580
/* Prepare prebuilt->trx in the table handle */
8581
update_session(getTable()->in_use);
8583
error = innobase_get_autoinc(&autoinc);
8585
if (error != DB_SUCCESS) {
8586
*first_value = (~(uint64_t) 0);
8590
/* This is a hack, since nb_desired_values seems to be accurate only
8591
for the first call to get_auto_increment() for multi-row INSERT and
8592
meaningless for other statements e.g, LOAD etc. Subsequent calls to
8593
this method for the same statement results in different values which
8594
don't make sense. Therefore we store the value the first time we are
8595
called and count down from that as rows are written (see doInsertRecord()).
8598
trx = prebuilt->trx;
8600
/* Note: We can't rely on *first_value since some MySQL engines,
8601
in particular the partition engine, don't initialize it to 0 when
8602
invoking this method. So we are not sure if it's guaranteed to
8605
/* We need the upper limit of the col type to check for
8606
whether we update the table autoinc counter or not. */
8607
uint64_t col_max_value = innobase_get_int_col_max_value(getTable()->next_number_field);
8609
/* Called for the first time ? */
8610
if (trx->n_autoinc_rows == 0) {
8612
trx->n_autoinc_rows = (ulint) nb_desired_values;
8614
/* It's possible for nb_desired_values to be 0:
8615
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
8616
if (nb_desired_values == 0) {
8618
trx->n_autoinc_rows = 1;
8621
set_if_bigger(*first_value, autoinc);
8622
/* Not in the middle of a mult-row INSERT. */
8623
} else if (prebuilt->autoinc_last_value == 0) {
8624
set_if_bigger(*first_value, autoinc);
8625
/* Check for -ve values. */
8626
} else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
8627
/* Set to next logical value. */
8628
ut_a(autoinc > trx->n_autoinc_rows);
8629
*first_value = (autoinc - trx->n_autoinc_rows) - 1;
8632
*nb_reserved_values = trx->n_autoinc_rows;
8634
/* This all current style autoinc. */
8638
uint64_t next_value;
8640
current = *first_value > col_max_value ? autoinc : *first_value;
8641
need = *nb_reserved_values * increment;
8643
/* Compute the last value in the interval */
8644
next_value = innobase_next_autoinc(current, need, offset, col_max_value);
8646
prebuilt->autoinc_last_value = next_value;
8648
if (prebuilt->autoinc_last_value < *first_value) {
8649
*first_value = (~(unsigned long long) 0);
8651
/* Update the table autoinc variable */
8652
dict_table_autoinc_update_if_greater(
8653
prebuilt->table, prebuilt->autoinc_last_value);
8657
/* The increment to be used to increase the AUTOINC value, we use
8658
this in doInsertRecord() and doUpdateRecord() to increase the autoinc counter
8659
for columns that are filled by the user. We need the offset and
8661
prebuilt->autoinc_offset = offset;
8662
prebuilt->autoinc_increment = increment;
8664
dict_table_autoinc_unlock(prebuilt->table);
8667
/*******************************************************************//**
8668
Reset the auto-increment counter to the given value, i.e. the next row
8669
inserted will get the given value. This is called e.g. after TRUNCATE
8670
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
8671
returned by storage engines that don't support this operation.
8672
@return 0 or error code */
8675
ha_innobase::reset_auto_increment(
8676
/*==============================*/
8677
uint64_t value) /*!< in: new value for table autoinc */
8681
update_session(getTable()->in_use);
8683
error = row_lock_table_autoinc_for_mysql(prebuilt);
8685
if (error != DB_SUCCESS) {
8686
error = convert_error_code_to_mysql(error,
8687
prebuilt->table->flags,
8693
/* The next value can never be 0. */
8698
innobase_reset_autoinc(value);
8703
/* See comment in Cursor.cc */
8706
InnobaseEngine::get_error_message(int, String *buf) const
8708
trx_t* trx = check_trx_exists(current_session);
8710
buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
8711
system_charset_info);
8716
/*******************************************************************//**
8717
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
8718
If there is no explicitly declared non-null unique key or a primary key, then
8719
InnoDB internally uses the row id as the primary key.
8720
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
8723
ha_innobase::cmp_ref(
8724
/*=================*/
8725
const unsigned char* ref1, /*!< in: an (internal) primary key value in the
8726
MySQL key value format */
8727
const unsigned char* ref2) /*!< in: an (internal) primary key value in the
8728
MySQL key value format */
8730
enum_field_types mysql_type;
8732
KeyPartInfo* key_part;
8733
KeyPartInfo* key_part_end;
8738
if (prebuilt->clust_index_was_generated) {
8739
/* The 'ref' is an InnoDB row id */
8741
return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
8744
/* Do a type-aware comparison of primary key fields. PK fields
8745
are always NOT NULL, so no checks for NULL are performed. */
8747
key_part = getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_part;
8749
key_part_end = key_part
8750
+ getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_parts;
8752
for (; key_part != key_part_end; ++key_part) {
8753
field = key_part->field;
8754
mysql_type = field->type();
8756
if (mysql_type == DRIZZLE_TYPE_BLOB) {
8758
/* In the MySQL key value format, a column prefix of
8759
a BLOB is preceded by a 2-byte length field */
8761
len1 = innobase_read_from_2_little_endian(ref1);
8762
len2 = innobase_read_from_2_little_endian(ref2);
8766
result = ((Field_blob*)field)->cmp( ref1, len1,
8769
result = field->key_cmp(ref1, ref2);
8777
ref1 += key_part->store_length;
8778
ref2 += key_part->store_length;
8784
/**********************************************************************
8785
This function is used to find the storage length in bytes of the first n
8786
characters for prefix indexes using a multibyte character set. The function
8787
finds charset information and returns length of prefix_len characters in the
8788
index field in bytes.
8789
@return number of bytes occupied by the first n characters */
8792
innobase_get_at_most_n_mbchars(
8793
/*===========================*/
8794
ulint charset_id, /*!< in: character set id */
8795
ulint prefix_len, /*!< in: prefix length in bytes of the index
8796
(this has to be divided by mbmaxlen to get the
8797
number of CHARACTERS n in the prefix) */
8798
ulint data_len, /*!< in: length of the string in bytes */
8799
const char* str) /*!< in: character string */
8801
ulint char_length; /*!< character length in bytes */
8802
ulint n_chars; /*!< number of characters in prefix */
8803
const CHARSET_INFO* charset; /*!< charset used in the field */
8805
charset = get_charset((uint) charset_id);
8808
ut_ad(charset->mbmaxlen);
8810
/* Calculate how many characters at most the prefix index contains */
8812
n_chars = prefix_len / charset->mbmaxlen;
8814
/* If the charset is multi-byte, then we must find the length of the
8815
first at most n chars in the string. If the string contains less
8816
characters than n, then we return the length to the end of the last
8819
if (charset->mbmaxlen > 1) {
8820
/* my_charpos() returns the byte length of the first n_chars
8821
characters, or a value bigger than the length of str, if
8822
there were not enough full characters in str.
8824
Why does the code below work:
8825
Suppose that we are looking for n UTF-8 characters.
8827
1) If the string is long enough, then the prefix contains at
8828
least n complete UTF-8 characters + maybe some extra
8829
characters + an incomplete UTF-8 character. No problem in
8830
this case. The function returns the pointer to the
8831
end of the nth character.
8833
2) If the string is not long enough, then the string contains
8834
the complete value of a column, that is, only complete UTF-8
8835
characters, and we can store in the column prefix index the
8838
char_length = my_charpos(charset, str,
8839
str + data_len, (int) n_chars);
8840
if (char_length > data_len) {
8841
char_length = data_len;
8844
if (data_len < prefix_len) {
8845
char_length = data_len;
8847
char_length = prefix_len;
8851
return(char_length);
8854
* We will also use this function to communicate
8855
* to InnoDB that a new SQL statement has started and that we must store a
8856
* savepoint to our transaction handle, so that we are able to roll back
8857
* the SQL statement in case of an error.
8860
InnobaseEngine::doStartStatement(
8861
Session *session) /*!< in: handle to the Drizzle session */
8864
* Create the InnoDB transaction structure
8867
trx_t *trx= check_trx_exists(session);
8869
/* "reset" the error message for the transaction */
8870
trx->detailed_error[0]= '\0';
8872
/* Set the isolation level of the transaction. */
8873
trx->isolation_level= innobase_map_isolation_level(session->getTxIsolation());
8877
InnobaseEngine::doEndStatement(
8880
trx_t *trx= check_trx_exists(session);
8882
/* Release a possible FIFO ticket and search latch. Since we
8883
may reserve the kernel mutex, we have to release the search
8884
system latch first to obey the latching order. */
8886
innobase_release_stat_resources(trx);
8890
/*******************************************************************//**
8891
This function is used to prepare an X/Open XA distributed transaction.
8892
@return 0 or error number */
8894
InnobaseEngine::doXaPrepare(
8895
/*================*/
8896
Session* session,/*!< in: handle to the MySQL thread of
8897
the user whose XA transaction should
8899
bool all) /*!< in: TRUE - commit transaction
8900
FALSE - the current SQL statement
8904
trx_t* trx = check_trx_exists(session);
8906
assert(this == innodb_engine_ptr);
8908
/* we use support_xa value as it was seen at transaction start
8909
time, not the current session variable value. Any possible changes
8910
to the session variable take effect only in the next transaction */
8911
if (!trx->support_xa) {
8916
session->get_xid(reinterpret_cast<DrizzleXid*>(&trx->xid));
8918
/* Release a possible FIFO ticket and search latch. Since we will
8919
reserve the kernel mutex, we have to release the search system latch
8920
first to obey the latching order. */
8922
innobase_release_stat_resources(trx);
8925
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
8927
/* We were instructed to prepare the whole transaction, or
8928
this is an SQL statement end and autocommit is on */
8930
ut_ad(trx->conc_state != TRX_NOT_STARTED);
8932
error = (int) trx_prepare_for_mysql(trx);
8934
/* We just mark the SQL statement ended and do not do a
8935
transaction prepare */
8937
/* If we had reserved the auto-inc lock for some
8938
table in this SQL statement we release it now */
8940
row_unlock_table_autoinc_for_mysql(trx);
8942
/* Store the current undo_no of the transaction so that we
8943
know where to roll back if we have to roll back the next
8946
trx_mark_sql_stat_end(trx);
8949
/* Tell the InnoDB server that there might be work for utility
8952
srv_active_wake_master_thread();
8957
uint64_t InnobaseEngine::doGetCurrentTransactionId(Session *session)
8959
trx_t *trx= session_to_trx(session);
8963
uint64_t InnobaseEngine::doGetNewTransactionId(Session *session)
8965
trx_t*& trx = session_to_trx(session);
8969
trx = innobase_trx_allocate(session);
8971
innobase_trx_init(session, trx);
8974
mutex_enter(&kernel_mutex);
8975
trx->id= trx_sys_get_new_trx_id();
8976
mutex_exit(&kernel_mutex);
8978
uint64_t transaction_id= trx->id;
8980
return transaction_id;
8983
/*******************************************************************//**
8984
This function is used to recover X/Open XA distributed transactions.
8985
@return number of prepared transactions stored in xid_list */
8987
InnobaseEngine::doXaRecover(
8988
/*================*/
8989
::drizzled::XID* xid_list,/*!< in/out: prepared transactions */
8990
size_t len) /*!< in: number of slots in xid_list */
8992
assert(this == innodb_engine_ptr);
8994
if (len == 0 || xid_list == NULL) {
8999
return(trx_recover_for_mysql((::XID *)xid_list, len));
9002
/*******************************************************************//**
9003
This function is used to commit one X/Open XA distributed transaction
9004
which is in the prepared state
9005
@return 0 or error number */
9007
InnobaseEngine::doXaCommitXid(
9008
/*===================*/
9009
::drizzled::XID* xid) /*!< in: X/Open XA transaction identification */
9013
assert(this == innodb_engine_ptr);
9015
trx = trx_get_trx_by_xid((::XID *)xid);
9018
innobase_commit_low(trx);
9026
/*******************************************************************//**
9027
This function is used to rollback one X/Open XA distributed transaction
9028
which is in the prepared state
9029
@return 0 or error number */
9031
InnobaseEngine::doXaRollbackXid(
9032
/*=====================*/
9033
::drizzled::XID* xid) /*!< in: X/Open XA transaction
9038
assert(this == innodb_engine_ptr);
9040
trx = trx_get_trx_by_xid((::XID *)xid);
9043
return(innobase_rollback_trx(trx));
9050
/************************************************************//**
9051
Validate the file format name and return its corresponding id.
9052
@return valid file format id */
9055
innobase_file_format_name_lookup(
9056
/*=============================*/
9057
const char* format_name) /*!< in: pointer to file format name */
9062
ut_a(format_name != NULL);
9064
/* The format name can contain the format id itself instead of
9065
the name and we check for that. */
9066
format_id = (uint) strtoul(format_name, &endp, 10);
9068
/* Check for valid parse. */
9069
if (*endp == '\0' && *format_name != '\0') {
9071
if (format_id <= DICT_TF_FORMAT_MAX) {
9077
for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
9081
name = trx_sys_file_format_id_to_name(format_id);
9083
if (!innobase_strcasecmp(format_name, name)) {
9090
return(DICT_TF_FORMAT_MAX + 1);
9093
/************************************************************//**
9094
Validate the file format check config parameters, as a side effect it
9095
sets the srv_max_file_format_at_startup variable.
9096
@return the format_id if valid config value, otherwise, return -1 */
9099
innobase_file_format_validate_and_set(
9100
/*================================*/
9101
const char* format_max) /*!< in: parameter value */
9105
format_id = innobase_file_format_name_lookup(format_max);
9107
if (format_id < DICT_TF_FORMAT_MAX + 1) {
9108
srv_max_file_format_at_startup = format_id;
9109
return((int) format_id);
9117
static void init_options(drizzled::module::option_context &context)
9119
context("disable-checksums",
9120
"Disable InnoDB checksums validation.");
9121
context("data-home-dir",
9122
po::value<string>(),
9123
"The common part for InnoDB table spaces.");
9124
context("disable-doublewrite",
9125
"Disable InnoDB doublewrite buffer.");
9126
context("io-capacity",
9127
po::value<io_capacity_constraint>(&innodb_io_capacity)->default_value(200),
9128
"Number of IOPs the server can do. Tunes the background IO rate");
9129
context("fast-shutdown",
9130
po::value<trinary_constraint>(&innobase_fast_shutdown)->default_value(1),
9131
"Speeds up the shutdown process of the InnoDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like).");
9132
context("purge-batch-size",
9133
po::value<purge_batch_constraint>(&innodb_purge_batch_size)->default_value(20),
9134
"Number of UNDO logs to purge in one batch from the history list. "
9136
context("purge-threads",
9137
po::value<purge_threads_constraint>(&innodb_n_purge_threads)->default_value(0),
9138
"Purge threads can be either 0 or 1. Defalut is 0.");
9139
context("file-per-table",
9140
po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
9141
"Stores each InnoDB table to an .ibd file in the database dir.");
9142
context("file-format-max",
9143
po::value<string>(&innobase_file_format_max)->default_value("Antelope"),
9144
"The highest file format in the tablespace.");
9145
context("file-format-check",
9146
po::value<bool>(&innobase_file_format_check)->default_value(true)->zero_tokens(),
9147
"Whether to perform system file format check.");
9148
context("file-format",
9149
po::value<string>(&innobase_file_format_name)->default_value("Antelope"),
9150
"File format to use for new tables in .ibd files.");
9151
context("flush-log-at-trx-commit",
9152
po::value<trinary_constraint>(&innodb_flush_log_at_trx_commit)->default_value(1),
9153
"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).");
9154
context("flush-method",
9155
po::value<string>(),
9156
"With which method to flush data.");
9157
context("log-group-home-dir",
9158
po::value<string>(),
9159
"Path to InnoDB log files.");
9160
context("max-dirty-pages-pct",
9161
po::value<max_dirty_pages_constraint>(&innodb_max_dirty_pages_pct)->default_value(75),
9162
"Percentage of dirty pages allowed in bufferpool.");
9163
context("disable-adaptive-flushing",
9164
"Do not attempt flushing dirty pages to avoid IO bursts at checkpoints.");
9165
context("max-purge-lag",
9166
po::value<uint64_constraint>(&innodb_max_purge_lag)->default_value(0),
9167
"Desired maximum length of the purge queue (0 = no limit)");
9168
context("status-file",
9169
po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
9170
"Enable SHOW INNODB STATUS output in the innodb_status.<pid> file");
9171
context("disable-stats-on-metadata",
9172
"Disable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)");
9173
context("stats-sample-pages",
9174
po::value<uint64_nonzero_constraint>(&innodb_stats_sample_pages)->default_value(8),
9175
"The number of index pages to sample when calculating statistics (default 8)");
9176
context("disable-adaptive-hash-index",
9177
"Enable InnoDB adaptive hash index (enabled by default)");
9178
context("replication-delay",
9179
po::value<uint64_constraint>(&innodb_replication_delay)->default_value(0),
9180
"Replication thread delay (ms) on the slave server if innodb_thread_concurrency is reached (0 by default)");
9181
context("additional-mem-pool-size",
9182
po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
9183
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.");
9184
context("autoextend-increment",
9185
po::value<autoextend_constraint>(&innodb_auto_extend_increment)->default_value(64L),
9186
"Data file autoextend increment in megabytes");
9187
context("buffer-pool-size",
9188
po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
9189
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.");
9190
context("buffer-pool-instances",
9191
po::value<buffer_pool_instances_constraint>(&innobase_buffer_pool_instances)->default_value(1),
9192
"Number of buffer pool instances, set to higher value on high-end machines to increase scalability");
9194
context("commit-concurrency",
9195
po::value<concurrency_constraint>(&innobase_commit_concurrency)->default_value(0),
9196
"Helps in performance tuning in heavily concurrent environments.");
9197
context("concurrency-tickets",
9198
po::value<uint32_nonzero_constraint>(&innodb_concurrency_tickets)->default_value(500L),
9199
"Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket");
9200
context("read-io-threads",
9201
po::value<io_threads_constraint>(&innobase_read_io_threads)->default_value(4),
9202
"Number of background read I/O threads in InnoDB.");
9203
context("write-io-threads",
9204
po::value<io_threads_constraint>(&innobase_write_io_threads)->default_value(4),
9205
"Number of background write I/O threads in InnoDB.");
9206
context("force-recovery",
9207
po::value<force_recovery_constraint>(&innobase_force_recovery)->default_value(0),
9208
"Helps to save your data in case the disk image of the database becomes corrupt.");
9209
context("log-buffer-size",
9210
po::value<log_buffer_constraint>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
9211
"The size of the buffer which InnoDB uses to write log to the log files on disk.");
9212
context("log-file-size",
9213
po::value<log_file_constraint>(&innobase_log_file_size)->default_value(20*1024*1024L),
9214
"The size of the buffer which InnoDB uses to write log to the log files on disk.");
9215
context("log-files-in-group",
9216
po::value<log_files_in_group_constraint>(&innobase_log_files_in_group)->default_value(2),
9217
"Number of log files in the log group. InnoDB writes to the files in a circular fashion.");
9218
context("mirrored-log-groups",
9219
po::value<mirrored_log_groups_constraint>(&innobase_mirrored_log_groups)->default_value(1),
9220
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.");
9221
context("open-files",
9222
po::value<open_files_constraint>(&innobase_open_files)->default_value(300L),
9223
"How many files at the maximum InnoDB keeps open at the same time.");
9224
context("sync-spin-loops",
9225
po::value<uint32_constraint>(&innodb_sync_spin_loops)->default_value(30L),
9226
"Count of spin-loop rounds in InnoDB mutexes (30 by default)");
9227
context("spin-wait-delay",
9228
po::value<uint32_constraint>(&innodb_spin_wait_delay)->default_value(6L),
9229
"Maximum delay between polling for a spin lock (6 by default)");
9230
context("thread-concurrency",
9231
po::value<concurrency_constraint>(&innobase_thread_concurrency)->default_value(0),
9232
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.");
9233
context("thread-sleep-delay",
9234
po::value<uint32_constraint>(&innodb_thread_sleep_delay)->default_value(10000L),
9235
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep");
9236
context("data-file-path",
9237
po::value<string>(),
9238
"Path to individual files and their sizes.");
9240
po::value<string>()->default_value(INNODB_VERSION_STR),
9242
context("use-internal-malloc",
9243
"Use InnoDB's internal memory allocator instal of the OS memory allocator.");
9244
context("disable-native-aio",
9245
_("Do not use Native AIO library for IO, even if available"));
9246
context("change-buffering",
9247
po::value<string>(&innobase_change_buffering),
9248
"Buffer changes to reduce random access: OFF, ON, inserting, deleting, changing, or purging.");
9249
context("read-ahead-threshold",
9250
po::value<read_ahead_threshold_constraint>(&innodb_read_ahead_threshold)->default_value(56),
9251
"Number of pages that must be accessed sequentially for InnoDB to trigger a readahead.");
9252
context("disable-xa",
9253
"Disable InnoDB support for the XA two-phase commit");
9254
context("disable-table-locks",
9255
"Disable InnoDB locking in LOCK TABLES");
9256
context("strict-mode",
9257
po::value<bool>(&strict_mode)->default_value(false)->zero_tokens(),
9258
"Use strict mode when evaluating create options.");
9259
context("replication-log",
9260
po::value<bool>(&innobase_use_replication_log)->default_value(false),
9261
_("Enable internal replication log."));
9262
context("lock-wait-timeout",
9263
po::value<lock_wait_constraint>(&lock_wait_timeout)->default_value(50),
9264
_("Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
9265
context("old-blocks-pct",
9266
po::value<old_blocks_constraint>(&innobase_old_blocks_pct)->default_value(100 * 3 / 8),
9267
_("Percentage of the buffer pool to reserve for 'old' blocks."));
9268
context("old-blocks-time",
9269
po::value<uint32_t>(&buf_LRU_old_threshold_ms)->default_value(0),
9270
_("ove blocks to the 'new' end of the buffer pool if the first access"
9271
" was at least this many milliseconds ago."
9272
" The timeout is disabled if 0 (the default)."));
9277
DRIZZLE_DECLARE_PLUGIN
9280
innobase_engine_name,
9283
"Supports transactions, row-level locking, and foreign keys",
9285
innobase_init, /* Plugin Init */
9287
init_options /* reserved */
9289
DRIZZLE_DECLARE_PLUGIN_END;
9291
int ha_innobase::read_range_first(const key_range *start_key,
9292
const key_range *end_key,
9297
//if (!eq_range_arg)
9298
//in_range_read= TRUE;
9299
res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
9301
// in_range_read= FALSE;
9306
int ha_innobase::read_range_next()
9308
int res= Cursor::read_range_next();
9310
// in_range_read= FALSE;
9314
/***********************************************************************
9315
This function checks each index name for a table against reserved
9316
system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
9317
this function pushes an warning message to the client, and returns true. */
9320
innobase_index_name_is_reserved(
9321
/*============================*/
9322
/* out: true if an index name
9323
matches the reserved name */
9324
const trx_t* trx, /* in: InnoDB transaction handle */
9325
const KeyInfo* key_info, /* in: Indexes to be created */
9326
ulint num_of_keys) /* in: Number of indexes to
9330
uint key_num; /* index number */
9332
for (key_num = 0; key_num < num_of_keys; key_num++) {
9333
key = &key_info[key_num];
9335
if (innobase_strcasecmp(key->name,
9336
innobase_index_reserve_name) == 0) {
9337
/* Push warning to drizzle */
9338
push_warning_printf(trx->mysql_thd,
9339
DRIZZLE_ERROR::WARN_LEVEL_WARN,
9340
ER_WRONG_NAME_FOR_INDEX,
9341
"Cannot Create Index with name "
9342
"'%s'. The name is reserved "
9343
"for the system default primary "
9345
innobase_index_reserve_name);
9347
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
9348
innobase_index_reserve_name);
9357
#ifdef UNIV_COMPILE_TEST_FUNCS
9359
typedef struct innobase_convert_name_test_struct {
9364
drizzled::Session *session;
9367
const char* expected;
9368
} innobase_convert_name_test_t;
9371
test_innobase_convert_name()
9376
innobase_convert_name_test_t test_input[] = {
9377
{buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
9378
{buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
9379
{buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
9380
{buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
9381
{buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
9383
{buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9384
{buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9385
{buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9386
{buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9387
{buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
9388
{buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
9389
{buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
9391
{buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
9392
"\"#mysql50#ab\"\"cd\""},
9393
{buf, 17, "ab\"cd", 5, NULL, TRUE,
9394
"\"#mysql50#ab\"\"cd\""},
9395
{buf, 16, "ab\"cd", 5, NULL, TRUE,
9396
"\"#mysql50#ab\"\"c\""},
9397
{buf, 15, "ab\"cd", 5, NULL, TRUE,
9398
"\"#mysql50#ab\"\"\""},
9399
{buf, 14, "ab\"cd", 5, NULL, TRUE,
9401
{buf, 13, "ab\"cd", 5, NULL, TRUE,
9403
{buf, 12, "ab\"cd", 5, NULL, TRUE,
9405
{buf, 11, "ab\"cd", 5, NULL, TRUE,
9407
{buf, 10, "ab\"cd", 5, NULL, TRUE,
9410
{buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9411
{buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9412
{buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
9413
{buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
9414
{buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9415
{buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9416
{buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
9417
{buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
9418
{buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
9419
/* XXX probably "" is a better result in this case
9420
{buf, 1, "ab/cd", 5, NULL, TRUE, "."},
9422
{buf, 0, "ab/cd", 5, NULL, TRUE, ""},
9425
for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
9431
fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
9432
test_input[i].buflen,
9434
test_input[i].idlen,
9435
test_input[i].expected);
9437
end = innobase_convert_name(
9439
test_input[i].buflen,
9441
test_input[i].idlen,
9442
test_input[i].session,
9443
test_input[i].file_id);
9445
res_len = (size_t) (end - test_input[i].buf);
9447
if (res_len != strlen(test_input[i].expected)) {
9449
fprintf(stderr, "unexpected len of the result: %u, "
9450
"expected: %u\n", (unsigned) res_len,
9451
(unsigned) strlen(test_input[i].expected));
9455
if (memcmp(test_input[i].buf,
9456
test_input[i].expected,
9457
strlen(test_input[i].expected)) != 0
9460
fprintf(stderr, "unexpected result: %.*s, "
9461
"expected: %s\n", (int) res_len,
9463
test_input[i].expected);
9468
fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9471
fprintf(stderr, "FAILED\n\n");
9477
#endif /* UNIV_COMPILE_TEST_FUNCS */