1
/*****************************************************************************
3
Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved.
4
Copyright (c) 2008, 2009 Google Inc.
6
Portions of this file contain modifications contributed and copyrighted by
7
Google, Inc. Those modifications are gratefully acknowledged and are described
8
briefly in the InnoDB documentation. The contributions by Google are
9
incorporated with their permission, and subject to the conditions contained in
10
the file COPYING.Google.
12
This program is free software; you can redistribute it and/or modify it under
13
the terms of the GNU General Public License as published by the Free Software
14
Foundation; version 2 of the License.
16
This program is distributed in the hope that it will be useful, but WITHOUT
17
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License along with
21
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22
Place, Suite 330, Boston, MA 02111-1307 USA
24
*****************************************************************************/
25
/***********************************************************************
27
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
28
Copyright (c) 2009, Percona Inc.
30
Portions of this file contain modifications contributed and copyrighted
31
by Percona Inc.. Those modifications are
32
gratefully acknowledged and are described briefly in the InnoDB
33
documentation. The contributions by Percona Inc. are incorporated with
34
their permission, and subject to the conditions contained in the file
37
This program is free software; you can redistribute it and/or modify it
38
under the terms of the GNU General Public License as published by the
39
Free Software Foundation; version 2 of the License.
41
This program is distributed in the hope that it will be useful, but
42
WITHOUT ANY WARRANTY; without even the implied warranty of
43
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
44
Public License for more details.
46
You should have received a copy of the GNU General Public License along
47
with this program; if not, write to the Free Software Foundation, Inc.,
48
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
50
***********************************************************************/
52
/* TODO list for the InnoDB Cursor in 5.0:
53
- fix savepoint functions to use savepoint storage area
54
- Find out what kind of problems the OS X case-insensitivity causes to
55
table and database names; should we 'normalize' the names like we do
64
#include "drizzled/error.h"
65
#include "drizzled/errmsg_print.h"
66
#include "drizzled/charset_info.h"
67
#include "drizzled/internal/m_string.h"
68
#include "drizzled/internal/my_sys.h"
69
#include "drizzled/my_hash.h"
70
#include "drizzled/plugin.h"
71
#include "drizzled/show.h"
72
#include "drizzled/data_home.h"
73
#include "drizzled/error.h"
74
#include "drizzled/field.h"
75
#include "drizzled/charset.h"
76
#include "drizzled/session.h"
77
#include "drizzled/current_session.h"
78
#include "drizzled/table.h"
79
#include "drizzled/field/blob.h"
80
#include "drizzled/field/varstring.h"
81
#include "drizzled/field/timestamp.h"
82
#include "drizzled/plugin/xa_storage_engine.h"
83
#include "drizzled/plugin/daemon.h"
84
#include "drizzled/memory/multi_malloc.h"
85
#include "drizzled/pthread_globals.h"
86
#include "drizzled/named_savepoint.h"
88
#include <drizzled/transaction_services.h>
90
/** @file ha_innodb.cc */
92
/* Include necessary InnoDB headers */
97
#include "os0thread.h"
98
#include "srv0start.h"
100
#include "trx0roll.h"
105
#include "row0mysql.h"
109
#include "lock0lock.h"
110
#include "dict0crea.h"
114
#include "sync0sync.h"
117
#include "row0merge.h"
119
#include "dict0boot.h"
120
#include "ha_prototypes.h"
122
#include "ibuf0ibuf.h"
125
#include "ha_innodb.h"
126
#include "data_dictionary.h"
127
#include "handler0vars.h"
133
#include "plugin/innobase/handler/status_function.h"
136
using namespace drizzled;
138
#ifndef DRIZZLE_SERVER
139
/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t
140
is defined the same in both builds: the MySQL server and the InnoDB plugin. */
141
extern pthread_mutex_t LOCK_thread_count;
143
#endif /* DRIZZLE_SERVER */
145
/** to protect innobase_open_files */
146
static pthread_mutex_t innobase_share_mutex;
147
/** to force correct commit order in binlog */
148
static pthread_mutex_t prepare_commit_mutex;
149
static ulong commit_threads = 0;
150
static pthread_mutex_t commit_threads_m;
151
static pthread_cond_t commit_cond;
152
static pthread_mutex_t commit_cond_m;
153
static bool innodb_inited = 0;
155
#define INSIDE_HA_INNOBASE_CC
157
/* In the Windows plugin, the return value of current_session is
158
undefined. Map it to NULL. */
159
#if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
160
# undef current_session
161
# define current_session NULL
162
# define EQ_CURRENT_SESSION(session) TRUE
163
#else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
164
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
165
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
167
static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
168
static plugin::TableFunction* status_table_function_ptr= NULL;
169
static plugin::TableFunction* cmp_tool= NULL;
170
static plugin::TableFunction* cmp_reset_tool= NULL;
171
static plugin::TableFunction* cmp_mem_tool= NULL;
172
static plugin::TableFunction* cmp_mem_reset_tool= NULL;
173
static plugin::TableFunction* innodb_trx_tool= NULL;
174
static plugin::TableFunction* innodb_locks_tool= NULL;
175
static plugin::TableFunction* innodb_lock_waits_tool= NULL;
177
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
178
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
179
static const long AUTOINC_NO_LOCKING = 2;
181
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
182
innobase_log_buffer_size,
183
innobase_additional_mem_pool_size, innobase_file_io_threads,
184
innobase_force_recovery, innobase_open_files,
185
innobase_autoinc_lock_mode;
186
static ulong innobase_commit_concurrency = 0;
187
static ulong innobase_read_io_threads;
188
static ulong innobase_write_io_threads;
191
* @TODO: Turn this into size_t as soon as we have a Variable<size_t>
193
static int64_t innobase_buffer_pool_size, innobase_log_file_size;
195
/* The default values for the following char* start-up parameters
196
are determined in innobase_init below: */
198
static char* innobase_data_home_dir = NULL;
199
static char* innobase_data_file_path = NULL;
200
static char* innobase_log_group_home_dir = NULL;
201
static char* innobase_file_format_name = NULL;
202
static char* innobase_change_buffering = NULL;
204
/* Note: This variable can be set to on/off and any of the supported
205
file formats in the configuration file, but can only be set to any
206
of the supported file formats during runtime. */
207
static char* innobase_file_format_check = NULL;
209
/* The following has a misleading name: starting from 4.0.5, this also
211
static char* innobase_unix_file_flush_method = NULL;
213
/* Below we have boolean-valued start-up parameters, and their default
216
static ulong innobase_fast_shutdown = 1;
217
#ifdef UNIV_LOG_ARCHIVE
218
static my_bool innobase_log_archive = FALSE;
219
static char* innobase_log_arch_dir = NULL;
220
#endif /* UNIV_LOG_ARCHIVE */
221
static my_bool innobase_use_doublewrite = TRUE;
222
static my_bool innobase_use_checksums = TRUE;
223
static my_bool innobase_rollback_on_timeout = FALSE;
224
static my_bool innobase_create_status_file = FALSE;
225
static my_bool innobase_stats_on_metadata = TRUE;
227
static char* internal_innobase_data_file_path = NULL;
229
static char* innodb_version_str = (char*) INNODB_VERSION_STR;
231
/* The following counter is used to convey information to InnoDB
232
about server activity: in selects it is not sensible to call
233
srv_active_wake_master_thread after each fetch or search, we only do
234
it every INNOBASE_WAKE_INTERVAL'th step. */
236
#define INNOBASE_WAKE_INTERVAL 32
237
static ulong innobase_active_counter = 0;
239
static hash_table_t* innobase_open_tables;
241
#ifdef __NETWARE__ /* some special cleanup for NetWare */
242
bool nw_panic = FALSE;
245
/** Allowed values of innodb_change_buffering */
246
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
247
"none", /* IBUF_USE_NONE */
248
"inserts" /* IBUF_USE_INSERT */
251
/********************************************************************
252
Gives the file extension of an InnoDB single-table tablespace. */
253
static const char* ha_innobase_exts[] = {
258
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
260
static INNOBASE_SHARE *get_share(const char *table_name);
261
static void free_share(INNOBASE_SHARE *share);
263
class InnobaseEngine : public plugin::XaStorageEngine
266
explicit InnobaseEngine(string name_arg) :
267
plugin::XaStorageEngine(name_arg,
269
HTON_CAN_INDEX_BLOBS |
270
HTON_PRIMARY_KEY_REQUIRED_FOR_POSITION |
271
HTON_PRIMARY_KEY_IN_READ_INDEX |
272
HTON_PARTIAL_COLUMN_READ |
273
HTON_TABLE_SCAN_ON_INDEX |
274
HTON_HAS_FOREIGN_KEYS |
275
HTON_HAS_DOES_TRANSACTIONS)
277
table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
278
addAlias("INNOBASE");
281
virtual ~InnobaseEngine()
286
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
288
hash_table_free(innobase_open_tables);
289
innobase_open_tables = NULL;
290
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
293
srv_free_paths_and_sizes();
294
if (internal_innobase_data_file_path)
295
free(internal_innobase_data_file_path);
296
pthread_mutex_destroy(&innobase_share_mutex);
297
pthread_mutex_destroy(&prepare_commit_mutex);
298
pthread_mutex_destroy(&commit_threads_m);
299
pthread_mutex_destroy(&commit_cond_m);
300
pthread_cond_destroy(&commit_cond);
305
virtual int doStartTransaction(Session *session, start_transaction_option_t options);
306
virtual void doStartStatement(Session *session);
307
virtual void doEndStatement(Session *session);
312
/*======================*/
313
/* out: 0 or error number */
314
Session* session); /* in: handle to the MySQL thread of the user
315
whose resources should be free'd */
317
virtual int doSetSavepoint(Session* session,
318
drizzled::NamedSavepoint &savepoint);
319
virtual int doRollbackToSavepoint(Session* session,
320
drizzled::NamedSavepoint &savepoint);
321
virtual int doReleaseSavepoint(Session* session,
322
drizzled::NamedSavepoint &savepoint);
323
virtual int doXaCommit(Session* session, bool all)
325
return doCommit(session, all); /* XA commit just does a SQL COMMIT */
327
virtual int doXaRollback(Session *session, bool all)
329
return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
331
virtual int doCommit(Session* session, bool all);
332
virtual int doRollback(Session* session, bool all);
334
/***********************************************************************
335
This function is used to prepare X/Open XA distributed transaction */
340
/* out: 0 or error number */
341
Session* session, /* in: handle to the MySQL thread of the user
342
whose XA transaction should be prepared */
343
bool all); /* in: TRUE - commit transaction
344
FALSE - the current SQL statement ended */
345
/***********************************************************************
346
This function is used to recover X/Open XA distributed transactions */
351
/* out: number of prepared transactions
352
stored in xid_list */
353
::drizzled::XID* xid_list, /* in/out: prepared transactions */
354
size_t len); /* in: number of slots in xid_list */
355
/***********************************************************************
356
This function is used to commit one X/Open XA distributed transaction
357
which is in the prepared state */
361
/*===================*/
362
/* out: 0 or error number */
363
::drizzled::XID* xid); /* in: X/Open XA transaction identification */
364
/***********************************************************************
365
This function is used to rollback one X/Open XA distributed transaction
366
which is in the prepared state */
370
/*=====================*/
371
/* out: 0 or error number */
372
::drizzled::XID *xid); /* in: X/Open XA transaction identification */
374
virtual Cursor *create(TableShare &table,
375
memory::Root *mem_root)
377
return new (mem_root) ha_innobase(*this, table);
380
/*********************************************************************
381
Removes all tables in the named database inside InnoDB. */
384
/*===================*/
385
/* out: error number */
386
SchemaIdentifier &identifier); /* in: database path; inside InnoDB the name
387
of the last directory in the path is used as
388
the database name: for example, in 'mysql/data/test'
389
the database name is 'test' */
391
/********************************************************************
392
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
393
the logs, and the name of this function should be innobase_checkpoint. */
398
/* out: TRUE if error */
400
/****************************************************************************
401
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
402
Monitor to the client. */
407
Session* session, /* in: the MySQL query thread of the caller */
408
stat_print_fn *stat_print,
409
enum ha_stat_type stat_type);
413
doReleaseTemporaryLatches(
414
/*===============================*/
416
Session* session); /* in: MySQL thread */
419
const char** bas_ext() const {
420
return(ha_innobase_exts);
423
UNIV_INTERN int doCreateTable(Session &session,
425
drizzled::TableIdentifier &identifier,
427
UNIV_INTERN int doRenameTable(Session&, TableIdentifier &from, TableIdentifier &to);
428
UNIV_INTERN int doDropTable(Session &session, TableIdentifier &identifier);
430
UNIV_INTERN virtual bool get_error_message(int error, String *buf);
432
UNIV_INTERN uint32_t max_supported_keys() const;
433
UNIV_INTERN uint32_t max_supported_key_length() const;
434
UNIV_INTERN uint32_t max_supported_key_part_length() const;
437
UNIV_INTERN uint32_t index_flags(enum ha_key_alg) const
439
return (HA_READ_NEXT |
446
int doGetTableDefinition(drizzled::Session& session,
447
drizzled::TableIdentifier &identifier,
448
drizzled::message::Table &table_proto);
450
void doGetTableNames(drizzled::CachedDirectory &directory,
451
drizzled::SchemaIdentifier &schema_identifier,
452
std::set<std::string> &set_of_names);
454
bool doDoesTableExist(drizzled::Session& session, drizzled::TableIdentifier &identifier);
456
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
457
drizzled::SchemaIdentifier &schema_identifier,
458
drizzled::TableIdentifiers &set_of_identifiers);
461
void InnobaseEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
462
drizzled::SchemaIdentifier &schema_identifier,
463
drizzled::TableIdentifiers &set_of_identifiers)
465
CachedDirectory::Entries entries= directory.getEntries();
467
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
468
entry_iter != entries.end(); ++entry_iter)
470
CachedDirectory::Entry *entry= *entry_iter;
471
const string *filename= &entry->filename;
473
assert(filename->size());
475
const char *ext= strchr(filename->c_str(), '.');
477
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
478
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
482
char uname[NAME_LEN + 1];
483
uint32_t file_name_len;
485
file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
486
// TODO: Remove need for memory copy here
487
uname[file_name_len - sizeof(DEFAULT_FILE_EXTENSION) + 1]= '\0'; // Subtract ending, place NULL
489
set_of_identifiers.push_back(TableIdentifier(schema_identifier, uname));
494
bool InnobaseEngine::doDoesTableExist(Session&, TableIdentifier &identifier)
496
string proto_path(identifier.getPath());
497
proto_path.append(DEFAULT_FILE_EXTENSION);
499
if (access(proto_path.c_str(), F_OK))
507
int InnobaseEngine::doGetTableDefinition(Session &,
508
drizzled::TableIdentifier &identifier,
509
message::Table &table_proto)
511
string proto_path(identifier.getPath());
512
proto_path.append(DEFAULT_FILE_EXTENSION);
514
if (access(proto_path.c_str(), F_OK))
519
if (StorageEngine::readTableFile(proto_path, table_proto))
525
void InnobaseEngine::doGetTableNames(CachedDirectory &directory, SchemaIdentifier&, set<string>& set_of_names)
527
CachedDirectory::Entries entries= directory.getEntries();
529
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
530
entry_iter != entries.end(); ++entry_iter)
532
CachedDirectory::Entry *entry= *entry_iter;
533
const string *filename= &entry->filename;
535
assert(filename->size());
537
const char *ext= strchr(filename->c_str(), '.');
539
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
540
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
544
char uname[NAME_LEN + 1];
545
uint32_t file_name_len;
547
file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
548
// TODO: Remove need for memory copy here
549
uname[file_name_len - sizeof(DEFAULT_FILE_EXTENSION) + 1]= '\0'; // Subtract ending, place NULL
550
set_of_names.insert(uname);
555
/** @brief Initialize the default value of innodb_commit_concurrency.
557
Once InnoDB is running, the innodb_commit_concurrency must not change
558
from zero to nonzero. (Bug #42101)
560
The initial default value is 0, and without this extra initialization,
561
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
562
to 0, even if it was initially set to nonzero at the command line
563
or configuration file. */
566
innobase_commit_concurrency_init_default(void);
567
/*==========================================*/
569
/************************************************************//**
570
Validate the file format name and return its corresponding id.
571
@return valid file format id */
574
innobase_file_format_name_lookup(
575
/*=============================*/
576
const char* format_name); /*!< in: pointer to file format
578
/************************************************************//**
579
Validate the file format check config parameters, as a side effect it
580
sets the srv_check_file_format_at_startup variable.
581
@return true if one of "on" or "off" */
584
innobase_file_format_check_on_off(
585
/*==============================*/
586
const char* format_check); /*!< in: parameter value */
587
/************************************************************//**
588
Validate the file format check config parameters, as a side effect it
589
sets the srv_check_file_format_at_startup variable.
590
@return true if valid config value */
593
innobase_file_format_check_validate(
594
/*================================*/
595
const char* format_check); /*!< in: parameter value */
597
static const char innobase_engine_name[]= "InnoDB";
599
/*************************************************************//**
600
Check for a valid value of innobase_commit_concurrency.
601
@return 0 for valid innodb_commit_concurrency */
604
innobase_commit_concurrency_validate(
605
/*=================================*/
606
Session* , /*!< in: thread handle */
607
drizzle_sys_var* , /*!< in: pointer to system
609
void* save, /*!< out: immediate result
610
for update function */
611
drizzle_value* value) /*!< in: incoming string */
614
ulong commit_concurrency;
616
if (value->val_int(value, &intbuf)) {
617
/* The value is NULL. That is invalid. */
621
*reinterpret_cast<ulong*>(save) = commit_concurrency
622
= static_cast<ulong>(intbuf);
624
/* Allow the value to be updated, as long as it remains zero
626
return(!(!commit_concurrency == !innobase_commit_concurrency));
629
static DRIZZLE_SessionVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
630
"Enable InnoDB support for the XA two-phase commit",
631
/* check_func */ NULL, /* update_func */ NULL,
634
static DRIZZLE_SessionVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
635
"Enable InnoDB locking in LOCK TABLES",
636
/* check_func */ NULL, /* update_func */ NULL,
639
static DRIZZLE_SessionVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
640
"Use strict mode when evaluating create options.",
643
static DRIZZLE_SessionVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
644
"Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
645
NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
648
/*****************************************************************//**
649
Commits a transaction in an InnoDB database. */
654
trx_t* trx); /*!< in: transaction handle */
656
static drizzle_show_var innodb_status_variables[]= {
657
{"buffer_pool_pages_data",
658
(char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
659
{"buffer_pool_pages_dirty",
660
(char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
661
{"buffer_pool_pages_flushed",
662
(char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
663
{"buffer_pool_pages_free",
664
(char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
666
{"buffer_pool_pages_latched",
667
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
668
#endif /* UNIV_DEBUG */
669
{"buffer_pool_pages_misc",
670
(char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
671
{"buffer_pool_pages_total",
672
(char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
673
{"buffer_pool_read_ahead_rnd",
674
(char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
675
{"buffer_pool_read_ahead_seq",
676
(char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG},
677
{"buffer_pool_read_requests",
678
(char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
679
{"buffer_pool_reads",
680
(char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
681
{"buffer_pool_wait_free",
682
(char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
683
{"buffer_pool_write_requests",
684
(char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
686
(char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
687
{"data_pending_fsyncs",
688
(char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
689
{"data_pending_reads",
690
(char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
691
{"data_pending_writes",
692
(char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
694
(char*) &export_vars.innodb_data_read, SHOW_LONG},
696
(char*) &export_vars.innodb_data_reads, SHOW_LONG},
698
(char*) &export_vars.innodb_data_writes, SHOW_LONG},
700
(char*) &export_vars.innodb_data_written, SHOW_LONG},
701
{"dblwr_pages_written",
702
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
704
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
705
{"have_atomic_builtins",
706
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
708
(char*) &export_vars.innodb_log_waits, SHOW_LONG},
709
{"log_write_requests",
710
(char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
712
(char*) &export_vars.innodb_log_writes, SHOW_LONG},
714
(char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
715
{"os_log_pending_fsyncs",
716
(char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
717
{"os_log_pending_writes",
718
(char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
720
(char*) &export_vars.innodb_os_log_written, SHOW_LONG},
722
(char*) &export_vars.innodb_page_size, SHOW_LONG},
724
(char*) &export_vars.innodb_pages_created, SHOW_LONG},
726
(char*) &export_vars.innodb_pages_read, SHOW_LONG},
728
(char*) &export_vars.innodb_pages_written, SHOW_LONG},
729
{"row_lock_current_waits",
730
(char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
732
(char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
733
{"row_lock_time_avg",
734
(char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
735
{"row_lock_time_max",
736
(char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
738
(char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
740
(char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
742
(char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
744
(char*) &export_vars.innodb_rows_read, SHOW_LONG},
746
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
747
{NULL, NULL, SHOW_LONG}
750
InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
751
plugin::TableFunction::Generator(fields)
753
srv_export_innodb_status();
754
status_var_ptr= innodb_status_variables;
757
bool InnodbStatusTool::Generator::populate()
759
if (status_var_ptr->name)
761
std::ostringstream oss;
763
const char *value= status_var_ptr->value;
766
push(status_var_ptr->name);
768
switch (status_var_ptr->type)
771
oss << *(int64_t*) value;
772
return_value= oss.str();
775
oss << *(int64_t*) value;
776
return_value= oss.str();
779
return_value= *(bool*) value ? "ON" : "OFF";
786
if (return_value.length())
798
/* General functions */
800
/******************************************************************//**
801
Returns true if the thread is the replication thread on the slave
802
server. Used in srv_conc_enter_innodb() to determine if the thread
803
should be allowed to enter InnoDB - the replication thread is treated
804
differently than other threads. Also used in
805
srv_conc_force_exit_innodb().
807
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
809
@return true if session is the replication thread */
810
extern "C" UNIV_INTERN
812
thd_is_replication_slave_thread(
813
/*============================*/
814
void* ) /*!< in: thread handle (Session*) */
819
/******************************************************************//**
820
Save some CPU by testing the value of srv_thread_concurrency in inline
824
innodb_srv_conc_enter_innodb(
825
/*=========================*/
826
trx_t* trx) /*!< in: transaction handle */
828
if (UNIV_LIKELY(!srv_thread_concurrency)) {
833
srv_conc_enter_innodb(trx);
836
/******************************************************************//**
837
Save some CPU by testing the value of srv_thread_concurrency in inline
841
innodb_srv_conc_exit_innodb(
842
/*========================*/
843
trx_t* trx) /*!< in: transaction handle */
845
if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
850
srv_conc_exit_innodb(trx);
853
/******************************************************************//**
854
Releases possible search latch and InnoDB thread FIFO ticket. These should
855
be released at each SQL statement end, and also when mysqld passes the
856
control to the client. It does no harm to release these also in the middle
857
of an SQL statement. */
860
innobase_release_stat_resources(
861
/*============================*/
862
trx_t* trx) /*!< in: transaction object */
864
if (trx->has_search_latch) {
865
trx_search_latch_release_if_reserved(trx);
868
if (trx->declared_to_be_inside_innodb) {
869
/* Release our possible ticket in the FIFO */
871
srv_conc_force_exit_innodb(trx);
875
/******************************************************************//**
876
Returns true if the transaction this thread is processing has edited
877
non-transactional tables. Used by the deadlock detector when deciding
878
which transaction to rollback in case of a deadlock - we try to avoid
879
rolling back transactions that have edited non-transactional tables.
881
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
883
@return true if non-transactional tables have been edited */
884
extern "C" UNIV_INTERN
886
thd_has_edited_nontrans_tables(
887
/*===========================*/
888
void* session) /*!< in: thread handle (Session*) */
890
return((ibool) session_non_transactional_update((Session*) session));
893
/******************************************************************//**
894
Returns true if the thread is executing a SELECT statement.
895
@return true if session is executing SELECT */
896
extern "C" UNIV_INTERN
900
const void* session) /*!< in: thread handle (Session*) */
902
return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
905
/******************************************************************//**
906
Returns true if the thread supports XA,
907
global value of innodb_supports_xa if session is NULL.
908
@return true if session has XA support */
909
extern "C" UNIV_INTERN
913
void* session) /*!< in: thread handle (Session*), or NULL to query
914
the global innodb_supports_xa */
916
return(SessionVAR((Session*) session, support_xa));
919
/******************************************************************//**
920
Returns the lock wait timeout for the current connection.
921
@return the lock wait timeout, in seconds */
922
extern "C" UNIV_INTERN
924
thd_lock_wait_timeout(
925
/*==================*/
926
void* session) /*!< in: thread handle (Session*), or NULL to query
927
the global innodb_lock_wait_timeout */
929
/* According to <drizzle/plugin.h>, passing session == NULL
930
returns the global value of the session variable. */
931
return(SessionVAR((Session*) session, lock_wait_timeout));
934
/********************************************************************//**
935
Obtain the InnoDB transaction of a MySQL thread.
936
@return reference to transaction pointer */
941
Session* session) /*!< in: Drizzle Session */
943
return *(trx_t**) session->getEngineData(innodb_engine_ptr);
946
/********************************************************************//**
947
Call this function when mysqld passes control to the client. That is to
948
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
949
documentation, see Cursor.cc.
952
InnobaseEngine::doReleaseTemporaryLatches(
953
/*===============================*/
954
Session* session) /*!< in: MySQL thread */
958
assert(this == innodb_engine_ptr);
960
if (!innodb_inited) {
965
trx = session_to_trx(session);
968
innobase_release_stat_resources(trx);
973
/********************************************************************//**
974
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
975
time calls srv_active_wake_master_thread. This function should be used
976
when a single database operation may introduce a small need for
977
server utility activity, like checkpointing. */
980
innobase_active_small(void)
981
/*=======================*/
983
innobase_active_counter++;
985
if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
986
srv_active_wake_master_thread();
990
/********************************************************************//**
991
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
992
about a possible transaction rollback inside InnoDB caused by a lock wait
993
timeout or a deadlock.
994
@return MySQL error code */
995
extern "C" UNIV_INTERN
997
convert_error_code_to_mysql(
998
/*========================*/
999
int error, /*!< in: InnoDB error code */
1000
ulint flags, /*!< in: InnoDB table flags, or 0 */
1001
Session* session)/*!< in: user thread handle or NULL */
1009
return(-1); /* unspecified error */
1011
case DB_DUPLICATE_KEY:
1012
return(HA_ERR_FOUND_DUPP_KEY);
1014
case DB_FOREIGN_DUPLICATE_KEY:
1015
return(HA_ERR_FOREIGN_DUPLICATE_KEY);
1017
case DB_MISSING_HISTORY:
1018
return(HA_ERR_TABLE_DEF_CHANGED);
1020
case DB_RECORD_NOT_FOUND:
1021
return(HA_ERR_NO_ACTIVE_RECORD);
1024
/* Since we rolled back the whole transaction, we must
1025
tell it also to MySQL so that MySQL knows to empty the
1026
cached binlog for this transaction */
1028
session_mark_transaction_to_rollback(session, TRUE);
1030
return(HA_ERR_LOCK_DEADLOCK);
1032
case DB_LOCK_WAIT_TIMEOUT:
1033
/* Starting from 5.0.13, we let MySQL just roll back the
1034
latest SQL statement in a lock wait timeout. Previously, we
1035
rolled back the whole transaction. */
1037
session_mark_transaction_to_rollback(session,
1038
(bool)row_rollback_on_timeout);
1040
return(HA_ERR_LOCK_WAIT_TIMEOUT);
1042
case DB_NO_REFERENCED_ROW:
1043
return(HA_ERR_NO_REFERENCED_ROW);
1045
case DB_ROW_IS_REFERENCED:
1046
return(HA_ERR_ROW_IS_REFERENCED);
1048
case DB_CANNOT_ADD_CONSTRAINT:
1049
return(HA_ERR_CANNOT_ADD_FOREIGN);
1051
case DB_CANNOT_DROP_CONSTRAINT:
1053
return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
1054
misleading, a new MySQL error
1055
code should be introduced */
1057
case DB_COL_APPEARS_TWICE_IN_INDEX:
1059
return(HA_ERR_CRASHED);
1061
case DB_OUT_OF_FILE_SPACE:
1062
return(HA_ERR_RECORD_FILE_FULL);
1064
case DB_TABLE_IS_BEING_USED:
1065
return(HA_ERR_WRONG_COMMAND);
1067
case DB_TABLE_NOT_FOUND:
1068
return(HA_ERR_NO_SUCH_TABLE);
1070
case DB_TOO_BIG_RECORD:
1071
my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
1072
page_get_free_space_of_empty(flags
1073
& DICT_TF_COMPACT) / 2);
1074
return(HA_ERR_TO_BIG_ROW);
1076
case DB_NO_SAVEPOINT:
1077
return(HA_ERR_NO_SAVEPOINT);
1079
case DB_LOCK_TABLE_FULL:
1080
/* Since we rolled back the whole transaction, we must
1081
tell it also to MySQL so that MySQL knows to empty the
1082
cached binlog for this transaction */
1084
session_mark_transaction_to_rollback(session, TRUE);
1086
return(HA_ERR_LOCK_TABLE_FULL);
1088
case DB_PRIMARY_KEY_IS_NULL:
1089
return(ER_PRIMARY_CANT_HAVE_NULL);
1091
case DB_TOO_MANY_CONCURRENT_TRXS:
1093
/* Once MySQL add the appropriate code to errmsg.txt then
1094
we can get rid of this #ifdef. NOTE: The code checked by
1095
the #ifdef is the suggested name for the error condition
1096
and the actual error code name could very well be different.
1097
This will require some monitoring, ie. the status
1098
of this request on our part.*/
1099
#ifdef ER_TOO_MANY_CONCURRENT_TRXS
1100
return(ER_TOO_MANY_CONCURRENT_TRXS);
1102
return(HA_ERR_RECORD_FILE_FULL);
1104
case DB_UNSUPPORTED:
1105
return(HA_ERR_UNSUPPORTED);
1109
/*************************************************************//**
1110
If you want to print a session that is not associated with the current thread,
1111
you must call this function before reserving the InnoDB kernel_mutex, to
1112
protect Drizzle from setting session->query NULL. If you print a session of the
1113
current thread, we know that Drizzle cannot modify sesion->query, and it is
1114
not necessary to call this. Call innobase_mysql_end_print_arbitrary_thd()
1115
after you release the kernel_mutex.
1117
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
1120
extern "C" UNIV_INTERN
1122
innobase_mysql_prepare_print_arbitrary_thd(void)
1123
/*============================================*/
1125
ut_ad(!mutex_own(&kernel_mutex));
1126
pthread_mutex_lock(&LOCK_thread_count);
1129
/*************************************************************//**
1130
Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd().
1131
In the InnoDB latching order, the mutex sits right above the
1132
kernel_mutex. In debug builds, we assert that the kernel_mutex is
1133
released before this function is invoked.
1135
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
1138
extern "C" UNIV_INTERN
1140
innobase_mysql_end_print_arbitrary_thd(void)
1141
/*========================================*/
1143
ut_ad(!mutex_own(&kernel_mutex));
1144
pthread_mutex_unlock(&LOCK_thread_count);
1147
/*************************************************************//**
1148
Prints info of a Session object (== user session thread) to the given file. */
1149
extern "C" UNIV_INTERN
1151
innobase_mysql_print_thd(
1152
/*=====================*/
1153
FILE* f, /*!< in: output stream */
1154
void * in_session, /*!< in: pointer to a Drizzle Session object */
1155
uint ) /*!< in: max query length to print, or 0 to
1156
use the default max length */
1158
Session *session= reinterpret_cast<Session *>(in_session);
1160
"Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
1161
static_cast<uint64_t>(session_get_thread_id( session)),
1162
static_cast<uint64_t>(session->getQueryId()),
1164
session->getSecurityContext().getIp().c_str(),
1165
session->getSecurityContext().getUser().c_str()
1168
"\n%s", session->getQueryString().c_str()
1173
/******************************************************************//**
1174
Get the variable length bounds of the given character set. */
1175
extern "C" UNIV_INTERN
1177
innobase_get_cset_width(
1178
/*====================*/
1179
ulint cset, /*!< in: MySQL charset-collation code */
1180
ulint* mbminlen, /*!< out: minimum length of a char (in bytes) */
1181
ulint* mbmaxlen) /*!< out: maximum length of a char (in bytes) */
1188
cs = all_charsets[cset];
1190
*mbminlen = cs->mbminlen;
1191
*mbmaxlen = cs->mbmaxlen;
1194
*mbminlen = *mbmaxlen = 0;
1198
/******************************************************************//**
1199
Converts an identifier to a table name. */
1200
extern "C" UNIV_INTERN
1202
innobase_convert_from_table_id(
1203
/*===========================*/
1204
const void*, /*!< in: the 'from' character set */
1205
char* to, /*!< out: converted identifier */
1206
const char* from, /*!< in: identifier to convert */
1207
ulint len) /*!< in: length of 'to', in bytes */
1209
strncpy(to, from, len);
1212
/******************************************************************//**
1213
Converts an identifier to UTF-8. */
1214
extern "C" UNIV_INTERN
1216
innobase_convert_from_id(
1217
/*=====================*/
1218
const void*, /*!< in: the 'from' character set */
1219
char* to, /*!< out: converted identifier */
1220
const char* from, /*!< in: identifier to convert */
1221
ulint len) /*!< in: length of 'to', in bytes */
1223
strncpy(to, from, len);
1226
/******************************************************************//**
1227
Compares NUL-terminated UTF-8 strings case insensitively.
1228
@return 0 if a=b, <0 if a<b, >1 if a>b */
1229
extern "C" UNIV_INTERN
1231
innobase_strcasecmp(
1232
/*================*/
1233
const char* a, /*!< in: first string to compare */
1234
const char* b) /*!< in: second string to compare */
1236
return(my_strcasecmp(system_charset_info, a, b));
1239
/******************************************************************//**
1240
Makes all characters in a NUL-terminated UTF-8 string lower case. */
1241
extern "C" UNIV_INTERN
1243
innobase_casedn_str(
1244
/*================*/
1245
char* a) /*!< in/out: string to put in lower case */
1247
my_casedn_str(system_charset_info, a);
1250
/**********************************************************************//**
1251
Determines the connection character set.
1252
@return connection character set */
1253
extern "C" UNIV_INTERN
1255
innobase_get_charset(
1256
/*=================*/
1257
void* mysql_session) /*!< in: MySQL thread handle */
1259
return session_charset(static_cast<Session*>(mysql_session));
1262
extern "C" UNIV_INTERN
1268
return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
1273
innobase_fast_mutex_init(
1274
os_fast_mutex_t* fast_mutex)
1276
return pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
1279
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1280
/*******************************************************************//**
1281
Map an OS error to an errno value. The OS error number is stored in
1282
_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 */
1291
extern "C" UNIV_INTERN
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 */
1371
extern "C" UNIV_INTERN
1373
innobase_mysql_tmpfile(void)
1374
/*========================*/
1377
int fd = mysql_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 */
1410
extern "C" UNIV_INTERN
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
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
1441
to reserve 3 values for the multi-value INSERT above.
1442
@return the next value */
1445
innobase_next_autoinc(
1446
/*==================*/
1447
uint64_t current, /*!< in: Current value */
1448
uint64_t increment, /*!< in: increment current by */
1449
uint64_t offset, /*!< in: AUTOINC offset */
1450
uint64_t max_value) /*!< in: max value for type */
1452
uint64_t next_value;
1454
/* Should never be 0. */
1455
ut_a(increment > 0);
1457
/* According to MySQL documentation, if the offset is greater than
1458
the increment then the offset is ignored. */
1459
if (offset > increment) {
1463
if (max_value <= current) {
1464
next_value = max_value;
1465
} else if (offset <= 1) {
1466
/* Offset 0 and 1 are the same, because there must be at
1467
least one node in the system. */
1468
if (max_value - current <= increment) {
1469
next_value = max_value;
1471
next_value = current + increment;
1473
} else if (max_value > current) {
1474
if (current > offset) {
1475
next_value = ((current - offset) / increment) + 1;
1477
next_value = ((offset - current) / increment) + 1;
1480
ut_a(increment > 0);
1481
ut_a(next_value > 0);
1483
/* Check for multiplication overflow. */
1484
if (increment > (max_value / next_value)) {
1486
next_value = max_value;
1488
next_value *= increment;
1490
ut_a(max_value >= next_value);
1492
/* Check for overflow. */
1493
if (max_value - next_value <= offset) {
1494
next_value = max_value;
1496
next_value += offset;
1500
next_value = max_value;
1503
ut_a(next_value <= max_value);
1508
/*********************************************************************//**
1509
Initializes some fields in an InnoDB transaction object. */
1514
Session* session, /*!< in: user thread handle */
1515
trx_t* trx) /*!< in/out: InnoDB transaction handle */
1517
assert(session == trx->mysql_thd);
1519
trx->check_foreigns = !session_test_options(
1520
session, OPTION_NO_FOREIGN_KEY_CHECKS);
1522
trx->check_unique_secondary = !session_test_options(
1523
session, OPTION_RELAXED_UNIQUE_CHECKS);
1528
/*********************************************************************//**
1529
Allocates an InnoDB transaction for a MySQL Cursor object.
1530
@return InnoDB transaction handle */
1531
extern "C" UNIV_INTERN
1533
innobase_trx_allocate(
1534
/*==================*/
1535
Session* session) /*!< in: user thread handle */
1539
assert(session != NULL);
1540
assert(EQ_CURRENT_SESSION(session));
1542
trx = trx_allocate_for_mysql();
1544
trx->mysql_thd = session;
1545
trx->mysql_query_str = session->query.c_str();
1547
innobase_trx_init(session, trx);
1552
/*********************************************************************//**
1553
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1554
an InnoDB transaction struct if the corresponding MySQL thread struct still
1556
@return InnoDB transaction handle */
1561
Session* session) /*!< in: user thread handle */
1563
trx_t*& trx = session_to_trx(session);
1565
ut_ad(EQ_CURRENT_SESSION(session));
1568
trx = innobase_trx_allocate(session);
1569
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1570
mem_analyze_corruption(trx);
1574
innobase_trx_init(session, trx);
1580
/*********************************************************************//**
1581
Construct ha_innobase Cursor. */
1583
ha_innobase::ha_innobase(plugin::StorageEngine &engine_arg,
1584
TableShare &table_arg)
1585
:Cursor(engine_arg, table_arg),
1586
primary_key(0), /* needs initialization because index_flags() may be called
1587
before this is set to the real value. It's ok to have any
1588
value here because it doesn't matter if we return the
1589
HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
1594
/*********************************************************************//**
1595
Destruct ha_innobase Cursor. */
1597
ha_innobase::~ha_innobase()
1601
/*********************************************************************//**
1602
Updates the user_thd field in a handle and also allocates a new InnoDB
1603
transaction handle if needed, and updates the transaction fields in the
1607
ha_innobase::update_session(
1608
/*====================*/
1609
Session* session) /*!< in: thd to use the handle */
1613
trx = check_trx_exists(session);
1615
if (prebuilt->trx != trx) {
1617
row_update_prebuilt_trx(prebuilt, trx);
1620
user_session = session;
1623
/*********************************************************************//**
1624
Updates the user_thd field in a handle and also allocates a new InnoDB
1625
transaction handle if needed, and updates the transaction fields in the
1629
ha_innobase::update_session()
1630
/*=====================*/
1632
Session* session = ha_session();
1633
ut_ad(EQ_CURRENT_SESSION(session));
1634
update_session(session);
1637
/*****************************************************************//**
1638
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1639
and quote it if needed.
1640
@return pointer to the end of buf */
1643
innobase_convert_identifier(
1644
/*========================*/
1645
char* buf, /*!< out: buffer for converted identifier */
1646
ulint buflen, /*!< in: length of buf, in bytes */
1647
const char* id, /*!< in: identifier to convert */
1648
ulint idlen, /*!< in: length of id, in bytes */
1649
void* session,/*!< in: MySQL connection thread, or NULL */
1650
ibool file_id)/*!< in: TRUE=id is a table or database name;
1651
FALSE=id is an UTF-8 string */
1653
char nz[NAME_LEN + 1];
1654
char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
1660
/* Decode the table name. The filename_to_tablename()
1661
function expects a NUL-terminated string. The input and
1662
output strings buffers must not be shared. */
1664
if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1665
idlen = (sizeof nz) - 1;
1668
memcpy(nz, id, idlen);
1672
idlen = filename_to_tablename(nz, nz2, sizeof nz2);
1675
/* See if the identifier needs to be quoted. */
1676
if (UNIV_UNLIKELY(!session)) {
1679
q = get_quote_char_for_identifier();
1683
if (UNIV_UNLIKELY(idlen > buflen)) {
1686
memcpy(buf, s, idlen);
1687
return(buf + idlen);
1690
/* Quote the identifier. */
1698
for (; idlen; idlen--) {
1700
if (UNIV_UNLIKELY(c == q)) {
1701
if (UNIV_UNLIKELY(buflen < 3)) {
1709
if (UNIV_UNLIKELY(buflen < 2)) {
1722
/*****************************************************************//**
1723
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1724
and quote it if needed.
1725
@return pointer to the end of buf */
1726
extern "C" UNIV_INTERN
1728
innobase_convert_name(
1729
/*==================*/
1730
char* buf, /*!< out: buffer for converted identifier */
1731
ulint buflen, /*!< in: length of buf, in bytes */
1732
const char* id, /*!< in: identifier to convert */
1733
ulint idlen, /*!< in: length of id, in bytes */
1734
void* session,/*!< in: MySQL connection thread, or NULL */
1735
ibool table_id)/*!< in: TRUE=id is a table or database name;
1736
FALSE=id is an index name */
1739
const char* bufend = buf + buflen;
1742
const char* slash = (const char*) memchr(id, '/', idlen);
1748
/* Print the database name and table name separately. */
1749
s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1751
if (UNIV_LIKELY(s < bufend)) {
1753
s = innobase_convert_identifier(s, bufend - s,
1758
} else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1759
/* Temporary index name (smart ALTER TABLE) */
1760
const char temp_index_suffix[]= "--temporary--";
1762
s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1764
if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1765
memcpy(s, temp_index_suffix,
1766
sizeof temp_index_suffix - 1);
1767
s += sizeof temp_index_suffix - 1;
1771
s = innobase_convert_identifier(buf, buflen, id, idlen,
1779
/**********************************************************************//**
1780
Determines if the currently running transaction has been interrupted.
1781
@return TRUE if interrupted */
1782
extern "C" UNIV_INTERN
1786
trx_t* trx) /*!< in: transaction */
1788
return(trx && trx->mysql_thd && session_killed((Session*) trx->mysql_thd));
1791
/**************************************************************//**
1792
Resets some fields of a prebuilt struct. The template is used in fast
1793
retrieval of just those column values MySQL needs in its processing. */
1798
row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1800
prebuilt->keep_other_fields_on_keyread = 0;
1801
prebuilt->read_just_key = 0;
1804
/*********************************************************************//**
1805
Opens an InnoDB database.
1806
@return 0 on success, error code on failure */
1811
plugin::Context &context) /*!< in: Drizzle Plugin Context */
1813
static char current_dir[3]; /*!< Set if using current lib */
1819
innodb_engine_ptr= new InnobaseEngine(innobase_engine_name);
1821
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
1824
static const char test_filename[] = "-@";
1825
char test_tablename[sizeof test_filename
1826
+ sizeof srv_mysql50_table_name_prefix];
1827
if ((sizeof test_tablename) - 1
1828
!= filename_to_tablename(test_filename, test_tablename,
1829
sizeof test_tablename)
1830
|| strncmp(test_tablename,
1831
srv_mysql50_table_name_prefix,
1832
sizeof srv_mysql50_table_name_prefix)
1833
|| strcmp(test_tablename
1834
+ sizeof srv_mysql50_table_name_prefix,
1836
errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
1839
#endif /* UNIV_DEBUG */
1841
/* Check that values don't overflow on 32-bit systems. */
1842
if (sizeof(ulint) == 4) {
1843
if (innobase_buffer_pool_size > UINT32_MAX) {
1844
errmsg_printf(ERRMSG_LVL_ERROR,
1845
"innobase_buffer_pool_size can't be over 4GB"
1846
" on 32-bit systems");
1851
if (innobase_log_file_size > UINT32_MAX) {
1852
errmsg_printf(ERRMSG_LVL_ERROR,
1853
"innobase_log_file_size can't be over 4GB"
1854
" on 32-bit systems");
1860
os_innodb_umask = (ulint)internal::my_umask;
1862
/* First calculate the default path for innodb_data_home_dir etc.,
1863
in case the user has not given any value.
1865
Note that when using the embedded server, the datadirectory is not
1866
necessarily the current directory of this program. */
1868
/* It's better to use current lib, to keep paths short */
1869
current_dir[0] = FN_CURLIB;
1870
current_dir[1] = FN_LIBCHAR;
1872
default_path = current_dir;
1876
srv_set_thread_priorities = TRUE;
1877
srv_query_thread_priority = QUERY_PRIOR;
1879
/* Set InnoDB initialization parameters according to the values
1880
read from MySQL .cnf file */
1882
/*--------------- Data files -------------------------*/
1884
/* The default dir for data files is the datadir of MySQL */
1886
srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
1889
/* Set default InnoDB data file size to 10 MB and let it be
1890
auto-extending. Thus users can use InnoDB in >= 4.0 without having
1891
to specify any startup options. */
1893
if (!innobase_data_file_path) {
1894
innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
1897
/* Since InnoDB edits the argument in the next call, we make another
1900
internal_innobase_data_file_path = strdup(innobase_data_file_path);
1902
ret = (bool) srv_parse_data_file_paths_and_sizes(
1903
internal_innobase_data_file_path);
1905
errmsg_printf(ERRMSG_LVL_ERROR,
1906
"InnoDB: syntax error in innodb_data_file_path");
1908
srv_free_paths_and_sizes();
1909
if (internal_innobase_data_file_path)
1910
free(internal_innobase_data_file_path);
1914
/* -------------- Log files ---------------------------*/
1916
/* The default dir for log files is the datadir of MySQL */
1918
if (!innobase_log_group_home_dir) {
1919
innobase_log_group_home_dir = default_path;
1922
#ifdef UNIV_LOG_ARCHIVE
1923
/* Since innodb_log_arch_dir has no relevance under MySQL,
1924
starting from 4.0.6 we always set it the same as
1925
innodb_log_group_home_dir: */
1927
innobase_log_arch_dir = innobase_log_group_home_dir;
1929
srv_arch_dir = innobase_log_arch_dir;
1930
#endif /* UNIG_LOG_ARCHIVE */
1933
srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
1935
if (ret == FALSE || innobase_mirrored_log_groups != 1) {
1936
errmsg_printf(ERRMSG_LVL_ERROR, "syntax error in innodb_log_group_home_dir, or a "
1937
"wrong number of mirrored log groups");
1939
goto mem_free_and_error;
1942
/* Validate the file format by animal name */
1943
if (innobase_file_format_name != NULL) {
1945
format_id = innobase_file_format_name_lookup(
1946
innobase_file_format_name);
1948
if (format_id > DICT_TF_FORMAT_MAX) {
1950
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
1952
goto mem_free_and_error;
1955
/* Set it to the default file format id. Though this
1956
should never happen. */
1960
srv_file_format = format_id;
1962
/* Given the type of innobase_file_format_name we have little
1963
choice but to cast away the constness from the returned name.
1964
innobase_file_format_name is used in the MySQL set variable
1965
interface and so can't be const. */
1967
innobase_file_format_name =
1968
(char*) trx_sys_file_format_id_to_name(format_id);
1970
/* Process innobase_file_format_check variable */
1971
ut_a(innobase_file_format_check != NULL);
1973
/* As a side effect it will set srv_check_file_format_at_startup
1974
on valid input. First we check for "on"/"off". */
1975
if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
1977
/* Did the user specify a format name that we support ?
1978
As a side effect it will update the variable
1979
srv_check_file_format_at_startup */
1980
if (!innobase_file_format_check_validate(
1981
innobase_file_format_check)) {
1983
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: invalid "
1984
"innodb_file_format_check value: "
1985
"should be either 'on' or 'off' or "
1986
"any value up to %s or its "
1987
"equivalent numeric id",
1988
trx_sys_file_format_id_to_name(
1989
DICT_TF_FORMAT_MAX));
1991
goto mem_free_and_error;
1995
if (innobase_change_buffering) {
1999
use < UT_ARR_SIZE(innobase_change_buffering_values);
2001
if (!innobase_strcasecmp(
2002
innobase_change_buffering,
2003
innobase_change_buffering_values[use])) {
2004
ibuf_use = (ibuf_use_t) use;
2005
goto innobase_change_buffering_inited_ok;
2009
errmsg_printf(ERRMSG_LVL_ERROR,
2010
"InnoDB: invalid value "
2011
"innodb_file_format_check=%s",
2012
innobase_change_buffering);
2013
goto mem_free_and_error;
2016
innobase_change_buffering_inited_ok:
2017
ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
2018
innobase_change_buffering = (char*)
2019
innobase_change_buffering_values[ibuf_use];
2021
/* --------------------------------------------------*/
2023
srv_file_flush_method_str = innobase_unix_file_flush_method;
2025
srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
2026
srv_n_log_files = (ulint) innobase_log_files_in_group;
2027
srv_log_file_size = (ulint) innobase_log_file_size;
2029
#ifdef UNIV_LOG_ARCHIVE
2030
srv_log_archive_on = (ulint) innobase_log_archive;
2031
#endif /* UNIV_LOG_ARCHIVE */
2032
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
2034
srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
2036
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
2038
srv_n_file_io_threads = (ulint) innobase_file_io_threads;
2039
srv_n_read_io_threads = (ulint) innobase_read_io_threads;
2040
srv_n_write_io_threads = (ulint) innobase_write_io_threads;
2042
srv_force_recovery = (ulint) innobase_force_recovery;
2044
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
2045
srv_use_checksums = (ibool) innobase_use_checksums;
2047
#ifdef HAVE_LARGE_PAGES
2048
if ((os_use_large_pages = (ibool) my_use_large_pages))
2049
os_large_page_size = (ulint) opt_large_page_size;
2052
row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
2054
srv_locks_unsafe_for_binlog = (ibool) TRUE;
2056
srv_max_n_open_files = (ulint) innobase_open_files;
2057
srv_innodb_status = (ibool) innobase_create_status_file;
2059
srv_print_verbose_log = true;
2061
/* Store the default charset-collation number of this MySQL
2064
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
2067
innobase_commit_concurrency_init_default();
2069
/* Since we in this module access directly the fields of a trx
2070
struct, and due to different headers and flags it might happen that
2071
mutex_t has a different size in this module and in InnoDB
2072
modules, we check at run time that the size is the same in
2073
these compilation modules. */
2075
err = innobase_start_or_create_for_mysql();
2077
if (err != DB_SUCCESS) {
2078
goto mem_free_and_error;
2081
innobase_open_tables = hash_create(200);
2082
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
2083
pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
2084
pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
2085
pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
2086
pthread_cond_init(&commit_cond, NULL);
2089
status_table_function_ptr= new InnodbStatusTool;
2091
context.add(innodb_engine_ptr);
2093
context.add(status_table_function_ptr);
2095
cmp_tool= new(std::nothrow)CmpTool(false);
2096
context.add(cmp_tool);
2098
cmp_reset_tool= new(std::nothrow)CmpTool(true);
2099
context.add(cmp_reset_tool);
2101
cmp_mem_tool= new(std::nothrow)CmpmemTool(false);
2102
context.add(cmp_mem_tool);
2104
cmp_mem_reset_tool= new(std::nothrow)CmpmemTool(true);
2105
context.add(cmp_mem_reset_tool);
2107
innodb_trx_tool= new(std::nothrow)InnodbTrxTool("INNODB_TRX");
2108
context.add(innodb_trx_tool);
2110
innodb_locks_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCKS");
2111
context.add(innodb_locks_tool);
2113
innodb_lock_waits_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS");
2114
context.add(innodb_lock_waits_tool);
2116
/* Get the current high water mark format. */
2117
innobase_file_format_check = (char*) trx_sys_file_format_max_get();
2125
/****************************************************************//**
2126
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2127
the logs, and the name of this function should be innobase_checkpoint.
2128
@return TRUE if error */
2130
InnobaseEngine::flush_logs()
2131
/*=====================*/
2135
assert(this == innodb_engine_ptr);
2137
log_buffer_flush_to_disk();
2142
/*****************************************************************//**
2143
Commits a transaction in an InnoDB database. */
2146
innobase_commit_low(
2147
/*================*/
2148
trx_t* trx) /*!< in: transaction handle */
2150
if (trx->conc_state == TRX_NOT_STARTED) {
2155
trx_commit_for_mysql(trx);
2158
/*****************************************************************//**
2159
Creates an InnoDB transaction struct for the thd if it does not yet have one.
2160
Starts a new InnoDB transaction if a transaction is not yet started. And
2161
assigns a new snapshot for a consistent read if the transaction does not yet
2165
InnobaseEngine::doStartTransaction(
2166
/*====================================*/
2167
Session* session, /*!< in: MySQL thread handle of the user for whom
2168
the transaction should be committed */
2169
start_transaction_option_t options)
2171
assert(this == innodb_engine_ptr);
2173
/* Create a new trx struct for session, if it does not yet have one */
2174
trx_t *trx = check_trx_exists(session);
2176
/* This is just to play safe: release a possible FIFO ticket and
2177
search latch. Since we will reserve the kernel mutex, we have to
2178
release the search system latch first to obey the latching order. */
2179
innobase_release_stat_resources(trx);
2181
/* If the transaction is not started yet, start it */
2182
trx_start_if_not_started(trx);
2184
/* Assign a read view if the transaction does not have it yet */
2185
if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2186
trx_assign_read_view(trx);
2191
/*****************************************************************//**
2192
Commits a transaction in an InnoDB database or marks an SQL statement
2196
InnobaseEngine::doCommit(
2198
Session* session, /*!< in: MySQL thread handle of the user for whom
2199
the transaction should be committed */
2200
bool all) /*!< in: TRUE - commit transaction
2201
FALSE - the current SQL statement ended */
2205
assert(this == innodb_engine_ptr);
2207
trx = check_trx_exists(session);
2209
/* Since we will reserve the kernel mutex, we have to release
2210
the search system latch first to obey the latching order. */
2212
if (trx->has_search_latch) {
2213
trx_search_latch_release_if_reserved(trx);
2217
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
2219
/* We were instructed to commit the whole transaction, or
2220
this is an SQL statement end and autocommit is on */
2222
/* We need current binlog position for ibbackup to work.
2223
Note, the position is current because of
2224
prepare_commit_mutex */
2226
if (innobase_commit_concurrency > 0) {
2227
pthread_mutex_lock(&commit_cond_m);
2230
if (commit_threads > innobase_commit_concurrency) {
2232
pthread_cond_wait(&commit_cond,
2234
pthread_mutex_unlock(&commit_cond_m);
2238
pthread_mutex_unlock(&commit_cond_m);
2242
/* Store transaction point for binlog
2243
Later logic tests that this is set to _something_. We need
2244
that logic to fire, even though we do not have a real name. */
2245
trx->mysql_log_file_name = "UNUSED";
2246
trx->mysql_log_offset = 0;
2248
/* Don't do write + flush right now. For group commit
2249
to work we want to do the flush after releasing the
2250
prepare_commit_mutex. */
2251
trx->flush_log_later = TRUE;
2252
innobase_commit_low(trx);
2253
trx->flush_log_later = FALSE;
2255
if (innobase_commit_concurrency > 0) {
2256
pthread_mutex_lock(&commit_cond_m);
2258
pthread_cond_signal(&commit_cond);
2259
pthread_mutex_unlock(&commit_cond_m);
2262
if (trx->conc_state == TRX_PREPARED) {
2264
pthread_mutex_unlock(&prepare_commit_mutex);
2267
/* Now do a write + flush of logs. */
2268
trx_commit_complete_for_mysql(trx);
2271
/* We just mark the SQL statement ended and do not do a
2272
transaction commit */
2274
/* If we had reserved the auto-inc lock for some
2275
table in this SQL statement we release it now */
2277
row_unlock_table_autoinc_for_mysql(trx);
2279
/* Store the current undo_no of the transaction so that we
2280
know where to roll back if we have to roll back the next
2283
trx_mark_sql_stat_end(trx);
2286
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2288
if (trx->declared_to_be_inside_innodb) {
2289
/* Release our possible ticket in the FIFO */
2291
srv_conc_force_exit_innodb(trx);
2294
/* Tell the InnoDB server that there might be work for utility
2296
srv_active_wake_master_thread();
2301
/*****************************************************************//**
2302
Rolls back a transaction or the latest SQL statement.
2303
@return 0 or error number */
2305
InnobaseEngine::doRollback(
2307
Session* session,/*!< in: handle to the MySQL thread of the user
2308
whose transaction should be rolled back */
2309
bool all) /*!< in: TRUE - commit transaction
2310
FALSE - the current SQL statement ended */
2315
assert(this == innodb_engine_ptr);
2317
trx = check_trx_exists(session);
2319
/* Release a possible FIFO ticket and search latch. Since we will
2320
reserve the kernel mutex, we have to release the search system latch
2321
first to obey the latching order. */
2323
innobase_release_stat_resources(trx);
2325
/* If we had reserved the auto-inc lock for some table (if
2326
we come here to roll back the latest SQL statement) we
2327
release it now before a possibly lengthy rollback */
2329
row_unlock_table_autoinc_for_mysql(trx);
2332
|| !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
2334
error = trx_rollback_for_mysql(trx);
2336
error = trx_rollback_last_sql_stat_for_mysql(trx);
2339
return(convert_error_code_to_mysql(error, 0, NULL));
2342
/*****************************************************************//**
2343
Rolls back a transaction
2344
@return 0 or error number */
2347
innobase_rollback_trx(
2348
/*==================*/
2349
trx_t* trx) /*!< in: transaction */
2353
/* Release a possible FIFO ticket and search latch. Since we will
2354
reserve the kernel mutex, we have to release the search system latch
2355
first to obey the latching order. */
2357
innobase_release_stat_resources(trx);
2359
/* If we had reserved the auto-inc lock for some table (if
2360
we come here to roll back the latest SQL statement) we
2361
release it now before a possibly lengthy rollback */
2363
row_unlock_table_autoinc_for_mysql(trx);
2365
error = trx_rollback_for_mysql(trx);
2367
return(convert_error_code_to_mysql(error, 0, NULL));
2370
/*****************************************************************//**
2371
Rolls back a transaction to a savepoint.
2372
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2375
InnobaseEngine::doRollbackToSavepoint(
2376
/*===========================*/
2377
Session* session, /*!< in: handle to the MySQL thread of the user
2378
whose transaction should be rolled back */
2379
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2381
ib_int64_t mysql_binlog_cache_pos;
2385
assert(this == innodb_engine_ptr);
2387
trx = check_trx_exists(session);
2389
/* Release a possible FIFO ticket and search latch. Since we will
2390
reserve the kernel mutex, we have to release the search system latch
2391
first to obey the latching order. */
2393
innobase_release_stat_resources(trx);
2395
error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2396
&mysql_binlog_cache_pos);
2397
return(convert_error_code_to_mysql(error, 0, NULL));
2400
/*****************************************************************//**
2401
Release transaction savepoint name.
2402
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2405
InnobaseEngine::doReleaseSavepoint(
2406
/*=======================*/
2407
Session* session, /*!< in: handle to the MySQL thread of the user
2408
whose transaction should be rolled back */
2409
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2414
assert(this == innodb_engine_ptr);
2416
trx = check_trx_exists(session);
2418
error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2420
return(convert_error_code_to_mysql(error, 0, NULL));
2423
/*****************************************************************//**
2424
Sets a transaction savepoint.
2425
@return always 0, that is, always succeeds */
2427
InnobaseEngine::doSetSavepoint(
2429
Session* session,/*!< in: handle to the MySQL thread */
2430
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2435
assert(this == innodb_engine_ptr);
2438
In the autocommit mode there is no sense to set a savepoint
2439
(unless we are in sub-statement), so SQL layer ensures that
2440
this method is never called in such situation.
2443
trx = check_trx_exists(session);
2445
/* Release a possible FIFO ticket and search latch. Since we will
2446
reserve the kernel mutex, we have to release the search system latch
2447
first to obey the latching order. */
2449
innobase_release_stat_resources(trx);
2451
/* cannot happen outside of transaction */
2452
assert(trx->conc_state != TRX_NOT_STARTED);
2454
error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2456
return(convert_error_code_to_mysql(error, 0, NULL));
2459
/*****************************************************************//**
2460
Frees a possible InnoDB trx object associated with the current Session.
2461
@return 0 or error number */
2463
InnobaseEngine::close_connection(
2464
/*======================*/
2465
Session* session)/*!< in: handle to the MySQL thread of the user
2466
whose resources should be free'd */
2470
assert(this == innodb_engine_ptr);
2471
trx = session_to_trx(session);
2475
assert(session->killed != Session::NOT_KILLED ||
2476
trx->conc_state == TRX_NOT_STARTED);
2478
/* Warn if rolling back some things... */
2479
if (session->killed != Session::NOT_KILLED &&
2480
trx->conc_state != TRX_NOT_STARTED &&
2481
trx->undo_no.low > 0 &&
2482
global_system_variables.log_warnings)
2484
errmsg_printf(ERRMSG_LVL_WARN,
2485
"Drizzle is closing a connection during a KILL operation\n"
2486
"that has an active InnoDB transaction. %lu row modifications will "
2488
(ulong) trx->undo_no.low);
2491
innobase_rollback_trx(trx);
2493
thr_local_free(trx->mysql_thread_id);
2494
trx_free_for_mysql(trx);
2500
/*************************************************************************//**
2501
** InnoDB database tables
2502
*****************************************************************************/
2504
/****************************************************************//**
2505
Get the record format from the data dictionary.
2506
@return one of ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT,
2507
ROW_TYPE_COMPRESSED, ROW_TYPE_DYNAMIC */
2510
ha_innobase::get_row_type() const
2511
/*=============================*/
2513
if (prebuilt && prebuilt->table) {
2514
const ulint flags = prebuilt->table->flags;
2516
if (UNIV_UNLIKELY(!flags)) {
2517
return(ROW_TYPE_REDUNDANT);
2520
ut_ad(flags & DICT_TF_COMPACT);
2522
switch (flags & DICT_TF_FORMAT_MASK) {
2523
case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
2524
return(ROW_TYPE_COMPACT);
2525
case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
2526
if (flags & DICT_TF_ZSSIZE_MASK) {
2527
return(ROW_TYPE_COMPRESSED);
2529
return(ROW_TYPE_DYNAMIC);
2531
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
2532
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
2537
return(ROW_TYPE_NOT_USED);
2541
/****************************************************************//**
2542
Returns the index type. */
2545
ha_innobase::index_type(
2546
/*====================*/
2548
/*!< out: index type */
2553
/****************************************************************//**
2554
Returns the maximum number of keys.
2558
InnobaseEngine::max_supported_keys() const
2559
/*===================================*/
2564
/****************************************************************//**
2565
Returns the maximum key length.
2566
@return maximum supported key length, in bytes */
2569
InnobaseEngine::max_supported_key_length() const
2570
/*=========================================*/
2572
/* An InnoDB page must store >= 2 keys; a secondary key record
2573
must also contain the primary key value: max key length is
2574
therefore set to slightly less than 1 / 4 of page size which
2575
is 16 kB; but currently MySQL does not work with keys whose
2576
size is > MAX_KEY_LENGTH */
2580
/****************************************************************//**
2581
Returns the key map of keys that are usable for scanning.
2582
@return key_map_full */
2585
ha_innobase::keys_to_use_for_scanning()
2587
return(&key_map_full);
2591
/****************************************************************//**
2592
Determines if the primary key is clustered index.
2596
ha_innobase::primary_key_is_clustered()
2601
/*****************************************************************//**
2602
Normalizes a table name string. A normalized name consists of the
2603
database name catenated to '/' and table name. An example:
2604
test/mytable. On Windows normalization puts both the database name and the
2605
table name always to lower case. */
2608
normalize_table_name(
2609
/*=================*/
2610
char* norm_name, /*!< out: normalized name as a
2611
null-terminated string */
2612
const char* name) /*!< in: table name string */
2614
const char* name_ptr;
2618
/* Scan name from the end */
2620
ptr = strchr(name, '\0')-1;
2622
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2632
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2638
memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
2640
norm_name[name_ptr - db_ptr - 1] = '/';
2643
innobase_casedn_str(norm_name);
2647
/********************************************************************//**
2648
Set the autoinc column max value. This should only be called once from
2649
ha_innobase::open(). Therefore there's no need for a covering lock.
2650
@return DB_SUCCESS or error code */
2653
ha_innobase::innobase_initialize_autoinc()
2654
/*======================================*/
2656
dict_index_t* index;
2658
const char* col_name;
2661
col_name = table->found_next_number_field->field_name;
2662
index = innobase_get_index(table->s->next_number_index);
2664
/* Execute SELECT MAX(col_name) FROM TABLE; */
2665
error = row_search_max_autoinc(index, col_name, &auto_inc);
2670
/* At the this stage we don't know the increment
2671
or the offset, so use default inrement of 1. */
2675
case DB_RECORD_NOT_FOUND:
2676
ut_print_timestamp(stderr);
2677
fprintf(stderr, " InnoDB: MySQL and InnoDB data "
2678
"dictionaries are out of sync.\n"
2679
"InnoDB: Unable to find the AUTOINC column %s in the "
2680
"InnoDB table %s.\n"
2681
"InnoDB: We set the next AUTOINC column value to the "
2682
"maximum possible value,\n"
2683
"InnoDB: in effect disabling the AUTOINC next value "
2685
"InnoDB: You can either set the next AUTOINC value "
2686
"explicitly using ALTER TABLE\n"
2687
"InnoDB: or fix the data dictionary by recreating "
2689
col_name, index->table->name);
2691
auto_inc = 0xFFFFFFFFFFFFFFFFULL;
2698
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
2703
/*****************************************************************//**
2704
Creates and opens a handle to a table which already exists in an InnoDB
2706
@return 1 if error, 0 if success */
2711
const char* name, /*!< in: table name */
2712
int mode, /*!< in: not used */
2713
uint test_if_locked) /*!< in: not used */
2715
dict_table_t* ib_table;
2716
char norm_name[1000];
2719
char* is_part = NULL;
2722
UT_NOT_USED(test_if_locked);
2724
session = ha_session();
2726
/* Under some cases Drizzle seems to call this function while
2727
holding btr_search_latch. This breaks the latching order as
2728
we acquire dict_sys->mutex below and leads to a deadlock. */
2729
if (session != NULL) {
2730
getTransactionalEngine()->releaseTemporaryLatches(session);
2733
normalize_table_name(norm_name, name);
2735
user_session = NULL;
2737
if (!(share=get_share(name))) {
2742
/* Create buffers for packing the fields of a record. Why
2743
table->stored_rec_length did not work here? Obviously, because char
2744
fields when packed actually became 1 byte longer, when we also
2745
stored the string length as the first byte. */
2747
upd_and_key_val_buff_len =
2748
table->s->stored_rec_length
2749
+ table->s->max_key_length
2750
+ MAX_REF_PARTS * 3;
2751
if (!(unsigned char*) memory::multi_malloc(false,
2752
&upd_buff, upd_and_key_val_buff_len,
2753
&key_val_buff, upd_and_key_val_buff_len,
2760
/* We look for pattern #P# to see if the table is partitioned
2761
MySQL table. The retry logic for partitioned tables is a
2762
workaround for http://bugs.mysql.com/bug.php?id=33349. Look
2763
at support issue https://support.mysql.com/view.php?id=21080
2764
for more details. */
2765
is_part = strstr(norm_name, "#P#");
2767
/* Get pointer to a table object in InnoDB dictionary cache */
2768
ib_table = dict_table_get(norm_name, TRUE);
2770
if (NULL == ib_table) {
2771
if (is_part && retries < 10) {
2773
os_thread_sleep(100000);
2778
errmsg_printf(ERRMSG_LVL_ERROR, "Failed to open table %s after "
2779
"%lu attemtps.\n", norm_name,
2783
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
2784
"the internal data dictionary of InnoDB "
2785
"though the .frm file for the\n"
2786
"table exists. Maybe you have deleted and "
2787
"recreated InnoDB data\n"
2788
"files but have forgotten to delete the "
2789
"corresponding .frm files\n"
2790
"of InnoDB tables, or you have moved .frm "
2791
"files to another database?\n"
2792
"or, the table contains indexes that this "
2793
"version of the engine\n"
2794
"doesn't support.\n"
2795
"See " REFMAN "innodb-troubleshooting.html\n"
2796
"how you can resolve the problem.\n",
2802
return(HA_ERR_NO_SUCH_TABLE);
2805
if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
2806
errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
2807
"the .ibd file for\ntable %s does not exist.\n"
2808
"Have you deleted the .ibd file from the "
2809
"database directory under\nthe MySQL datadir, "
2810
"or have you used DISCARD TABLESPACE?\n"
2811
"See " REFMAN "innodb-troubleshooting.html\n"
2812
"how you can resolve the problem.\n",
2818
dict_table_decrement_handle_count(ib_table, FALSE);
2819
return(HA_ERR_NO_SUCH_TABLE);
2822
prebuilt = row_create_prebuilt(ib_table);
2824
prebuilt->mysql_row_len = table->s->stored_rec_length;
2825
prebuilt->default_rec = table->s->default_values;
2826
ut_ad(prebuilt->default_rec);
2828
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
2830
primary_key = table->s->primary_key;
2831
key_used_on_scan = primary_key;
2833
/* Allocate a buffer for a 'row reference'. A row reference is
2834
a string of bytes of length ref_length which uniquely specifies
2835
a row in our table. Note that MySQL may also compare two row
2836
references for equality by doing a simple memcmp on the strings
2837
of length ref_length! */
2839
if (!row_table_got_default_clust_index(ib_table)) {
2840
if (primary_key >= MAX_KEY) {
2841
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in InnoDB data "
2842
"dictionary, but not in MySQL!", name);
2845
prebuilt->clust_index_was_generated = FALSE;
2847
/* MySQL allocates the buffer for ref. key_info->key_length
2848
includes space for all key columns + one byte for each column
2849
that may be NULL. ref_length must be as exact as possible to
2850
save space, because all row reference buffers are allocated
2851
based on ref_length. */
2853
ref_length = table->key_info[primary_key].key_length;
2855
if (primary_key != MAX_KEY) {
2856
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has no primary key in InnoDB data "
2857
"dictionary, but has one in MySQL! If you "
2858
"created the table with a MySQL version < "
2859
"3.23.54 and did not define a primary key, "
2860
"but defined a unique key with all non-NULL "
2861
"columns, then MySQL internally treats that "
2862
"key as the primary key. You can fix this "
2863
"error by dump + DROP + CREATE + reimport "
2864
"of the table.", name);
2867
prebuilt->clust_index_was_generated = TRUE;
2869
ref_length = DATA_ROW_ID_LEN;
2871
/* If we automatically created the clustered index, then
2872
MySQL does not know about it, and MySQL must NOT be aware
2873
of the index used on scan, to make it avoid checking if we
2874
update the column of the index. That is why we assert below
2875
that key_used_on_scan is the undefined value MAX_KEY.
2876
The column is the row id in the automatical generation case,
2877
and it will never be updated anyway. */
2879
if (key_used_on_scan != MAX_KEY) {
2880
errmsg_printf(ERRMSG_LVL_WARN,
2881
"Table %s key_used_on_scan is %lu even "
2882
"though there is no primary key inside "
2883
"InnoDB.", name, (ulong) key_used_on_scan);
2887
/* Index block size in InnoDB: used by MySQL in query optimization */
2888
stats.block_size = 16 * 1024;
2890
/* Init table lock structure */
2891
thr_lock_data_init(&share->lock,&lock,(void*) 0);
2893
if (prebuilt->table) {
2894
/* We update the highest file format in the system table
2895
space, if this table has higher file format setting. */
2897
trx_sys_file_format_max_upgrade(
2898
(const char**) &innobase_file_format_check,
2899
dict_table_get_format(prebuilt->table));
2902
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
2904
/* Only if the table has an AUTOINC column. */
2905
if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
2908
dict_table_autoinc_lock(prebuilt->table);
2910
/* Since a table can already be "open" in InnoDB's internal
2911
data dictionary, we only init the autoinc counter once, the
2912
first time the table is loaded. We can safely reuse the
2913
autoinc value from a previous Drizzle open. */
2914
if (dict_table_autoinc_read(prebuilt->table) == 0) {
2916
error = innobase_initialize_autoinc();
2917
ut_a(error == DB_SUCCESS);
2920
dict_table_autoinc_unlock(prebuilt->table);
2928
InnobaseEngine::max_supported_key_part_length() const
2930
return(DICT_MAX_INDEX_COL_LEN - 1);
2933
/******************************************************************//**
2934
Closes a handle to an InnoDB table.
2938
ha_innobase::close(void)
2939
/*====================*/
2943
session = ha_session();
2944
if (session != NULL) {
2945
getTransactionalEngine()->releaseTemporaryLatches(session);
2948
row_prebuilt_free(prebuilt, FALSE);
2953
/* Tell InnoDB server that there might be work for
2956
srv_active_wake_master_thread();
2961
/* The following accessor functions should really be inside MySQL code! */
2963
/**************************************************************//**
2964
Gets field offset for a field in a table.
2970
Table* table, /*!< in: MySQL table object */
2971
Field* field) /*!< in: MySQL field object */
2973
return((uint) (field->ptr - table->record[0]));
2976
/**************************************************************//**
2977
Checks if a field in a record is SQL NULL. Uses the record format
2978
information in table to track the null bit in record.
2979
@return 1 if NULL, 0 otherwise */
2982
field_in_record_is_null(
2983
/*====================*/
2984
Table* table, /*!< in: MySQL table object */
2985
Field* field, /*!< in: MySQL field object */
2986
char* record) /*!< in: a row in MySQL format */
2990
if (!field->null_ptr) {
2995
null_offset = (uint) ((char*) field->null_ptr
2996
- (char*) table->record[0]);
2998
if (record[null_offset] & field->null_bit) {
3006
/**************************************************************//**
3007
Sets a field in a record to SQL NULL. Uses the record format
3008
information in table to track the null bit in record. */
3011
set_field_in_record_to_null(
3012
/*========================*/
3013
Table* table, /*!< in: MySQL table object */
3014
Field* field, /*!< in: MySQL field object */
3015
char* record) /*!< in: a row in MySQL format */
3019
null_offset = (uint) ((char*) field->null_ptr
3020
- (char*) table->record[0]);
3022
record[null_offset] = record[null_offset] | field->null_bit;
3025
/*************************************************************//**
3026
InnoDB uses this function to compare two data fields for which the data type
3027
is such that we must use MySQL code to compare them. NOTE that the prototype
3028
of this function is in rem0cmp.c in InnoDB source code! If you change this
3029
function, remember to update the prototype there!
3030
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
3031
extern "C" UNIV_INTERN
3035
int mysql_type, /*!< in: MySQL type */
3036
uint charset_number, /*!< in: number of the charset */
3037
const unsigned char* a, /*!< in: data field */
3038
unsigned int a_length, /*!< in: data field length,
3039
not UNIV_SQL_NULL */
3040
const unsigned char* b, /* in: data field */
3041
unsigned int b_length); /* in: data field length,
3042
not UNIV_SQL_NULL */
3047
/* out: 1, 0, -1, if a is greater,
3048
equal, less than b, respectively */
3049
int mysql_type, /* in: MySQL type */
3050
uint charset_number, /* in: number of the charset */
3051
const unsigned char* a, /* in: data field */
3052
unsigned int a_length, /* in: data field length,
3053
not UNIV_SQL_NULL */
3054
const unsigned char* b, /* in: data field */
3055
unsigned int b_length) /* in: data field length,
3056
not UNIV_SQL_NULL */
3058
const CHARSET_INFO* charset;
3059
enum_field_types mysql_tp;
3062
assert(a_length != UNIV_SQL_NULL);
3063
assert(b_length != UNIV_SQL_NULL);
3065
mysql_tp = (enum_field_types) mysql_type;
3069
case DRIZZLE_TYPE_BLOB:
3070
case DRIZZLE_TYPE_VARCHAR:
3071
/* Use the charset number to pick the right charset struct for
3072
the comparison. Since the MySQL function get_charset may be
3073
slow before Bar removes the mutex operation there, we first
3074
look at 2 common charsets directly. */
3076
if (charset_number == default_charset_info->number) {
3077
charset = default_charset_info;
3079
charset = get_charset(charset_number);
3081
if (charset == NULL) {
3082
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
3083
"a comparison, but MySQL cannot "
3084
"find that charset.",
3085
(ulong) charset_number);
3090
/* Starting from 4.1.3, we use strnncollsp() in comparisons of
3091
non-latin1_swedish_ci strings. NOTE that the collation order
3092
changes then: 'b\0\0...' is ordered BEFORE 'b ...'. Users
3093
having indexes on such data need to rebuild their tables! */
3095
ret = charset->coll->strnncollsp(charset,
3100
} else if (ret > 0) {
3112
/**************************************************************//**
3113
Converts a MySQL type to an InnoDB type. Note that this function returns
3114
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3115
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3116
@return DATA_BINARY, DATA_VARCHAR, ... */
3117
extern "C" UNIV_INTERN
3119
get_innobase_type_from_mysql_type(
3120
/*==============================*/
3121
ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
3123
at least ENUM and SET,
3124
and unsigned integer
3125
types are 'unsigned types' */
3126
const void* f) /*!< in: MySQL Field */
3128
const class Field* field = reinterpret_cast<const class Field*>(f);
3130
/* The following asserts try to check that the MySQL type code fits in
3131
8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3134
assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3136
if (field->flags & UNSIGNED_FLAG) {
3138
*unsigned_flag = DATA_UNSIGNED;
3143
if (field->real_type() == DRIZZLE_TYPE_ENUM)
3145
/* MySQL has field->type() a string type for these, but the
3146
data is actually internally stored as an unsigned integer
3149
*unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3150
flag set to zero, even though
3151
internally this is an unsigned
3156
switch (field->type()) {
3157
/* NOTE that we only allow string types in DATA_DRIZZLE and
3159
case DRIZZLE_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
3160
if (field->binary()) {
3161
return(DATA_BINARY);
3163
return(DATA_VARMYSQL);
3165
case DRIZZLE_TYPE_DECIMAL:
3166
return(DATA_FIXBINARY);
3167
case DRIZZLE_TYPE_LONG:
3168
case DRIZZLE_TYPE_LONGLONG:
3169
case DRIZZLE_TYPE_DATETIME:
3170
case DRIZZLE_TYPE_DATE:
3171
case DRIZZLE_TYPE_TIMESTAMP:
3173
case DRIZZLE_TYPE_DOUBLE:
3174
return(DATA_DOUBLE);
3175
case DRIZZLE_TYPE_BLOB:
3184
/*******************************************************************//**
3185
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
3189
innobase_write_to_2_little_endian(
3190
/*==============================*/
3191
byte* buf, /*!< in: where to store */
3192
ulint val) /*!< in: value to write, must be < 64k */
3194
ut_a(val < 256 * 256);
3196
buf[0] = (byte)(val & 0xFF);
3197
buf[1] = (byte)(val / 256);
3200
/*******************************************************************//**
3201
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
3206
innobase_read_from_2_little_endian(
3207
/*===============================*/
3208
const unsigned char* buf) /*!< in: from where to read */
3210
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
3213
/*******************************************************************//**
3214
Stores a key value for a row to a buffer.
3215
@return key value length as stored in buff */
3218
ha_innobase::store_key_val_for_row(
3219
/*===============================*/
3220
uint keynr, /*!< in: key number */
3221
char* buff, /*!< in/out: buffer for the key value (in MySQL
3223
uint buff_len,/*!< in: buffer length */
3224
const unsigned char* record)/*!< in: row in MySQL format */
3226
KEY* key_info = table->key_info + keynr;
3227
KEY_PART_INFO* key_part = key_info->key_part;
3228
KEY_PART_INFO* end = key_part + key_info->key_parts;
3229
char* buff_start = buff;
3230
enum_field_types mysql_type;
3234
/* The format for storing a key field in MySQL is the following:
3236
1. If the column can be NULL, then in the first byte we put 1 if the
3237
field value is NULL, 0 otherwise.
3239
2. If the column is of a BLOB type (it must be a column prefix field
3240
in this case), then we put the length of the data in the field to the
3241
next 2 bytes, in the little-endian format. If the field is SQL NULL,
3242
then these 2 bytes are set to 0. Note that the length of data in the
3243
field is <= column prefix length.
3245
3. In a column prefix field, prefix_len next bytes are reserved for
3246
data. In a normal field the max field length next bytes are reserved
3247
for data. For a VARCHAR(n) the max field length is n. If the stored
3248
value is the SQL NULL then these data bytes are set to 0.
3250
4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
3251
in the MySQL row format, the length is stored in 1 or 2 bytes,
3252
depending on the maximum allowed length. But in the MySQL key value
3253
format, the length always takes 2 bytes.
3255
We have to zero-fill the buffer so that MySQL is able to use a
3256
simple memcmp to compare two key values to determine if they are
3257
equal. MySQL does this to compare contents of two 'ref' values. */
3259
bzero(buff, buff_len);
3261
for (; key_part != end; key_part++) {
3264
if (key_part->null_bit) {
3265
if (record[key_part->null_offset]
3266
& key_part->null_bit) {
3275
field = key_part->field;
3276
mysql_type = field->type();
3278
if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
3279
/* >= 5.0.3 true VARCHAR */
3285
const CHARSET_INFO* cs;
3288
key_len = key_part->length;
3291
buff += key_len + 2;
3295
cs = field->charset();
3298
(((Field_varstring*)field)->length_bytes);
3300
data = row_mysql_read_true_varchar(&len,
3302
+ (ulint)get_field_offset(table, field)),
3307
/* For multi byte character sets we need to calculate
3308
the true length of the key */
3310
if (len > 0 && cs->mbmaxlen > 1) {
3311
true_len = (ulint) cs->cset->well_formed_len(cs,
3312
(const char *) data,
3313
(const char *) data + len,
3319
/* In a column prefix index, we may need to truncate
3320
the stored value: */
3322
if (true_len > key_len) {
3326
/* The length in a key value is always stored in 2
3329
row_mysql_store_true_var_len((byte*)buff, true_len, 2);
3332
memcpy(buff, data, true_len);
3334
/* Note that we always reserve the maximum possible
3335
length of the true VARCHAR in the key value, though
3336
only len first bytes after the 2 length bytes contain
3337
actual data. The rest of the space was reset to zero
3338
in the bzero() call above. */
3342
} else if (mysql_type == DRIZZLE_TYPE_BLOB) {
3344
const CHARSET_INFO* cs;
3349
const byte* blob_data;
3351
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
3353
key_len = key_part->length;
3356
buff += key_len + 2;
3361
cs = field->charset();
3363
blob_data = row_mysql_read_blob_ref(&blob_len,
3365
+ (ulint)get_field_offset(table, field)),
3366
(ulint) field->pack_length());
3368
true_len = blob_len;
3370
ut_a(get_field_offset(table, field)
3371
== key_part->offset);
3373
/* For multi byte character sets we need to calculate
3374
the true length of the key */
3376
if (blob_len > 0 && cs->mbmaxlen > 1) {
3377
true_len = (ulint) cs->cset->well_formed_len(cs,
3378
(const char *) blob_data,
3379
(const char *) blob_data
3386
/* All indexes on BLOB and TEXT are column prefix
3387
indexes, and we may need to truncate the data to be
3388
stored in the key value: */
3390
if (true_len > key_len) {
3394
/* MySQL reserves 2 bytes for the length and the
3395
storage of the number is little-endian */
3397
innobase_write_to_2_little_endian(
3398
(byte*)buff, true_len);
3401
memcpy(buff, blob_data, true_len);
3403
/* Note that we always reserve the maximum possible
3404
length of the BLOB prefix in the key value. */
3408
/* Here we handle all other data types except the
3409
true VARCHAR, BLOB and TEXT. Note that the column
3410
value we store may be also in a column prefix
3415
const unsigned char* src_start;
3416
enum_field_types real_type;
3418
key_len = key_part->length;
3426
src_start = record + key_part->offset;
3427
real_type = field->real_type();
3430
/* Character set for the field is defined only
3431
to fields whose type is string and real field
3432
type is not enum or set. For these fields check
3433
if character set is multi byte. */
3435
memcpy(buff, src_start, true_len);
3438
/* Pad the unused space with spaces. Note that no
3439
padding is ever needed for UCS-2 because in MySQL,
3440
all UCS2 characters are 2 bytes, as MySQL does not
3441
support surrogate pairs, which are needed to represent
3442
characters in the range U+10000 to U+10FFFF. */
3444
if (true_len < key_len) {
3445
ulint pad_len = key_len - true_len;
3446
memset(buff, ' ', pad_len);
3452
ut_a(buff <= buff_start + buff_len);
3454
return((uint)(buff - buff_start));
3457
/**************************************************************//**
3458
Builds a 'template' to the prebuilt struct. The template is used in fast
3459
retrieval of just those column values MySQL needs in its processing. */
3464
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
3465
Session* , /*!< in: current user thread, used
3466
only if templ_type is
3467
ROW_DRIZZLE_REC_FIELDS */
3468
Table* table, /*!< in: MySQL table */
3469
uint templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
3470
ROW_DRIZZLE_REC_FIELDS */
3472
dict_index_t* index;
3473
dict_index_t* clust_index;
3474
mysql_row_templ_t* templ;
3477
ulint n_requested_fields = 0;
3478
ibool fetch_all_in_key = FALSE;
3479
ibool fetch_primary_key_cols = FALSE;
3481
/* byte offset of the end of last requested column */
3482
ulint mysql_prefix_len = 0;
3484
if (prebuilt->select_lock_type == LOCK_X) {
3485
/* We always retrieve the whole clustered index record if we
3486
use exclusive row level locks, for example, if the read is
3487
done in an UPDATE statement. */
3489
templ_type = ROW_MYSQL_WHOLE_ROW;
3492
if (templ_type == ROW_MYSQL_REC_FIELDS) {
3493
if (prebuilt->hint_need_to_fetch_extra_cols
3494
== ROW_RETRIEVE_ALL_COLS) {
3496
/* We know we must at least fetch all columns in the
3497
key, or all columns in the table */
3499
if (prebuilt->read_just_key) {
3500
/* MySQL has instructed us that it is enough
3501
to fetch the columns in the key; looks like
3502
MySQL can set this flag also when there is
3503
only a prefix of the column in the key: in
3504
that case we retrieve the whole column from
3505
the clustered index */
3507
fetch_all_in_key = TRUE;
3509
templ_type = ROW_MYSQL_WHOLE_ROW;
3511
} else if (prebuilt->hint_need_to_fetch_extra_cols
3512
== ROW_RETRIEVE_PRIMARY_KEY) {
3513
/* We must at least fetch all primary key cols. Note
3514
that if the clustered index was internally generated
3515
by InnoDB on the row id (no primary key was
3516
defined), then row_search_for_mysql() will always
3517
retrieve the row id to a special buffer in the
3520
fetch_primary_key_cols = TRUE;
3524
clust_index = dict_table_get_first_index(prebuilt->table);
3526
if (templ_type == ROW_MYSQL_REC_FIELDS) {
3527
index = prebuilt->index;
3529
index = clust_index;
3532
if (index == clust_index) {
3533
prebuilt->need_to_access_clustered = TRUE;
3535
prebuilt->need_to_access_clustered = FALSE;
3536
/* Below we check column by column if we need to access
3537
the clustered index */
3540
n_fields = (ulint)table->s->fields; /* number of columns */
3542
if (!prebuilt->mysql_template) {
3543
prebuilt->mysql_template = (mysql_row_templ_t*)
3544
mem_alloc(n_fields * sizeof(mysql_row_templ_t));
3547
prebuilt->template_type = templ_type;
3548
prebuilt->null_bitmap_len = table->s->null_bytes;
3550
prebuilt->templ_contains_blob = FALSE;
3552
/* Note that in InnoDB, i is the column number. MySQL calls columns
3554
for (i = 0; i < n_fields; i++) {
3555
templ = prebuilt->mysql_template + n_requested_fields;
3556
field = table->field[i];
3558
if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
3559
/* Decide which columns we should fetch
3560
and which we can skip. */
3561
register const ibool index_contains_field =
3562
dict_index_contains_col_or_prefix(index, i);
3564
if (!index_contains_field && prebuilt->read_just_key) {
3565
/* If this is a 'key read', we do not need
3566
columns that are not in the key */
3571
if (index_contains_field && fetch_all_in_key) {
3572
/* This field is needed in the query */
3577
if (field->isReadSet() || field->isWriteSet())
3578
/* This field is needed in the query */
3581
assert(table->isReadSet(i) == field->isReadSet());
3582
assert(table->isWriteSet(i) == field->isWriteSet());
3584
if (fetch_primary_key_cols
3585
&& dict_table_col_in_clustered_key(
3587
/* This field is needed in the query */
3592
/* This field is not needed in the query, skip it */
3597
n_requested_fields++;
3601
if (index == clust_index) {
3602
templ->rec_field_no = dict_col_get_clust_pos(
3603
&index->table->cols[i], index);
3605
templ->rec_field_no = dict_index_get_nth_col_pos(
3609
if (templ->rec_field_no == ULINT_UNDEFINED) {
3610
prebuilt->need_to_access_clustered = TRUE;
3613
if (field->null_ptr) {
3614
templ->mysql_null_byte_offset =
3615
(ulint) ((char*) field->null_ptr
3616
- (char*) table->record[0]);
3618
templ->mysql_null_bit_mask = (ulint) field->null_bit;
3620
templ->mysql_null_bit_mask = 0;
3623
templ->mysql_col_offset = (ulint)
3624
get_field_offset(table, field);
3626
templ->mysql_col_len = (ulint) field->pack_length();
3627
if (mysql_prefix_len < templ->mysql_col_offset
3628
+ templ->mysql_col_len) {
3629
mysql_prefix_len = templ->mysql_col_offset
3630
+ templ->mysql_col_len;
3632
templ->type = index->table->cols[i].mtype;
3633
templ->mysql_type = (ulint)field->type();
3635
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
3636
templ->mysql_length_bytes = (ulint)
3637
(((Field_varstring*)field)->length_bytes);
3640
templ->charset = dtype_get_charset_coll(
3641
index->table->cols[i].prtype);
3642
templ->mbminlen = index->table->cols[i].mbminlen;
3643
templ->mbmaxlen = index->table->cols[i].mbmaxlen;
3644
templ->is_unsigned = index->table->cols[i].prtype
3646
if (templ->type == DATA_BLOB) {
3647
prebuilt->templ_contains_blob = TRUE;
3653
prebuilt->n_template = n_requested_fields;
3654
prebuilt->mysql_prefix_len = mysql_prefix_len;
3656
if (index != clust_index && prebuilt->need_to_access_clustered) {
3657
/* Change rec_field_no's to correspond to the clustered index
3659
for (i = 0; i < n_requested_fields; i++) {
3660
templ = prebuilt->mysql_template + i;
3662
templ->rec_field_no = dict_col_get_clust_pos(
3663
&index->table->cols[templ->col_no],
3669
/********************************************************************//**
3670
Get the upper limit of the MySQL integral and floating-point type. */
3673
ha_innobase::innobase_get_int_col_max_value(
3674
/*========================================*/
3677
uint64_t max_value = 0;
3679
switch(field->key_type()) {
3681
case HA_KEYTYPE_BINARY:
3682
max_value = 0xFFULL;
3685
case HA_KEYTYPE_UINT24:
3686
max_value = 0xFFFFFFULL;
3689
case HA_KEYTYPE_ULONG_INT:
3690
max_value = 0xFFFFFFFFULL;
3692
case HA_KEYTYPE_LONG_INT:
3693
max_value = 0x7FFFFFFFULL;
3696
case HA_KEYTYPE_ULONGLONG:
3697
max_value = 0xFFFFFFFFFFFFFFFFULL;
3699
case HA_KEYTYPE_LONGLONG:
3700
max_value = 0x7FFFFFFFFFFFFFFFULL;
3702
case HA_KEYTYPE_DOUBLE:
3703
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
3704
max_value = 0x20000000000000ULL;
3713
/********************************************************************//**
3714
This special handling is really to overcome the limitations of MySQL's
3715
binlogging. We need to eliminate the non-determinism that will arise in
3716
INSERT ... SELECT type of statements, since MySQL binlog only stores the
3717
min value of the autoinc interval. Once that is fixed we can get rid of
3718
the special lock handling.
3719
@return DB_SUCCESS if all OK else error code */
3722
ha_innobase::innobase_lock_autoinc(void)
3723
/*====================================*/
3725
ulint error = DB_SUCCESS;
3727
switch (innobase_autoinc_lock_mode) {
3728
case AUTOINC_NO_LOCKING:
3729
/* Acquire only the AUTOINC mutex. */
3730
dict_table_autoinc_lock(prebuilt->table);
3733
case AUTOINC_NEW_STYLE_LOCKING:
3734
/* For simple (single/multi) row INSERTs, we fallback to the
3735
old style only if another transaction has already acquired
3736
the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
3737
etc. type of statement. */
3738
if (session_sql_command(user_session) == SQLCOM_INSERT
3739
|| session_sql_command(user_session) == SQLCOM_REPLACE) {
3740
dict_table_t* d_table = prebuilt->table;
3742
/* Acquire the AUTOINC mutex. */
3743
dict_table_autoinc_lock(d_table);
3745
/* We need to check that another transaction isn't
3746
already holding the AUTOINC lock on the table. */
3747
if (d_table->n_waiting_or_granted_auto_inc_locks) {
3748
/* Release the mutex to avoid deadlocks. */
3749
dict_table_autoinc_unlock(d_table);
3754
/* Fall through to old style locking. */
3756
case AUTOINC_OLD_STYLE_LOCKING:
3757
error = row_lock_table_autoinc_for_mysql(prebuilt);
3759
if (error == DB_SUCCESS) {
3761
/* Acquire the AUTOINC mutex. */
3762
dict_table_autoinc_lock(prebuilt->table);
3770
return(ulong(error));
3773
/********************************************************************//**
3774
Reset the autoinc value in the table.
3775
@return DB_SUCCESS if all went well else error code */
3778
ha_innobase::innobase_reset_autoinc(
3779
/*================================*/
3780
uint64_t autoinc) /*!< in: value to store */
3784
error = innobase_lock_autoinc();
3786
if (error == DB_SUCCESS) {
3788
dict_table_autoinc_initialize(prebuilt->table, autoinc);
3790
dict_table_autoinc_unlock(prebuilt->table);
3793
return(ulong(error));
3796
/********************************************************************//**
3797
Store the autoinc value in the table. The autoinc value is only set if
3798
it's greater than the existing autoinc value in the table.
3799
@return DB_SUCCESS if all went well else error code */
3802
ha_innobase::innobase_set_max_autoinc(
3803
/*==================================*/
3804
uint64_t auto_inc) /*!< in: value to store */
3808
error = innobase_lock_autoinc();
3810
if (error == DB_SUCCESS) {
3812
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
3814
dict_table_autoinc_unlock(prebuilt->table);
3817
return(ulong(error));
3820
/********************************************************************//**
3821
Stores a row in an InnoDB database, to the table specified in this
3823
@return error code */
3826
ha_innobase::write_row(
3827
/*===================*/
3828
unsigned char* record) /*!< in: a row in MySQL format */
3831
int error_result= 0;
3832
ibool auto_inc_used= FALSE;
3834
trx_t* trx = session_to_trx(user_session);
3836
if (prebuilt->trx != trx) {
3837
errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
3838
"%p, but for the current thread it is at %p",
3839
(const void*) prebuilt->trx, (const void*) trx);
3841
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
3842
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
3844
"InnoDB: Dump of 200 bytes around ha_data: ",
3846
ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
3851
ha_statistic_increment(&system_status_var::ha_write_count);
3853
sql_command = session_sql_command(user_session);
3855
if ((sql_command == SQLCOM_ALTER_TABLE
3856
|| sql_command == SQLCOM_CREATE_INDEX
3857
|| sql_command == SQLCOM_DROP_INDEX)
3858
&& num_write_row >= 10000) {
3859
/* ALTER TABLE is COMMITted at every 10000 copied rows.
3860
The IX table lock for the original table has to be re-issued.
3861
As this method will be called on a temporary table where the
3862
contents of the original table is being copied to, it is
3863
a bit tricky to determine the source table. The cursor
3864
position in the source table need not be adjusted after the
3865
intermediate COMMIT, since writes by other transactions are
3866
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
3868
dict_table_t* src_table;
3869
enum lock_mode mode;
3873
/* Commit the transaction. This will release the table
3874
locks, so they have to be acquired again. */
3876
/* Altering an InnoDB table */
3877
/* Get the source table. */
3878
src_table = lock_get_src_table(
3879
prebuilt->trx, prebuilt->table, &mode);
3882
/* Unknown situation: do not commit */
3884
ut_print_timestamp(stderr);
3886
" InnoDB: ALTER TABLE is holding lock"
3887
" on %lu tables!\n",
3888
prebuilt->trx->mysql_n_tables_locked);
3891
} else if (src_table == prebuilt->table) {
3892
/* Source table is not in InnoDB format:
3893
no need to re-acquire locks on it. */
3895
/* Altering to InnoDB format */
3896
getTransactionalEngine()->commit(user_session, 1);
3897
/* We will need an IX lock on the destination table. */
3898
prebuilt->sql_stat_start = TRUE;
3900
/* Ensure that there are no other table locks than
3901
LOCK_IX and LOCK_AUTO_INC on the destination table. */
3903
if (!lock_is_table_exclusive(prebuilt->table,
3908
/* Commit the transaction. This will release the table
3909
locks, so they have to be acquired again. */
3910
getTransactionalEngine()->commit(user_session, 1);
3911
/* Re-acquire the table lock on the source table. */
3912
row_lock_table_for_mysql(prebuilt, src_table, mode);
3913
/* We will need an IX lock on the destination table. */
3914
prebuilt->sql_stat_start = TRUE;
3920
/* This is the case where the table has an auto-increment column */
3921
if (table->next_number_field && record == table->record[0]) {
3923
/* Reset the error code before calling
3924
innobase_get_auto_increment(). */
3925
prebuilt->autoinc_error = DB_SUCCESS;
3927
if ((error = update_auto_increment())) {
3929
/* We don't want to mask autoinc overflow errors. */
3930
if (prebuilt->autoinc_error != DB_SUCCESS) {
3931
error = (int) prebuilt->autoinc_error;
3936
/* MySQL errors are passed straight back. */
3937
error_result = (int) error;
3941
auto_inc_used = TRUE;
3944
if (prebuilt->mysql_template == NULL
3945
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
3947
/* Build the template used in converting quickly between
3948
the two database formats */
3950
build_template(prebuilt, NULL, table,
3951
ROW_MYSQL_WHOLE_ROW);
3954
innodb_srv_conc_enter_innodb(prebuilt->trx);
3956
error = row_insert_for_mysql((byte*) record, prebuilt);
3958
/* Handle duplicate key errors */
3959
if (auto_inc_used) {
3962
uint64_t col_max_value;
3964
/* Note the number of rows processed for this statement, used
3965
by get_auto_increment() to determine the number of AUTO-INC
3966
values to reserve. This is only useful for a mult-value INSERT
3967
and is a statement level counter.*/
3968
if (trx->n_autoinc_rows > 0) {
3969
--trx->n_autoinc_rows;
3972
/* We need the upper limit of the col type to check for
3973
whether we update the table autoinc counter or not. */
3974
col_max_value = innobase_get_int_col_max_value(
3975
table->next_number_field);
3977
/* Get the value that MySQL attempted to store in the table.*/
3978
auto_inc = table->next_number_field->val_int();
3981
case DB_DUPLICATE_KEY:
3983
/* A REPLACE command and LOAD DATA INFILE REPLACE
3984
handle a duplicate key error themselves, but we
3985
must update the autoinc counter if we are performing
3986
those statements. */
3988
switch (sql_command) {
3990
if ((trx->duplicates
3991
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
3993
goto set_max_autoinc;
3997
case SQLCOM_REPLACE:
3998
case SQLCOM_INSERT_SELECT:
3999
case SQLCOM_REPLACE_SELECT:
4000
goto set_max_autoinc;
4009
/* If the actual value inserted is greater than
4010
the upper limit of the interval, then we try and
4011
update the table upper limit. Note: last_value
4012
will be 0 if get_auto_increment() was not called.*/
4014
if (auto_inc <= col_max_value
4015
&& auto_inc >= prebuilt->autoinc_last_value) {
4017
ut_a(prebuilt->autoinc_increment > 0);
4022
offset = prebuilt->autoinc_offset;
4023
need = prebuilt->autoinc_increment;
4025
auto_inc = innobase_next_autoinc(
4026
auto_inc, need, offset, col_max_value);
4028
err = innobase_set_max_autoinc(auto_inc);
4030
if (err != DB_SUCCESS) {
4038
innodb_srv_conc_exit_innodb(prebuilt->trx);
4041
error_result = convert_error_code_to_mysql((int) error,
4042
prebuilt->table->flags,
4046
innobase_active_small();
4048
return(error_result);
4051
/**********************************************************************//**
4052
Checks which fields have changed in a row and stores information
4053
of them to an update vector.
4054
@return error number or 0 */
4057
calc_row_difference(
4058
/*================*/
4059
upd_t* uvect, /*!< in/out: update vector */
4060
unsigned char* old_row, /*!< in: old row in MySQL format */
4061
unsigned char* new_row, /*!< in: new row in MySQL format */
4062
Table* table, /*!< in: table in MySQL data
4064
unsigned char* upd_buff, /*!< in: buffer to use */
4065
ulint buff_len, /*!< in: buffer length */
4066
row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
4067
Session* ) /*!< in: user thread */
4069
unsigned char* original_upd_buff = upd_buff;
4071
enum_field_types field_mysql_type;
4076
const byte* new_mysql_row_col;
4080
upd_field_t* ufield;
4082
ulint n_changed = 0;
4084
dict_index_t* clust_index;
4087
n_fields = table->s->fields;
4088
clust_index = dict_table_get_first_index(prebuilt->table);
4090
/* We use upd_buff to convert changed fields */
4091
buf = (byte*) upd_buff;
4093
for (i = 0; i < n_fields; i++) {
4094
field = table->field[i];
4096
o_ptr = (const byte*) old_row + get_field_offset(table, field);
4097
n_ptr = (const byte*) new_row + get_field_offset(table, field);
4099
/* Use new_mysql_row_col and col_pack_len save the values */
4101
new_mysql_row_col = n_ptr;
4102
col_pack_len = field->pack_length();
4104
o_len = col_pack_len;
4105
n_len = col_pack_len;
4107
/* We use o_ptr and n_ptr to dig up the actual data for
4110
field_mysql_type = field->type();
4112
col_type = prebuilt->table->cols[i].mtype;
4117
o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4118
n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4125
if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4126
/* This is a >= 5.0.3 type true VARCHAR where
4127
the real payload data length is stored in
4130
o_ptr = row_mysql_read_true_varchar(
4133
(((Field_varstring*)field)->length_bytes));
4135
n_ptr = row_mysql_read_true_varchar(
4138
(((Field_varstring*)field)->length_bytes));
4146
if (field->null_ptr) {
4147
if (field_in_record_is_null(table, field,
4149
o_len = UNIV_SQL_NULL;
4152
if (field_in_record_is_null(table, field,
4154
n_len = UNIV_SQL_NULL;
4158
if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4159
0 != memcmp(o_ptr, n_ptr, o_len))) {
4160
/* The field has changed */
4162
ufield = uvect->fields + n_changed;
4164
/* Let us use a dummy dfield to make the conversion
4165
from the MySQL column format to the InnoDB format */
4167
dict_col_copy_type(prebuilt->table->cols + i,
4170
if (n_len != UNIV_SQL_NULL) {
4171
buf = row_mysql_store_col_in_innobase_format(
4177
dict_table_is_comp(prebuilt->table));
4178
dfield_copy_data(&ufield->new_val, &dfield);
4180
dfield_set_null(&ufield->new_val);
4184
ufield->orig_len = 0;
4185
ufield->field_no = dict_col_get_clust_pos(
4186
&prebuilt->table->cols[i], clust_index);
4191
uvect->n_fields = n_changed;
4192
uvect->info_bits = 0;
4194
ut_a(buf <= (byte*)original_upd_buff + buff_len);
4199
/**********************************************************************//**
4200
Updates a row given as a parameter to a new value. Note that we are given
4201
whole rows, not just the fields which are updated: this incurs some
4202
overhead for CPU when we check which fields are actually updated.
4203
TODO: currently InnoDB does not prevent the 'Halloween problem':
4204
in a searched update a single row can get updated several times
4205
if its index columns are updated!
4206
@return error number or 0 */
4209
ha_innobase::update_row(
4210
/*====================*/
4211
const unsigned char* old_row,/*!< in: old row in MySQL format */
4212
unsigned char* new_row)/*!< in: new row in MySQL format */
4216
trx_t* trx = session_to_trx(user_session);
4218
ut_a(prebuilt->trx == trx);
4220
ha_statistic_increment(&system_status_var::ha_update_count);
4222
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
4223
table->timestamp_field->set_time();
4225
if (prebuilt->upd_node) {
4226
uvect = prebuilt->upd_node->update;
4228
uvect = row_get_prebuilt_update_vector(prebuilt);
4231
/* Build an update vector from the modified fields in the rows
4232
(uses upd_buff of the handle) */
4234
calc_row_difference(uvect, (unsigned char*) old_row, new_row, table,
4235
upd_buff, (ulint)upd_and_key_val_buff_len,
4236
prebuilt, user_session);
4238
/* This is not a delete */
4239
prebuilt->upd_node->is_delete = FALSE;
4241
ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4243
innodb_srv_conc_enter_innodb(trx);
4245
error = row_update_for_mysql((byte*) old_row, prebuilt);
4247
/* We need to do some special AUTOINC handling for the following case:
4249
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4251
We need to use the AUTOINC counter that was actually used by
4252
MySQL in the UPDATE statement, which can be different from the
4253
value used in the INSERT statement.*/
4255
if (error == DB_SUCCESS
4256
&& table->next_number_field
4257
&& new_row == table->record[0]
4258
&& session_sql_command(user_session) == SQLCOM_INSERT
4259
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
4260
== TRX_DUP_IGNORE) {
4263
uint64_t col_max_value;
4265
auto_inc = table->next_number_field->val_int();
4267
/* We need the upper limit of the col type to check for
4268
whether we update the table autoinc counter or not. */
4269
col_max_value = innobase_get_int_col_max_value(
4270
table->next_number_field);
4272
if (auto_inc <= col_max_value && auto_inc != 0) {
4277
offset = prebuilt->autoinc_offset;
4278
need = prebuilt->autoinc_increment;
4280
auto_inc = innobase_next_autoinc(
4281
auto_inc, need, offset, col_max_value);
4283
error = innobase_set_max_autoinc(auto_inc);
4287
innodb_srv_conc_exit_innodb(trx);
4289
error = convert_error_code_to_mysql(error,
4290
prebuilt->table->flags,
4293
if (error == 0 /* success */
4294
&& uvect->n_fields == 0 /* no columns were updated */) {
4296
/* This is the same as success, but instructs
4297
MySQL that the row is not really updated and it
4298
should not increase the count of updated rows.
4299
This is fix for http://bugs.mysql.com/29157 */
4300
error = HA_ERR_RECORD_IS_THE_SAME;
4303
/* Tell InnoDB server that there might be work for
4306
innobase_active_small();
4311
/**********************************************************************//**
4312
Deletes a row given as the parameter.
4313
@return error number or 0 */
4316
ha_innobase::delete_row(
4317
/*====================*/
4318
const unsigned char* record) /*!< in: a row in MySQL format */
4321
trx_t* trx = session_to_trx(user_session);
4323
ut_a(prebuilt->trx == trx);
4325
ha_statistic_increment(&system_status_var::ha_delete_count);
4327
if (!prebuilt->upd_node) {
4328
row_get_prebuilt_update_vector(prebuilt);
4331
/* This is a delete */
4333
prebuilt->upd_node->is_delete = TRUE;
4335
innodb_srv_conc_enter_innodb(trx);
4337
error = row_update_for_mysql((byte*) record, prebuilt);
4339
innodb_srv_conc_exit_innodb(trx);
4341
error = convert_error_code_to_mysql(
4342
error, prebuilt->table->flags, user_session);
4344
/* Tell the InnoDB server that there might be work for
4347
innobase_active_small();
4352
/**********************************************************************//**
4353
Removes a new lock set on a row, if it was not read optimistically. This can
4354
be called after a row has been read in the processing of an UPDATE or a DELETE
4355
query, if the option innodb_locks_unsafe_for_binlog is set. */
4358
ha_innobase::unlock_row(void)
4359
/*=========================*/
4361
/* Consistent read does not take any locks, thus there is
4362
nothing to unlock. */
4364
if (prebuilt->select_lock_type == LOCK_NONE) {
4368
switch (prebuilt->row_read_type) {
4369
case ROW_READ_WITH_LOCKS:
4370
if (!srv_locks_unsafe_for_binlog
4371
&& prebuilt->trx->isolation_level
4372
!= TRX_ISO_READ_COMMITTED) {
4376
case ROW_READ_TRY_SEMI_CONSISTENT:
4377
row_unlock_for_mysql(prebuilt, FALSE);
4379
case ROW_READ_DID_SEMI_CONSISTENT:
4380
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4387
/* See Cursor.h and row0mysql.h for docs on this function. */
4390
ha_innobase::was_semi_consistent_read(void)
4391
/*=======================================*/
4393
return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
4396
/* See Cursor.h and row0mysql.h for docs on this function. */
4399
ha_innobase::try_semi_consistent_read(bool yes)
4400
/*===========================================*/
4402
ut_a(prebuilt->trx == session_to_trx(ha_session()));
4404
/* Row read type is set to semi consistent read if this was
4405
requested by the MySQL and either innodb_locks_unsafe_for_binlog
4406
option is used or this session is using READ COMMITTED isolation
4410
&& (srv_locks_unsafe_for_binlog
4411
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
4412
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4414
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
4418
/******************************************************************//**
4419
Initializes a handle to use an index.
4420
@return 0 or error number */
4423
ha_innobase::index_init(
4424
/*====================*/
4425
uint keynr, /*!< in: key (index) number */
4426
bool ) /*!< in: 1 if result MUST be sorted according to index */
4428
return(change_active_index(keynr));
4431
/******************************************************************//**
4432
Currently does nothing.
4436
ha_innobase::index_end(void)
4437
/*========================*/
4440
active_index=MAX_KEY;
4444
/*********************************************************************//**
4445
Converts a search mode flag understood by MySQL to a flag understood
4449
convert_search_mode_to_innobase(
4450
/*============================*/
4451
enum ha_rkey_function find_flag)
4453
switch (find_flag) {
4454
case HA_READ_KEY_EXACT:
4455
/* this does not require the index to be UNIQUE */
4456
return(PAGE_CUR_GE);
4457
case HA_READ_KEY_OR_NEXT:
4458
return(PAGE_CUR_GE);
4459
case HA_READ_KEY_OR_PREV:
4460
return(PAGE_CUR_LE);
4461
case HA_READ_AFTER_KEY:
4463
case HA_READ_BEFORE_KEY:
4465
case HA_READ_PREFIX:
4466
return(PAGE_CUR_GE);
4467
case HA_READ_PREFIX_LAST:
4468
return(PAGE_CUR_LE);
4469
case HA_READ_PREFIX_LAST_OR_PREV:
4470
return(PAGE_CUR_LE);
4471
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
4472
pass a complete-field prefix of a key value as the search
4473
tuple. I.e., it is not allowed that the last field would
4474
just contain n first bytes of the full field value.
4475
MySQL uses a 'padding' trick to convert LIKE 'abc%'
4476
type queries so that it can use as a search tuple
4477
a complete-field-prefix of a key value. Thus, the InnoDB
4478
search mode PAGE_CUR_LE_OR_EXTENDS is never used.
4479
TODO: when/if MySQL starts to use also partial-field
4480
prefixes, we have to deal with stripping of spaces
4481
and comparison of non-latin1 char type fields in
4482
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
4484
case HA_READ_MBR_CONTAIN:
4485
case HA_READ_MBR_INTERSECT:
4486
case HA_READ_MBR_WITHIN:
4487
case HA_READ_MBR_DISJOINT:
4488
case HA_READ_MBR_EQUAL:
4489
return(PAGE_CUR_UNSUPP);
4490
/* do not use "default:" in order to produce a gcc warning:
4491
enumeration value '...' not handled in switch
4492
(if -Wswitch or -Wall is used) */
4495
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
4497
return(PAGE_CUR_UNSUPP);
4501
BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
4502
---------------------------------------------------
4503
The following does not cover all the details, but explains how we determine
4504
the start of a new SQL statement, and what is associated with it.
4506
For each table in the database the MySQL interpreter may have several
4507
table handle instances in use, also in a single SQL query. For each table
4508
handle instance there is an InnoDB 'prebuilt' struct which contains most
4509
of the InnoDB data associated with this table handle instance.
4511
A) if the user has not explicitly set any MySQL table level locks:
4513
1) Drizzle calls StorageEngine::doStartStatement(), indicating to
4514
InnoDB that a new SQL statement has begun.
4516
2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
4517
to set an 'intention' table level lock on the table of the Cursor instance.
4518
There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should
4519
be set true if we are taking this table handle instance to use in a new SQL
4520
statement issued by the user.
4522
2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
4523
instructions to prebuilt->template of the table handle instance in
4524
::index_read. The template is used to save CPU time in large joins.
4526
3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
4527
allocate a new consistent read view for the trx if it does not yet have one,
4528
or in the case of a locking read, set an InnoDB 'intention' table level
4531
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
4532
same table handle instance, if it is a join.
4534
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
4536
(a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter
4537
does NOT execute autocommit for pure read transactions, though it should.
4538
That is why we must execute the COMMIT in ::doEndStatement().
4539
(b) we also release possible 'SQL statement level resources' InnoDB may
4540
have for this SQL statement.
4544
Remove need for InnoDB to call autocommit for read-only trx
4546
@todo Check the below is still valid (I don't think it is...)
4548
B) If the user has explicitly set MySQL table level locks, then MySQL
4549
does NOT call ::external_lock at the start of the statement. To determine
4550
when we are at the start of a new SQL statement we at the start of
4551
::index_read also compare the query id to the latest query id where the
4552
table handle instance was used. If it has changed, we know we are at the
4553
start of a new SQL statement. Since the query id can theoretically
4554
overwrap, we use this test only as a secondary way of determining the
4555
start of a new SQL statement. */
4558
/**********************************************************************//**
4559
Positions an index cursor to the index specified in the handle. Fetches the
4561
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
4564
ha_innobase::index_read(
4565
/*====================*/
4566
unsigned char* buf, /*!< in/out: buffer for the returned
4568
const unsigned char* key_ptr,/*!< in: key value; if this is NULL
4569
we position the cursor at the
4570
start or end of index; this can
4571
also contain an InnoDB row id, in
4572
which case key_len is the InnoDB
4573
row id length; the key value can
4574
also be a prefix of a full key value,
4575
and the last column can be a prefix
4577
uint key_len,/*!< in: key value length */
4578
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4581
dict_index_t* index;
4582
ulint match_mode = 0;
4586
ut_a(prebuilt->trx == session_to_trx(user_session));
4588
ha_statistic_increment(&system_status_var::ha_read_key_count);
4590
index = prebuilt->index;
4592
/* Note that if the index for which the search template is built is not
4593
necessarily prebuilt->index, but can also be the clustered index */
4595
if (prebuilt->sql_stat_start) {
4596
build_template(prebuilt, user_session, table,
4597
ROW_MYSQL_REC_FIELDS);
4601
/* Convert the search key value to InnoDB format into
4602
prebuilt->search_tuple */
4604
row_sel_convert_mysql_key_to_innobase(
4605
prebuilt->search_tuple,
4606
(byte*) key_val_buff,
4607
(ulint)upd_and_key_val_buff_len,
4613
/* We position the cursor to the last or the first entry
4616
dtuple_set_n_fields(prebuilt->search_tuple, 0);
4619
mode = convert_search_mode_to_innobase(find_flag);
4623
if (find_flag == HA_READ_KEY_EXACT) {
4625
match_mode = ROW_SEL_EXACT;
4627
} else if (find_flag == HA_READ_PREFIX
4628
|| find_flag == HA_READ_PREFIX_LAST) {
4630
match_mode = ROW_SEL_EXACT_PREFIX;
4633
last_match_mode = (uint) match_mode;
4635
if (mode != PAGE_CUR_UNSUPP) {
4637
innodb_srv_conc_enter_innodb(prebuilt->trx);
4639
ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
4642
innodb_srv_conc_exit_innodb(prebuilt->trx);
4645
ret = DB_UNSUPPORTED;
4653
case DB_RECORD_NOT_FOUND:
4654
error = HA_ERR_KEY_NOT_FOUND;
4655
table->status = STATUS_NOT_FOUND;
4657
case DB_END_OF_INDEX:
4658
error = HA_ERR_KEY_NOT_FOUND;
4659
table->status = STATUS_NOT_FOUND;
4662
error = convert_error_code_to_mysql((int) ret,
4663
prebuilt->table->flags,
4665
table->status = STATUS_NOT_FOUND;
4672
/*******************************************************************//**
4673
The following functions works like index_read, but it find the last
4674
row with the current key value or prefix.
4675
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
4678
ha_innobase::index_read_last(
4679
/*=========================*/
4680
unsigned char* buf, /*!< out: fetched row */
4681
const unsigned char* key_ptr,/*!< in: key value, or a prefix of a full
4683
uint key_len)/*!< in: length of the key val or prefix
4686
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
4689
/********************************************************************//**
4690
Get the index for a handle. Does not change active index.
4691
@return NULL or index instance. */
4694
ha_innobase::innobase_get_index(
4695
/*============================*/
4696
uint keynr) /*!< in: use this index; MAX_KEY means always
4697
clustered index, even if it was internally
4698
generated by InnoDB */
4701
dict_index_t* index = 0;
4703
ha_statistic_increment(&system_status_var::ha_read_key_count);
4705
ut_ad(user_session == ha_session());
4706
ut_a(prebuilt->trx == session_to_trx(user_session));
4708
if (keynr != MAX_KEY && table->s->keys > 0) {
4709
key = table->key_info + keynr;
4711
index = dict_table_get_index_on_name(prebuilt->table,
4714
index = dict_table_get_first_index(prebuilt->table);
4718
errmsg_printf(ERRMSG_LVL_ERROR,
4719
"Innodb could not find key n:o %u with name %s "
4720
"from dict cache for table %s",
4721
keynr, key ? key->name : "NULL",
4722
prebuilt->table->name);
4728
/********************************************************************//**
4729
Changes the active index of a handle.
4730
@return 0 or error code */
4733
ha_innobase::change_active_index(
4734
/*=============================*/
4735
uint keynr) /*!< in: use this index; MAX_KEY means always clustered
4736
index, even if it was internally generated by
4739
ut_ad(user_session == ha_session());
4740
ut_a(prebuilt->trx == session_to_trx(user_session));
4742
active_index = keynr;
4744
prebuilt->index = innobase_get_index(keynr);
4746
if (UNIV_UNLIKELY(!prebuilt->index)) {
4747
errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
4752
prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
4755
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
4756
errmsg_printf(ERRMSG_LVL_WARN,
4757
"InnoDB: insufficient history for index %u",
4759
/* The caller seems to ignore this. Thus, we must check
4760
this again in row_search_for_mysql(). */
4764
ut_a(prebuilt->search_tuple != 0);
4766
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
4768
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
4769
prebuilt->index->n_fields);
4771
/* MySQL changes the active index for a handle also during some
4772
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
4773
and then calculates the sum. Previously we played safe and used
4774
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
4775
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
4777
build_template(prebuilt, user_session, table, ROW_MYSQL_REC_FIELDS);
4782
/**********************************************************************//**
4783
Positions an index cursor to the index specified in keynr. Fetches the
4785
??? This is only used to read whole keys ???
4786
@return error number or 0 */
4789
ha_innobase::index_read_idx(
4790
/*========================*/
4791
unsigned char* buf, /*!< in/out: buffer for the returned
4793
uint keynr, /*!< in: use this index */
4794
const unsigned char* key, /*!< in: key value; if this is NULL
4795
we position the cursor at the
4796
start or end of index */
4797
uint key_len, /*!< in: key value length */
4798
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4800
if (change_active_index(keynr)) {
4805
return(index_read(buf, key, key_len, find_flag));
4808
/***********************************************************************//**
4809
Reads the next or previous row from a cursor, which must have previously been
4810
positioned using index_read.
4811
@return 0, HA_ERR_END_OF_FILE, or error number */
4814
ha_innobase::general_fetch(
4815
/*=======================*/
4816
unsigned char* buf, /*!< in/out: buffer for next row in MySQL
4818
uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
4819
uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
4820
ROW_SEL_EXACT_PREFIX */
4825
ut_a(prebuilt->trx == session_to_trx(user_session));
4827
innodb_srv_conc_enter_innodb(prebuilt->trx);
4829
ret = row_search_for_mysql(
4830
(byte*)buf, 0, prebuilt, match_mode, direction);
4832
innodb_srv_conc_exit_innodb(prebuilt->trx);
4839
case DB_RECORD_NOT_FOUND:
4840
error = HA_ERR_END_OF_FILE;
4841
table->status = STATUS_NOT_FOUND;
4843
case DB_END_OF_INDEX:
4844
error = HA_ERR_END_OF_FILE;
4845
table->status = STATUS_NOT_FOUND;
4848
error = convert_error_code_to_mysql(
4849
(int) ret, prebuilt->table->flags, user_session);
4850
table->status = STATUS_NOT_FOUND;
4857
/***********************************************************************//**
4858
Reads the next row from a cursor, which must have previously been
4859
positioned using index_read.
4860
@return 0, HA_ERR_END_OF_FILE, or error number */
4863
ha_innobase::index_next(
4864
/*====================*/
4865
unsigned char* buf) /*!< in/out: buffer for next row in MySQL
4868
ha_statistic_increment(&system_status_var::ha_read_next_count);
4870
return(general_fetch(buf, ROW_SEL_NEXT, 0));
4873
/*******************************************************************//**
4874
Reads the next row matching to the key value given as the parameter.
4875
@return 0, HA_ERR_END_OF_FILE, or error number */
4878
ha_innobase::index_next_same(
4879
/*=========================*/
4880
unsigned char* buf, /*!< in/out: buffer for the row */
4881
const unsigned char* , /*!< in: key value */
4882
uint ) /*!< in: key value length */
4884
ha_statistic_increment(&system_status_var::ha_read_next_count);
4886
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
4889
/***********************************************************************//**
4890
Reads the previous row from a cursor, which must have previously been
4891
positioned using index_read.
4892
@return 0, HA_ERR_END_OF_FILE, or error number */
4895
ha_innobase::index_prev(
4896
/*====================*/
4897
unsigned char* buf) /*!< in/out: buffer for previous row in MySQL format */
4899
ha_statistic_increment(&system_status_var::ha_read_prev_count);
4901
return(general_fetch(buf, ROW_SEL_PREV, 0));
4904
/********************************************************************//**
4905
Positions a cursor on the first record in an index and reads the
4906
corresponding row to buf.
4907
@return 0, HA_ERR_END_OF_FILE, or error code */
4910
ha_innobase::index_first(
4911
/*=====================*/
4912
unsigned char* buf) /*!< in/out: buffer for the row */
4916
ha_statistic_increment(&system_status_var::ha_read_first_count);
4918
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
4920
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4922
if (error == HA_ERR_KEY_NOT_FOUND) {
4923
error = HA_ERR_END_OF_FILE;
4929
/********************************************************************//**
4930
Positions a cursor on the last record in an index and reads the
4931
corresponding row to buf.
4932
@return 0, HA_ERR_END_OF_FILE, or error code */
4935
ha_innobase::index_last(
4936
/*====================*/
4937
unsigned char* buf) /*!< in/out: buffer for the row */
4941
ha_statistic_increment(&system_status_var::ha_read_last_count);
4943
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
4945
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4947
if (error == HA_ERR_KEY_NOT_FOUND) {
4948
error = HA_ERR_END_OF_FILE;
4954
/****************************************************************//**
4955
Initialize a table scan.
4956
@return 0 or error number */
4959
ha_innobase::rnd_init(
4960
/*==================*/
4961
bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
4965
/* Store the active index value so that we can restore the original
4966
value after a scan */
4968
if (prebuilt->clust_index_was_generated) {
4969
err = change_active_index(MAX_KEY);
4971
err = change_active_index(primary_key);
4974
/* Don't use semi-consistent read in random row reads (by position).
4975
This means we must disable semi_consistent_read if scan is false */
4978
try_semi_consistent_read(0);
4986
/*****************************************************************//**
4988
@return 0 or error number */
4991
ha_innobase::rnd_end(void)
4992
/*======================*/
4994
return(index_end());
4997
/*****************************************************************//**
4998
Reads the next row in a table scan (also used to read the FIRST row
5000
@return 0, HA_ERR_END_OF_FILE, or error number */
5003
ha_innobase::rnd_next(
5004
/*==================*/
5005
unsigned char* buf) /*!< in/out: returns the row in this buffer,
5010
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
5012
if (start_of_scan) {
5013
error = index_first(buf);
5015
if (error == HA_ERR_KEY_NOT_FOUND) {
5016
error = HA_ERR_END_OF_FILE;
5021
error = general_fetch(buf, ROW_SEL_NEXT, 0);
5027
/**********************************************************************//**
5028
Fetches a row from the table based on a row reference.
5029
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
5032
ha_innobase::rnd_pos(
5033
/*=================*/
5034
unsigned char* buf, /*!< in/out: buffer for the row */
5035
unsigned char* pos) /*!< in: primary key value of the row in the
5036
MySQL format, or the row id if the clustered
5037
index was internally generated by InnoDB; the
5038
length of data in pos has to be ref_length */
5041
uint keynr = active_index;
5043
ha_statistic_increment(&system_status_var::ha_read_rnd_count);
5045
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5047
if (prebuilt->clust_index_was_generated) {
5048
/* No primary key was defined for the table and we
5049
generated the clustered index from the row id: the
5050
row reference is the row id, not any key value
5051
that MySQL knows of */
5053
error = change_active_index(MAX_KEY);
5055
error = change_active_index(primary_key);
5062
/* Note that we assume the length of the row reference is fixed
5063
for the table, and it is == ref_length */
5065
error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5070
change_active_index(keynr);
5075
/*********************************************************************//**
5076
Stores a reference to the current row to 'ref' field of the handle. Note
5077
that in the case where we have generated the clustered index for the
5078
table, the function parameter is illogical: we MUST ASSUME that 'record'
5079
is the current 'position' of the handle, because if row ref is actually
5080
the row id internally generated in InnoDB, then 'record' does not contain
5081
it. We just guess that the row id must be for the record where the handle
5082
was positioned the last time. */
5085
ha_innobase::position(
5086
/*==================*/
5087
const unsigned char* record) /*!< in: row in MySQL format */
5091
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5093
if (prebuilt->clust_index_was_generated) {
5094
/* No primary key was defined for the table and we
5095
generated the clustered index from row id: the
5096
row reference will be the row id, not any key value
5097
that MySQL knows of */
5099
len = DATA_ROW_ID_LEN;
5101
memcpy(ref, prebuilt->row_id, len);
5103
len = store_key_val_for_row(primary_key, (char*)ref,
5104
ref_length, record);
5107
/* We assume that the 'ref' value len is always fixed for the same
5110
if (len != ref_length) {
5111
errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
5112
(ulong) len, (ulong) ref_length);
5117
/*****************************************************************//**
5118
Creates a table definition to an InnoDB database. */
5123
trx_t* trx, /*!< in: InnoDB transaction handle */
5124
Table* form, /*!< in: information on table
5125
columns and indexes */
5126
const char* table_name, /*!< in: table name */
5127
const char* path_of_temp_table,/*!< in: if this is a table explicitly
5128
created by the user with the
5129
TEMPORARY keyword, then this
5130
parameter is the dir path where the
5131
table should be placed if we create
5132
an .ibd file for it (no .ibd extension
5133
in the path, though); otherwise this
5135
ulint flags) /*!< in: table flags */
5138
dict_table_t* table;
5143
ulint nulls_allowed;
5144
ulint unsigned_type;
5146
ulint long_true_varchar;
5150
n_cols = form->s->fields;
5152
/* We pass 0 as the space id, and determine at a lower level the space
5153
id where to store the table */
5155
table = dict_mem_table_create(table_name, 0, n_cols, flags);
5157
if (path_of_temp_table) {
5158
table->dir_path_of_temp_table =
5159
mem_heap_strdup(table->heap, path_of_temp_table);
5162
for (i = 0; i < n_cols; i++) {
5163
field = form->field[i];
5165
col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5167
if (field->null_ptr) {
5170
nulls_allowed = DATA_NOT_NULL;
5173
if (field->binary()) {
5174
binary_type = DATA_BINARY_TYPE;
5181
if (dtype_is_string_type(col_type)) {
5183
charset_no = (ulint)field->charset()->number;
5185
if (UNIV_UNLIKELY(charset_no >= 256)) {
5186
/* in data0type.h we assume that the
5187
number fits in one byte in prtype */
5188
push_warning_printf(
5189
(Session*) trx->mysql_thd,
5190
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5191
ER_CANT_CREATE_TABLE,
5192
"In InnoDB, charset-collation codes"
5193
" must be below 256."
5194
" Unsupported code %lu.",
5195
(ulong) charset_no);
5196
return(ER_CANT_CREATE_TABLE);
5200
ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5201
that this fits in one byte */
5202
col_len = field->pack_length();
5204
/* The MySQL pack length contains 1 or 2 bytes length field
5205
for a true VARCHAR. Let us subtract that, so that the InnoDB
5206
column length in the InnoDB data dictionary is the real
5207
maximum byte length of the actual data. */
5209
long_true_varchar = 0;
5211
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5212
col_len -= ((Field_varstring*)field)->length_bytes;
5214
if (((Field_varstring*)field)->length_bytes == 2) {
5215
long_true_varchar = DATA_LONG_TRUE_VARCHAR;
5219
dict_mem_table_add_col(table, table->heap,
5220
(char*) field->field_name,
5223
(ulint)field->type()
5224
| nulls_allowed | unsigned_type
5225
| binary_type | long_true_varchar,
5230
error = row_create_table_for_mysql(table, trx);
5232
error = convert_error_code_to_mysql(error, flags, NULL);
5237
/*****************************************************************//**
5238
Creates an index in an InnoDB database. */
5243
trx_t* trx, /*!< in: InnoDB transaction handle */
5244
Table* form, /*!< in: information on table
5245
columns and indexes */
5246
ulint flags, /*!< in: InnoDB table flags */
5247
const char* table_name, /*!< in: table name */
5248
uint key_num) /*!< in: index number */
5251
dict_index_t* index;
5255
KEY_PART_INFO* key_part;
5262
ulint* field_lengths;
5264
key = form->key_info + key_num;
5266
n_fields = key->key_parts;
5270
if (key_num == form->s->primary_key) {
5271
ind_type = ind_type | DICT_CLUSTERED;
5274
if (key->flags & HA_NOSAME ) {
5275
ind_type = ind_type | DICT_UNIQUE;
5278
/* We pass 0 as the space id, and determine at a lower level the space
5279
id where to store the table */
5281
index = dict_mem_index_create(table_name, key->name, 0,
5282
ind_type, n_fields);
5284
field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
5286
for (i = 0; i < n_fields; i++) {
5287
key_part = key->key_part + i;
5289
/* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
5290
field in an index: we only store a specified number of first
5291
bytes of the column to the index field.) The flag does not
5292
seem to be properly set by MySQL. Let us fall back on testing
5293
the length of the key part versus the column. */
5296
for (j = 0; j < form->s->fields; j++) {
5298
field = form->field[j];
5300
if (0 == innobase_strcasecmp(
5302
key_part->field->field_name)) {
5303
/* Found the corresponding column */
5309
ut_a(j < form->s->fields);
5311
col_type = get_innobase_type_from_mysql_type(
5312
&is_unsigned, key_part->field);
5314
if (DATA_BLOB == col_type
5315
|| (key_part->length < field->pack_length()
5316
&& field->type() != DRIZZLE_TYPE_VARCHAR)
5317
|| (field->type() == DRIZZLE_TYPE_VARCHAR
5318
&& key_part->length < field->pack_length()
5319
- ((Field_varstring*)field)->length_bytes)) {
5321
prefix_len = key_part->length;
5323
if (col_type == DATA_INT
5324
|| col_type == DATA_FLOAT
5325
|| col_type == DATA_DOUBLE
5326
|| col_type == DATA_DECIMAL) {
5327
errmsg_printf(ERRMSG_LVL_ERROR,
5328
"MySQL is trying to create a column "
5329
"prefix index field, on an "
5330
"inappropriate data type. Table "
5331
"name %s, column name %s.",
5333
key_part->field->field_name);
5341
field_lengths[i] = key_part->length;
5343
dict_mem_index_add_field(index,
5344
(char*) key_part->field->field_name, prefix_len);
5347
/* Even though we've defined max_supported_key_part_length, we
5348
still do our own checking using field_lengths to be absolutely
5349
sure we don't create too long indexes. */
5350
error = row_create_index_for_mysql(index, trx, field_lengths);
5352
error = convert_error_code_to_mysql(error, flags, NULL);
5354
free(field_lengths);
5359
/*****************************************************************//**
5360
Creates an index to an InnoDB table when the user has defined no
5364
create_clustered_index_when_no_primary(
5365
/*===================================*/
5366
trx_t* trx, /*!< in: InnoDB transaction handle */
5367
ulint flags, /*!< in: InnoDB table flags */
5368
const char* table_name) /*!< in: table name */
5370
dict_index_t* index;
5373
/* We pass 0 as the space id, and determine at a lower level the space
5374
id where to store the table */
5376
index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
5377
0, DICT_CLUSTERED, 0);
5379
error = row_create_index_for_mysql(index, trx, NULL);
5381
error = convert_error_code_to_mysql(error, flags, NULL);
5386
/*****************************************************************//**
5387
Validates the create options. We may build on this function
5388
in future. For now, it checks two specifiers:
5389
KEY_BLOCK_SIZE and ROW_FORMAT
5390
If innodb_strict_mode is not set then this function is a no-op
5391
@return TRUE if valid. */
5394
create_options_are_valid(
5395
/*=====================*/
5396
Session* session, /*!< in: connection thread. */
5397
Table& form, /*!< in: information on table
5398
columns and indexes */
5399
message::Table& create_proto)
5401
ibool kbs_specified = FALSE;
5405
ut_ad(session != NULL);
5407
/* If innodb_strict_mode is not set don't do any validation. */
5408
if (!(SessionVAR(session, strict_mode))) {
5412
/* First check if KEY_BLOCK_SIZE was specified. */
5413
if (create_proto.options().has_key_block_size()) {
5415
kbs_specified = TRUE;
5416
switch (create_proto.options().key_block_size()) {
5425
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5426
ER_ILLEGAL_HA_CREATE_OPTION,
5428
" KEY_BLOCK_SIZE = %lu."
5430
" [1, 2, 4, 8, 16]",
5431
create_proto.options().key_block_size());
5436
/* If KEY_BLOCK_SIZE was specified, check for its
5438
if (kbs_specified && !srv_file_per_table) {
5439
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5440
ER_ILLEGAL_HA_CREATE_OPTION,
5441
"InnoDB: KEY_BLOCK_SIZE"
5442
" requires innodb_file_per_table.");
5446
if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
5447
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5448
ER_ILLEGAL_HA_CREATE_OPTION,
5449
"InnoDB: KEY_BLOCK_SIZE"
5450
" requires innodb_file_format >"
5455
/* Now check for ROW_FORMAT specifier. */
5456
if (create_proto.options().has_row_type()) {
5457
switch (form.s->row_type) {
5458
const char* row_format_name;
5459
case ROW_TYPE_COMPRESSED:
5460
case ROW_TYPE_DYNAMIC:
5462
= form.s->row_type == ROW_TYPE_COMPRESSED
5466
/* These two ROW_FORMATs require
5467
srv_file_per_table and srv_file_format */
5468
if (!srv_file_per_table) {
5469
push_warning_printf(
5471
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5472
ER_ILLEGAL_HA_CREATE_OPTION,
5473
"InnoDB: ROW_FORMAT=%s"
5474
" requires innodb_file_per_table.",
5480
if (srv_file_format < DICT_TF_FORMAT_ZIP) {
5481
push_warning_printf(
5483
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5484
ER_ILLEGAL_HA_CREATE_OPTION,
5485
"InnoDB: ROW_FORMAT=%s"
5486
" requires innodb_file_format >"
5492
/* Cannot specify KEY_BLOCK_SIZE with
5493
ROW_FORMAT = DYNAMIC.
5494
However, we do allow COMPRESSED to be
5495
specified with KEY_BLOCK_SIZE. */
5497
&& form.s->row_type == ROW_TYPE_DYNAMIC) {
5498
push_warning_printf(
5500
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5501
ER_ILLEGAL_HA_CREATE_OPTION,
5502
"InnoDB: cannot specify"
5503
" ROW_FORMAT = DYNAMIC with"
5504
" KEY_BLOCK_SIZE.");
5510
case ROW_TYPE_REDUNDANT:
5511
case ROW_TYPE_COMPACT:
5512
case ROW_TYPE_DEFAULT:
5513
/* Default is COMPACT. */
5515
= form.s->row_type == ROW_TYPE_REDUNDANT
5519
/* Cannot specify KEY_BLOCK_SIZE with these
5520
format specifiers. */
5521
if (kbs_specified) {
5522
push_warning_printf(
5524
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5525
ER_ILLEGAL_HA_CREATE_OPTION,
5526
"InnoDB: cannot specify"
5527
" ROW_FORMAT = %s with"
5536
push_warning(session,
5537
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5538
ER_ILLEGAL_HA_CREATE_OPTION,
5539
"InnoDB: invalid ROW_FORMAT specifier.");
5548
/*********************************************************************
5549
Creates a new table to an InnoDB database. */
5552
InnobaseEngine::doCreateTable(
5553
/*================*/
5554
Session &session, /*!< in: Session */
5555
Table& form, /*!< in: information on table columns and indexes */
5556
drizzled::TableIdentifier &identifier,
5557
message::Table& create_proto)
5560
dict_table_t* innobase_table;
5565
char name2[FN_REFLEN];
5566
char norm_name[FN_REFLEN];
5567
ib_int64_t auto_inc_value;
5569
/* Cache the value of innodb_file_format, in case it is
5570
modified by another thread while the table is being created. */
5571
const ulint file_format = srv_file_format;
5572
bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
5574
const char *table_name= identifier.getPath().c_str();
5577
/* Names passed in from server are in two formats:
5578
1. <database_name>/<table_name>: for normal table creation
5579
2. full path: for temp table creation, or sym link
5581
When srv_file_per_table is on, check for full path pattern, i.e.
5582
X:\dir\..., X is a driver letter, or
5583
\\dir1\dir2\..., UNC path
5584
returns error if it is in full path format, but not creating a temp.
5585
table. Currently InnoDB does not support symbolic link on Windows. */
5587
if (srv_file_per_table
5588
&& (! lex_identified_temp_table)) {
5590
if ((table_name[1] == ':')
5591
|| (table_name[0] == '\\' && table_name[1] == '\\')) {
5592
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot create table %s\n", table_name);
5593
return(HA_ERR_GENERIC);
5598
if (form.s->fields > 1000) {
5599
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
5600
but we play safe here */
5602
return(HA_ERR_TO_BIG_ROW);
5605
/* Get the transaction associated with the current session, or create one
5606
if not yet created */
5608
parent_trx = check_trx_exists(&session);
5610
/* In case MySQL calls this in the middle of a SELECT query, release
5611
possible adaptive hash latch to avoid deadlocks of threads */
5613
trx_search_latch_release_if_reserved(parent_trx);
5615
trx = innobase_trx_allocate(&session);
5617
srv_lower_case_table_names = TRUE;
5619
strcpy(name2, table_name);
5621
normalize_table_name(norm_name, name2);
5623
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
5624
or lock waits can happen in it during a table create operation.
5625
Drop table etc. do this latching in row0mysql.c. */
5627
row_mysql_lock_data_dictionary(trx);
5629
/* Create the table definition in InnoDB */
5633
/* Validate create options if innodb_strict_mode is set. */
5634
if (! create_options_are_valid(&session, form, create_proto)) {
5635
error = ER_ILLEGAL_HA_CREATE_OPTION;
5639
if (create_proto.options().has_key_block_size()) {
5640
/* Determine the page_zip.ssize corresponding to the
5641
requested page size (key_block_size) in kilobytes. */
5644
ulint key_block_size = create_proto.options().key_block_size();
5646
for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
5647
ssize++, ksize <<= 1) {
5648
if (key_block_size == ksize) {
5649
iflags = ssize << DICT_TF_ZSSIZE_SHIFT
5651
| DICT_TF_FORMAT_ZIP
5652
<< DICT_TF_FORMAT_SHIFT;
5657
if (!srv_file_per_table) {
5658
push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5659
ER_ILLEGAL_HA_CREATE_OPTION,
5660
"InnoDB: KEY_BLOCK_SIZE"
5661
" requires innodb_file_per_table.");
5665
if (file_format < DICT_TF_FORMAT_ZIP) {
5666
push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5667
ER_ILLEGAL_HA_CREATE_OPTION,
5668
"InnoDB: KEY_BLOCK_SIZE"
5669
" requires innodb_file_format >"
5675
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5676
ER_ILLEGAL_HA_CREATE_OPTION,
5678
" KEY_BLOCK_SIZE=%lu.",
5679
create_proto.options().key_block_size());
5683
if (create_proto.options().has_row_type()) {
5685
/* KEY_BLOCK_SIZE was specified. */
5686
if (form.s->row_type != ROW_TYPE_COMPRESSED) {
5687
/* ROW_FORMAT other than COMPRESSED
5688
ignores KEY_BLOCK_SIZE. It does not
5689
make sense to reject conflicting
5690
KEY_BLOCK_SIZE and ROW_FORMAT, because
5691
such combinations can be obtained
5692
with ALTER TABLE anyway. */
5693
push_warning_printf(
5695
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5696
ER_ILLEGAL_HA_CREATE_OPTION,
5697
"InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
5698
" unless ROW_FORMAT=COMPRESSED.",
5699
create_proto.options().key_block_size());
5703
/* No KEY_BLOCK_SIZE */
5704
if (form.s->row_type == ROW_TYPE_COMPRESSED) {
5705
/* ROW_FORMAT=COMPRESSED without
5706
KEY_BLOCK_SIZE implies half the
5707
maximum KEY_BLOCK_SIZE. */
5708
iflags = (DICT_TF_ZSSIZE_MAX - 1)
5709
<< DICT_TF_ZSSIZE_SHIFT
5711
| DICT_TF_FORMAT_ZIP
5712
<< DICT_TF_FORMAT_SHIFT;
5713
#if DICT_TF_ZSSIZE_MAX < 1
5714
# error "DICT_TF_ZSSIZE_MAX < 1"
5719
switch (form.s->row_type) {
5720
const char* row_format_name;
5721
case ROW_TYPE_REDUNDANT:
5723
case ROW_TYPE_COMPRESSED:
5724
case ROW_TYPE_DYNAMIC:
5726
= form.s->row_type == ROW_TYPE_COMPRESSED
5730
if (!srv_file_per_table) {
5731
push_warning_printf(
5733
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5734
ER_ILLEGAL_HA_CREATE_OPTION,
5735
"InnoDB: ROW_FORMAT=%s"
5736
" requires innodb_file_per_table.",
5738
} else if (file_format < DICT_TF_FORMAT_ZIP) {
5739
push_warning_printf(
5741
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5742
ER_ILLEGAL_HA_CREATE_OPTION,
5743
"InnoDB: ROW_FORMAT=%s"
5744
" requires innodb_file_format >"
5748
iflags |= DICT_TF_COMPACT
5749
| (DICT_TF_FORMAT_ZIP
5750
<< DICT_TF_FORMAT_SHIFT);
5755
case ROW_TYPE_NOT_USED:
5756
case ROW_TYPE_FIXED:
5758
error = ER_ILLEGAL_HA_CREATE_OPTION;
5760
case ROW_TYPE_DEFAULT:
5761
case ROW_TYPE_COMPACT:
5762
iflags = DICT_TF_COMPACT;
5765
} else if (!iflags) {
5766
/* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
5767
use ROW_FORMAT=COMPACT by default. */
5768
iflags = DICT_TF_COMPACT;
5771
error = create_table_def(trx, &form, norm_name,
5772
lex_identified_temp_table ? name2 : NULL,
5779
/* Look for a primary key */
5781
primary_key_no= (form.s->primary_key != MAX_KEY ?
5782
(int) form.s->primary_key :
5785
/* Our function row_get_mysql_key_number_for_index assumes
5786
the primary key is always number 0, if it exists */
5788
assert(primary_key_no == -1 || primary_key_no == 0);
5790
/* Create the keys */
5792
if (form.s->keys == 0 || primary_key_no == -1) {
5793
/* Create an index which is used as the clustered index;
5794
order the rows by their row id which is internally generated
5797
error = create_clustered_index_when_no_primary(
5798
trx, iflags, norm_name);
5804
if (primary_key_no != -1) {
5805
/* In InnoDB the clustered index must always be created
5807
if ((error = create_index(trx, &form, iflags, norm_name,
5808
(uint) primary_key_no))) {
5813
for (i = 0; i < form.s->keys; i++) {
5815
if (i != (uint) primary_key_no) {
5817
if ((error = create_index(trx, &form, iflags, norm_name,
5824
if (trx->mysql_query_str) {
5825
error = row_table_add_foreign_constraints(trx,
5826
trx->mysql_query_str, norm_name,
5827
lex_identified_temp_table);
5829
error = convert_error_code_to_mysql(error, iflags, NULL);
5836
innobase_commit_low(trx);
5838
row_mysql_unlock_data_dictionary(trx);
5840
/* Flush the log to reduce probability that the .frm files and
5841
the InnoDB data dictionary get out-of-sync if the user runs
5842
with innodb_flush_log_at_trx_commit = 0 */
5844
log_buffer_flush_to_disk();
5846
innobase_table = dict_table_get(norm_name, FALSE);
5848
assert(innobase_table != 0);
5850
if (innobase_table) {
5851
/* We update the highest file format in the system table
5852
space, if this table has higher file format setting. */
5854
trx_sys_file_format_max_upgrade(
5855
(const char**) &innobase_file_format_check,
5856
dict_table_get_format(innobase_table));
5859
/* Note: We can't call update_session() as prebuilt will not be
5860
setup at this stage and so we use session. */
5862
/* We need to copy the AUTOINC value from the old table if
5863
this is an ALTER TABLE. */
5865
if ((create_proto.options().has_auto_increment_value()
5866
|| session_sql_command(&session) == SQLCOM_ALTER_TABLE)
5867
&& create_proto.options().auto_increment_value() != 0) {
5869
/* Query was ALTER TABLE...AUTO_INCREMENT = x; or
5870
CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
5871
definition from the dictionary and get the current value
5872
of the auto increment field. Set a new value to the
5873
auto increment field if the value is greater than the
5874
maximum value in the column. */
5876
auto_inc_value = create_proto.options().auto_increment_value();
5878
dict_table_autoinc_lock(innobase_table);
5879
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
5880
dict_table_autoinc_unlock(innobase_table);
5883
/* Tell the InnoDB server that there might be work for
5886
srv_active_wake_master_thread();
5888
trx_free_for_mysql(trx);
5890
StorageEngine::writeDefinitionFromPath(identifier, create_proto);
5895
innobase_commit_low(trx);
5897
row_mysql_unlock_data_dictionary(trx);
5899
trx_free_for_mysql(trx);
5904
/*****************************************************************//**
5905
Discards or imports an InnoDB tablespace.
5906
@return 0 == success, -1 == error */
5909
ha_innobase::discard_or_import_tablespace(
5910
/*======================================*/
5911
my_bool discard) /*!< in: TRUE if discard, else import */
5913
dict_table_t* dict_table;
5917
ut_a(prebuilt->trx);
5918
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
5919
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5921
dict_table = prebuilt->table;
5922
trx = prebuilt->trx;
5925
err = row_discard_tablespace_for_mysql(dict_table->name, trx);
5927
err = row_import_tablespace_for_mysql(dict_table->name, trx);
5930
err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
5935
/*****************************************************************//**
5936
Deletes all rows of an InnoDB table.
5937
@return error number */
5940
ha_innobase::delete_all_rows(void)
5941
/*==============================*/
5945
/* Get the transaction associated with the current session, or create one
5946
if not yet created, and update prebuilt->trx */
5948
update_session(ha_session());
5950
if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
5952
/* We only handle TRUNCATE TABLE t as a special case.
5953
DELETE FROM t will have to use ha_innobase::delete_row(),
5954
because DELETE is transactional while TRUNCATE is not. */
5955
return(errno=HA_ERR_WRONG_COMMAND);
5958
/* Truncate the table in InnoDB */
5960
error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
5961
if (error == DB_ERROR) {
5962
/* Cannot truncate; resort to ha_innobase::delete_row() */
5966
error = convert_error_code_to_mysql(error, prebuilt->table->flags,
5972
/*****************************************************************//**
5973
Drops a table from an InnoDB database. Before calling this function,
5974
MySQL calls innobase_commit to commit the transaction of the current user.
5975
Then the current user cannot have locks set on the table. Drop table
5976
operation inside InnoDB will remove all locks any user has on the table
5978
@return error number */
5981
InnobaseEngine::doDropTable(
5982
/*======================*/
5984
TableIdentifier &identifier)
5989
char norm_name[1000];
5991
ut_a(identifier.getPath().length() < 1000);
5993
/* Strangely, MySQL passes the table name without the '.frm'
5994
extension, in contrast to ::create */
5995
normalize_table_name(norm_name, identifier.getPath().c_str());
5997
/* Get the transaction associated with the current session, or create one
5998
if not yet created */
6000
parent_trx = check_trx_exists(&session);
6002
/* In case MySQL calls this in the middle of a SELECT query, release
6003
possible adaptive hash latch to avoid deadlocks of threads */
6005
trx_search_latch_release_if_reserved(parent_trx);
6007
trx = innobase_trx_allocate(&session);
6009
srv_lower_case_table_names = TRUE;
6011
/* Drop the table in InnoDB */
6013
error = row_drop_table_for_mysql(norm_name, trx,
6014
session_sql_command(&session)
6017
/* Flush the log to reduce probability that the .frm files and
6018
the InnoDB data dictionary get out-of-sync if the user runs
6019
with innodb_flush_log_at_trx_commit = 0 */
6021
log_buffer_flush_to_disk();
6023
/* Tell the InnoDB server that there might be work for
6026
srv_active_wake_master_thread();
6028
innobase_commit_low(trx);
6030
trx_free_for_mysql(trx);
6033
error = convert_error_code_to_mysql(error, 0, NULL);
6035
if (error == 0 || error == ENOENT)
6037
string path(identifier.getPath());
6039
path.append(DEFAULT_FILE_EXTENSION);
6041
(void)internal::my_delete(path.c_str(), MYF(0));
6047
/*****************************************************************//**
6048
Removes all tables in the named database inside InnoDB. */
6050
InnobaseEngine::doDropSchema(
6051
/*===================*/
6052
SchemaIdentifier &identifier)
6053
/*!< in: database path; inside InnoDB the name
6054
of the last directory in the path is used as
6055
the database name: for example, in 'mysql/data/test'
6056
the database name is 'test' */
6060
string schema_path(identifier.getPath());
6061
Session* session = current_session;
6063
/* Get the transaction associated with the current session, or create one
6064
if not yet created */
6066
assert(this == innodb_engine_ptr);
6068
/* In the Windows plugin, session = current_session is always NULL */
6070
trx_t* parent_trx = check_trx_exists(session);
6072
/* In case Drizzle calls this in the middle of a SELECT
6073
query, release possible adaptive hash latch to avoid
6074
deadlocks of threads */
6076
trx_search_latch_release_if_reserved(parent_trx);
6079
schema_path.append("/");
6080
trx = innobase_trx_allocate(session);
6081
error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6083
/* Flush the log to reduce probability that the .frm files and
6084
the InnoDB data dictionary get out-of-sync if the user runs
6085
with innodb_flush_log_at_trx_commit = 0 */
6087
log_buffer_flush_to_disk();
6089
/* Tell the InnoDB server that there might be work for
6092
srv_active_wake_master_thread();
6094
innobase_commit_low(trx);
6095
trx_free_for_mysql(trx);
6097
return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement.
6099
/*********************************************************************//**
6100
Renames an InnoDB table.
6101
@return 0 or error code */
6104
innobase_rename_table(
6105
/*==================*/
6106
trx_t* trx, /*!< in: transaction */
6107
const char* from, /*!< in: old name of the table */
6108
const char* to, /*!< in: new name of the table */
6109
ibool lock_and_commit)
6110
/*!< in: TRUE=lock data dictionary and commit */
6116
srv_lower_case_table_names = TRUE;
6118
// Magic number 64 arbitrary
6119
norm_to = (char*) malloc(strlen(to) + 64);
6120
norm_from = (char*) malloc(strlen(from) + 64);
6122
normalize_table_name(norm_to, to);
6123
normalize_table_name(norm_from, from);
6125
/* Serialize data dictionary operations with dictionary mutex:
6126
no deadlocks can occur then in these operations */
6128
if (lock_and_commit) {
6129
row_mysql_lock_data_dictionary(trx);
6132
error = row_rename_table_for_mysql(
6133
norm_from, norm_to, trx, lock_and_commit);
6135
if (error != DB_SUCCESS) {
6136
FILE* ef = dict_foreign_err_file;
6138
fputs("InnoDB: Renaming table ", ef);
6139
ut_print_name(ef, trx, TRUE, norm_from);
6141
ut_print_name(ef, trx, TRUE, norm_to);
6142
fputs(" failed!\n", ef);
6145
if (lock_and_commit) {
6146
row_mysql_unlock_data_dictionary(trx);
6148
/* Flush the log to reduce probability that the .frm
6149
files and the InnoDB data dictionary get out-of-sync
6150
if the user runs with innodb_flush_log_at_trx_commit = 0 */
6152
log_buffer_flush_to_disk();
6160
/*********************************************************************//**
6161
Renames an InnoDB table.
6162
@return 0 or error code */
6163
UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, TableIdentifier &from, TableIdentifier &to)
6165
// A temp table alter table/rename is a shallow rename and only the
6166
// definition needs to be updated.
6167
if (to.getType() == message::Table::TEMPORARY && from.getType() == message::Table::TEMPORARY)
6169
return plugin::StorageEngine::renameDefinitionFromPath(to, from);
6176
/* Get the transaction associated with the current session, or create one
6177
if not yet created */
6179
parent_trx = check_trx_exists(&session);
6181
/* In case MySQL calls this in the middle of a SELECT query, release
6182
possible adaptive hash latch to avoid deadlocks of threads */
6184
trx_search_latch_release_if_reserved(parent_trx);
6186
trx = innobase_trx_allocate(&session);
6188
error = innobase_rename_table(trx, from.getPath().c_str(), to.getPath().c_str(), TRUE);
6190
/* Tell the InnoDB server that there might be work for
6193
srv_active_wake_master_thread();
6195
innobase_commit_low(trx);
6196
trx_free_for_mysql(trx);
6198
error = convert_error_code_to_mysql(error, 0, NULL);
6202
// If this fails, we are in trouble
6203
plugin::StorageEngine::renameDefinitionFromPath(to, from);
6209
/*********************************************************************//**
6210
Estimates the number of index records in a range.
6211
@return estimated number of rows */
6214
ha_innobase::records_in_range(
6215
/*==========================*/
6216
uint keynr, /*!< in: index number */
6217
key_range *min_key, /*!< in: start key value of the
6218
range, may also be 0 */
6219
key_range *max_key) /*!< in: range end key val, may
6223
dict_index_t* index;
6224
unsigned char* key_val_buff2 = (unsigned char*) malloc(
6225
table->s->stored_rec_length
6226
+ table->s->max_key_length + 100);
6227
ulint buff2_len = table->s->stored_rec_length
6228
+ table->s->max_key_length + 100;
6229
dtuple_t* range_start;
6230
dtuple_t* range_end;
6236
ut_a(prebuilt->trx == session_to_trx(ha_session()));
6238
prebuilt->trx->op_info = (char*)"estimating records in index range";
6240
/* In case MySQL calls this in the middle of a SELECT query, release
6241
possible adaptive hash latch to avoid deadlocks of threads */
6243
trx_search_latch_release_if_reserved(prebuilt->trx);
6245
active_index = keynr;
6247
key = table->key_info + active_index;
6249
index = dict_table_get_index_on_name(prebuilt->table, key->name);
6251
/* MySQL knows about this index and so we must be able to find it.*/
6254
heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6255
+ sizeof(dtuple_t)));
6257
range_start = dtuple_create(heap, key->key_parts);
6258
dict_index_copy_types(range_start, index, key->key_parts);
6260
range_end = dtuple_create(heap, key->key_parts);
6261
dict_index_copy_types(range_end, index, key->key_parts);
6263
row_sel_convert_mysql_key_to_innobase(
6264
range_start, (byte*) key_val_buff,
6265
(ulint)upd_and_key_val_buff_len,
6267
(byte*) (min_key ? min_key->key :
6268
(const unsigned char*) 0),
6269
(ulint) (min_key ? min_key->length : 0),
6272
row_sel_convert_mysql_key_to_innobase(
6273
range_end, (byte*) key_val_buff2,
6275
(byte*) (max_key ? max_key->key :
6276
(const unsigned char*) 0),
6277
(ulint) (max_key ? max_key->length : 0),
6280
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
6282
mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
6285
if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
6287
n_rows = btr_estimate_n_rows_in_range(index, range_start,
6292
n_rows = HA_POS_ERROR;
6295
mem_heap_free(heap);
6297
free(key_val_buff2);
6299
prebuilt->trx->op_info = (char*)"";
6301
/* The MySQL optimizer seems to believe an estimate of 0 rows is
6302
always accurate and may return the result 'Empty set' based on that.
6303
The accuracy is not guaranteed, and even if it were, for a locking
6304
read we should anyway perform the search to set the next-key lock.
6305
Add 1 to the value to make sure MySQL does not make the assumption! */
6311
return((ha_rows) n_rows);
6314
/*********************************************************************//**
6315
Gives an UPPER BOUND to the number of rows in a table. This is used in
6317
@return upper bound of rows */
6320
ha_innobase::estimate_rows_upper_bound(void)
6321
/*======================================*/
6323
dict_index_t* index;
6325
uint64_t local_data_file_length;
6327
/* We do not know if MySQL can call this function before calling
6328
external_lock(). To be safe, update the session of the current table
6331
update_session(ha_session());
6333
prebuilt->trx->op_info = (char*)
6334
"calculating upper bound for table rows";
6336
/* In case MySQL calls this in the middle of a SELECT query, release
6337
possible adaptive hash latch to avoid deadlocks of threads */
6339
trx_search_latch_release_if_reserved(prebuilt->trx);
6341
index = dict_table_get_first_index(prebuilt->table);
6343
ut_a(index->stat_n_leaf_pages > 0);
6345
local_data_file_length =
6346
((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
6349
/* Calculate a minimum length for a clustered index record and from
6350
that an upper bound for the number of rows. Since we only calculate
6351
new statistics in row0mysql.c when a table has grown by a threshold
6352
factor, we must add a safety factor 2 in front of the formula below. */
6354
estimate = 2 * local_data_file_length /
6355
dict_index_calc_min_rec_len(index);
6357
prebuilt->trx->op_info = (char*)"";
6359
return((ha_rows) estimate);
6362
/*********************************************************************//**
6363
How many seeks it will take to read through the table. This is to be
6364
comparable to the number returned by records_in_range so that we can
6365
decide if we should scan the table or use keys.
6366
@return estimated time measured in disk seeks */
6369
ha_innobase::scan_time()
6370
/*====================*/
6372
/* Since MySQL seems to favor table scans too much over index
6373
searches, we pretend that a sequential read takes the same time
6374
as a random disk read, that is, we do not divide the following
6375
by 10, which would be physically realistic. */
6377
return((double) (prebuilt->table->stat_clustered_index_size));
6380
/******************************************************************//**
6381
Calculate the time it takes to read a set of ranges through an index
6382
This enables us to optimise reads for clustered indexes.
6383
@return estimated time measured in disk seeks */
6386
ha_innobase::read_time(
6387
/*===================*/
6388
uint index, /*!< in: key number */
6389
uint ranges, /*!< in: how many ranges */
6390
ha_rows rows) /*!< in: estimated number of rows in the ranges */
6393
double time_for_scan;
6395
if (index != table->s->primary_key) {
6397
return(Cursor::read_time(index, ranges, rows));
6402
return((double) rows);
6405
/* Assume that the read time is proportional to the scan time for all
6406
rows + at most one seek per range. */
6408
time_for_scan = scan_time();
6410
if ((total_rows = estimate_rows_upper_bound()) < rows) {
6412
return(time_for_scan);
6415
return(ranges + (double) rows / (double) total_rows * time_for_scan);
6418
/*********************************************************************//**
6419
Returns statistics information of the table to the MySQL interpreter,
6420
in various fields of the handle object. */
6425
uint flag) /*!< in: what information MySQL requests */
6427
dict_table_t* ib_table;
6428
dict_index_t* index;
6429
ha_rows rec_per_key;
6433
char path[FN_REFLEN];
6434
os_file_stat_t stat_info;
6436
/* If we are forcing recovery at a high level, we will suppress
6437
statistics calculation on tables, because that may crash the
6438
server if an index is badly corrupted. */
6440
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
6442
/* We return success (0) instead of HA_ERR_CRASHED,
6443
because we want MySQL to process this query and not
6444
stop, like it would do if it received the error code
6450
/* We do not know if MySQL can call this function before calling
6451
external_lock(). To be safe, update the session of the current table
6454
update_session(ha_session());
6456
/* In case MySQL calls this in the middle of a SELECT query, release
6457
possible adaptive hash latch to avoid deadlocks of threads */
6459
prebuilt->trx->op_info = (char*)"returning various info to MySQL";
6461
trx_search_latch_release_if_reserved(prebuilt->trx);
6463
ib_table = prebuilt->table;
6465
if (flag & HA_STATUS_TIME) {
6466
if (innobase_stats_on_metadata) {
6467
/* In sql_show we call with this flag: update
6468
then statistics so that they are up-to-date */
6470
prebuilt->trx->op_info = "updating table statistics";
6472
dict_update_statistics(ib_table);
6474
prebuilt->trx->op_info = "returning various info to MySQL";
6477
snprintf(path, sizeof(path), "%s/%s%s",
6478
drizzle_data_home, ib_table->name, ".dfe");
6480
internal::unpack_filename(path,path);
6482
/* Note that we do not know the access time of the table,
6483
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
6485
if (os_file_get_status(path,&stat_info)) {
6486
stats.create_time = (ulong) stat_info.ctime;
6490
if (flag & HA_STATUS_VARIABLE) {
6491
n_rows = ib_table->stat_n_rows;
6493
/* Because we do not protect stat_n_rows by any mutex in a
6494
delete, it is theoretically possible that the value can be
6495
smaller than zero! TODO: fix this race.
6497
The MySQL optimizer seems to assume in a left join that n_rows
6498
is an accurate estimate if it is zero. Of course, it is not,
6499
since we do not have any locks on the rows yet at this phase.
6500
Since SHOW TABLE STATUS seems to call this function with the
6501
HA_STATUS_TIME flag set, while the left join optimizer does not
6502
set that flag, we add one to a zero value if the flag is not
6503
set. That way SHOW TABLE STATUS will show the best estimate,
6504
while the optimizer never sees the table empty. */
6510
if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
6514
/* Fix bug#40386: Not flushing query cache after truncate.
6515
n_rows can not be 0 unless the table is empty, set to 1
6516
instead. The original problem of bug#29507 is actually
6517
fixed in the server code. */
6518
if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
6522
/* We need to reset the prebuilt value too, otherwise
6523
checks for values greater than the last value written
6524
to the table will fail and the autoinc counter will
6525
not be updated. This will force write_row() into
6526
attempting an update of the table's AUTOINC counter. */
6528
prebuilt->autoinc_last_value = 0;
6531
stats.records = (ha_rows)n_rows;
6533
stats.data_file_length = ((uint64_t)
6534
ib_table->stat_clustered_index_size)
6536
stats.index_file_length = ((uint64_t)
6537
ib_table->stat_sum_of_other_index_sizes)
6540
/* Since fsp_get_available_space_in_free_extents() is
6541
acquiring latches inside InnoDB, we do not call it if we
6542
are asked by MySQL to avoid locking. Another reason to
6543
avoid the call is that it uses quite a lot of CPU.
6545
We do not update delete_length if no locking is requested
6546
so the "old" value can remain. delete_length is initialized
6547
to 0 in the ha_statistics' constructor. */
6548
if (!(flag & HA_STATUS_NO_LOCK)) {
6550
/* lock the data dictionary to avoid races with
6551
ibd_file_missing and tablespace_discarded */
6552
row_mysql_lock_data_dictionary(prebuilt->trx);
6554
/* ib_table->space must be an existent tablespace */
6555
if (!ib_table->ibd_file_missing
6556
&& !ib_table->tablespace_discarded) {
6558
stats.delete_length =
6559
fsp_get_available_space_in_free_extents(
6560
ib_table->space) * 1024;
6565
session = ha_session();
6567
push_warning_printf(
6569
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6571
"InnoDB: Trying to get the free "
6572
"space for table %s but its "
6573
"tablespace has been discarded or "
6574
"the .ibd file is missing. Setting "
6575
"the free space to zero.",
6578
stats.delete_length = 0;
6581
row_mysql_unlock_data_dictionary(prebuilt->trx);
6584
stats.check_time = 0;
6586
if (stats.records == 0) {
6587
stats.mean_rec_length = 0;
6589
stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
6593
if (flag & HA_STATUS_CONST) {
6594
index = dict_table_get_first_index(ib_table);
6596
if (prebuilt->clust_index_was_generated) {
6597
index = dict_table_get_next_index(index);
6600
for (i = 0; i < table->s->keys; i++) {
6601
if (index == NULL) {
6602
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
6603
"indexes inside InnoDB than "
6604
"are defined in the MySQL "
6605
".frm file. Have you mixed up "
6606
".frm files from different "
6607
"installations? See "
6609
"innodb-troubleshooting.html\n",
6614
for (j = 0; j < table->key_info[i].key_parts; j++) {
6616
if (j + 1 > index->n_uniq) {
6617
errmsg_printf(ERRMSG_LVL_ERROR,
6618
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
6619
"statistics for %lu columns. Have you mixed up .frm files from different "
6621
"See " REFMAN "innodb-troubleshooting.html\n",
6625
index->n_uniq, j + 1);
6629
if (index->stat_n_diff_key_vals[j + 1] == 0) {
6631
rec_per_key = stats.records;
6633
rec_per_key = (ha_rows)(stats.records /
6634
index->stat_n_diff_key_vals[j + 1]);
6637
/* Since MySQL seems to favor table scans
6638
too much over index searches, we pretend
6639
index selectivity is 2 times better than
6642
rec_per_key = rec_per_key / 2;
6644
if (rec_per_key == 0) {
6648
table->key_info[i].rec_per_key[j]=
6649
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
6650
(ulong) rec_per_key;
6653
index = dict_table_get_next_index(index);
6657
if (flag & HA_STATUS_ERRKEY) {
6658
const dict_index_t* err_index;
6660
ut_a(prebuilt->trx);
6661
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6663
err_index = trx_get_error_info(prebuilt->trx);
6666
errkey = (unsigned int)
6667
row_get_mysql_key_number_for_index(err_index);
6669
errkey = (unsigned int) prebuilt->trx->error_key_num;
6673
if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
6674
stats.auto_increment_value = innobase_peek_autoinc();
6677
prebuilt->trx->op_info = (char*)"";
6682
/**********************************************************************//**
6683
Updates index cardinalities of the table, based on 8 random dives into
6684
each index tree. This does NOT calculate exact statistics on the table.
6685
@return returns always 0 (success) */
6688
ha_innobase::analyze(
6689
/*=================*/
6690
Session*) /*!< in: connection thread handle */
6692
/* Simply call ::info() with all the flags */
6693
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
6698
/*******************************************************************//**
6699
Tries to check that an InnoDB table is not corrupted. If corruption is
6700
noticed, prints to stderr information about it. In case of corruption
6701
may also assert a failure and crash the server.
6702
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
6707
Session* session) /*!< in: user thread handle */
6711
assert(session == ha_session());
6712
ut_a(prebuilt->trx);
6713
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6714
ut_a(prebuilt->trx == session_to_trx(session));
6716
if (prebuilt->mysql_template == NULL) {
6717
/* Build the template; we will use a dummy template
6718
in index scans done in checking */
6720
build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
6723
ret = row_check_table_for_mysql(prebuilt);
6725
if (ret == DB_SUCCESS) {
6726
return(HA_ADMIN_OK);
6729
return(HA_ADMIN_CORRUPT);
6732
/*************************************************************//**
6733
Adds information about free space in the InnoDB tablespace to a table comment
6734
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
6736
@return table comment + InnoDB free space + info on foreign keys */
6739
ha_innobase::update_table_comment(
6740
/*==============================*/
6741
const char* comment)/*!< in: table comment defined by user */
6743
uint length = (uint) strlen(comment);
6747
/* We do not know if MySQL can call this function before calling
6748
external_lock(). To be safe, update the session of the current table
6751
if (length > 64000 - 3) {
6752
return((char*)comment); /* string too long */
6755
update_session(ha_session());
6757
prebuilt->trx->op_info = (char*)"returning table comment";
6759
/* In case MySQL calls this in the middle of a SELECT query, release
6760
possible adaptive hash latch to avoid deadlocks of threads */
6762
trx_search_latch_release_if_reserved(prebuilt->trx);
6765
/* output the data to a temporary file */
6767
mutex_enter(&srv_dict_tmpfile_mutex);
6768
rewind(srv_dict_tmpfile);
6770
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
6771
fsp_get_available_space_in_free_extents(
6772
prebuilt->table->space));
6774
dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
6775
prebuilt->trx, prebuilt->table);
6776
flen = ftell(srv_dict_tmpfile);
6779
} else if (length + flen + 3 > 64000) {
6780
flen = 64000 - 3 - length;
6783
/* allocate buffer for the full string, and
6784
read the contents of the temporary file */
6786
str = (char*) malloc(length + flen + 3);
6789
char* pos = str + length;
6791
memcpy(str, comment, length);
6795
rewind(srv_dict_tmpfile);
6796
flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
6800
mutex_exit(&srv_dict_tmpfile_mutex);
6802
prebuilt->trx->op_info = (char*)"";
6804
return(str ? str : (char*) comment);
6807
/*******************************************************************//**
6808
Gets the foreign key create info for a table stored in InnoDB.
6809
@return own: character string in the form which can be inserted to the
6810
CREATE TABLE statement, MUST be freed with
6811
ha_innobase::free_foreign_key_create_info */
6814
ha_innobase::get_foreign_key_create_info(void)
6815
/*==========================================*/
6820
ut_a(prebuilt != NULL);
6822
/* We do not know if MySQL can call this function before calling
6823
external_lock(). To be safe, update the session of the current table
6826
update_session(ha_session());
6828
prebuilt->trx->op_info = (char*)"getting info on foreign keys";
6830
/* In case MySQL calls this in the middle of a SELECT query,
6831
release possible adaptive hash latch to avoid
6832
deadlocks of threads */
6834
trx_search_latch_release_if_reserved(prebuilt->trx);
6836
mutex_enter(&srv_dict_tmpfile_mutex);
6837
rewind(srv_dict_tmpfile);
6839
/* output the data to a temporary file */
6840
dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
6841
prebuilt->trx, prebuilt->table);
6842
prebuilt->trx->op_info = (char*)"";
6844
flen = ftell(srv_dict_tmpfile);
6847
} else if (flen > 64000 - 1) {
6851
/* allocate buffer for the string, and
6852
read the contents of the temporary file */
6854
str = (char*) malloc(flen + 1);
6857
rewind(srv_dict_tmpfile);
6858
flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
6862
mutex_exit(&srv_dict_tmpfile_mutex);
6870
ha_innobase::get_foreign_key_list(Session *session, List<FOREIGN_KEY_INFO> *f_key_list)
6872
dict_foreign_t* foreign;
6874
ut_a(prebuilt != NULL);
6875
update_session(ha_session());
6876
prebuilt->trx->op_info = (char*)"getting list of foreign keys";
6877
trx_search_latch_release_if_reserved(prebuilt->trx);
6878
mutex_enter(&(dict_sys->mutex));
6879
foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
6881
while (foreign != NULL) {
6883
FOREIGN_KEY_INFO f_key_info;
6884
LEX_STRING *name= 0;
6886
char uname[NAME_LEN+1]; /* Unencoded name */
6887
char db_name[NAME_LEN+1];
6888
const char *tmp_buff;
6890
tmp_buff= foreign->id;
6892
while (tmp_buff[i] != '/')
6895
f_key_info.forein_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
6896
tmp_buff= foreign->referenced_table_name;
6900
while (tmp_buff[i] != '/')
6902
db_name[i]= tmp_buff[i];
6906
ulen= filename_to_tablename(db_name, uname, sizeof(uname));
6907
f_key_info.referenced_db = session->make_lex_string(NULL, uname, ulen, true);
6911
ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
6912
f_key_info.referenced_table = session->make_lex_string(NULL, uname, ulen, true);
6915
tmp_buff= foreign->foreign_col_names[i];
6916
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6917
f_key_info.foreign_fields.push_back(name);
6918
tmp_buff= foreign->referenced_col_names[i];
6919
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6920
f_key_info.referenced_fields.push_back(name);
6921
if (++i >= foreign->n_fields)
6926
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
6929
tmp_buff= "CASCADE";
6931
else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
6934
tmp_buff= "SET NULL";
6936
else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
6939
tmp_buff= "NO ACTION";
6944
tmp_buff= "RESTRICT";
6946
f_key_info.delete_method = session->make_lex_string(
6947
f_key_info.delete_method, tmp_buff, length, true);
6950
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
6953
tmp_buff= "CASCADE";
6955
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
6958
tmp_buff= "SET NULL";
6960
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
6963
tmp_buff= "NO ACTION";
6968
tmp_buff= "RESTRICT";
6970
f_key_info.update_method = session->make_lex_string(
6971
f_key_info.update_method, tmp_buff, length, true);
6972
if (foreign->referenced_index &&
6973
foreign->referenced_index->name)
6975
f_key_info.referenced_key_name = session->make_lex_string(
6976
f_key_info.referenced_key_name,
6977
foreign->referenced_index->name,
6978
strlen(foreign->referenced_index->name), true);
6981
f_key_info.referenced_key_name= 0;
6983
FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
6984
session_memdup(session, &f_key_info, sizeof(FOREIGN_KEY_INFO));
6985
f_key_list->push_back(pf_key_info);
6986
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
6988
mutex_exit(&(dict_sys->mutex));
6989
prebuilt->trx->op_info = (char*)"";
6994
/*****************************************************************//**
6995
Checks if ALTER TABLE may change the storage engine of the table.
6996
Changing storage engines is not allowed for tables for which there
6997
are foreign key constraints (parent or child tables).
6998
@return TRUE if can switch engines */
7001
ha_innobase::can_switch_engines(void)
7002
/*=================================*/
7006
ut_a(prebuilt->trx == session_to_trx(ha_session()));
7008
prebuilt->trx->op_info =
7009
"determining if there are foreign key constraints";
7010
row_mysql_lock_data_dictionary(prebuilt->trx);
7012
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
7013
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7015
row_mysql_unlock_data_dictionary(prebuilt->trx);
7016
prebuilt->trx->op_info = "";
7021
/*******************************************************************//**
7022
Checks if a table is referenced by a foreign key. The MySQL manual states that
7023
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
7024
delete is then allowed internally to resolve a duplicate key conflict in
7025
REPLACE, not an update.
7026
@return > 0 if referenced by a FOREIGN KEY */
7029
ha_innobase::referenced_by_foreign_key(void)
7030
/*========================================*/
7032
if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
7040
/*******************************************************************//**
7041
Frees the foreign key create info for a table stored in InnoDB, if it is
7045
ha_innobase::free_foreign_key_create_info(
7046
/*======================================*/
7047
char* str) /*!< in, own: create info string to free */
7054
/*******************************************************************//**
7055
Tells something additional to the Cursor about how to do things.
7056
@return 0 or error number */
7061
enum ha_extra_function operation)
7062
/*!< in: HA_EXTRA_FLUSH or some other flag */
7064
/* Warning: since it is not sure that MySQL calls external_lock
7065
before calling this function, the trx field in prebuilt can be
7068
switch (operation) {
7069
case HA_EXTRA_FLUSH:
7070
if (prebuilt->blob_heap) {
7071
row_mysql_prebuilt_free_blob_heap(prebuilt);
7074
case HA_EXTRA_RESET_STATE:
7075
reset_template(prebuilt);
7077
case HA_EXTRA_NO_KEYREAD:
7078
prebuilt->read_just_key = 0;
7080
case HA_EXTRA_KEYREAD:
7081
prebuilt->read_just_key = 1;
7083
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
7084
prebuilt->keep_other_fields_on_keyread = 1;
7087
/* IMPORTANT: prebuilt->trx can be obsolete in
7088
this method, because it is not sure that MySQL
7089
calls external_lock before this method with the
7090
parameters below. We must not invoke update_session()
7091
either, because the calling threads may change.
7092
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
7093
case HA_EXTRA_IGNORE_DUP_KEY:
7094
session_to_trx(ha_session())->duplicates |= TRX_DUP_IGNORE;
7096
case HA_EXTRA_WRITE_CAN_REPLACE:
7097
session_to_trx(ha_session())->duplicates |= TRX_DUP_REPLACE;
7099
case HA_EXTRA_WRITE_CANNOT_REPLACE:
7100
session_to_trx(ha_session())->duplicates &= ~TRX_DUP_REPLACE;
7102
case HA_EXTRA_NO_IGNORE_DUP_KEY:
7103
session_to_trx(ha_session())->duplicates &=
7104
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
7106
default:/* Do nothing */
7115
ha_innobase::reset()
7117
if (prebuilt->blob_heap) {
7118
row_mysql_prebuilt_free_blob_heap(prebuilt);
7121
reset_template(prebuilt);
7123
/* TODO: This should really be reset in reset_template() but for now
7124
it's safer to do it explicitly here. */
7126
/* This is a statement level counter. */
7127
prebuilt->autoinc_last_value = 0;
7132
/******************************************************************//**
7133
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7134
@return InnoDB isolation level */
7137
innobase_map_isolation_level(
7138
/*=========================*/
7139
enum_tx_isolation iso) /*!< in: MySQL isolation level code */
7142
case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
7143
case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
7144
case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
7145
case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
7146
default: ut_a(0); return(0);
7150
/******************************************************************//**
7151
As MySQL will execute an external lock for every new table it uses when it
7152
starts to process an SQL statement. We can use this function to store the pointer to
7153
the Session in the handle.
7157
ha_innobase::external_lock(
7158
/*=======================*/
7159
Session* session, /*!< in: handle to the user thread */
7160
int lock_type) /*!< in: lock type */
7162
update_session(session);
7164
trx_t *trx= prebuilt->trx;
7166
prebuilt->sql_stat_start = TRUE;
7167
prebuilt->hint_need_to_fetch_extra_cols = 0;
7169
reset_template(prebuilt);
7171
if (lock_type == F_WRLCK) {
7173
/* If this is a SELECT, then it is in UPDATE TABLE ...
7174
or SELECT ... FOR UPDATE */
7175
prebuilt->select_lock_type = LOCK_X;
7176
prebuilt->stored_select_lock_type = LOCK_X;
7179
if (lock_type != F_UNLCK) {
7180
/* MySQL is setting a new table lock */
7182
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
7183
&& prebuilt->select_lock_type == LOCK_NONE
7184
&& session_test_options(session,
7185
OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7187
/* To get serializable execution, we let InnoDB
7188
conceptually add 'LOCK IN SHARE MODE' to all SELECTs
7189
which otherwise would have been consistent reads. An
7190
exception is consistent reads in the AUTOCOMMIT=1 mode:
7191
we know that they are read-only transactions, and they
7192
can be serialized also if performed as consistent
7195
prebuilt->select_lock_type = LOCK_S;
7196
prebuilt->stored_select_lock_type = LOCK_S;
7199
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
7200
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
7201
an InnoDB table lock if it is released immediately at the end
7202
of LOCK TABLES, and InnoDB's table locks in that case cause
7203
VERY easily deadlocks.
7205
We do not set InnoDB table locks if user has not explicitly
7206
requested a table lock. Note that session_in_lock_tables(session)
7207
can hold in some cases, e.g., at the start of a stored
7208
procedure call (SQLCOM_CALL). */
7210
if (prebuilt->select_lock_type != LOCK_NONE) {
7211
trx->mysql_n_tables_locked++;
7214
prebuilt->mysql_has_locked = TRUE;
7219
/* MySQL is releasing a table lock */
7220
prebuilt->mysql_has_locked = FALSE;
7221
trx->mysql_n_tables_locked= 0;
7226
/************************************************************************//**
7227
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
7228
Monitor to the client. */
7233
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7234
Session* session,/*!< in: the MySQL query thread of the caller */
7235
stat_print_fn *stat_print)
7238
static const char truncated_msg[] = "... truncated...\n";
7239
const long MAX_STATUS_SIZE = 64000;
7240
ulint trx_list_start = ULINT_UNDEFINED;
7241
ulint trx_list_end = ULINT_UNDEFINED;
7243
assert(engine == innodb_engine_ptr);
7245
trx = check_trx_exists(session);
7247
innobase_release_stat_resources(trx);
7249
/* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
7252
long flen, usable_len;
7255
mutex_enter(&srv_monitor_file_mutex);
7256
rewind(srv_monitor_file);
7257
srv_printf_innodb_monitor(srv_monitor_file,
7258
&trx_list_start, &trx_list_end);
7259
flen = ftell(srv_monitor_file);
7260
os_file_set_eof(srv_monitor_file);
7266
if (flen > MAX_STATUS_SIZE) {
7267
usable_len = MAX_STATUS_SIZE;
7272
/* allocate buffer for the string, and
7273
read the contents of the temporary file */
7275
if (!(str = (char*) malloc(usable_len + 1))) {
7276
mutex_exit(&srv_monitor_file_mutex);
7280
rewind(srv_monitor_file);
7281
if (flen < MAX_STATUS_SIZE) {
7282
/* Display the entire output. */
7283
flen = (long) fread(str, 1, flen, srv_monitor_file);
7284
} else if (trx_list_end < (ulint) flen
7285
&& trx_list_start < trx_list_end
7286
&& trx_list_start + (flen - trx_list_end)
7287
< MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
7288
/* Omit the beginning of the list of active transactions. */
7289
long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
7290
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
7291
len += sizeof truncated_msg - 1;
7292
usable_len = (MAX_STATUS_SIZE - 1) - len;
7293
fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
7294
len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
7297
/* Omit the end of the output. */
7298
flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
7301
mutex_exit(&srv_monitor_file_mutex);
7303
bool result = FALSE;
7305
if (stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
7306
STRING_WITH_LEN(""), str, flen)) {
7314
/************************************************************************//**
7315
Implements the SHOW MUTEX STATUS command. . */
7318
innodb_mutex_show_status(
7319
/*=====================*/
7320
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7321
Session* session, /*!< in: the MySQL query thread of the
7323
stat_print_fn* stat_print)
7325
char buf1[IO_SIZE], buf2[IO_SIZE];
7329
ulint rw_lock_count= 0;
7330
ulint rw_lock_count_spin_loop= 0;
7331
ulint rw_lock_count_spin_rounds= 0;
7332
ulint rw_lock_count_os_wait= 0;
7333
ulint rw_lock_count_os_yield= 0;
7334
uint64_t rw_lock_wait_time= 0;
7335
#endif /* UNIV_DEBUG */
7336
uint engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
7337
assert(engine == innodb_engine_ptr);
7339
mutex_enter(&mutex_list_mutex);
7341
mutex = UT_LIST_GET_FIRST(mutex_list);
7343
while (mutex != NULL) {
7344
if (mutex->count_os_wait == 0
7345
|| buf_pool_is_block_mutex(mutex)) {
7349
if (mutex->mutex_type != 1) {
7350
if (mutex->count_using > 0) {
7351
buf1len= my_snprintf(buf1, sizeof(buf1),
7353
mutex->cmutex_name, mutex->cfile_name);
7354
buf2len= my_snprintf(buf2, sizeof(buf2),
7355
"count=%lu, spin_waits=%lu,"
7356
" spin_rounds=%lu, "
7357
"os_waits=%lu, os_yields=%lu,"
7358
" os_wait_times=%lu",
7360
mutex->count_spin_loop,
7361
mutex->count_spin_rounds,
7362
mutex->count_os_wait,
7363
mutex->count_os_yield,
7364
(ulong) (mutex->lspent_time/1000));
7366
if (stat_print(session, innobase_engine_name,
7367
engine_name_len, buf1, buf1len,
7369
mutex_exit(&mutex_list_mutex);
7375
rw_lock_count += mutex->count_using;
7376
rw_lock_count_spin_loop += mutex->count_spin_loop;
7377
rw_lock_count_spin_rounds += mutex->count_spin_rounds;
7378
rw_lock_count_os_wait += mutex->count_os_wait;
7379
rw_lock_count_os_yield += mutex->count_os_yield;
7380
rw_lock_wait_time += mutex->lspent_time;
7382
#else /* UNIV_DEBUG */
7383
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7384
mutex->cfile_name, (ulong) mutex->cline);
7385
buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
7386
mutex->count_os_wait);
7388
if (stat_print(session, innobase_engine_name,
7389
engine_name_len, buf1, buf1len,
7391
mutex_exit(&mutex_list_mutex);
7394
#endif /* UNIV_DEBUG */
7397
mutex = UT_LIST_GET_NEXT(list, mutex);
7400
mutex_exit(&mutex_list_mutex);
7402
mutex_enter(&rw_lock_list_mutex);
7404
lock = UT_LIST_GET_FIRST(rw_lock_list);
7406
while (lock != NULL) {
7407
if (lock->count_os_wait
7408
&& !buf_pool_is_block_lock(lock)) {
7409
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7410
lock->cfile_name, (unsigned long) lock->cline);
7411
buf2len= snprintf(buf2, sizeof(buf2),
7412
"os_waits=%lu", lock->count_os_wait);
7414
if (stat_print(session, innobase_engine_name,
7415
engine_name_len, buf1, buf1len,
7417
mutex_exit(&rw_lock_list_mutex);
7421
lock = UT_LIST_GET_NEXT(list, lock);
7424
mutex_exit(&rw_lock_list_mutex);
7427
buf2len= my_snprintf(buf2, sizeof(buf2),
7428
"count=%lu, spin_waits=%lu, spin_rounds=%lu, "
7429
"os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
7430
rw_lock_count, rw_lock_count_spin_loop,
7431
rw_lock_count_spin_rounds,
7432
rw_lock_count_os_wait, rw_lock_count_os_yield,
7433
(ulong) (rw_lock_wait_time/1000));
7435
if (stat_print(session, innobase_engine_name, engine_name_len,
7436
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
7439
#endif /* UNIV_DEBUG */
7444
bool InnobaseEngine::show_status(Session* session,
7445
stat_print_fn* stat_print,
7446
enum ha_stat_type stat_type)
7448
assert(this == innodb_engine_ptr);
7450
switch (stat_type) {
7451
case HA_ENGINE_STATUS:
7452
return innodb_show_status(this, session, stat_print);
7453
case HA_ENGINE_MUTEX:
7454
return innodb_mutex_show_status(this, session, stat_print);
7460
/************************************************************************//**
7461
Handling the shared INNOBASE_SHARE structure that is needed to provide table
7463
****************************************************************************/
7465
static INNOBASE_SHARE* get_share(const char* table_name)
7467
INNOBASE_SHARE *share;
7468
pthread_mutex_lock(&innobase_share_mutex);
7470
ulint fold = ut_fold_string(table_name);
7472
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7473
INNOBASE_SHARE*, share,
7474
ut_ad(share->use_count > 0),
7475
!strcmp(share->table_name, table_name));
7479
uint length = (uint) strlen(table_name);
7481
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
7484
share = (INNOBASE_SHARE *) malloc(sizeof(*share)+length+1);
7485
memset(share, 0, sizeof(*share)+length+1);
7487
share->table_name = (char*) memcpy(share + 1,
7488
table_name, length + 1);
7490
HASH_INSERT(INNOBASE_SHARE, table_name_hash,
7491
innobase_open_tables, fold, share);
7493
thr_lock_init(&share->lock);
7497
pthread_mutex_unlock(&innobase_share_mutex);
7502
static void free_share(INNOBASE_SHARE* share)
7504
pthread_mutex_lock(&innobase_share_mutex);
7507
INNOBASE_SHARE* share2;
7508
ulint fold = ut_fold_string(share->table_name);
7510
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7511
INNOBASE_SHARE*, share2,
7512
ut_ad(share->use_count > 0),
7513
!strcmp(share->table_name, share2->table_name));
7515
ut_a(share2 == share);
7516
#endif /* UNIV_DEBUG */
7518
if (!--share->use_count) {
7519
ulint fold = ut_fold_string(share->table_name);
7521
HASH_DELETE(INNOBASE_SHARE, table_name_hash,
7522
innobase_open_tables, fold, share);
7523
thr_lock_delete(&share->lock);
7526
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
7530
pthread_mutex_unlock(&innobase_share_mutex);
7533
/*****************************************************************//**
7534
Converts a MySQL table lock stored in the 'lock' field of the handle to
7535
a proper type before storing pointer to the lock into an array of pointers.
7536
MySQL also calls this if it wants to reset some table locks to a not-locked
7537
state during the processing of an SQL query. An example is that during a
7538
SELECT the read lock is released early on the 'const' tables where we only
7539
fetch one row. MySQL does not call this when it releases all locks at the
7540
end of an SQL statement.
7541
@return pointer to the next element in the 'to' array */
7544
ha_innobase::store_lock(
7545
/*====================*/
7546
Session* session, /*!< in: user thread handle */
7547
THR_LOCK_DATA** to, /*!< in: pointer to an array
7548
of pointers to lock structs;
7549
pointer to the 'lock' field
7550
of current handle is stored
7551
next to this array */
7552
enum thr_lock_type lock_type) /*!< in: lock type to store in
7553
'lock'; this may also be
7558
/* Note that trx in this function is NOT necessarily prebuilt->trx
7559
because we call update_session() later, in ::external_lock()! Failure to
7560
understand this caused a serious memory corruption bug in 5.1.11. */
7562
trx = check_trx_exists(session);
7564
assert(EQ_CURRENT_SESSION(session));
7565
const uint32_t sql_command = session_sql_command(session);
7567
if (sql_command == SQLCOM_DROP_TABLE) {
7569
/* MySQL calls this function in DROP Table though this table
7570
handle may belong to another session that is running a query.
7571
Let us in that case skip any changes to the prebuilt struct. */
7573
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
7574
|| lock_type == TL_READ_NO_INSERT
7575
|| (lock_type != TL_IGNORE
7576
&& sql_command != SQLCOM_SELECT)) {
7578
/* The OR cases above are in this order:
7579
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
7580
are processing a stored procedure or function, or
7581
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
7582
3) this is a SELECT ... IN SHARE MODE, or
7583
4) we are doing a complex SQL statement like
7584
INSERT INTO ... SELECT ... and the logical logging (MySQL
7585
binlog) requires the use of a locking read, or
7586
MySQL is doing LOCK TABLES ... READ.
7587
5) we let InnoDB do locking reads for all SQL statements that
7588
are not simple SELECTs; note that select_lock_type in this
7589
case may get strengthened in ::external_lock() to LOCK_X.
7590
Note that we MUST use a locking read in all data modifying
7591
SQL statements, because otherwise the execution would not be
7592
serializable, and also the results from the update could be
7593
unexpected if an obsolete consistent read view would be
7596
ulint isolation_level;
7598
isolation_level = trx->isolation_level;
7600
if ((srv_locks_unsafe_for_binlog
7601
|| isolation_level == TRX_ISO_READ_COMMITTED)
7602
&& isolation_level != TRX_ISO_SERIALIZABLE
7603
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
7604
&& (sql_command == SQLCOM_INSERT_SELECT
7605
|| sql_command == SQLCOM_UPDATE
7606
|| sql_command == SQLCOM_CREATE_TABLE)) {
7608
/* If we either have innobase_locks_unsafe_for_binlog
7609
option set or this session is using READ COMMITTED
7610
isolation level and isolation level of the transaction
7611
is not set to serializable and MySQL is doing
7612
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
7613
CREATE ... SELECT... without FOR UPDATE or
7614
IN SHARE MODE in select, then we use consistent
7617
prebuilt->select_lock_type = LOCK_NONE;
7618
prebuilt->stored_select_lock_type = LOCK_NONE;
7619
} else if (sql_command == SQLCOM_CHECKSUM) {
7620
/* Use consistent read for checksum table */
7622
prebuilt->select_lock_type = LOCK_NONE;
7623
prebuilt->stored_select_lock_type = LOCK_NONE;
7625
prebuilt->select_lock_type = LOCK_S;
7626
prebuilt->stored_select_lock_type = LOCK_S;
7629
} else if (lock_type != TL_IGNORE) {
7631
/* We set possible LOCK_X value in external_lock, not yet
7632
here even if this would be SELECT ... FOR UPDATE */
7634
prebuilt->select_lock_type = LOCK_NONE;
7635
prebuilt->stored_select_lock_type = LOCK_NONE;
7638
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
7640
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
7641
TABLESPACE or TRUNCATE TABLE then allow multiple
7642
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
7643
< TL_WRITE_CONCURRENT_INSERT.
7646
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
7647
&& lock_type <= TL_WRITE)
7648
&& !session_tablespace_op(session)
7649
&& sql_command != SQLCOM_TRUNCATE
7650
&& sql_command != SQLCOM_CREATE_TABLE) {
7652
lock_type = TL_WRITE_ALLOW_WRITE;
7655
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
7656
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
7657
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
7658
to t2. Convert the lock to a normal read lock to allow
7659
concurrent inserts to t2.
7662
if (lock_type == TL_READ_NO_INSERT) {
7664
lock_type = TL_READ;
7667
lock.type = lock_type;
7675
/*********************************************************************//**
7676
Read the next autoinc value. Acquire the relevant locks before reading
7677
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
7678
on return and all relevant locks acquired.
7679
@return DB_SUCCESS or error code */
7682
ha_innobase::innobase_get_autoinc(
7683
/*==============================*/
7684
uint64_t* value) /*!< out: autoinc value */
7688
prebuilt->autoinc_error = innobase_lock_autoinc();
7690
if (prebuilt->autoinc_error == DB_SUCCESS) {
7692
/* Determine the first value of the interval */
7693
*value = dict_table_autoinc_read(prebuilt->table);
7695
/* It should have been initialized during open. */
7699
return(prebuilt->autoinc_error);
7702
/*******************************************************************//**
7703
This function reads the global auto-inc counter. It doesn't use the
7704
AUTOINC lock even if the lock mode is set to TRADITIONAL.
7705
@return the autoinc value */
7708
ha_innobase::innobase_peek_autoinc(void)
7709
/*====================================*/
7712
dict_table_t* innodb_table;
7714
ut_a(prebuilt != NULL);
7715
ut_a(prebuilt->table != NULL);
7717
innodb_table = prebuilt->table;
7719
dict_table_autoinc_lock(innodb_table);
7721
auto_inc = dict_table_autoinc_read(innodb_table);
7725
dict_table_autoinc_unlock(innodb_table);
7730
/*********************************************************************//**
7731
This function initializes the auto-inc counter if it has not been
7732
initialized yet. This function does not change the value of the auto-inc
7733
counter if it already has been initialized. Returns the value of the
7734
auto-inc counter in *first_value, and UINT64_T_MAX in *nb_reserved_values (as
7735
we have a table-level lock). offset, increment, nb_desired_values are ignored.
7736
*first_value is set to -1 if error (deadlock or lock wait timeout) */
7739
ha_innobase::get_auto_increment(
7740
/*============================*/
7741
uint64_t offset, /*!< in: table autoinc offset */
7742
uint64_t increment, /*!< in: table autoinc increment */
7743
uint64_t nb_desired_values, /*!< in: number of values reqd */
7744
uint64_t *first_value, /*!< out: the autoinc value */
7745
uint64_t *nb_reserved_values) /*!< out: count of reserved values */
7749
uint64_t autoinc = 0;
7751
/* Prepare prebuilt->trx in the table handle */
7752
update_session(ha_session());
7754
error = innobase_get_autoinc(&autoinc);
7756
if (error != DB_SUCCESS) {
7757
*first_value = (~(uint64_t) 0);
7761
/* This is a hack, since nb_desired_values seems to be accurate only
7762
for the first call to get_auto_increment() for multi-row INSERT and
7763
meaningless for other statements e.g, LOAD etc. Subsequent calls to
7764
this method for the same statement results in different values which
7765
don't make sense. Therefore we store the value the first time we are
7766
called and count down from that as rows are written (see write_row()).
7769
trx = prebuilt->trx;
7771
/* Note: We can't rely on *first_value since some MySQL engines,
7772
in particular the partition engine, don't initialize it to 0 when
7773
invoking this method. So we are not sure if it's guaranteed to
7776
/* Called for the first time ? */
7777
if (trx->n_autoinc_rows == 0) {
7779
trx->n_autoinc_rows = (ulint) nb_desired_values;
7781
/* It's possible for nb_desired_values to be 0:
7782
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
7783
if (nb_desired_values == 0) {
7785
trx->n_autoinc_rows = 1;
7788
set_if_bigger(*first_value, autoinc);
7789
/* Not in the middle of a mult-row INSERT. */
7790
} else if (prebuilt->autoinc_last_value == 0) {
7791
set_if_bigger(*first_value, autoinc);
7794
*nb_reserved_values = trx->n_autoinc_rows;
7796
/* With old style AUTOINC locking we only update the table's
7797
AUTOINC counter after attempting to insert the row. */
7798
if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
7800
uint64_t next_value;
7801
uint64_t col_max_value;
7803
/* We need the upper limit of the col type to check for
7804
whether we update the table autoinc counter or not. */
7805
col_max_value = innobase_get_int_col_max_value(
7806
table->next_number_field);
7808
need = *nb_reserved_values * increment;
7810
/* Compute the last value in the interval */
7811
next_value = innobase_next_autoinc(
7812
*first_value, need, offset, col_max_value);
7814
prebuilt->autoinc_last_value = next_value;
7816
if (prebuilt->autoinc_last_value < *first_value) {
7817
*first_value = (~(unsigned long long) 0);
7819
/* Update the table autoinc variable */
7820
dict_table_autoinc_update_if_greater(
7821
prebuilt->table, prebuilt->autoinc_last_value);
7824
/* This will force write_row() into attempting an update
7825
of the table's AUTOINC counter. */
7826
prebuilt->autoinc_last_value = 0;
7829
/* The increment to be used to increase the AUTOINC value, we use
7830
this in write_row() and update_row() to increase the autoinc counter
7831
for columns that are filled by the user. We need the offset and
7833
prebuilt->autoinc_offset = offset;
7834
prebuilt->autoinc_increment = increment;
7836
dict_table_autoinc_unlock(prebuilt->table);
7839
/*******************************************************************//**
7840
Reset the auto-increment counter to the given value, i.e. the next row
7841
inserted will get the given value. This is called e.g. after TRUNCATE
7842
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
7843
returned by storage engines that don't support this operation.
7844
@return 0 or error code */
7847
ha_innobase::reset_auto_increment(
7848
/*==============================*/
7849
uint64_t value) /*!< in: new value for table autoinc */
7853
update_session(ha_session());
7855
error = row_lock_table_autoinc_for_mysql(prebuilt);
7857
if (error != DB_SUCCESS) {
7858
error = convert_error_code_to_mysql(error,
7859
prebuilt->table->flags,
7865
/* The next value can never be 0. */
7870
innobase_reset_autoinc(value);
7875
/* See comment in Cursor.cc */
7878
InnobaseEngine::get_error_message(int, String *buf)
7880
trx_t* trx = check_trx_exists(current_session);
7882
buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
7883
system_charset_info);
7888
/*******************************************************************//**
7889
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
7890
If there is no explicitly declared non-null unique key or a primary key, then
7891
InnoDB internally uses the row id as the primary key.
7892
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
7895
ha_innobase::cmp_ref(
7896
/*=================*/
7897
const unsigned char* ref1, /*!< in: an (internal) primary key value in the
7898
MySQL key value format */
7899
const unsigned char* ref2) /*!< in: an (internal) primary key value in the
7900
MySQL key value format */
7902
enum_field_types mysql_type;
7904
KEY_PART_INFO* key_part;
7905
KEY_PART_INFO* key_part_end;
7910
if (prebuilt->clust_index_was_generated) {
7911
/* The 'ref' is an InnoDB row id */
7913
return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
7916
/* Do a type-aware comparison of primary key fields. PK fields
7917
are always NOT NULL, so no checks for NULL are performed. */
7919
key_part = table->key_info[table->s->primary_key].key_part;
7921
key_part_end = key_part
7922
+ table->key_info[table->s->primary_key].key_parts;
7924
for (; key_part != key_part_end; ++key_part) {
7925
field = key_part->field;
7926
mysql_type = field->type();
7928
if (mysql_type == DRIZZLE_TYPE_BLOB) {
7930
/* In the MySQL key value format, a column prefix of
7931
a BLOB is preceded by a 2-byte length field */
7933
len1 = innobase_read_from_2_little_endian(ref1);
7934
len2 = innobase_read_from_2_little_endian(ref2);
7938
result = ((Field_blob*)field)->cmp( ref1, len1,
7941
result = field->key_cmp(ref1, ref2);
7949
ref1 += key_part->store_length;
7950
ref2 += key_part->store_length;
7956
/**********************************************************************
7957
This function is used to find the storage length in bytes of the first n
7958
characters for prefix indexes using a multibyte character set. The function
7959
finds charset information and returns length of prefix_len characters in the
7960
index field in bytes.
7961
@return number of bytes occupied by the first n characters */
7962
extern "C" UNIV_INTERN
7964
innobase_get_at_most_n_mbchars(
7965
/*===========================*/
7966
ulint charset_id, /*!< in: character set id */
7967
ulint prefix_len, /*!< in: prefix length in bytes of the index
7968
(this has to be divided by mbmaxlen to get the
7969
number of CHARACTERS n in the prefix) */
7970
ulint data_len, /*!< in: length of the string in bytes */
7971
const char* str); /*!< in: character string */
7974
innobase_get_at_most_n_mbchars(
7975
/*===========================*/
7976
ulint charset_id, /*!< in: character set id */
7977
ulint prefix_len, /*!< in: prefix length in bytes of the index
7978
(this has to be divided by mbmaxlen to get the
7979
number of CHARACTERS n in the prefix) */
7980
ulint data_len, /*!< in: length of the string in bytes */
7981
const char* str) /*!< in: character string */
7983
ulint char_length; /*!< character length in bytes */
7984
ulint n_chars; /*!< number of characters in prefix */
7985
const CHARSET_INFO* charset; /*!< charset used in the field */
7987
charset = get_charset((uint) charset_id);
7990
ut_ad(charset->mbmaxlen);
7992
/* Calculate how many characters at most the prefix index contains */
7994
n_chars = prefix_len / charset->mbmaxlen;
7996
/* If the charset is multi-byte, then we must find the length of the
7997
first at most n chars in the string. If the string contains less
7998
characters than n, then we return the length to the end of the last
8001
if (charset->mbmaxlen > 1) {
8002
/* my_charpos() returns the byte length of the first n_chars
8003
characters, or a value bigger than the length of str, if
8004
there were not enough full characters in str.
8006
Why does the code below work:
8007
Suppose that we are looking for n UTF-8 characters.
8009
1) If the string is long enough, then the prefix contains at
8010
least n complete UTF-8 characters + maybe some extra
8011
characters + an incomplete UTF-8 character. No problem in
8012
this case. The function returns the pointer to the
8013
end of the nth character.
8015
2) If the string is not long enough, then the string contains
8016
the complete value of a column, that is, only complete UTF-8
8017
characters, and we can store in the column prefix index the
8020
char_length = my_charpos(charset, str,
8021
str + data_len, (int) n_chars);
8022
if (char_length > data_len) {
8023
char_length = data_len;
8026
if (data_len < prefix_len) {
8027
char_length = data_len;
8029
char_length = prefix_len;
8033
return(char_length);
8036
* We will also use this function to communicate
8037
* to InnoDB that a new SQL statement has started and that we must store a
8038
* savepoint to our transaction handle, so that we are able to roll back
8039
* the SQL statement in case of an error.
8042
InnobaseEngine::doStartStatement(
8043
Session *session) /*!< in: handle to the Drizzle session */
8046
* Create the InnoDB transaction structure
8049
trx_t *trx= check_trx_exists(session);
8051
/* "reset" the error message for the transaction */
8052
trx->detailed_error[0]= '\0';
8054
/* Set the isolation level of the transaction. */
8055
trx->isolation_level= innobase_map_isolation_level((enum_tx_isolation) session_tx_isolation(session));
8059
InnobaseEngine::doEndStatement(
8062
trx_t *trx= check_trx_exists(session);
8064
/* Release a possible FIFO ticket and search latch. Since we
8065
may reserve the kernel mutex, we have to release the search
8066
system latch first to obey the latching order. */
8068
innobase_release_stat_resources(trx);
8070
if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
8072
if (trx->conc_state != TRX_NOT_STARTED)
8074
commit(session, TRUE);
8079
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
8080
trx->global_read_view)
8082
/* At low transaction isolation levels we let
8083
each consistent read set its own snapshot */
8084
read_view_close_for_mysql(trx);
8089
/*******************************************************************//**
8090
This function is used to prepare an X/Open XA distributed transaction.
8091
@return 0 or error number */
8093
InnobaseEngine::doXaPrepare(
8094
/*================*/
8095
Session* session,/*!< in: handle to the MySQL thread of
8096
the user whose XA transaction should
8098
bool all) /*!< in: TRUE - commit transaction
8099
FALSE - the current SQL statement
8103
trx_t* trx = check_trx_exists(session);
8105
assert(this == innodb_engine_ptr);
8107
/* we use support_xa value as it was seen at transaction start
8108
time, not the current session variable value. Any possible changes
8109
to the session variable take effect only in the next transaction */
8110
if (!trx->support_xa) {
8115
session_get_xid(session, reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
8117
/* Release a possible FIFO ticket and search latch. Since we will
8118
reserve the kernel mutex, we have to release the search system latch
8119
first to obey the latching order. */
8121
innobase_release_stat_resources(trx);
8124
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
8126
/* We were instructed to prepare the whole transaction, or
8127
this is an SQL statement end and autocommit is on */
8129
ut_ad(trx->conc_state != TRX_NOT_STARTED);
8131
error = (int) trx_prepare_for_mysql(trx);
8133
/* We just mark the SQL statement ended and do not do a
8134
transaction prepare */
8136
/* If we had reserved the auto-inc lock for some
8137
table in this SQL statement we release it now */
8139
row_unlock_table_autoinc_for_mysql(trx);
8141
/* Store the current undo_no of the transaction so that we
8142
know where to roll back if we have to roll back the next
8145
trx_mark_sql_stat_end(trx);
8148
/* Tell the InnoDB server that there might be work for utility
8151
srv_active_wake_master_thread();
8153
if (all || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
8156
/* For ibbackup to work the order of transactions in binlog
8157
and InnoDB must be the same. Consider the situation
8159
thread1> prepare; write to binlog; ...
8161
thread2> prepare; write to binlog; commit
8164
To ensure this will not happen we're taking the mutex on
8165
prepare, and releasing it on commit.
8167
Note: only do it for normal commits, done via ha_commit_trans.
8168
If 2pc protocol is executed by external transaction
8169
coordinator, it will be just a regular MySQL client
8170
executing XA PREPARE and XA COMMIT commands.
8171
In this case we cannot know how many minutes or hours
8172
will be between XA PREPARE and XA COMMIT, and we don't want
8173
to block for undefined period of time.
8175
pthread_mutex_lock(&prepare_commit_mutex);
8176
trx->conc_state = TRX_PREPARED;
8181
/*******************************************************************//**
8182
This function is used to recover X/Open XA distributed transactions.
8183
@return number of prepared transactions stored in xid_list */
8185
InnobaseEngine::doXaRecover(
8186
/*================*/
8187
::drizzled::XID* xid_list,/*!< in/out: prepared transactions */
8188
size_t len) /*!< in: number of slots in xid_list */
8190
assert(this == innodb_engine_ptr);
8192
if (len == 0 || xid_list == NULL) {
8197
return(trx_recover_for_mysql((::XID *)xid_list, len));
8200
/*******************************************************************//**
8201
This function is used to commit one X/Open XA distributed transaction
8202
which is in the prepared state
8203
@return 0 or error number */
8205
InnobaseEngine::doXaCommitXid(
8206
/*===================*/
8207
::drizzled::XID* xid) /*!< in: X/Open XA transaction identification */
8211
assert(this == innodb_engine_ptr);
8213
trx = trx_get_trx_by_xid((::XID *)xid);
8216
innobase_commit_low(trx);
8224
/*******************************************************************//**
8225
This function is used to rollback one X/Open XA distributed transaction
8226
which is in the prepared state
8227
@return 0 or error number */
8229
InnobaseEngine::doXaRollbackXid(
8230
/*=====================*/
8231
::drizzled::XID* xid) /*!< in: X/Open XA transaction
8236
assert(this == innodb_engine_ptr);
8238
trx = trx_get_trx_by_xid((::XID *)xid);
8241
return(innobase_rollback_trx(trx));
8248
/************************************************************//**
8249
Validate the file format name and return its corresponding id.
8250
@return valid file format id */
8253
innobase_file_format_name_lookup(
8254
/*=============================*/
8255
const char* format_name) /*!< in: pointer to file format name */
8260
ut_a(format_name != NULL);
8262
/* The format name can contain the format id itself instead of
8263
the name and we check for that. */
8264
format_id = (uint) strtoul(format_name, &endp, 10);
8266
/* Check for valid parse. */
8267
if (*endp == '\0' && *format_name != '\0') {
8269
if (format_id <= DICT_TF_FORMAT_MAX) {
8275
for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
8279
name = trx_sys_file_format_id_to_name(format_id);
8281
if (!innobase_strcasecmp(format_name, name)) {
8288
return(DICT_TF_FORMAT_MAX + 1);
8291
/************************************************************//**
8292
Validate the file format check value, is it one of "on" or "off",
8293
as a side effect it sets the srv_check_file_format_at_startup variable.
8294
@return true if config value one of "on" or "off" */
8297
innobase_file_format_check_on_off(
8298
/*==============================*/
8299
const char* format_check) /*!< in: parameter value */
8303
if (!innobase_strcasecmp(format_check, "off")) {
8305
/* Set the value to disable checking. */
8306
srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
8308
} else if (!innobase_strcasecmp(format_check, "on")) {
8310
/* Set the value to the lowest supported format. */
8311
srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
8319
/************************************************************//**
8320
Validate the file format check config parameters, as a side effect it
8321
sets the srv_check_file_format_at_startup variable.
8322
@return true if valid config value */
8325
innobase_file_format_check_validate(
8326
/*================================*/
8327
const char* format_check) /*!< in: parameter value */
8332
format_id = innobase_file_format_name_lookup(format_check);
8334
if (format_id < DICT_TF_FORMAT_MAX + 1) {
8335
srv_check_file_format_at_startup = format_id;
8343
/*************************************************************//**
8344
Check if it is a valid file format. This function is registered as
8345
a callback with MySQL.
8346
@return 0 for valid file format */
8349
innodb_file_format_name_validate(
8350
/*=============================*/
8351
Session* , /*!< in: thread handle */
8352
drizzle_sys_var* , /*!< in: pointer to system
8354
void* save, /*!< out: immediate result
8355
for update function */
8356
drizzle_value* value) /*!< in: incoming string */
8358
const char* file_format_input;
8359
char buff[STRING_BUFFER_USUAL_SIZE];
8360
int len = sizeof(buff);
8363
ut_a(value != NULL);
8365
file_format_input = value->val_str(value, buff, &len);
8367
if (file_format_input != NULL) {
8370
format_id = innobase_file_format_name_lookup(
8373
if (format_id <= DICT_TF_FORMAT_MAX) {
8375
*static_cast<const char**>(save) = file_format_input;
8380
*static_cast<const char**>(save) = NULL;
8384
/****************************************************************//**
8385
Update the system variable innodb_file_format using the "saved"
8386
value. This function is registered as a callback with MySQL. */
8389
innodb_file_format_name_update(
8390
/*===========================*/
8391
Session* , /*!< in: thread handle */
8392
drizzle_sys_var* , /*!< in: pointer to
8394
void* var_ptr, /*!< out: where the
8395
formal string goes */
8396
const void* save) /*!< in: immediate result
8397
from check function */
8399
const char* format_name;
8401
ut_a(var_ptr != NULL);
8404
format_name = *static_cast<const char*const*>(save);
8409
format_id = innobase_file_format_name_lookup(format_name);
8411
if (format_id <= DICT_TF_FORMAT_MAX) {
8412
srv_file_format = format_id;
8416
*static_cast<const char**>(var_ptr)
8417
= trx_sys_file_format_id_to_name(srv_file_format);
8420
/*************************************************************//**
8421
Check if valid argument to innodb_file_format_check. This
8422
function is registered as a callback with MySQL.
8423
@return 0 for valid file format */
8426
innodb_file_format_check_validate(
8427
/*==============================*/
8428
Session* , /*!< in: thread handle */
8429
drizzle_sys_var* , /*!< in: pointer to system
8431
void* save, /*!< out: immediate result
8432
for update function */
8433
drizzle_value* value) /*!< in: incoming string */
8435
const char* file_format_input;
8436
char buff[STRING_BUFFER_USUAL_SIZE];
8437
int len = sizeof(buff);
8440
ut_a(value != NULL);
8442
file_format_input = value->val_str(value, buff, &len);
8444
if (file_format_input != NULL) {
8446
/* Check if user set on/off, we want to print a suitable
8447
message if they did so. */
8449
if (innobase_file_format_check_on_off(file_format_input)) {
8450
errmsg_printf(ERRMSG_LVL_WARN,
8451
"InnoDB: invalid innodb_file_format_check "
8452
"value; on/off can only be set at startup or "
8453
"in the configuration file");
8454
} else if (innobase_file_format_check_validate(
8455
file_format_input)) {
8457
*static_cast<const char**>(save) = file_format_input;
8462
errmsg_printf(ERRMSG_LVL_WARN,
8463
"InnoDB: invalid innodb_file_format_check "
8464
"value; can be any format up to %s "
8465
"or its equivalent numeric id",
8466
trx_sys_file_format_id_to_name(
8467
DICT_TF_FORMAT_MAX));
8471
*static_cast<const char**>(save) = NULL;
8475
/****************************************************************//**
8476
Update the system variable innodb_file_format_check using the "saved"
8477
value. This function is registered as a callback with MySQL. */
8480
innodb_file_format_check_update(
8481
/*============================*/
8482
Session* session, /*!< in: thread handle */
8483
drizzle_sys_var* , /*!< in: pointer to
8485
void* var_ptr, /*!< out: where the
8486
formal string goes */
8487
const void* save) /*!< in: immediate result
8488
from check function */
8490
const char* format_name_in;
8491
const char** format_name_out;
8495
ut_a(var_ptr != NULL);
8497
format_name_in = *static_cast<const char*const*>(save);
8499
if (!format_name_in) {
8504
format_id = innobase_file_format_name_lookup(format_name_in);
8506
if (format_id > DICT_TF_FORMAT_MAX) {
8507
/* DEFAULT is "on", which is invalid at runtime. */
8508
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
8510
"Ignoring SET innodb_file_format=%s",
8515
format_name_out = static_cast<const char**>(var_ptr);
8517
/* Update the max format id in the system tablespace. */
8518
if (trx_sys_file_format_max_set(format_id, format_name_out)) {
8519
ut_print_timestamp(stderr);
8521
" [Info] InnoDB: the file format in the system "
8522
"tablespace is now set to %s.\n", *format_name_out);
8526
/****************************************************************//**
8527
Update the system variable innodb_adaptive_hash_index using the "saved"
8528
value. This function is registered as a callback with MySQL. */
8531
innodb_adaptive_hash_index_update(
8532
/*==============================*/
8533
Session* , /*!< in: thread handle */
8534
drizzle_sys_var* , /*!< in: pointer to
8536
void* , /*!< out: where the
8537
formal string goes */
8538
const void* save) /*!< in: immediate result
8539
from check function */
8541
if (*(bool*) save) {
8542
btr_search_enable();
8544
btr_search_disable();
8548
/*************************************************************//**
8549
Check if it is a valid value of innodb_change_buffering. This function is
8550
registered as a callback with MySQL.
8551
@return 0 for valid innodb_change_buffering */
8554
innodb_change_buffering_validate(
8555
/*=============================*/
8556
Session* , /*!< in: thread handle */
8557
drizzle_sys_var* , /*!< in: pointer to system
8559
void* save, /*!< out: immediate result
8560
for update function */
8561
drizzle_value* value) /*!< in: incoming string */
8563
const char* change_buffering_input;
8564
char buff[STRING_BUFFER_USUAL_SIZE];
8565
int len = sizeof(buff);
8568
ut_a(value != NULL);
8570
change_buffering_input = value->val_str(value, buff, &len);
8572
if (change_buffering_input != NULL) {
8575
for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
8577
if (!innobase_strcasecmp(
8578
change_buffering_input,
8579
innobase_change_buffering_values[use])) {
8580
*(ibuf_use_t*) save = (ibuf_use_t) use;
8589
/****************************************************************//**
8590
Update the system variable innodb_change_buffering using the "saved"
8591
value. This function is registered as a callback with MySQL. */
8594
innodb_change_buffering_update(
8595
/*===========================*/
8596
Session* , /*!< in: thread handle */
8597
drizzle_sys_var* , /*!< in: pointer to
8599
void* var_ptr, /*!< out: where the
8600
formal string goes */
8601
const void* save) /*!< in: immediate result
8602
from check function */
8604
ut_a(var_ptr != NULL);
8606
ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
8608
ibuf_use = *(const ibuf_use_t*) save;
8610
*(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
8613
/* plugin options */
8614
static DRIZZLE_SYSVAR_BOOL(checksums, innobase_use_checksums,
8615
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8616
"Enable InnoDB checksums validation (enabled by default). "
8617
"Disable with --skip-innodb-checksums.",
8620
static DRIZZLE_SYSVAR_STR(data_home_dir, innobase_data_home_dir,
8621
PLUGIN_VAR_READONLY,
8622
"The common part for InnoDB table spaces.",
8625
static DRIZZLE_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
8626
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8627
"Enable InnoDB doublewrite buffer (enabled by default). "
8628
"Disable with --skip-innodb-doublewrite.",
8631
static DRIZZLE_SYSVAR_ULONG(io_capacity, srv_io_capacity,
8632
PLUGIN_VAR_RQCMDARG,
8633
"Number of IOPs the server can do. Tunes the background IO rate",
8634
NULL, NULL, 200, 100, ~0L, 0);
8636
static DRIZZLE_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
8637
PLUGIN_VAR_OPCMDARG,
8638
"Speeds up the shutdown process of the InnoDB storage engine. Possible "
8639
"values are 0, 1 (faster)"
8640
" or 2 (fastest - crash-like)"
8642
NULL, NULL, 1, 0, 2, 0);
8644
static DRIZZLE_SYSVAR_BOOL(file_per_table, srv_file_per_table,
8645
PLUGIN_VAR_NOCMDARG,
8646
"Stores each InnoDB table to an .ibd file in the database dir.",
8649
static DRIZZLE_SYSVAR_STR(file_format, innobase_file_format_name,
8650
PLUGIN_VAR_RQCMDARG,
8651
"File format to use for new tables in .ibd files.",
8652
innodb_file_format_name_validate,
8653
innodb_file_format_name_update, "Antelope");
8655
static DRIZZLE_SYSVAR_STR(file_format_check, innobase_file_format_check,
8656
PLUGIN_VAR_OPCMDARG,
8657
"The highest file format in the tablespace.",
8658
innodb_file_format_check_validate,
8659
innodb_file_format_check_update,
8662
static DRIZZLE_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
8663
PLUGIN_VAR_OPCMDARG,
8664
"Set to 0 (write and flush once per second),"
8665
" 1 (write and flush at each commit)"
8666
" or 2 (write at commit, flush once per second).",
8667
NULL, NULL, 1, 0, 2, 0);
8669
static DRIZZLE_SYSVAR_STR(flush_method, innobase_unix_file_flush_method,
8670
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8671
"With which method to flush data.", NULL, NULL, NULL);
8673
#ifdef UNIV_LOG_ARCHIVE
8674
static DRIZZLE_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
8675
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8676
"Where full logs should be archived.", NULL, NULL, NULL);
8678
static DRIZZLE_SYSVAR_BOOL(log_archive, innobase_log_archive,
8679
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
8680
"Set to 1 if you want to have logs archived.", NULL, NULL, FALSE);
8681
#endif /* UNIV_LOG_ARCHIVE */
8683
static DRIZZLE_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir,
8684
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8685
"Path to InnoDB log files.", NULL, NULL, NULL);
8687
static DRIZZLE_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
8688
PLUGIN_VAR_RQCMDARG,
8689
"Percentage of dirty pages allowed in bufferpool.",
8690
NULL, NULL, 75, 0, 99, 0);
8692
static DRIZZLE_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing,
8693
PLUGIN_VAR_NOCMDARG,
8694
"Attempt flushing dirty pages to avoid IO bursts at checkpoints.",
8697
static DRIZZLE_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
8698
PLUGIN_VAR_RQCMDARG,
8699
"Desired maximum length of the purge queue (0 = no limit)",
8700
NULL, NULL, 0, 0, ~0L, 0);
8702
static DRIZZLE_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
8703
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
8704
"Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
8707
static DRIZZLE_SYSVAR_BOOL(status_file, innobase_create_status_file,
8708
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR,
8709
"Enable SHOW INNODB STATUS output in the innodb_status.<pid> file",
8712
static DRIZZLE_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
8713
PLUGIN_VAR_OPCMDARG,
8714
"Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
8717
static DRIZZLE_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_sample_pages,
8718
PLUGIN_VAR_RQCMDARG,
8719
"The number of index pages to sample when calculating statistics (default 8)",
8720
NULL, NULL, 8, 1, ~0ULL, 0);
8722
static DRIZZLE_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
8723
PLUGIN_VAR_OPCMDARG,
8724
"Enable InnoDB adaptive hash index (enabled by default). "
8725
"Disable with --skip-innodb-adaptive-hash-index.",
8726
NULL, innodb_adaptive_hash_index_update, TRUE);
8728
static DRIZZLE_SYSVAR_ULONG(replication_delay, srv_replication_delay,
8729
PLUGIN_VAR_RQCMDARG,
8730
"Replication thread delay (ms) on the slave server if "
8731
"innodb_thread_concurrency is reached (0 by default)",
8732
NULL, NULL, 0, 0, ~0UL, 0);
8734
static DRIZZLE_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
8735
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8736
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
8737
NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024);
8739
static DRIZZLE_SYSVAR_UINT(autoextend_increment, srv_auto_extend_increment,
8740
PLUGIN_VAR_RQCMDARG,
8741
"Data file autoextend increment in megabytes",
8742
NULL, NULL, 8L, 1L, 1000L, 0);
8744
static DRIZZLE_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
8745
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8746
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
8747
NULL, NULL, 128*1024*1024L, 5*1024*1024L, INT64_MAX, 1024*1024L);
8749
static DRIZZLE_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
8750
PLUGIN_VAR_RQCMDARG,
8751
"Helps in performance tuning in heavily concurrent environments.",
8752
innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0);
8754
static DRIZZLE_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter,
8755
PLUGIN_VAR_RQCMDARG,
8756
"Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
8757
NULL, NULL, 500L, 1L, ~0L, 0);
8759
static DRIZZLE_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
8760
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8761
"Number of file I/O threads in InnoDB.",
8762
NULL, NULL, 4, 4, 64, 0);
8764
static DRIZZLE_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
8765
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8766
"Number of background read I/O threads in InnoDB.",
8767
NULL, NULL, 4, 1, 64, 0);
8769
static DRIZZLE_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
8770
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8771
"Number of background write I/O threads in InnoDB.",
8772
NULL, NULL, 4, 1, 64, 0);
8774
static DRIZZLE_SYSVAR_LONG(force_recovery, innobase_force_recovery,
8775
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8776
"Helps to save your data in case the disk image of the database becomes corrupt.",
8777
NULL, NULL, 0, 0, 6, 0);
8779
static DRIZZLE_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
8780
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8781
"The size of the buffer which InnoDB uses to write log to the log files on disk.",
8782
NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
8784
static DRIZZLE_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
8785
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8786
"Size of each log file in a log group.",
8787
NULL, NULL, 5*1024*1024L, 1*1024*1024L, INT64_MAX, 1024*1024L);
8789
static DRIZZLE_SYSVAR_LONG(log_files_in_group, innobase_log_files_in_group,
8790
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8791
"Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.",
8792
NULL, NULL, 2, 2, 100, 0);
8794
static DRIZZLE_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
8795
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8796
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
8797
NULL, NULL, 1, 1, 10, 0);
8799
static DRIZZLE_SYSVAR_LONG(open_files, innobase_open_files,
8800
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8801
"How many files at the maximum InnoDB keeps open at the same time.",
8802
NULL, NULL, 300L, 10L, LONG_MAX, 0);
8804
static DRIZZLE_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
8805
PLUGIN_VAR_RQCMDARG,
8806
"Count of spin-loop rounds in InnoDB mutexes (30 by default)",
8807
NULL, NULL, 30L, 0L, ~0L, 0);
8809
static DRIZZLE_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay,
8810
PLUGIN_VAR_OPCMDARG,
8811
"Maximum delay between polling for a spin lock (6 by default)",
8812
NULL, NULL, 6L, 0L, ~0L, 0);
8814
static DRIZZLE_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
8815
PLUGIN_VAR_RQCMDARG,
8816
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
8817
NULL, NULL, 0, 0, 1000, 0);
8819
static DRIZZLE_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
8820
PLUGIN_VAR_RQCMDARG,
8821
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep",
8822
NULL, NULL, 10000L, 0L, ~0L, 0);
8824
static DRIZZLE_SYSVAR_STR(data_file_path, innobase_data_file_path,
8825
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8826
"Path to individual files and their sizes.",
8829
static DRIZZLE_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
8830
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8831
"The AUTOINC lock modes supported by InnoDB: "
8832
"0 => Old style AUTOINC locking (for backward"
8834
"1 => New style AUTOINC locking "
8835
"2 => No AUTOINC locking (unsafe for SBR)",
8837
AUTOINC_NO_LOCKING, /* Default setting */
8838
AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */
8839
AUTOINC_NO_LOCKING, 0); /* Maximum value */
8841
static DRIZZLE_SYSVAR_STR(version, innodb_version_str,
8842
PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
8843
"InnoDB version", NULL, NULL, INNODB_VERSION_STR);
8845
static DRIZZLE_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
8846
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8847
"Use OS memory allocator instead of InnoDB's internal memory allocator",
8850
static DRIZZLE_SYSVAR_STR(change_buffering, innobase_change_buffering,
8851
PLUGIN_VAR_RQCMDARG,
8852
"Buffer changes to reduce random access: "
8853
"OFF, ON, inserting, deleting, changing, or purging.",
8854
innodb_change_buffering_validate,
8855
innodb_change_buffering_update, NULL);
8857
static DRIZZLE_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
8858
PLUGIN_VAR_RQCMDARG,
8859
"Number of pages that must be accessed sequentially for InnoDB to"
8860
"trigger a readahead.",
8861
NULL, NULL, 56, 0, 64, 0);
8863
static drizzle_sys_var* innobase_system_variables[]= {
8864
DRIZZLE_SYSVAR(additional_mem_pool_size),
8865
DRIZZLE_SYSVAR(autoextend_increment),
8866
DRIZZLE_SYSVAR(buffer_pool_size),
8867
DRIZZLE_SYSVAR(checksums),
8868
DRIZZLE_SYSVAR(commit_concurrency),
8869
DRIZZLE_SYSVAR(concurrency_tickets),
8870
DRIZZLE_SYSVAR(data_file_path),
8871
DRIZZLE_SYSVAR(data_home_dir),
8872
DRIZZLE_SYSVAR(doublewrite),
8873
DRIZZLE_SYSVAR(fast_shutdown),
8874
DRIZZLE_SYSVAR(file_io_threads),
8875
DRIZZLE_SYSVAR(read_io_threads),
8876
DRIZZLE_SYSVAR(write_io_threads),
8877
DRIZZLE_SYSVAR(file_per_table),
8878
DRIZZLE_SYSVAR(file_format),
8879
DRIZZLE_SYSVAR(file_format_check),
8880
DRIZZLE_SYSVAR(flush_log_at_trx_commit),
8881
DRIZZLE_SYSVAR(flush_method),
8882
DRIZZLE_SYSVAR(force_recovery),
8883
DRIZZLE_SYSVAR(lock_wait_timeout),
8884
#ifdef UNIV_LOG_ARCHIVE
8885
DRIZZLE_SYSVAR(log_arch_dir),
8886
DRIZZLE_SYSVAR(log_archive),
8887
#endif /* UNIV_LOG_ARCHIVE */
8888
DRIZZLE_SYSVAR(log_buffer_size),
8889
DRIZZLE_SYSVAR(log_file_size),
8890
DRIZZLE_SYSVAR(log_files_in_group),
8891
DRIZZLE_SYSVAR(log_group_home_dir),
8892
DRIZZLE_SYSVAR(max_dirty_pages_pct),
8893
DRIZZLE_SYSVAR(max_purge_lag),
8894
DRIZZLE_SYSVAR(adaptive_flushing),
8895
DRIZZLE_SYSVAR(mirrored_log_groups),
8896
DRIZZLE_SYSVAR(open_files),
8897
DRIZZLE_SYSVAR(rollback_on_timeout),
8898
DRIZZLE_SYSVAR(stats_on_metadata),
8899
DRIZZLE_SYSVAR(stats_sample_pages),
8900
DRIZZLE_SYSVAR(adaptive_hash_index),
8901
DRIZZLE_SYSVAR(replication_delay),
8902
DRIZZLE_SYSVAR(status_file),
8903
DRIZZLE_SYSVAR(strict_mode),
8904
DRIZZLE_SYSVAR(support_xa),
8905
DRIZZLE_SYSVAR(sync_spin_loops),
8906
DRIZZLE_SYSVAR(spin_wait_delay),
8907
DRIZZLE_SYSVAR(table_locks),
8908
DRIZZLE_SYSVAR(thread_concurrency),
8909
DRIZZLE_SYSVAR(thread_sleep_delay),
8910
DRIZZLE_SYSVAR(autoinc_lock_mode),
8911
DRIZZLE_SYSVAR(version),
8912
DRIZZLE_SYSVAR(use_sys_malloc),
8913
DRIZZLE_SYSVAR(change_buffering),
8914
DRIZZLE_SYSVAR(read_ahead_threshold),
8915
DRIZZLE_SYSVAR(io_capacity),
8919
DRIZZLE_DECLARE_PLUGIN
8922
innobase_engine_name,
8925
"Supports transactions, row-level locking, and foreign keys",
8927
innobase_init, /* Plugin Init */
8928
innobase_system_variables, /* system variables */
8931
DRIZZLE_DECLARE_PLUGIN_END;
8933
int ha_innobase::read_range_first(const key_range *start_key,
8934
const key_range *end_key,
8939
//if (!eq_range_arg)
8940
//in_range_read= TRUE;
8941
res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
8943
// in_range_read= FALSE;
8948
int ha_innobase::read_range_next()
8950
int res= Cursor::read_range_next();
8952
// in_range_read= FALSE;
8956
/** @brief Initialize the default value of innodb_commit_concurrency.
8958
Once InnoDB is running, the innodb_commit_concurrency must not change
8959
from zero to nonzero. (Bug #42101)
8961
The initial default value is 0, and without this extra initialization,
8962
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
8963
to 0, even if it was initially set to nonzero at the command line
8964
or configuration file. */
8967
innobase_commit_concurrency_init_default(void)
8968
/*==========================================*/
8970
DRIZZLE_SYSVAR_NAME(commit_concurrency).def_val
8971
= innobase_commit_concurrency;
8974
#ifdef UNIV_COMPILE_TEST_FUNCS
8976
typedef struct innobase_convert_name_test_struct {
8984
const char* expected;
8985
} innobase_convert_name_test_t;
8988
test_innobase_convert_name()
8993
innobase_convert_name_test_t test_input[] = {
8994
{buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
8995
{buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
8996
{buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
8997
{buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
8998
{buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
9000
{buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9001
{buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9002
{buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9003
{buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9004
{buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
9005
{buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
9006
{buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
9008
{buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
9009
"\"#mysql50#ab\"\"cd\""},
9010
{buf, 17, "ab\"cd", 5, NULL, TRUE,
9011
"\"#mysql50#ab\"\"cd\""},
9012
{buf, 16, "ab\"cd", 5, NULL, TRUE,
9013
"\"#mysql50#ab\"\"c\""},
9014
{buf, 15, "ab\"cd", 5, NULL, TRUE,
9015
"\"#mysql50#ab\"\"\""},
9016
{buf, 14, "ab\"cd", 5, NULL, TRUE,
9018
{buf, 13, "ab\"cd", 5, NULL, TRUE,
9020
{buf, 12, "ab\"cd", 5, NULL, TRUE,
9022
{buf, 11, "ab\"cd", 5, NULL, TRUE,
9024
{buf, 10, "ab\"cd", 5, NULL, TRUE,
9027
{buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9028
{buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9029
{buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
9030
{buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
9031
{buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9032
{buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9033
{buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
9034
{buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
9035
{buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
9036
/* XXX probably "" is a better result in this case
9037
{buf, 1, "ab/cd", 5, NULL, TRUE, "."},
9039
{buf, 0, "ab/cd", 5, NULL, TRUE, ""},
9042
for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
9048
fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
9049
test_input[i].buflen,
9051
test_input[i].idlen,
9052
test_input[i].expected);
9054
end = innobase_convert_name(
9056
test_input[i].buflen,
9058
test_input[i].idlen,
9059
test_input[i].session,
9060
test_input[i].file_id);
9062
res_len = (size_t) (end - test_input[i].buf);
9064
if (res_len != strlen(test_input[i].expected)) {
9066
fprintf(stderr, "unexpected len of the result: %u, "
9067
"expected: %u\n", (unsigned) res_len,
9068
(unsigned) strlen(test_input[i].expected));
9072
if (memcmp(test_input[i].buf,
9073
test_input[i].expected,
9074
strlen(test_input[i].expected)) != 0
9077
fprintf(stderr, "unexpected result: %.*s, "
9078
"expected: %s\n", (int) res_len,
9080
test_input[i].expected);
9085
fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9088
fprintf(stderr, "FAILED\n\n");
9094
#endif /* UNIV_COMPILE_TEST_FUNCS */