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/memory/multi_malloc.h"
84
#include "drizzled/pthread_globals.h"
85
#include "drizzled/named_savepoint.h"
87
#include <drizzled/transaction_services.h>
89
/** @file ha_innodb.cc */
91
/* Include necessary InnoDB headers */
96
#include "os0thread.h"
97
#include "srv0start.h"
104
#include "row0mysql.h"
108
#include "lock0lock.h"
109
#include "dict0crea.h"
113
#include "sync0sync.h"
116
#include "row0merge.h"
118
#include "dict0boot.h"
119
#include "ha_prototypes.h"
121
#include "ibuf0ibuf.h"
124
#include "ha_innodb.h"
125
#include "data_dictionary.h"
126
#include "handler0vars.h"
132
#include "plugin/innobase/handler/status_function.h"
135
using namespace drizzled;
137
#ifndef DRIZZLE_SERVER
138
/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t
139
is defined the same in both builds: the MySQL server and the InnoDB plugin. */
140
extern pthread_mutex_t LOCK_thread_count;
142
#endif /* DRIZZLE_SERVER */
144
/** to protect innobase_open_files */
145
static pthread_mutex_t innobase_share_mutex;
146
/** to force correct commit order in binlog */
147
static pthread_mutex_t prepare_commit_mutex;
148
static ulong commit_threads = 0;
149
static pthread_mutex_t commit_threads_m;
150
static pthread_cond_t commit_cond;
151
static pthread_mutex_t commit_cond_m;
152
static bool innodb_inited = 0;
154
#define INSIDE_HA_INNOBASE_CC
156
/* In the Windows plugin, the return value of current_session is
157
undefined. Map it to NULL. */
158
#if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
159
# undef current_session
160
# define current_session NULL
161
# define EQ_CURRENT_SESSION(session) TRUE
162
#else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
163
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
164
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
166
static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
167
static plugin::TableFunction* status_table_function_ptr= NULL;
168
static plugin::TableFunction* cmp_tool= NULL;
169
static plugin::TableFunction* cmp_reset_tool= NULL;
170
static plugin::TableFunction* cmp_mem_tool= NULL;
171
static plugin::TableFunction* cmp_mem_reset_tool= NULL;
172
static plugin::TableFunction* innodb_trx_tool= NULL;
173
static plugin::TableFunction* innodb_locks_tool= NULL;
174
static plugin::TableFunction* innodb_lock_waits_tool= NULL;
176
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
177
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
178
static const long AUTOINC_NO_LOCKING = 2;
180
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
181
innobase_log_buffer_size,
182
innobase_additional_mem_pool_size, innobase_file_io_threads,
183
innobase_force_recovery, innobase_open_files,
184
innobase_autoinc_lock_mode;
185
static ulong innobase_commit_concurrency = 0;
186
static ulong innobase_read_io_threads;
187
static ulong innobase_write_io_threads;
190
* @TODO: Turn this into size_t as soon as we have a Variable<size_t>
192
static int64_t innobase_buffer_pool_size, innobase_log_file_size;
194
/* The default values for the following char* start-up parameters
195
are determined in innobase_init below: */
197
static char* innobase_data_home_dir = NULL;
198
static char* innobase_data_file_path = NULL;
199
static char* innobase_log_group_home_dir = NULL;
200
static char* innobase_file_format_name = NULL;
201
static char* innobase_change_buffering = NULL;
203
/* Note: This variable can be set to on/off and any of the supported
204
file formats in the configuration file, but can only be set to any
205
of the supported file formats during runtime. */
206
static char* innobase_file_format_check = NULL;
208
/* The following has a misleading name: starting from 4.0.5, this also
210
static char* innobase_unix_file_flush_method = NULL;
212
/* Below we have boolean-valued start-up parameters, and their default
215
static ulong innobase_fast_shutdown = 1;
216
#ifdef UNIV_LOG_ARCHIVE
217
static my_bool innobase_log_archive = FALSE;
218
static char* innobase_log_arch_dir = NULL;
219
#endif /* UNIV_LOG_ARCHIVE */
220
static my_bool innobase_use_doublewrite = TRUE;
221
static my_bool innobase_use_checksums = TRUE;
222
static my_bool innobase_rollback_on_timeout = FALSE;
223
static my_bool innobase_create_status_file = FALSE;
224
static my_bool innobase_stats_on_metadata = TRUE;
226
static char* internal_innobase_data_file_path = NULL;
228
static char* innodb_version_str = (char*) INNODB_VERSION_STR;
230
/* The following counter is used to convey information to InnoDB
231
about server activity: in selects it is not sensible to call
232
srv_active_wake_master_thread after each fetch or search, we only do
233
it every INNOBASE_WAKE_INTERVAL'th step. */
235
#define INNOBASE_WAKE_INTERVAL 32
236
static ulong innobase_active_counter = 0;
238
static hash_table_t* innobase_open_tables;
240
#ifdef __NETWARE__ /* some special cleanup for NetWare */
241
bool nw_panic = FALSE;
244
/** Allowed values of innodb_change_buffering */
245
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
246
"none", /* IBUF_USE_NONE */
247
"inserts" /* IBUF_USE_INSERT */
250
/********************************************************************
251
Gives the file extension of an InnoDB single-table tablespace. */
252
static const char* ha_innobase_exts[] = {
257
static INNOBASE_SHARE *get_share(const char *table_name);
258
static void free_share(INNOBASE_SHARE *share);
260
class InnobaseEngine : public plugin::XaStorageEngine
263
InnobaseEngine(string name_arg) :
264
plugin::XaStorageEngine(name_arg,
266
HTON_CAN_INDEX_BLOBS |
267
HTON_PRIMARY_KEY_REQUIRED_FOR_POSITION |
268
HTON_PRIMARY_KEY_IN_READ_INDEX |
269
HTON_PARTIAL_COLUMN_READ |
270
HTON_TABLE_SCAN_ON_INDEX |
271
HTON_HAS_DOES_TRANSACTIONS)
273
table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
274
addAlias("INNOBASE");
277
virtual int doStartTransaction(Session *session, start_transaction_option_t options);
278
virtual void doStartStatement(Session *session);
279
virtual void doEndStatement(Session *session);
284
/*======================*/
285
/* out: 0 or error number */
286
Session* session); /* in: handle to the MySQL thread of the user
287
whose resources should be free'd */
289
virtual int doSetSavepoint(Session* session,
290
drizzled::NamedSavepoint &savepoint);
291
virtual int doRollbackToSavepoint(Session* session,
292
drizzled::NamedSavepoint &savepoint);
293
virtual int doReleaseSavepoint(Session* session,
294
drizzled::NamedSavepoint &savepoint);
295
virtual int doXaCommit(Session* session, bool all)
297
return doCommit(session, all); /* XA commit just does a SQL COMMIT */
299
virtual int doXaRollback(Session *session, bool all)
301
return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
303
virtual int doCommit(Session* session, bool all);
304
virtual int doRollback(Session* session, bool all);
306
/***********************************************************************
307
This function is used to prepare X/Open XA distributed transaction */
312
/* out: 0 or error number */
313
Session* session, /* in: handle to the MySQL thread of the user
314
whose XA transaction should be prepared */
315
bool all); /* in: TRUE - commit transaction
316
FALSE - the current SQL statement ended */
317
/***********************************************************************
318
This function is used to recover X/Open XA distributed transactions */
323
/* out: number of prepared transactions
324
stored in xid_list */
325
::drizzled::XID* xid_list, /* in/out: prepared transactions */
326
size_t len); /* in: number of slots in xid_list */
327
/***********************************************************************
328
This function is used to commit one X/Open XA distributed transaction
329
which is in the prepared state */
333
/*===================*/
334
/* out: 0 or error number */
335
::drizzled::XID* xid); /* in: X/Open XA transaction identification */
336
/***********************************************************************
337
This function is used to rollback one X/Open XA distributed transaction
338
which is in the prepared state */
342
/*=====================*/
343
/* out: 0 or error number */
344
::drizzled::XID *xid); /* in: X/Open XA transaction identification */
346
virtual Cursor *create(TableShare &table,
347
memory::Root *mem_root)
349
return new (mem_root) ha_innobase(*this, table);
352
/*********************************************************************
353
Removes all tables in the named database inside InnoDB. */
356
/*===================*/
357
/* out: error number */
358
const std::string &schema_name); /* in: database path; inside InnoDB the name
359
of the last directory in the path is used as
360
the database name: for example, in 'mysql/data/test'
361
the database name is 'test' */
363
/********************************************************************
364
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
365
the logs, and the name of this function should be innobase_checkpoint. */
370
/* out: TRUE if error */
372
/****************************************************************************
373
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
374
Monitor to the client. */
379
Session* session, /* in: the MySQL query thread of the caller */
380
stat_print_fn *stat_print,
381
enum ha_stat_type stat_type);
385
doReleaseTemporaryLatches(
386
/*===============================*/
388
Session* session); /* in: MySQL thread */
391
const char** bas_ext() const {
392
return(ha_innobase_exts);
395
UNIV_INTERN int doCreateTable(Session *session,
396
const char *table_name,
399
UNIV_INTERN int doRenameTable(Session* session,
402
UNIV_INTERN int doDropTable(Session& session, const string &table_path);
404
UNIV_INTERN virtual bool get_error_message(int error, String *buf);
406
UNIV_INTERN uint32_t max_supported_keys() const;
407
UNIV_INTERN uint32_t max_supported_key_length() const;
408
UNIV_INTERN uint32_t max_supported_key_part_length() const;
411
UNIV_INTERN uint32_t index_flags(enum ha_key_alg) const
413
return (HA_READ_NEXT |
421
/** @brief Initialize the default value of innodb_commit_concurrency.
423
Once InnoDB is running, the innodb_commit_concurrency must not change
424
from zero to nonzero. (Bug #42101)
426
The initial default value is 0, and without this extra initialization,
427
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
428
to 0, even if it was initially set to nonzero at the command line
429
or configuration file. */
432
innobase_commit_concurrency_init_default(void);
433
/*==========================================*/
435
/************************************************************//**
436
Validate the file format name and return its corresponding id.
437
@return valid file format id */
440
innobase_file_format_name_lookup(
441
/*=============================*/
442
const char* format_name); /*!< in: pointer to file format
444
/************************************************************//**
445
Validate the file format check config parameters, as a side effect it
446
sets the srv_check_file_format_at_startup variable.
447
@return true if one of "on" or "off" */
450
innobase_file_format_check_on_off(
451
/*==============================*/
452
const char* format_check); /*!< in: parameter value */
453
/************************************************************//**
454
Validate the file format check config parameters, as a side effect it
455
sets the srv_check_file_format_at_startup variable.
456
@return true if valid config value */
459
innobase_file_format_check_validate(
460
/*================================*/
461
const char* format_check); /*!< in: parameter value */
463
static const char innobase_engine_name[]= "InnoDB";
465
/*************************************************************//**
466
Check for a valid value of innobase_commit_concurrency.
467
@return 0 for valid innodb_commit_concurrency */
470
innobase_commit_concurrency_validate(
471
/*=================================*/
472
Session* , /*!< in: thread handle */
473
drizzle_sys_var* , /*!< in: pointer to system
475
void* save, /*!< out: immediate result
476
for update function */
477
drizzle_value* value) /*!< in: incoming string */
480
ulong commit_concurrency;
482
if (value->val_int(value, &intbuf)) {
483
/* The value is NULL. That is invalid. */
487
*reinterpret_cast<ulong*>(save) = commit_concurrency
488
= static_cast<ulong>(intbuf);
490
/* Allow the value to be updated, as long as it remains zero
492
return(!(!commit_concurrency == !innobase_commit_concurrency));
495
static DRIZZLE_SessionVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
496
"Enable InnoDB support for the XA two-phase commit",
497
/* check_func */ NULL, /* update_func */ NULL,
500
static DRIZZLE_SessionVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
501
"Enable InnoDB locking in LOCK TABLES",
502
/* check_func */ NULL, /* update_func */ NULL,
505
static DRIZZLE_SessionVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
506
"Use strict mode when evaluating create options.",
509
static DRIZZLE_SessionVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
510
"Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
511
NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
514
/***********************************************************************
515
Closes an InnoDB database. */
518
innobase_deinit(plugin::Registry ®istry);
520
/*****************************************************************//**
521
Commits a transaction in an InnoDB database. */
526
trx_t* trx); /*!< in: transaction handle */
528
static drizzle_show_var innodb_status_variables[]= {
529
{"buffer_pool_pages_data",
530
(char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
531
{"buffer_pool_pages_dirty",
532
(char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
533
{"buffer_pool_pages_flushed",
534
(char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
535
{"buffer_pool_pages_free",
536
(char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
538
{"buffer_pool_pages_latched",
539
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
540
#endif /* UNIV_DEBUG */
541
{"buffer_pool_pages_misc",
542
(char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
543
{"buffer_pool_pages_total",
544
(char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
545
{"buffer_pool_read_ahead_rnd",
546
(char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
547
{"buffer_pool_read_ahead_seq",
548
(char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG},
549
{"buffer_pool_read_requests",
550
(char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
551
{"buffer_pool_reads",
552
(char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
553
{"buffer_pool_wait_free",
554
(char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
555
{"buffer_pool_write_requests",
556
(char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
558
(char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
559
{"data_pending_fsyncs",
560
(char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
561
{"data_pending_reads",
562
(char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
563
{"data_pending_writes",
564
(char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
566
(char*) &export_vars.innodb_data_read, SHOW_LONG},
568
(char*) &export_vars.innodb_data_reads, SHOW_LONG},
570
(char*) &export_vars.innodb_data_writes, SHOW_LONG},
572
(char*) &export_vars.innodb_data_written, SHOW_LONG},
573
{"dblwr_pages_written",
574
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
576
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
577
{"have_atomic_builtins",
578
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
580
(char*) &export_vars.innodb_log_waits, SHOW_LONG},
581
{"log_write_requests",
582
(char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
584
(char*) &export_vars.innodb_log_writes, SHOW_LONG},
586
(char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
587
{"os_log_pending_fsyncs",
588
(char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
589
{"os_log_pending_writes",
590
(char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
592
(char*) &export_vars.innodb_os_log_written, SHOW_LONG},
594
(char*) &export_vars.innodb_page_size, SHOW_LONG},
596
(char*) &export_vars.innodb_pages_created, SHOW_LONG},
598
(char*) &export_vars.innodb_pages_read, SHOW_LONG},
600
(char*) &export_vars.innodb_pages_written, SHOW_LONG},
601
{"row_lock_current_waits",
602
(char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
604
(char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
605
{"row_lock_time_avg",
606
(char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
607
{"row_lock_time_max",
608
(char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
610
(char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
612
(char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
614
(char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
616
(char*) &export_vars.innodb_rows_read, SHOW_LONG},
618
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
619
{NULL, NULL, SHOW_LONG}
622
InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
623
plugin::TableFunction::Generator(fields)
625
srv_export_innodb_status();
626
status_var_ptr= innodb_status_variables;
629
bool InnodbStatusTool::Generator::populate()
631
if (status_var_ptr->name)
633
std::ostringstream oss;
635
const char *value= status_var_ptr->value;
638
push(status_var_ptr->name);
640
switch (status_var_ptr->type)
643
oss << *(int64_t*) value;
644
return_value= oss.str();
647
oss << *(int64_t*) value;
648
return_value= oss.str();
651
return_value= *(bool*) value ? "ON" : "OFF";
658
if (return_value.length())
670
/* General functions */
672
/******************************************************************//**
673
Returns true if the thread is the replication thread on the slave
674
server. Used in srv_conc_enter_innodb() to determine if the thread
675
should be allowed to enter InnoDB - the replication thread is treated
676
differently than other threads. Also used in
677
srv_conc_force_exit_innodb().
679
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
681
@return true if session is the replication thread */
682
extern "C" UNIV_INTERN
684
thd_is_replication_slave_thread(
685
/*============================*/
686
void* ) /*!< in: thread handle (Session*) */
691
/******************************************************************//**
692
Save some CPU by testing the value of srv_thread_concurrency in inline
696
innodb_srv_conc_enter_innodb(
697
/*=========================*/
698
trx_t* trx) /*!< in: transaction handle */
700
if (UNIV_LIKELY(!srv_thread_concurrency)) {
705
srv_conc_enter_innodb(trx);
708
/******************************************************************//**
709
Save some CPU by testing the value of srv_thread_concurrency in inline
713
innodb_srv_conc_exit_innodb(
714
/*========================*/
715
trx_t* trx) /*!< in: transaction handle */
717
if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
722
srv_conc_exit_innodb(trx);
725
/******************************************************************//**
726
Releases possible search latch and InnoDB thread FIFO ticket. These should
727
be released at each SQL statement end, and also when mysqld passes the
728
control to the client. It does no harm to release these also in the middle
729
of an SQL statement. */
732
innobase_release_stat_resources(
733
/*============================*/
734
trx_t* trx) /*!< in: transaction object */
736
if (trx->has_search_latch) {
737
trx_search_latch_release_if_reserved(trx);
740
if (trx->declared_to_be_inside_innodb) {
741
/* Release our possible ticket in the FIFO */
743
srv_conc_force_exit_innodb(trx);
747
/******************************************************************//**
748
Returns true if the transaction this thread is processing has edited
749
non-transactional tables. Used by the deadlock detector when deciding
750
which transaction to rollback in case of a deadlock - we try to avoid
751
rolling back transactions that have edited non-transactional tables.
753
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
755
@return true if non-transactional tables have been edited */
756
extern "C" UNIV_INTERN
758
thd_has_edited_nontrans_tables(
759
/*===========================*/
760
void* session) /*!< in: thread handle (Session*) */
762
return((ibool) session_non_transactional_update((Session*) session));
765
/******************************************************************//**
766
Returns true if the thread is executing a SELECT statement.
767
@return true if session is executing SELECT */
768
extern "C" UNIV_INTERN
772
const void* session) /*!< in: thread handle (Session*) */
774
return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
777
/******************************************************************//**
778
Returns true if the thread supports XA,
779
global value of innodb_supports_xa if session is NULL.
780
@return true if session has XA support */
781
extern "C" UNIV_INTERN
785
void* session) /*!< in: thread handle (Session*), or NULL to query
786
the global innodb_supports_xa */
788
return(SessionVAR((Session*) session, support_xa));
791
/******************************************************************//**
792
Returns the lock wait timeout for the current connection.
793
@return the lock wait timeout, in seconds */
794
extern "C" UNIV_INTERN
796
thd_lock_wait_timeout(
797
/*==================*/
798
void* session) /*!< in: thread handle (Session*), or NULL to query
799
the global innodb_lock_wait_timeout */
801
/* According to <drizzle/plugin.h>, passing session == NULL
802
returns the global value of the session variable. */
803
return(SessionVAR((Session*) session, lock_wait_timeout));
806
/********************************************************************//**
807
Obtain the InnoDB transaction of a MySQL thread.
808
@return reference to transaction pointer */
813
Session* session) /*!< in: Drizzle Session */
815
return *(trx_t**) session->getEngineData(innodb_engine_ptr);
818
/********************************************************************//**
819
Call this function when mysqld passes control to the client. That is to
820
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
821
documentation, see Cursor.cc.
824
InnobaseEngine::doReleaseTemporaryLatches(
825
/*===============================*/
826
Session* session) /*!< in: MySQL thread */
830
assert(this == innodb_engine_ptr);
832
if (!innodb_inited) {
837
trx = session_to_trx(session);
840
innobase_release_stat_resources(trx);
845
/********************************************************************//**
846
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
847
time calls srv_active_wake_master_thread. This function should be used
848
when a single database operation may introduce a small need for
849
server utility activity, like checkpointing. */
852
innobase_active_small(void)
853
/*=======================*/
855
innobase_active_counter++;
857
if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
858
srv_active_wake_master_thread();
862
/********************************************************************//**
863
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
864
about a possible transaction rollback inside InnoDB caused by a lock wait
865
timeout or a deadlock.
866
@return MySQL error code */
867
extern "C" UNIV_INTERN
869
convert_error_code_to_mysql(
870
/*========================*/
871
int error, /*!< in: InnoDB error code */
872
ulint flags, /*!< in: InnoDB table flags, or 0 */
873
Session* session)/*!< in: user thread handle or NULL */
881
return(-1); /* unspecified error */
883
case DB_DUPLICATE_KEY:
884
return(HA_ERR_FOUND_DUPP_KEY);
886
case DB_FOREIGN_DUPLICATE_KEY:
887
return(HA_ERR_FOREIGN_DUPLICATE_KEY);
889
case DB_MISSING_HISTORY:
890
return(HA_ERR_TABLE_DEF_CHANGED);
892
case DB_RECORD_NOT_FOUND:
893
return(HA_ERR_NO_ACTIVE_RECORD);
896
/* Since we rolled back the whole transaction, we must
897
tell it also to MySQL so that MySQL knows to empty the
898
cached binlog for this transaction */
900
session_mark_transaction_to_rollback(session, TRUE);
902
return(HA_ERR_LOCK_DEADLOCK);
904
case DB_LOCK_WAIT_TIMEOUT:
905
/* Starting from 5.0.13, we let MySQL just roll back the
906
latest SQL statement in a lock wait timeout. Previously, we
907
rolled back the whole transaction. */
909
session_mark_transaction_to_rollback(session,
910
(bool)row_rollback_on_timeout);
912
return(HA_ERR_LOCK_WAIT_TIMEOUT);
914
case DB_NO_REFERENCED_ROW:
915
return(HA_ERR_NO_REFERENCED_ROW);
917
case DB_ROW_IS_REFERENCED:
918
return(HA_ERR_ROW_IS_REFERENCED);
920
case DB_CANNOT_ADD_CONSTRAINT:
921
return(HA_ERR_CANNOT_ADD_FOREIGN);
923
case DB_CANNOT_DROP_CONSTRAINT:
925
return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
926
misleading, a new MySQL error
927
code should be introduced */
929
case DB_COL_APPEARS_TWICE_IN_INDEX:
931
return(HA_ERR_CRASHED);
933
case DB_OUT_OF_FILE_SPACE:
934
return(HA_ERR_RECORD_FILE_FULL);
936
case DB_TABLE_IS_BEING_USED:
937
return(HA_ERR_WRONG_COMMAND);
939
case DB_TABLE_NOT_FOUND:
940
return(HA_ERR_NO_SUCH_TABLE);
942
case DB_TOO_BIG_RECORD:
943
my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
944
page_get_free_space_of_empty(flags
945
& DICT_TF_COMPACT) / 2);
946
return(HA_ERR_TO_BIG_ROW);
948
case DB_NO_SAVEPOINT:
949
return(HA_ERR_NO_SAVEPOINT);
951
case DB_LOCK_TABLE_FULL:
952
/* Since we rolled back the whole transaction, we must
953
tell it also to MySQL so that MySQL knows to empty the
954
cached binlog for this transaction */
956
session_mark_transaction_to_rollback(session, TRUE);
958
return(HA_ERR_LOCK_TABLE_FULL);
960
case DB_PRIMARY_KEY_IS_NULL:
961
return(ER_PRIMARY_CANT_HAVE_NULL);
963
case DB_TOO_MANY_CONCURRENT_TRXS:
965
/* Once MySQL add the appropriate code to errmsg.txt then
966
we can get rid of this #ifdef. NOTE: The code checked by
967
the #ifdef is the suggested name for the error condition
968
and the actual error code name could very well be different.
969
This will require some monitoring, ie. the status
970
of this request on our part.*/
971
#ifdef ER_TOO_MANY_CONCURRENT_TRXS
972
return(ER_TOO_MANY_CONCURRENT_TRXS);
974
return(HA_ERR_RECORD_FILE_FULL);
977
return(HA_ERR_UNSUPPORTED);
981
/*************************************************************//**
982
If you want to print a session that is not associated with the current thread,
983
you must call this function before reserving the InnoDB kernel_mutex, to
984
protect Drizzle from setting session->query NULL. If you print a session of the
985
current thread, we know that Drizzle cannot modify sesion->query, and it is
986
not necessary to call this. Call innobase_mysql_end_print_arbitrary_thd()
987
after you release the kernel_mutex.
989
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
992
extern "C" UNIV_INTERN
994
innobase_mysql_prepare_print_arbitrary_thd(void)
995
/*============================================*/
997
ut_ad(!mutex_own(&kernel_mutex));
998
pthread_mutex_lock(&LOCK_thread_count);
1001
/*************************************************************//**
1002
Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd().
1003
In the InnoDB latching order, the mutex sits right above the
1004
kernel_mutex. In debug builds, we assert that the kernel_mutex is
1005
released before this function is invoked.
1007
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
1010
extern "C" UNIV_INTERN
1012
innobase_mysql_end_print_arbitrary_thd(void)
1013
/*========================================*/
1015
ut_ad(!mutex_own(&kernel_mutex));
1016
pthread_mutex_unlock(&LOCK_thread_count);
1019
/*************************************************************//**
1020
Prints info of a Session object (== user session thread) to the given file. */
1021
extern "C" UNIV_INTERN
1023
innobase_mysql_print_thd(
1024
/*=====================*/
1025
FILE* f, /*!< in: output stream */
1026
void * in_session, /*!< in: pointer to a Drizzle Session object */
1027
uint ) /*!< in: max query length to print, or 0 to
1028
use the default max length */
1030
Session *session= reinterpret_cast<Session *>(in_session);
1032
"Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
1033
static_cast<uint64_t>(session_get_thread_id( session)),
1034
static_cast<uint64_t>(session->getQueryId()),
1036
session->getSecurityContext().getIp().c_str(),
1037
session->getSecurityContext().getUser().c_str()
1040
"\n%s", session->getQueryString().c_str()
1045
/******************************************************************//**
1046
Get the variable length bounds of the given character set. */
1047
extern "C" UNIV_INTERN
1049
innobase_get_cset_width(
1050
/*====================*/
1051
ulint cset, /*!< in: MySQL charset-collation code */
1052
ulint* mbminlen, /*!< out: minimum length of a char (in bytes) */
1053
ulint* mbmaxlen) /*!< out: maximum length of a char (in bytes) */
1060
cs = all_charsets[cset];
1062
*mbminlen = cs->mbminlen;
1063
*mbmaxlen = cs->mbmaxlen;
1066
*mbminlen = *mbmaxlen = 0;
1070
/******************************************************************//**
1071
Converts an identifier to a table name. */
1072
extern "C" UNIV_INTERN
1074
innobase_convert_from_table_id(
1075
/*===========================*/
1076
const void*, /*!< in: the 'from' character set */
1077
char* to, /*!< out: converted identifier */
1078
const char* from, /*!< in: identifier to convert */
1079
ulint len) /*!< in: length of 'to', in bytes */
1081
strncpy(to, from, len);
1084
/******************************************************************//**
1085
Converts an identifier to UTF-8. */
1086
extern "C" UNIV_INTERN
1088
innobase_convert_from_id(
1089
/*=====================*/
1090
const void*, /*!< in: the 'from' character set */
1091
char* to, /*!< out: converted identifier */
1092
const char* from, /*!< in: identifier to convert */
1093
ulint len) /*!< in: length of 'to', in bytes */
1095
strncpy(to, from, len);
1098
/******************************************************************//**
1099
Compares NUL-terminated UTF-8 strings case insensitively.
1100
@return 0 if a=b, <0 if a<b, >1 if a>b */
1101
extern "C" UNIV_INTERN
1103
innobase_strcasecmp(
1104
/*================*/
1105
const char* a, /*!< in: first string to compare */
1106
const char* b) /*!< in: second string to compare */
1108
return(my_strcasecmp(system_charset_info, a, b));
1111
/******************************************************************//**
1112
Makes all characters in a NUL-terminated UTF-8 string lower case. */
1113
extern "C" UNIV_INTERN
1115
innobase_casedn_str(
1116
/*================*/
1117
char* a) /*!< in/out: string to put in lower case */
1119
my_casedn_str(system_charset_info, a);
1122
/**********************************************************************//**
1123
Determines the connection character set.
1124
@return connection character set */
1125
extern "C" UNIV_INTERN
1127
innobase_get_charset(
1128
/*=================*/
1129
void* mysql_session) /*!< in: MySQL thread handle */
1131
return session_charset(static_cast<Session*>(mysql_session));
1134
extern "C" UNIV_INTERN
1140
return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
1145
innobase_fast_mutex_init(
1146
os_fast_mutex_t* fast_mutex)
1148
return pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
1151
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1152
/*******************************************************************//**
1153
Map an OS error to an errno value. The OS error number is stored in
1154
_doserrno and the mapped value is stored in errno) */
1158
unsigned long); /*!< in: OS error value */
1160
/*********************************************************************//**
1161
Creates a temporary file.
1162
@return temporary file descriptor, or < 0 on error */
1163
extern "C" UNIV_INTERN
1165
innobase_mysql_tmpfile(void)
1166
/*========================*/
1168
int fd; /* handle of opened file */
1169
HANDLE osfh; /* OS handle of opened file */
1170
char* tmpdir; /* point to the directory
1171
where to create file */
1172
TCHAR path_buf[MAX_PATH - 14]; /* buffer for tmp file path.
1173
The length cannot be longer
1174
than MAX_PATH - 14, or
1175
GetTempFileName will fail. */
1176
char filename[MAX_PATH]; /* name of the tmpfile */
1177
DWORD fileaccess = GENERIC_READ /* OS file access */
1180
DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
1182
| FILE_SHARE_DELETE;
1183
DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
1184
DWORD fileattrib = /* OS file attribute flags */
1185
FILE_ATTRIBUTE_NORMAL
1186
| FILE_FLAG_DELETE_ON_CLOSE
1187
| FILE_ATTRIBUTE_TEMPORARY
1188
| FILE_FLAG_SEQUENTIAL_SCAN;
1190
tmpdir = my_tmpdir(&mysql_tmpdir_list);
1192
/* The tmpdir parameter can not be NULL for GetTempFileName. */
1196
/* Use GetTempPath to determine path for temporary files. */
1197
ret = GetTempPath(sizeof(path_buf), path_buf);
1198
if (ret > sizeof(path_buf) || (ret == 0)) {
1200
_dosmaperr(GetLastError()); /* map error */
1207
/* Use GetTempFileName to generate a unique filename. */
1208
if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
1210
_dosmaperr(GetLastError()); /* map error */
1214
/* Open/Create the file. */
1215
osfh = CreateFile(filename, fileaccess, fileshare, NULL,
1216
filecreate, fileattrib, NULL);
1217
if (osfh == INVALID_HANDLE_VALUE) {
1219
/* open/create file failed! */
1220
_dosmaperr(GetLastError()); /* map error */
1225
/* Associates a CRT file descriptor with the OS file handle. */
1226
fd = _open_osfhandle((intptr_t) osfh, 0);
1227
} while (fd == -1 && errno == EINTR);
1230
/* Open failed, close the file handle. */
1232
_dosmaperr(GetLastError()); /* map error */
1233
CloseHandle(osfh); /* no need to check if
1234
CloseHandle fails */
1240
/*********************************************************************//**
1241
Creates a temporary file.
1242
@return temporary file descriptor, or < 0 on error */
1243
extern "C" UNIV_INTERN
1245
innobase_mysql_tmpfile(void)
1246
/*========================*/
1249
int fd = mysql_tmpfile("ib");
1251
/* Copy the file descriptor, so that the additional resources
1252
allocated by create_temp_file() can be freed by invoking
1253
internal::my_close().
1255
Because the file descriptor returned by this function
1256
will be passed to fdopen(), it will be closed by invoking
1257
fclose(), which in turn will invoke close() instead of
1258
internal::my_close(). */
1262
my_error(EE_OUT_OF_FILERESOURCES,
1263
MYF(ME_BELL+ME_WAITTANG),
1266
internal::my_close(fd, MYF(MY_WME));
1270
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
1273
/*******************************************************************//**
1274
Formats the raw data in "data" (in InnoDB on-disk format) that is of
1275
type DATA_(CHAR|VARCHAR|DRIZZLE|VARDRIZZLE) using "charset_coll" and writes
1276
the result to "buf". The result is converted to "system_charset_info".
1277
Not more than "buf_size" bytes are written to "buf".
1278
The result is always NUL-terminated (provided buf_size > 0) and the
1279
number of bytes that were written to "buf" is returned (including the
1281
@return number of bytes that were written */
1282
extern "C" UNIV_INTERN
1284
innobase_raw_format(
1285
/*================*/
1286
const char* data, /*!< in: raw data */
1287
ulint data_len, /*!< in: raw data length
1289
ulint , /*!< in: charset collation */
1290
char* buf, /*!< out: output buffer */
1291
ulint buf_size) /*!< in: output buffer size
1294
return(ut_str_sql_format(data, data_len, buf, buf_size));
1297
/*********************************************************************//**
1298
Compute the next autoinc value.
1300
For MySQL replication the autoincrement values can be partitioned among
1301
the nodes. The offset is the start or origin of the autoincrement value
1302
for a particular node. For n nodes the increment will be n and the offset
1303
will be in the interval [1, n]. The formula tries to allocate the next
1304
value for a particular node.
1306
Note: This function is also called with increment set to the number of
1307
values we want to reserve for multi-value inserts e.g.,
1309
INSERT INTO T VALUES(), (), ();
1311
innobase_next_autoinc() will be called with increment set to
1312
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
1313
to reserve 3 values for the multi-value INSERT above.
1314
@return the next value */
1317
innobase_next_autoinc(
1318
/*==================*/
1319
uint64_t current, /*!< in: Current value */
1320
uint64_t increment, /*!< in: increment current by */
1321
uint64_t offset, /*!< in: AUTOINC offset */
1322
uint64_t max_value) /*!< in: max value for type */
1324
uint64_t next_value;
1326
/* Should never be 0. */
1327
ut_a(increment > 0);
1329
/* According to MySQL documentation, if the offset is greater than
1330
the increment then the offset is ignored. */
1331
if (offset > increment) {
1335
if (max_value <= current) {
1336
next_value = max_value;
1337
} else if (offset <= 1) {
1338
/* Offset 0 and 1 are the same, because there must be at
1339
least one node in the system. */
1340
if (max_value - current <= increment) {
1341
next_value = max_value;
1343
next_value = current + increment;
1345
} else if (max_value > current) {
1346
if (current > offset) {
1347
next_value = ((current - offset) / increment) + 1;
1349
next_value = ((offset - current) / increment) + 1;
1352
ut_a(increment > 0);
1353
ut_a(next_value > 0);
1355
/* Check for multiplication overflow. */
1356
if (increment > (max_value / next_value)) {
1358
next_value = max_value;
1360
next_value *= increment;
1362
ut_a(max_value >= next_value);
1364
/* Check for overflow. */
1365
if (max_value - next_value <= offset) {
1366
next_value = max_value;
1368
next_value += offset;
1372
next_value = max_value;
1375
ut_a(next_value <= max_value);
1380
/*********************************************************************//**
1381
Initializes some fields in an InnoDB transaction object. */
1386
Session* session, /*!< in: user thread handle */
1387
trx_t* trx) /*!< in/out: InnoDB transaction handle */
1389
assert(session == trx->mysql_thd);
1391
trx->check_foreigns = !session_test_options(
1392
session, OPTION_NO_FOREIGN_KEY_CHECKS);
1394
trx->check_unique_secondary = !session_test_options(
1395
session, OPTION_RELAXED_UNIQUE_CHECKS);
1400
/*********************************************************************//**
1401
Allocates an InnoDB transaction for a MySQL Cursor object.
1402
@return InnoDB transaction handle */
1403
extern "C" UNIV_INTERN
1405
innobase_trx_allocate(
1406
/*==================*/
1407
Session* session) /*!< in: user thread handle */
1411
assert(session != NULL);
1412
assert(EQ_CURRENT_SESSION(session));
1414
trx = trx_allocate_for_mysql();
1416
trx->mysql_thd = session;
1417
trx->mysql_query_str = session->query.c_str();
1419
innobase_trx_init(session, trx);
1424
/*********************************************************************//**
1425
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1426
an InnoDB transaction struct if the corresponding MySQL thread struct still
1428
@return InnoDB transaction handle */
1433
Session* session) /*!< in: user thread handle */
1435
trx_t*& trx = session_to_trx(session);
1437
ut_ad(EQ_CURRENT_SESSION(session));
1440
trx = innobase_trx_allocate(session);
1441
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1442
mem_analyze_corruption(trx);
1446
innobase_trx_init(session, trx);
1452
/*********************************************************************//**
1453
Construct ha_innobase Cursor. */
1455
ha_innobase::ha_innobase(plugin::StorageEngine &engine_arg,
1456
TableShare &table_arg)
1457
:Cursor(engine_arg, table_arg),
1458
primary_key(0), /* needs initialization because index_flags() may be called
1459
before this is set to the real value. It's ok to have any
1460
value here because it doesn't matter if we return the
1461
HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
1466
/*********************************************************************//**
1467
Destruct ha_innobase Cursor. */
1469
ha_innobase::~ha_innobase()
1473
/*********************************************************************//**
1474
Updates the user_thd field in a handle and also allocates a new InnoDB
1475
transaction handle if needed, and updates the transaction fields in the
1479
ha_innobase::update_session(
1480
/*====================*/
1481
Session* session) /*!< in: thd to use the handle */
1485
trx = check_trx_exists(session);
1487
if (prebuilt->trx != trx) {
1489
row_update_prebuilt_trx(prebuilt, trx);
1492
user_session = session;
1495
/*********************************************************************//**
1496
Updates the user_thd field in a handle and also allocates a new InnoDB
1497
transaction handle if needed, and updates the transaction fields in the
1501
ha_innobase::update_session()
1502
/*=====================*/
1504
Session* session = ha_session();
1505
ut_ad(EQ_CURRENT_SESSION(session));
1506
update_session(session);
1509
/*****************************************************************//**
1510
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1511
and quote it if needed.
1512
@return pointer to the end of buf */
1515
innobase_convert_identifier(
1516
/*========================*/
1517
char* buf, /*!< out: buffer for converted identifier */
1518
ulint buflen, /*!< in: length of buf, in bytes */
1519
const char* id, /*!< in: identifier to convert */
1520
ulint idlen, /*!< in: length of id, in bytes */
1521
void* session,/*!< in: MySQL connection thread, or NULL */
1522
ibool file_id)/*!< in: TRUE=id is a table or database name;
1523
FALSE=id is an UTF-8 string */
1525
char nz[NAME_LEN + 1];
1526
char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
1532
/* Decode the table name. The filename_to_tablename()
1533
function expects a NUL-terminated string. The input and
1534
output strings buffers must not be shared. */
1536
if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1537
idlen = (sizeof nz) - 1;
1540
memcpy(nz, id, idlen);
1544
idlen = filename_to_tablename(nz, nz2, sizeof nz2);
1547
/* See if the identifier needs to be quoted. */
1548
if (UNIV_UNLIKELY(!session)) {
1551
q = get_quote_char_for_identifier();
1555
if (UNIV_UNLIKELY(idlen > buflen)) {
1558
memcpy(buf, s, idlen);
1559
return(buf + idlen);
1562
/* Quote the identifier. */
1570
for (; idlen; idlen--) {
1572
if (UNIV_UNLIKELY(c == q)) {
1573
if (UNIV_UNLIKELY(buflen < 3)) {
1581
if (UNIV_UNLIKELY(buflen < 2)) {
1594
/*****************************************************************//**
1595
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1596
and quote it if needed.
1597
@return pointer to the end of buf */
1598
extern "C" UNIV_INTERN
1600
innobase_convert_name(
1601
/*==================*/
1602
char* buf, /*!< out: buffer for converted identifier */
1603
ulint buflen, /*!< in: length of buf, in bytes */
1604
const char* id, /*!< in: identifier to convert */
1605
ulint idlen, /*!< in: length of id, in bytes */
1606
void* session,/*!< in: MySQL connection thread, or NULL */
1607
ibool table_id)/*!< in: TRUE=id is a table or database name;
1608
FALSE=id is an index name */
1611
const char* bufend = buf + buflen;
1614
const char* slash = (const char*) memchr(id, '/', idlen);
1620
/* Print the database name and table name separately. */
1621
s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1623
if (UNIV_LIKELY(s < bufend)) {
1625
s = innobase_convert_identifier(s, bufend - s,
1630
} else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1631
/* Temporary index name (smart ALTER TABLE) */
1632
const char temp_index_suffix[]= "--temporary--";
1634
s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1636
if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1637
memcpy(s, temp_index_suffix,
1638
sizeof temp_index_suffix - 1);
1639
s += sizeof temp_index_suffix - 1;
1643
s = innobase_convert_identifier(buf, buflen, id, idlen,
1651
/**********************************************************************//**
1652
Determines if the currently running transaction has been interrupted.
1653
@return TRUE if interrupted */
1654
extern "C" UNIV_INTERN
1658
trx_t* trx) /*!< in: transaction */
1660
return(trx && trx->mysql_thd && session_killed((Session*) trx->mysql_thd));
1663
/**************************************************************//**
1664
Resets some fields of a prebuilt struct. The template is used in fast
1665
retrieval of just those column values MySQL needs in its processing. */
1670
row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1672
prebuilt->keep_other_fields_on_keyread = 0;
1673
prebuilt->read_just_key = 0;
1676
/*********************************************************************//**
1677
Opens an InnoDB database.
1678
@return 0 on success, error code on failure */
1683
plugin::Registry ®istry) /*!< in: Drizzle Plugin Registry */
1685
static char current_dir[3]; /*!< Set if using current lib */
1691
innodb_engine_ptr= new InnobaseEngine(innobase_engine_name);
1694
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
1697
static const char test_filename[] = "-@";
1698
char test_tablename[sizeof test_filename
1699
+ sizeof srv_mysql50_table_name_prefix];
1700
if ((sizeof test_tablename) - 1
1701
!= filename_to_tablename(test_filename, test_tablename,
1702
sizeof test_tablename)
1703
|| strncmp(test_tablename,
1704
srv_mysql50_table_name_prefix,
1705
sizeof srv_mysql50_table_name_prefix)
1706
|| strcmp(test_tablename
1707
+ sizeof srv_mysql50_table_name_prefix,
1709
errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
1712
#endif /* UNIV_DEBUG */
1714
/* Check that values don't overflow on 32-bit systems. */
1715
if (sizeof(ulint) == 4) {
1716
if (innobase_buffer_pool_size > UINT32_MAX) {
1717
errmsg_printf(ERRMSG_LVL_ERROR,
1718
"innobase_buffer_pool_size can't be over 4GB"
1719
" on 32-bit systems");
1724
if (innobase_log_file_size > UINT32_MAX) {
1725
errmsg_printf(ERRMSG_LVL_ERROR,
1726
"innobase_log_file_size can't be over 4GB"
1727
" on 32-bit systems");
1733
os_innodb_umask = (ulint)internal::my_umask;
1735
/* First calculate the default path for innodb_data_home_dir etc.,
1736
in case the user has not given any value.
1738
Note that when using the embedded server, the datadirectory is not
1739
necessarily the current directory of this program. */
1741
/* It's better to use current lib, to keep paths short */
1742
current_dir[0] = FN_CURLIB;
1743
current_dir[1] = FN_LIBCHAR;
1745
default_path = current_dir;
1749
srv_set_thread_priorities = TRUE;
1750
srv_query_thread_priority = QUERY_PRIOR;
1752
/* Set InnoDB initialization parameters according to the values
1753
read from MySQL .cnf file */
1755
/*--------------- Data files -------------------------*/
1757
/* The default dir for data files is the datadir of MySQL */
1759
srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
1762
/* Set default InnoDB data file size to 10 MB and let it be
1763
auto-extending. Thus users can use InnoDB in >= 4.0 without having
1764
to specify any startup options. */
1766
if (!innobase_data_file_path) {
1767
innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
1770
/* Since InnoDB edits the argument in the next call, we make another
1773
internal_innobase_data_file_path = strdup(innobase_data_file_path);
1775
ret = (bool) srv_parse_data_file_paths_and_sizes(
1776
internal_innobase_data_file_path);
1778
errmsg_printf(ERRMSG_LVL_ERROR,
1779
"InnoDB: syntax error in innodb_data_file_path");
1781
srv_free_paths_and_sizes();
1782
if (internal_innobase_data_file_path)
1783
free(internal_innobase_data_file_path);
1787
/* -------------- Log files ---------------------------*/
1789
/* The default dir for log files is the datadir of MySQL */
1791
if (!innobase_log_group_home_dir) {
1792
innobase_log_group_home_dir = default_path;
1795
#ifdef UNIV_LOG_ARCHIVE
1796
/* Since innodb_log_arch_dir has no relevance under MySQL,
1797
starting from 4.0.6 we always set it the same as
1798
innodb_log_group_home_dir: */
1800
innobase_log_arch_dir = innobase_log_group_home_dir;
1802
srv_arch_dir = innobase_log_arch_dir;
1803
#endif /* UNIG_LOG_ARCHIVE */
1806
srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
1808
if (ret == FALSE || innobase_mirrored_log_groups != 1) {
1809
errmsg_printf(ERRMSG_LVL_ERROR, "syntax error in innodb_log_group_home_dir, or a "
1810
"wrong number of mirrored log groups");
1812
goto mem_free_and_error;
1815
/* Validate the file format by animal name */
1816
if (innobase_file_format_name != NULL) {
1818
format_id = innobase_file_format_name_lookup(
1819
innobase_file_format_name);
1821
if (format_id > DICT_TF_FORMAT_MAX) {
1823
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
1825
goto mem_free_and_error;
1828
/* Set it to the default file format id. Though this
1829
should never happen. */
1833
srv_file_format = format_id;
1835
/* Given the type of innobase_file_format_name we have little
1836
choice but to cast away the constness from the returned name.
1837
innobase_file_format_name is used in the MySQL set variable
1838
interface and so can't be const. */
1840
innobase_file_format_name =
1841
(char*) trx_sys_file_format_id_to_name(format_id);
1843
/* Process innobase_file_format_check variable */
1844
ut_a(innobase_file_format_check != NULL);
1846
/* As a side effect it will set srv_check_file_format_at_startup
1847
on valid input. First we check for "on"/"off". */
1848
if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
1850
/* Did the user specify a format name that we support ?
1851
As a side effect it will update the variable
1852
srv_check_file_format_at_startup */
1853
if (!innobase_file_format_check_validate(
1854
innobase_file_format_check)) {
1856
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: invalid "
1857
"innodb_file_format_check value: "
1858
"should be either 'on' or 'off' or "
1859
"any value up to %s or its "
1860
"equivalent numeric id",
1861
trx_sys_file_format_id_to_name(
1862
DICT_TF_FORMAT_MAX));
1864
goto mem_free_and_error;
1868
if (innobase_change_buffering) {
1872
use < UT_ARR_SIZE(innobase_change_buffering_values);
1874
if (!innobase_strcasecmp(
1875
innobase_change_buffering,
1876
innobase_change_buffering_values[use])) {
1877
ibuf_use = (ibuf_use_t) use;
1878
goto innobase_change_buffering_inited_ok;
1882
errmsg_printf(ERRMSG_LVL_ERROR,
1883
"InnoDB: invalid value "
1884
"innodb_file_format_check=%s",
1885
innobase_change_buffering);
1886
goto mem_free_and_error;
1889
innobase_change_buffering_inited_ok:
1890
ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
1891
innobase_change_buffering = (char*)
1892
innobase_change_buffering_values[ibuf_use];
1894
/* --------------------------------------------------*/
1896
srv_file_flush_method_str = innobase_unix_file_flush_method;
1898
srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
1899
srv_n_log_files = (ulint) innobase_log_files_in_group;
1900
srv_log_file_size = (ulint) innobase_log_file_size;
1902
#ifdef UNIV_LOG_ARCHIVE
1903
srv_log_archive_on = (ulint) innobase_log_archive;
1904
#endif /* UNIV_LOG_ARCHIVE */
1905
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
1907
srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
1909
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
1911
srv_n_file_io_threads = (ulint) innobase_file_io_threads;
1912
srv_n_read_io_threads = (ulint) innobase_read_io_threads;
1913
srv_n_write_io_threads = (ulint) innobase_write_io_threads;
1915
srv_force_recovery = (ulint) innobase_force_recovery;
1917
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
1918
srv_use_checksums = (ibool) innobase_use_checksums;
1920
#ifdef HAVE_LARGE_PAGES
1921
if ((os_use_large_pages = (ibool) my_use_large_pages))
1922
os_large_page_size = (ulint) opt_large_page_size;
1925
row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
1927
srv_locks_unsafe_for_binlog = (ibool) TRUE;
1929
srv_max_n_open_files = (ulint) innobase_open_files;
1930
srv_innodb_status = (ibool) innobase_create_status_file;
1932
srv_print_verbose_log = true;
1934
/* Store the default charset-collation number of this MySQL
1937
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
1940
innobase_commit_concurrency_init_default();
1942
/* Since we in this module access directly the fields of a trx
1943
struct, and due to different headers and flags it might happen that
1944
mutex_t has a different size in this module and in InnoDB
1945
modules, we check at run time that the size is the same in
1946
these compilation modules. */
1948
err = innobase_start_or_create_for_mysql();
1950
if (err != DB_SUCCESS) {
1951
goto mem_free_and_error;
1954
innobase_open_tables = hash_create(200);
1955
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
1956
pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
1957
pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
1958
pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
1959
pthread_cond_init(&commit_cond, NULL);
1962
status_table_function_ptr= new InnodbStatusTool;
1964
registry.add(innodb_engine_ptr);
1966
registry.add(status_table_function_ptr);
1968
cmp_tool= new(std::nothrow)CmpTool(false);
1969
registry.add(cmp_tool);
1971
cmp_reset_tool= new(std::nothrow)CmpTool(true);
1972
registry.add(cmp_reset_tool);
1974
cmp_mem_tool= new(std::nothrow)CmpmemTool(false);
1975
registry.add(cmp_mem_tool);
1977
cmp_mem_reset_tool= new(std::nothrow)CmpmemTool(true);
1978
registry.add(cmp_mem_reset_tool);
1980
innodb_trx_tool= new(std::nothrow)InnodbTrxTool("INNODB_TRX");
1981
registry.add(innodb_trx_tool);
1983
innodb_locks_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCKS");
1984
registry.add(innodb_locks_tool);
1986
innodb_lock_waits_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS");
1987
registry.add(innodb_lock_waits_tool);
1989
/* Get the current high water mark format. */
1990
innobase_file_format_check = (char*) trx_sys_file_format_max_get();
1997
/*******************************************************************//**
1998
Closes an InnoDB database.
1999
@return TRUE if error */
2002
innobase_deinit(plugin::Registry ®istry)
2006
registry.remove(status_table_function_ptr);
2007
delete status_table_function_ptr;
2009
registry.remove(cmp_tool);
2012
registry.remove(cmp_reset_tool);
2013
delete cmp_reset_tool;
2015
registry.remove(cmp_mem_tool);
2016
delete cmp_mem_tool;
2018
registry.remove(cmp_mem_reset_tool);
2019
delete cmp_mem_reset_tool;
2021
registry.remove(innodb_trx_tool);
2022
delete innodb_trx_tool;
2024
registry.remove(innodb_locks_tool);
2025
delete innodb_locks_tool;
2027
registry.remove(innodb_lock_waits_tool);
2028
delete innodb_lock_waits_tool;
2030
registry.remove(innodb_engine_ptr);
2031
delete innodb_engine_ptr;
2033
if (innodb_inited) {
2035
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
2037
hash_table_free(innobase_open_tables);
2038
innobase_open_tables = NULL;
2039
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
2042
srv_free_paths_and_sizes();
2043
if (internal_innobase_data_file_path)
2044
free(internal_innobase_data_file_path);
2045
pthread_mutex_destroy(&innobase_share_mutex);
2046
pthread_mutex_destroy(&prepare_commit_mutex);
2047
pthread_mutex_destroy(&commit_threads_m);
2048
pthread_mutex_destroy(&commit_cond_m);
2049
pthread_cond_destroy(&commit_cond);
2055
/****************************************************************//**
2056
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2057
the logs, and the name of this function should be innobase_checkpoint.
2058
@return TRUE if error */
2060
InnobaseEngine::flush_logs()
2061
/*=====================*/
2065
assert(this == innodb_engine_ptr);
2067
log_buffer_flush_to_disk();
2072
/*****************************************************************//**
2073
Commits a transaction in an InnoDB database. */
2076
innobase_commit_low(
2077
/*================*/
2078
trx_t* trx) /*!< in: transaction handle */
2080
if (trx->conc_state == TRX_NOT_STARTED) {
2085
trx_commit_for_mysql(trx);
2088
/*****************************************************************//**
2089
Creates an InnoDB transaction struct for the thd if it does not yet have one.
2090
Starts a new InnoDB transaction if a transaction is not yet started. And
2091
assigns a new snapshot for a consistent read if the transaction does not yet
2095
InnobaseEngine::doStartTransaction(
2096
/*====================================*/
2097
Session* session, /*!< in: MySQL thread handle of the user for whom
2098
the transaction should be committed */
2099
start_transaction_option_t options)
2101
assert(this == innodb_engine_ptr);
2103
/* Create a new trx struct for session, if it does not yet have one */
2104
trx_t *trx = check_trx_exists(session);
2106
/* This is just to play safe: release a possible FIFO ticket and
2107
search latch. Since we will reserve the kernel mutex, we have to
2108
release the search system latch first to obey the latching order. */
2109
innobase_release_stat_resources(trx);
2111
/* If the transaction is not started yet, start it */
2112
trx_start_if_not_started(trx);
2114
/* Assign a read view if the transaction does not have it yet */
2115
if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2116
trx_assign_read_view(trx);
2121
/*****************************************************************//**
2122
Commits a transaction in an InnoDB database or marks an SQL statement
2126
InnobaseEngine::doCommit(
2128
Session* session, /*!< in: MySQL thread handle of the user for whom
2129
the transaction should be committed */
2130
bool all) /*!< in: TRUE - commit transaction
2131
FALSE - the current SQL statement ended */
2135
assert(this == innodb_engine_ptr);
2137
trx = check_trx_exists(session);
2139
/* Since we will reserve the kernel mutex, we have to release
2140
the search system latch first to obey the latching order. */
2142
if (trx->has_search_latch) {
2143
trx_search_latch_release_if_reserved(trx);
2147
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
2149
/* We were instructed to commit the whole transaction, or
2150
this is an SQL statement end and autocommit is on */
2152
/* We need current binlog position for ibbackup to work.
2153
Note, the position is current because of
2154
prepare_commit_mutex */
2156
if (innobase_commit_concurrency > 0) {
2157
pthread_mutex_lock(&commit_cond_m);
2160
if (commit_threads > innobase_commit_concurrency) {
2162
pthread_cond_wait(&commit_cond,
2164
pthread_mutex_unlock(&commit_cond_m);
2168
pthread_mutex_unlock(&commit_cond_m);
2172
/* Store transaction point for binlog
2173
Later logic tests that this is set to _something_. We need
2174
that logic to fire, even though we do not have a real name. */
2175
trx->mysql_log_file_name = "UNUSED";
2176
trx->mysql_log_offset = 0;
2178
/* Don't do write + flush right now. For group commit
2179
to work we want to do the flush after releasing the
2180
prepare_commit_mutex. */
2181
trx->flush_log_later = TRUE;
2182
innobase_commit_low(trx);
2183
trx->flush_log_later = FALSE;
2185
if (innobase_commit_concurrency > 0) {
2186
pthread_mutex_lock(&commit_cond_m);
2188
pthread_cond_signal(&commit_cond);
2189
pthread_mutex_unlock(&commit_cond_m);
2192
if (trx->conc_state == TRX_PREPARED) {
2194
pthread_mutex_unlock(&prepare_commit_mutex);
2197
/* Now do a write + flush of logs. */
2198
trx_commit_complete_for_mysql(trx);
2201
/* We just mark the SQL statement ended and do not do a
2202
transaction commit */
2204
/* If we had reserved the auto-inc lock for some
2205
table in this SQL statement we release it now */
2207
row_unlock_table_autoinc_for_mysql(trx);
2209
/* Store the current undo_no of the transaction so that we
2210
know where to roll back if we have to roll back the next
2213
trx_mark_sql_stat_end(trx);
2216
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2218
if (trx->declared_to_be_inside_innodb) {
2219
/* Release our possible ticket in the FIFO */
2221
srv_conc_force_exit_innodb(trx);
2224
/* Tell the InnoDB server that there might be work for utility
2226
srv_active_wake_master_thread();
2231
/*****************************************************************//**
2232
Rolls back a transaction or the latest SQL statement.
2233
@return 0 or error number */
2235
InnobaseEngine::doRollback(
2237
Session* session,/*!< in: handle to the MySQL thread of the user
2238
whose transaction should be rolled back */
2239
bool all) /*!< in: TRUE - commit transaction
2240
FALSE - the current SQL statement ended */
2245
assert(this == innodb_engine_ptr);
2247
trx = check_trx_exists(session);
2249
/* Release a possible FIFO ticket and search latch. Since we will
2250
reserve the kernel mutex, we have to release the search system latch
2251
first to obey the latching order. */
2253
innobase_release_stat_resources(trx);
2255
/* If we had reserved the auto-inc lock for some table (if
2256
we come here to roll back the latest SQL statement) we
2257
release it now before a possibly lengthy rollback */
2259
row_unlock_table_autoinc_for_mysql(trx);
2262
|| !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
2264
error = trx_rollback_for_mysql(trx);
2266
error = trx_rollback_last_sql_stat_for_mysql(trx);
2269
return(convert_error_code_to_mysql(error, 0, NULL));
2272
/*****************************************************************//**
2273
Rolls back a transaction
2274
@return 0 or error number */
2277
innobase_rollback_trx(
2278
/*==================*/
2279
trx_t* trx) /*!< in: transaction */
2283
/* Release a possible FIFO ticket and search latch. Since we will
2284
reserve the kernel mutex, we have to release the search system latch
2285
first to obey the latching order. */
2287
innobase_release_stat_resources(trx);
2289
/* If we had reserved the auto-inc lock for some table (if
2290
we come here to roll back the latest SQL statement) we
2291
release it now before a possibly lengthy rollback */
2293
row_unlock_table_autoinc_for_mysql(trx);
2295
error = trx_rollback_for_mysql(trx);
2297
return(convert_error_code_to_mysql(error, 0, NULL));
2300
/*****************************************************************//**
2301
Rolls back a transaction to a savepoint.
2302
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2305
InnobaseEngine::doRollbackToSavepoint(
2306
/*===========================*/
2307
Session* session, /*!< in: handle to the MySQL thread of the user
2308
whose transaction should be rolled back */
2309
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2311
ib_int64_t mysql_binlog_cache_pos;
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
error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2326
&mysql_binlog_cache_pos);
2327
return(convert_error_code_to_mysql(error, 0, NULL));
2330
/*****************************************************************//**
2331
Release transaction savepoint name.
2332
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2335
InnobaseEngine::doReleaseSavepoint(
2336
/*=======================*/
2337
Session* session, /*!< in: handle to the MySQL thread of the user
2338
whose transaction should be rolled back */
2339
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2344
assert(this == innodb_engine_ptr);
2346
trx = check_trx_exists(session);
2348
error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2350
return(convert_error_code_to_mysql(error, 0, NULL));
2353
/*****************************************************************//**
2354
Sets a transaction savepoint.
2355
@return always 0, that is, always succeeds */
2357
InnobaseEngine::doSetSavepoint(
2359
Session* session,/*!< in: handle to the MySQL thread */
2360
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2365
assert(this == innodb_engine_ptr);
2368
In the autocommit mode there is no sense to set a savepoint
2369
(unless we are in sub-statement), so SQL layer ensures that
2370
this method is never called in such situation.
2373
trx = check_trx_exists(session);
2375
/* Release a possible FIFO ticket and search latch. Since we will
2376
reserve the kernel mutex, we have to release the search system latch
2377
first to obey the latching order. */
2379
innobase_release_stat_resources(trx);
2381
/* cannot happen outside of transaction */
2382
assert(trx->conc_state != TRX_NOT_STARTED);
2384
error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2386
return(convert_error_code_to_mysql(error, 0, NULL));
2389
/*****************************************************************//**
2390
Frees a possible InnoDB trx object associated with the current Session.
2391
@return 0 or error number */
2393
InnobaseEngine::close_connection(
2394
/*======================*/
2395
Session* session)/*!< in: handle to the MySQL thread of the user
2396
whose resources should be free'd */
2400
assert(this == innodb_engine_ptr);
2401
trx = session_to_trx(session);
2405
assert(session->killed != Session::NOT_KILLED ||
2406
trx->conc_state == TRX_NOT_STARTED);
2408
/* Warn if rolling back some things... */
2409
if (session->killed != Session::NOT_KILLED &&
2410
trx->conc_state != TRX_NOT_STARTED &&
2411
trx->undo_no.low > 0 &&
2412
global_system_variables.log_warnings)
2414
errmsg_printf(ERRMSG_LVL_WARN,
2415
"Drizzle is closing a connection during a KILL operation\n"
2416
"that has an active InnoDB transaction. %lu row modifications will "
2418
(ulong) trx->undo_no.low);
2421
innobase_rollback_trx(trx);
2423
thr_local_free(trx->mysql_thread_id);
2424
trx_free_for_mysql(trx);
2430
/*************************************************************************//**
2431
** InnoDB database tables
2432
*****************************************************************************/
2434
/****************************************************************//**
2435
Get the record format from the data dictionary.
2436
@return one of ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT,
2437
ROW_TYPE_COMPRESSED, ROW_TYPE_DYNAMIC */
2440
ha_innobase::get_row_type() const
2441
/*=============================*/
2443
if (prebuilt && prebuilt->table) {
2444
const ulint flags = prebuilt->table->flags;
2446
if (UNIV_UNLIKELY(!flags)) {
2447
return(ROW_TYPE_REDUNDANT);
2450
ut_ad(flags & DICT_TF_COMPACT);
2452
switch (flags & DICT_TF_FORMAT_MASK) {
2453
case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
2454
return(ROW_TYPE_COMPACT);
2455
case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
2456
if (flags & DICT_TF_ZSSIZE_MASK) {
2457
return(ROW_TYPE_COMPRESSED);
2459
return(ROW_TYPE_DYNAMIC);
2461
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
2462
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
2467
return(ROW_TYPE_NOT_USED);
2471
/****************************************************************//**
2472
Returns the index type. */
2475
ha_innobase::index_type(
2476
/*====================*/
2478
/*!< out: index type */
2483
/****************************************************************//**
2484
Returns the maximum number of keys.
2488
InnobaseEngine::max_supported_keys() const
2489
/*===================================*/
2494
/****************************************************************//**
2495
Returns the maximum key length.
2496
@return maximum supported key length, in bytes */
2499
InnobaseEngine::max_supported_key_length() const
2500
/*=========================================*/
2502
/* An InnoDB page must store >= 2 keys; a secondary key record
2503
must also contain the primary key value: max key length is
2504
therefore set to slightly less than 1 / 4 of page size which
2505
is 16 kB; but currently MySQL does not work with keys whose
2506
size is > MAX_KEY_LENGTH */
2510
/****************************************************************//**
2511
Returns the key map of keys that are usable for scanning.
2512
@return key_map_full */
2515
ha_innobase::keys_to_use_for_scanning()
2517
return(&key_map_full);
2521
/****************************************************************//**
2522
Determines if the primary key is clustered index.
2526
ha_innobase::primary_key_is_clustered()
2531
/*****************************************************************//**
2532
Normalizes a table name string. A normalized name consists of the
2533
database name catenated to '/' and table name. An example:
2534
test/mytable. On Windows normalization puts both the database name and the
2535
table name always to lower case. */
2538
normalize_table_name(
2539
/*=================*/
2540
char* norm_name, /*!< out: normalized name as a
2541
null-terminated string */
2542
const char* name) /*!< in: table name string */
2544
const char* name_ptr;
2548
/* Scan name from the end */
2550
ptr = strchr(name, '\0')-1;
2552
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2562
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2568
memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
2570
norm_name[name_ptr - db_ptr - 1] = '/';
2573
innobase_casedn_str(norm_name);
2577
/********************************************************************//**
2578
Set the autoinc column max value. This should only be called once from
2579
ha_innobase::open(). Therefore there's no need for a covering lock.
2580
@return DB_SUCCESS or error code */
2583
ha_innobase::innobase_initialize_autoinc()
2584
/*======================================*/
2586
dict_index_t* index;
2588
const char* col_name;
2591
col_name = table->found_next_number_field->field_name;
2592
index = innobase_get_index(table->s->next_number_index);
2594
/* Execute SELECT MAX(col_name) FROM TABLE; */
2595
error = row_search_max_autoinc(index, col_name, &auto_inc);
2600
/* At the this stage we don't know the increment
2601
or the offset, so use default inrement of 1. */
2605
case DB_RECORD_NOT_FOUND:
2606
ut_print_timestamp(stderr);
2607
fprintf(stderr, " InnoDB: MySQL and InnoDB data "
2608
"dictionaries are out of sync.\n"
2609
"InnoDB: Unable to find the AUTOINC column %s in the "
2610
"InnoDB table %s.\n"
2611
"InnoDB: We set the next AUTOINC column value to the "
2612
"maximum possible value,\n"
2613
"InnoDB: in effect disabling the AUTOINC next value "
2615
"InnoDB: You can either set the next AUTOINC value "
2616
"explicitly using ALTER TABLE\n"
2617
"InnoDB: or fix the data dictionary by recreating "
2619
col_name, index->table->name);
2621
auto_inc = 0xFFFFFFFFFFFFFFFFULL;
2628
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
2633
/*****************************************************************//**
2634
Creates and opens a handle to a table which already exists in an InnoDB
2636
@return 1 if error, 0 if success */
2641
const char* name, /*!< in: table name */
2642
int mode, /*!< in: not used */
2643
uint test_if_locked) /*!< in: not used */
2645
dict_table_t* ib_table;
2646
char norm_name[1000];
2649
char* is_part = NULL;
2652
UT_NOT_USED(test_if_locked);
2654
session = ha_session();
2656
/* Under some cases Drizzle seems to call this function while
2657
holding btr_search_latch. This breaks the latching order as
2658
we acquire dict_sys->mutex below and leads to a deadlock. */
2659
if (session != NULL) {
2660
getTransactionalEngine()->releaseTemporaryLatches(session);
2663
normalize_table_name(norm_name, name);
2665
user_session = NULL;
2667
if (!(share=get_share(name))) {
2672
/* Create buffers for packing the fields of a record. Why
2673
table->stored_rec_length did not work here? Obviously, because char
2674
fields when packed actually became 1 byte longer, when we also
2675
stored the string length as the first byte. */
2677
upd_and_key_val_buff_len =
2678
table->s->stored_rec_length
2679
+ table->s->max_key_length
2680
+ MAX_REF_PARTS * 3;
2681
if (!(unsigned char*) memory::multi_malloc(false,
2682
&upd_buff, upd_and_key_val_buff_len,
2683
&key_val_buff, upd_and_key_val_buff_len,
2690
/* We look for pattern #P# to see if the table is partitioned
2691
MySQL table. The retry logic for partitioned tables is a
2692
workaround for http://bugs.mysql.com/bug.php?id=33349. Look
2693
at support issue https://support.mysql.com/view.php?id=21080
2694
for more details. */
2695
is_part = strstr(norm_name, "#P#");
2697
/* Get pointer to a table object in InnoDB dictionary cache */
2698
ib_table = dict_table_get(norm_name, TRUE);
2700
if (NULL == ib_table) {
2701
if (is_part && retries < 10) {
2703
os_thread_sleep(100000);
2708
errmsg_printf(ERRMSG_LVL_ERROR, "Failed to open table %s after "
2709
"%lu attemtps.\n", norm_name,
2713
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
2714
"the internal data dictionary of InnoDB "
2715
"though the .frm file for the\n"
2716
"table exists. Maybe you have deleted and "
2717
"recreated InnoDB data\n"
2718
"files but have forgotten to delete the "
2719
"corresponding .frm files\n"
2720
"of InnoDB tables, or you have moved .frm "
2721
"files to another database?\n"
2722
"or, the table contains indexes that this "
2723
"version of the engine\n"
2724
"doesn't support.\n"
2725
"See " REFMAN "innodb-troubleshooting.html\n"
2726
"how you can resolve the problem.\n",
2732
return(HA_ERR_NO_SUCH_TABLE);
2735
if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
2736
errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
2737
"the .ibd file for\ntable %s does not exist.\n"
2738
"Have you deleted the .ibd file from the "
2739
"database directory under\nthe MySQL datadir, "
2740
"or have you used DISCARD TABLESPACE?\n"
2741
"See " REFMAN "innodb-troubleshooting.html\n"
2742
"how you can resolve the problem.\n",
2748
dict_table_decrement_handle_count(ib_table, FALSE);
2749
return(HA_ERR_NO_SUCH_TABLE);
2752
prebuilt = row_create_prebuilt(ib_table);
2754
prebuilt->mysql_row_len = table->s->stored_rec_length;
2755
prebuilt->default_rec = table->s->default_values;
2756
ut_ad(prebuilt->default_rec);
2758
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
2760
primary_key = table->s->primary_key;
2761
key_used_on_scan = primary_key;
2763
/* Allocate a buffer for a 'row reference'. A row reference is
2764
a string of bytes of length ref_length which uniquely specifies
2765
a row in our table. Note that MySQL may also compare two row
2766
references for equality by doing a simple memcmp on the strings
2767
of length ref_length! */
2769
if (!row_table_got_default_clust_index(ib_table)) {
2770
if (primary_key >= MAX_KEY) {
2771
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in InnoDB data "
2772
"dictionary, but not in MySQL!", name);
2775
prebuilt->clust_index_was_generated = FALSE;
2777
/* MySQL allocates the buffer for ref. key_info->key_length
2778
includes space for all key columns + one byte for each column
2779
that may be NULL. ref_length must be as exact as possible to
2780
save space, because all row reference buffers are allocated
2781
based on ref_length. */
2783
ref_length = table->key_info[primary_key].key_length;
2785
if (primary_key != MAX_KEY) {
2786
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has no primary key in InnoDB data "
2787
"dictionary, but has one in MySQL! If you "
2788
"created the table with a MySQL version < "
2789
"3.23.54 and did not define a primary key, "
2790
"but defined a unique key with all non-NULL "
2791
"columns, then MySQL internally treats that "
2792
"key as the primary key. You can fix this "
2793
"error by dump + DROP + CREATE + reimport "
2794
"of the table.", name);
2797
prebuilt->clust_index_was_generated = TRUE;
2799
ref_length = DATA_ROW_ID_LEN;
2801
/* If we automatically created the clustered index, then
2802
MySQL does not know about it, and MySQL must NOT be aware
2803
of the index used on scan, to make it avoid checking if we
2804
update the column of the index. That is why we assert below
2805
that key_used_on_scan is the undefined value MAX_KEY.
2806
The column is the row id in the automatical generation case,
2807
and it will never be updated anyway. */
2809
if (key_used_on_scan != MAX_KEY) {
2810
errmsg_printf(ERRMSG_LVL_WARN,
2811
"Table %s key_used_on_scan is %lu even "
2812
"though there is no primary key inside "
2813
"InnoDB.", name, (ulong) key_used_on_scan);
2817
/* Index block size in InnoDB: used by MySQL in query optimization */
2818
stats.block_size = 16 * 1024;
2820
/* Init table lock structure */
2821
thr_lock_data_init(&share->lock,&lock,(void*) 0);
2823
if (prebuilt->table) {
2824
/* We update the highest file format in the system table
2825
space, if this table has higher file format setting. */
2827
trx_sys_file_format_max_upgrade(
2828
(const char**) &innobase_file_format_check,
2829
dict_table_get_format(prebuilt->table));
2832
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
2834
/* Only if the table has an AUTOINC column. */
2835
if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
2838
dict_table_autoinc_lock(prebuilt->table);
2840
/* Since a table can already be "open" in InnoDB's internal
2841
data dictionary, we only init the autoinc counter once, the
2842
first time the table is loaded. We can safely reuse the
2843
autoinc value from a previous Drizzle open. */
2844
if (dict_table_autoinc_read(prebuilt->table) == 0) {
2846
error = innobase_initialize_autoinc();
2847
ut_a(error == DB_SUCCESS);
2850
dict_table_autoinc_unlock(prebuilt->table);
2858
InnobaseEngine::max_supported_key_part_length() const
2860
return(DICT_MAX_INDEX_COL_LEN - 1);
2863
/******************************************************************//**
2864
Closes a handle to an InnoDB table.
2868
ha_innobase::close(void)
2869
/*====================*/
2873
session = ha_session();
2874
if (session != NULL) {
2875
getTransactionalEngine()->releaseTemporaryLatches(session);
2878
row_prebuilt_free(prebuilt, FALSE);
2883
/* Tell InnoDB server that there might be work for
2886
srv_active_wake_master_thread();
2891
/* The following accessor functions should really be inside MySQL code! */
2893
/**************************************************************//**
2894
Gets field offset for a field in a table.
2900
Table* table, /*!< in: MySQL table object */
2901
Field* field) /*!< in: MySQL field object */
2903
return((uint) (field->ptr - table->record[0]));
2906
/**************************************************************//**
2907
Checks if a field in a record is SQL NULL. Uses the record format
2908
information in table to track the null bit in record.
2909
@return 1 if NULL, 0 otherwise */
2912
field_in_record_is_null(
2913
/*====================*/
2914
Table* table, /*!< in: MySQL table object */
2915
Field* field, /*!< in: MySQL field object */
2916
char* record) /*!< in: a row in MySQL format */
2920
if (!field->null_ptr) {
2925
null_offset = (uint) ((char*) field->null_ptr
2926
- (char*) table->record[0]);
2928
if (record[null_offset] & field->null_bit) {
2936
/**************************************************************//**
2937
Sets a field in a record to SQL NULL. Uses the record format
2938
information in table to track the null bit in record. */
2941
set_field_in_record_to_null(
2942
/*========================*/
2943
Table* table, /*!< in: MySQL table object */
2944
Field* field, /*!< in: MySQL field object */
2945
char* record) /*!< in: a row in MySQL format */
2949
null_offset = (uint) ((char*) field->null_ptr
2950
- (char*) table->record[0]);
2952
record[null_offset] = record[null_offset] | field->null_bit;
2955
/*************************************************************//**
2956
InnoDB uses this function to compare two data fields for which the data type
2957
is such that we must use MySQL code to compare them. NOTE that the prototype
2958
of this function is in rem0cmp.c in InnoDB source code! If you change this
2959
function, remember to update the prototype there!
2960
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
2961
extern "C" UNIV_INTERN
2965
int mysql_type, /*!< in: MySQL type */
2966
uint charset_number, /*!< in: number of the charset */
2967
const unsigned char* a, /*!< in: data field */
2968
unsigned int a_length, /*!< in: data field length,
2969
not UNIV_SQL_NULL */
2970
const unsigned char* b, /* in: data field */
2971
unsigned int b_length); /* in: data field length,
2972
not UNIV_SQL_NULL */
2977
/* out: 1, 0, -1, if a is greater,
2978
equal, less than b, respectively */
2979
int mysql_type, /* in: MySQL type */
2980
uint charset_number, /* in: number of the charset */
2981
const unsigned char* a, /* in: data field */
2982
unsigned int a_length, /* in: data field length,
2983
not UNIV_SQL_NULL */
2984
const unsigned char* b, /* in: data field */
2985
unsigned int b_length) /* in: data field length,
2986
not UNIV_SQL_NULL */
2988
const CHARSET_INFO* charset;
2989
enum_field_types mysql_tp;
2992
assert(a_length != UNIV_SQL_NULL);
2993
assert(b_length != UNIV_SQL_NULL);
2995
mysql_tp = (enum_field_types) mysql_type;
2999
case DRIZZLE_TYPE_BLOB:
3000
case DRIZZLE_TYPE_VARCHAR:
3001
/* Use the charset number to pick the right charset struct for
3002
the comparison. Since the MySQL function get_charset may be
3003
slow before Bar removes the mutex operation there, we first
3004
look at 2 common charsets directly. */
3006
if (charset_number == default_charset_info->number) {
3007
charset = default_charset_info;
3009
charset = get_charset(charset_number);
3011
if (charset == NULL) {
3012
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
3013
"a comparison, but MySQL cannot "
3014
"find that charset.",
3015
(ulong) charset_number);
3020
/* Starting from 4.1.3, we use strnncollsp() in comparisons of
3021
non-latin1_swedish_ci strings. NOTE that the collation order
3022
changes then: 'b\0\0...' is ordered BEFORE 'b ...'. Users
3023
having indexes on such data need to rebuild their tables! */
3025
ret = charset->coll->strnncollsp(charset,
3030
} else if (ret > 0) {
3042
/**************************************************************//**
3043
Converts a MySQL type to an InnoDB type. Note that this function returns
3044
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3045
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3046
@return DATA_BINARY, DATA_VARCHAR, ... */
3047
extern "C" UNIV_INTERN
3049
get_innobase_type_from_mysql_type(
3050
/*==============================*/
3051
ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
3053
at least ENUM and SET,
3054
and unsigned integer
3055
types are 'unsigned types' */
3056
const void* f) /*!< in: MySQL Field */
3058
const class Field* field = reinterpret_cast<const class Field*>(f);
3060
/* The following asserts try to check that the MySQL type code fits in
3061
8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3064
assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3066
if (field->flags & UNSIGNED_FLAG) {
3068
*unsigned_flag = DATA_UNSIGNED;
3073
if (field->real_type() == DRIZZLE_TYPE_ENUM)
3075
/* MySQL has field->type() a string type for these, but the
3076
data is actually internally stored as an unsigned integer
3079
*unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3080
flag set to zero, even though
3081
internally this is an unsigned
3086
switch (field->type()) {
3087
/* NOTE that we only allow string types in DATA_DRIZZLE and
3089
case DRIZZLE_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
3090
if (field->binary()) {
3091
return(DATA_BINARY);
3093
return(DATA_VARMYSQL);
3095
case DRIZZLE_TYPE_DECIMAL:
3096
return(DATA_FIXBINARY);
3097
case DRIZZLE_TYPE_LONG:
3098
case DRIZZLE_TYPE_LONGLONG:
3099
case DRIZZLE_TYPE_DATETIME:
3100
case DRIZZLE_TYPE_DATE:
3101
case DRIZZLE_TYPE_TIMESTAMP:
3103
case DRIZZLE_TYPE_DOUBLE:
3104
return(DATA_DOUBLE);
3105
case DRIZZLE_TYPE_BLOB:
3114
/*******************************************************************//**
3115
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
3119
innobase_write_to_2_little_endian(
3120
/*==============================*/
3121
byte* buf, /*!< in: where to store */
3122
ulint val) /*!< in: value to write, must be < 64k */
3124
ut_a(val < 256 * 256);
3126
buf[0] = (byte)(val & 0xFF);
3127
buf[1] = (byte)(val / 256);
3130
/*******************************************************************//**
3131
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
3136
innobase_read_from_2_little_endian(
3137
/*===============================*/
3138
const unsigned char* buf) /*!< in: from where to read */
3140
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
3143
/*******************************************************************//**
3144
Stores a key value for a row to a buffer.
3145
@return key value length as stored in buff */
3148
ha_innobase::store_key_val_for_row(
3149
/*===============================*/
3150
uint keynr, /*!< in: key number */
3151
char* buff, /*!< in/out: buffer for the key value (in MySQL
3153
uint buff_len,/*!< in: buffer length */
3154
const unsigned char* record)/*!< in: row in MySQL format */
3156
KEY* key_info = table->key_info + keynr;
3157
KEY_PART_INFO* key_part = key_info->key_part;
3158
KEY_PART_INFO* end = key_part + key_info->key_parts;
3159
char* buff_start = buff;
3160
enum_field_types mysql_type;
3164
/* The format for storing a key field in MySQL is the following:
3166
1. If the column can be NULL, then in the first byte we put 1 if the
3167
field value is NULL, 0 otherwise.
3169
2. If the column is of a BLOB type (it must be a column prefix field
3170
in this case), then we put the length of the data in the field to the
3171
next 2 bytes, in the little-endian format. If the field is SQL NULL,
3172
then these 2 bytes are set to 0. Note that the length of data in the
3173
field is <= column prefix length.
3175
3. In a column prefix field, prefix_len next bytes are reserved for
3176
data. In a normal field the max field length next bytes are reserved
3177
for data. For a VARCHAR(n) the max field length is n. If the stored
3178
value is the SQL NULL then these data bytes are set to 0.
3180
4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
3181
in the MySQL row format, the length is stored in 1 or 2 bytes,
3182
depending on the maximum allowed length. But in the MySQL key value
3183
format, the length always takes 2 bytes.
3185
We have to zero-fill the buffer so that MySQL is able to use a
3186
simple memcmp to compare two key values to determine if they are
3187
equal. MySQL does this to compare contents of two 'ref' values. */
3189
bzero(buff, buff_len);
3191
for (; key_part != end; key_part++) {
3194
if (key_part->null_bit) {
3195
if (record[key_part->null_offset]
3196
& key_part->null_bit) {
3205
field = key_part->field;
3206
mysql_type = field->type();
3208
if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
3209
/* >= 5.0.3 true VARCHAR */
3215
const CHARSET_INFO* cs;
3218
key_len = key_part->length;
3221
buff += key_len + 2;
3225
cs = field->charset();
3228
(((Field_varstring*)field)->length_bytes);
3230
data = row_mysql_read_true_varchar(&len,
3232
+ (ulint)get_field_offset(table, field)),
3237
/* For multi byte character sets we need to calculate
3238
the true length of the key */
3240
if (len > 0 && cs->mbmaxlen > 1) {
3241
true_len = (ulint) cs->cset->well_formed_len(cs,
3242
(const char *) data,
3243
(const char *) data + len,
3249
/* In a column prefix index, we may need to truncate
3250
the stored value: */
3252
if (true_len > key_len) {
3256
/* The length in a key value is always stored in 2
3259
row_mysql_store_true_var_len((byte*)buff, true_len, 2);
3262
memcpy(buff, data, true_len);
3264
/* Note that we always reserve the maximum possible
3265
length of the true VARCHAR in the key value, though
3266
only len first bytes after the 2 length bytes contain
3267
actual data. The rest of the space was reset to zero
3268
in the bzero() call above. */
3272
} else if (mysql_type == DRIZZLE_TYPE_BLOB) {
3274
const CHARSET_INFO* cs;
3279
const byte* blob_data;
3281
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
3283
key_len = key_part->length;
3286
buff += key_len + 2;
3291
cs = field->charset();
3293
blob_data = row_mysql_read_blob_ref(&blob_len,
3295
+ (ulint)get_field_offset(table, field)),
3296
(ulint) field->pack_length());
3298
true_len = blob_len;
3300
ut_a(get_field_offset(table, field)
3301
== key_part->offset);
3303
/* For multi byte character sets we need to calculate
3304
the true length of the key */
3306
if (blob_len > 0 && cs->mbmaxlen > 1) {
3307
true_len = (ulint) cs->cset->well_formed_len(cs,
3308
(const char *) blob_data,
3309
(const char *) blob_data
3316
/* All indexes on BLOB and TEXT are column prefix
3317
indexes, and we may need to truncate the data to be
3318
stored in the key value: */
3320
if (true_len > key_len) {
3324
/* MySQL reserves 2 bytes for the length and the
3325
storage of the number is little-endian */
3327
innobase_write_to_2_little_endian(
3328
(byte*)buff, true_len);
3331
memcpy(buff, blob_data, true_len);
3333
/* Note that we always reserve the maximum possible
3334
length of the BLOB prefix in the key value. */
3338
/* Here we handle all other data types except the
3339
true VARCHAR, BLOB and TEXT. Note that the column
3340
value we store may be also in a column prefix
3345
const unsigned char* src_start;
3346
enum_field_types real_type;
3348
key_len = key_part->length;
3356
src_start = record + key_part->offset;
3357
real_type = field->real_type();
3360
/* Character set for the field is defined only
3361
to fields whose type is string and real field
3362
type is not enum or set. For these fields check
3363
if character set is multi byte. */
3365
memcpy(buff, src_start, true_len);
3368
/* Pad the unused space with spaces. Note that no
3369
padding is ever needed for UCS-2 because in MySQL,
3370
all UCS2 characters are 2 bytes, as MySQL does not
3371
support surrogate pairs, which are needed to represent
3372
characters in the range U+10000 to U+10FFFF. */
3374
if (true_len < key_len) {
3375
ulint pad_len = key_len - true_len;
3376
memset(buff, ' ', pad_len);
3382
ut_a(buff <= buff_start + buff_len);
3384
return((uint)(buff - buff_start));
3387
/**************************************************************//**
3388
Builds a 'template' to the prebuilt struct. The template is used in fast
3389
retrieval of just those column values MySQL needs in its processing. */
3394
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
3395
Session* , /*!< in: current user thread, used
3396
only if templ_type is
3397
ROW_DRIZZLE_REC_FIELDS */
3398
Table* table, /*!< in: MySQL table */
3399
uint templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
3400
ROW_DRIZZLE_REC_FIELDS */
3402
dict_index_t* index;
3403
dict_index_t* clust_index;
3404
mysql_row_templ_t* templ;
3407
ulint n_requested_fields = 0;
3408
ibool fetch_all_in_key = FALSE;
3409
ibool fetch_primary_key_cols = FALSE;
3411
/* byte offset of the end of last requested column */
3412
ulint mysql_prefix_len = 0;
3414
if (prebuilt->select_lock_type == LOCK_X) {
3415
/* We always retrieve the whole clustered index record if we
3416
use exclusive row level locks, for example, if the read is
3417
done in an UPDATE statement. */
3419
templ_type = ROW_MYSQL_WHOLE_ROW;
3422
if (templ_type == ROW_MYSQL_REC_FIELDS) {
3423
if (prebuilt->hint_need_to_fetch_extra_cols
3424
== ROW_RETRIEVE_ALL_COLS) {
3426
/* We know we must at least fetch all columns in the
3427
key, or all columns in the table */
3429
if (prebuilt->read_just_key) {
3430
/* MySQL has instructed us that it is enough
3431
to fetch the columns in the key; looks like
3432
MySQL can set this flag also when there is
3433
only a prefix of the column in the key: in
3434
that case we retrieve the whole column from
3435
the clustered index */
3437
fetch_all_in_key = TRUE;
3439
templ_type = ROW_MYSQL_WHOLE_ROW;
3441
} else if (prebuilt->hint_need_to_fetch_extra_cols
3442
== ROW_RETRIEVE_PRIMARY_KEY) {
3443
/* We must at least fetch all primary key cols. Note
3444
that if the clustered index was internally generated
3445
by InnoDB on the row id (no primary key was
3446
defined), then row_search_for_mysql() will always
3447
retrieve the row id to a special buffer in the
3450
fetch_primary_key_cols = TRUE;
3454
clust_index = dict_table_get_first_index(prebuilt->table);
3456
if (templ_type == ROW_MYSQL_REC_FIELDS) {
3457
index = prebuilt->index;
3459
index = clust_index;
3462
if (index == clust_index) {
3463
prebuilt->need_to_access_clustered = TRUE;
3465
prebuilt->need_to_access_clustered = FALSE;
3466
/* Below we check column by column if we need to access
3467
the clustered index */
3470
n_fields = (ulint)table->s->fields; /* number of columns */
3472
if (!prebuilt->mysql_template) {
3473
prebuilt->mysql_template = (mysql_row_templ_t*)
3474
mem_alloc(n_fields * sizeof(mysql_row_templ_t));
3477
prebuilt->template_type = templ_type;
3478
prebuilt->null_bitmap_len = table->s->null_bytes;
3480
prebuilt->templ_contains_blob = FALSE;
3482
/* Note that in InnoDB, i is the column number. MySQL calls columns
3484
for (i = 0; i < n_fields; i++) {
3485
templ = prebuilt->mysql_template + n_requested_fields;
3486
field = table->field[i];
3488
if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
3489
/* Decide which columns we should fetch
3490
and which we can skip. */
3491
register const ibool index_contains_field =
3492
dict_index_contains_col_or_prefix(index, i);
3494
if (!index_contains_field && prebuilt->read_just_key) {
3495
/* If this is a 'key read', we do not need
3496
columns that are not in the key */
3501
if (index_contains_field && fetch_all_in_key) {
3502
/* This field is needed in the query */
3507
if (field->isReadSet() || field->isWriteSet())
3508
/* This field is needed in the query */
3511
assert(table->isReadSet(i) == field->isReadSet());
3512
assert(table->isWriteSet(i) == field->isWriteSet());
3514
if (fetch_primary_key_cols
3515
&& dict_table_col_in_clustered_key(
3517
/* This field is needed in the query */
3522
/* This field is not needed in the query, skip it */
3527
n_requested_fields++;
3531
if (index == clust_index) {
3532
templ->rec_field_no = dict_col_get_clust_pos(
3533
&index->table->cols[i], index);
3535
templ->rec_field_no = dict_index_get_nth_col_pos(
3539
if (templ->rec_field_no == ULINT_UNDEFINED) {
3540
prebuilt->need_to_access_clustered = TRUE;
3543
if (field->null_ptr) {
3544
templ->mysql_null_byte_offset =
3545
(ulint) ((char*) field->null_ptr
3546
- (char*) table->record[0]);
3548
templ->mysql_null_bit_mask = (ulint) field->null_bit;
3550
templ->mysql_null_bit_mask = 0;
3553
templ->mysql_col_offset = (ulint)
3554
get_field_offset(table, field);
3556
templ->mysql_col_len = (ulint) field->pack_length();
3557
if (mysql_prefix_len < templ->mysql_col_offset
3558
+ templ->mysql_col_len) {
3559
mysql_prefix_len = templ->mysql_col_offset
3560
+ templ->mysql_col_len;
3562
templ->type = index->table->cols[i].mtype;
3563
templ->mysql_type = (ulint)field->type();
3565
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
3566
templ->mysql_length_bytes = (ulint)
3567
(((Field_varstring*)field)->length_bytes);
3570
templ->charset = dtype_get_charset_coll(
3571
index->table->cols[i].prtype);
3572
templ->mbminlen = index->table->cols[i].mbminlen;
3573
templ->mbmaxlen = index->table->cols[i].mbmaxlen;
3574
templ->is_unsigned = index->table->cols[i].prtype
3576
if (templ->type == DATA_BLOB) {
3577
prebuilt->templ_contains_blob = TRUE;
3583
prebuilt->n_template = n_requested_fields;
3584
prebuilt->mysql_prefix_len = mysql_prefix_len;
3586
if (index != clust_index && prebuilt->need_to_access_clustered) {
3587
/* Change rec_field_no's to correspond to the clustered index
3589
for (i = 0; i < n_requested_fields; i++) {
3590
templ = prebuilt->mysql_template + i;
3592
templ->rec_field_no = dict_col_get_clust_pos(
3593
&index->table->cols[templ->col_no],
3599
/********************************************************************//**
3600
Get the upper limit of the MySQL integral and floating-point type. */
3603
ha_innobase::innobase_get_int_col_max_value(
3604
/*========================================*/
3607
uint64_t max_value = 0;
3609
switch(field->key_type()) {
3611
case HA_KEYTYPE_BINARY:
3612
max_value = 0xFFULL;
3615
case HA_KEYTYPE_UINT24:
3616
max_value = 0xFFFFFFULL;
3619
case HA_KEYTYPE_ULONG_INT:
3620
max_value = 0xFFFFFFFFULL;
3622
case HA_KEYTYPE_LONG_INT:
3623
max_value = 0x7FFFFFFFULL;
3626
case HA_KEYTYPE_ULONGLONG:
3627
max_value = 0xFFFFFFFFFFFFFFFFULL;
3629
case HA_KEYTYPE_LONGLONG:
3630
max_value = 0x7FFFFFFFFFFFFFFFULL;
3632
case HA_KEYTYPE_DOUBLE:
3633
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
3634
max_value = 0x20000000000000ULL;
3643
/********************************************************************//**
3644
This special handling is really to overcome the limitations of MySQL's
3645
binlogging. We need to eliminate the non-determinism that will arise in
3646
INSERT ... SELECT type of statements, since MySQL binlog only stores the
3647
min value of the autoinc interval. Once that is fixed we can get rid of
3648
the special lock handling.
3649
@return DB_SUCCESS if all OK else error code */
3652
ha_innobase::innobase_lock_autoinc(void)
3653
/*====================================*/
3655
ulint error = DB_SUCCESS;
3657
switch (innobase_autoinc_lock_mode) {
3658
case AUTOINC_NO_LOCKING:
3659
/* Acquire only the AUTOINC mutex. */
3660
dict_table_autoinc_lock(prebuilt->table);
3663
case AUTOINC_NEW_STYLE_LOCKING:
3664
/* For simple (single/multi) row INSERTs, we fallback to the
3665
old style only if another transaction has already acquired
3666
the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
3667
etc. type of statement. */
3668
if (session_sql_command(user_session) == SQLCOM_INSERT
3669
|| session_sql_command(user_session) == SQLCOM_REPLACE) {
3670
dict_table_t* d_table = prebuilt->table;
3672
/* Acquire the AUTOINC mutex. */
3673
dict_table_autoinc_lock(d_table);
3675
/* We need to check that another transaction isn't
3676
already holding the AUTOINC lock on the table. */
3677
if (d_table->n_waiting_or_granted_auto_inc_locks) {
3678
/* Release the mutex to avoid deadlocks. */
3679
dict_table_autoinc_unlock(d_table);
3684
/* Fall through to old style locking. */
3686
case AUTOINC_OLD_STYLE_LOCKING:
3687
error = row_lock_table_autoinc_for_mysql(prebuilt);
3689
if (error == DB_SUCCESS) {
3691
/* Acquire the AUTOINC mutex. */
3692
dict_table_autoinc_lock(prebuilt->table);
3700
return(ulong(error));
3703
/********************************************************************//**
3704
Reset the autoinc value in the table.
3705
@return DB_SUCCESS if all went well else error code */
3708
ha_innobase::innobase_reset_autoinc(
3709
/*================================*/
3710
uint64_t autoinc) /*!< in: value to store */
3714
error = innobase_lock_autoinc();
3716
if (error == DB_SUCCESS) {
3718
dict_table_autoinc_initialize(prebuilt->table, autoinc);
3720
dict_table_autoinc_unlock(prebuilt->table);
3723
return(ulong(error));
3726
/********************************************************************//**
3727
Store the autoinc value in the table. The autoinc value is only set if
3728
it's greater than the existing autoinc value in the table.
3729
@return DB_SUCCESS if all went well else error code */
3732
ha_innobase::innobase_set_max_autoinc(
3733
/*==================================*/
3734
uint64_t auto_inc) /*!< in: value to store */
3738
error = innobase_lock_autoinc();
3740
if (error == DB_SUCCESS) {
3742
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
3744
dict_table_autoinc_unlock(prebuilt->table);
3747
return(ulong(error));
3750
/********************************************************************//**
3751
Stores a row in an InnoDB database, to the table specified in this
3753
@return error code */
3756
ha_innobase::write_row(
3757
/*===================*/
3758
unsigned char* record) /*!< in: a row in MySQL format */
3761
int error_result= 0;
3762
ibool auto_inc_used= FALSE;
3764
trx_t* trx = session_to_trx(user_session);
3766
if (prebuilt->trx != trx) {
3767
errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
3768
"%p, but for the current thread it is at %p",
3769
(const void*) prebuilt->trx, (const void*) trx);
3771
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
3772
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
3774
"InnoDB: Dump of 200 bytes around ha_data: ",
3776
ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
3781
ha_statistic_increment(&system_status_var::ha_write_count);
3783
sql_command = session_sql_command(user_session);
3785
if ((sql_command == SQLCOM_ALTER_TABLE
3786
|| sql_command == SQLCOM_CREATE_INDEX
3787
|| sql_command == SQLCOM_DROP_INDEX)
3788
&& num_write_row >= 10000) {
3789
/* ALTER TABLE is COMMITted at every 10000 copied rows.
3790
The IX table lock for the original table has to be re-issued.
3791
As this method will be called on a temporary table where the
3792
contents of the original table is being copied to, it is
3793
a bit tricky to determine the source table. The cursor
3794
position in the source table need not be adjusted after the
3795
intermediate COMMIT, since writes by other transactions are
3796
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
3798
dict_table_t* src_table;
3799
enum lock_mode mode;
3803
/* Commit the transaction. This will release the table
3804
locks, so they have to be acquired again. */
3806
/* Altering an InnoDB table */
3807
/* Get the source table. */
3808
src_table = lock_get_src_table(
3809
prebuilt->trx, prebuilt->table, &mode);
3812
/* Unknown situation: do not commit */
3814
ut_print_timestamp(stderr);
3816
" InnoDB: ALTER TABLE is holding lock"
3817
" on %lu tables!\n",
3818
prebuilt->trx->mysql_n_tables_locked);
3821
} else if (src_table == prebuilt->table) {
3822
/* Source table is not in InnoDB format:
3823
no need to re-acquire locks on it. */
3825
/* Altering to InnoDB format */
3826
getTransactionalEngine()->commit(user_session, 1);
3827
/* We will need an IX lock on the destination table. */
3828
prebuilt->sql_stat_start = TRUE;
3830
/* Ensure that there are no other table locks than
3831
LOCK_IX and LOCK_AUTO_INC on the destination table. */
3833
if (!lock_is_table_exclusive(prebuilt->table,
3838
/* Commit the transaction. This will release the table
3839
locks, so they have to be acquired again. */
3840
getTransactionalEngine()->commit(user_session, 1);
3841
/* Re-acquire the table lock on the source table. */
3842
row_lock_table_for_mysql(prebuilt, src_table, mode);
3843
/* We will need an IX lock on the destination table. */
3844
prebuilt->sql_stat_start = TRUE;
3850
/* This is the case where the table has an auto-increment column */
3851
if (table->next_number_field && record == table->record[0]) {
3853
/* Reset the error code before calling
3854
innobase_get_auto_increment(). */
3855
prebuilt->autoinc_error = DB_SUCCESS;
3857
if ((error = update_auto_increment())) {
3859
/* We don't want to mask autoinc overflow errors. */
3860
if (prebuilt->autoinc_error != DB_SUCCESS) {
3861
error = (int) prebuilt->autoinc_error;
3866
/* MySQL errors are passed straight back. */
3867
error_result = (int) error;
3871
auto_inc_used = TRUE;
3874
if (prebuilt->mysql_template == NULL
3875
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
3877
/* Build the template used in converting quickly between
3878
the two database formats */
3880
build_template(prebuilt, NULL, table,
3881
ROW_MYSQL_WHOLE_ROW);
3884
innodb_srv_conc_enter_innodb(prebuilt->trx);
3886
error = row_insert_for_mysql((byte*) record, prebuilt);
3888
/* Handle duplicate key errors */
3889
if (auto_inc_used) {
3892
uint64_t col_max_value;
3894
/* Note the number of rows processed for this statement, used
3895
by get_auto_increment() to determine the number of AUTO-INC
3896
values to reserve. This is only useful for a mult-value INSERT
3897
and is a statement level counter.*/
3898
if (trx->n_autoinc_rows > 0) {
3899
--trx->n_autoinc_rows;
3902
/* We need the upper limit of the col type to check for
3903
whether we update the table autoinc counter or not. */
3904
col_max_value = innobase_get_int_col_max_value(
3905
table->next_number_field);
3907
/* Get the value that MySQL attempted to store in the table.*/
3908
auto_inc = table->next_number_field->val_int();
3911
case DB_DUPLICATE_KEY:
3913
/* A REPLACE command and LOAD DATA INFILE REPLACE
3914
handle a duplicate key error themselves, but we
3915
must update the autoinc counter if we are performing
3916
those statements. */
3918
switch (sql_command) {
3920
if ((trx->duplicates
3921
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
3923
goto set_max_autoinc;
3927
case SQLCOM_REPLACE:
3928
case SQLCOM_INSERT_SELECT:
3929
case SQLCOM_REPLACE_SELECT:
3930
goto set_max_autoinc;
3939
/* If the actual value inserted is greater than
3940
the upper limit of the interval, then we try and
3941
update the table upper limit. Note: last_value
3942
will be 0 if get_auto_increment() was not called.*/
3944
if (auto_inc <= col_max_value
3945
&& auto_inc >= prebuilt->autoinc_last_value) {
3947
ut_a(prebuilt->autoinc_increment > 0);
3952
offset = prebuilt->autoinc_offset;
3953
need = prebuilt->autoinc_increment;
3955
auto_inc = innobase_next_autoinc(
3956
auto_inc, need, offset, col_max_value);
3958
err = innobase_set_max_autoinc(auto_inc);
3960
if (err != DB_SUCCESS) {
3968
innodb_srv_conc_exit_innodb(prebuilt->trx);
3971
error_result = convert_error_code_to_mysql((int) error,
3972
prebuilt->table->flags,
3976
innobase_active_small();
3978
return(error_result);
3981
/**********************************************************************//**
3982
Checks which fields have changed in a row and stores information
3983
of them to an update vector.
3984
@return error number or 0 */
3987
calc_row_difference(
3988
/*================*/
3989
upd_t* uvect, /*!< in/out: update vector */
3990
unsigned char* old_row, /*!< in: old row in MySQL format */
3991
unsigned char* new_row, /*!< in: new row in MySQL format */
3992
Table* table, /*!< in: table in MySQL data
3994
unsigned char* upd_buff, /*!< in: buffer to use */
3995
ulint buff_len, /*!< in: buffer length */
3996
row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
3997
Session* ) /*!< in: user thread */
3999
unsigned char* original_upd_buff = upd_buff;
4001
enum_field_types field_mysql_type;
4006
const byte* new_mysql_row_col;
4010
upd_field_t* ufield;
4012
ulint n_changed = 0;
4014
dict_index_t* clust_index;
4017
n_fields = table->s->fields;
4018
clust_index = dict_table_get_first_index(prebuilt->table);
4020
/* We use upd_buff to convert changed fields */
4021
buf = (byte*) upd_buff;
4023
for (i = 0; i < n_fields; i++) {
4024
field = table->field[i];
4026
o_ptr = (const byte*) old_row + get_field_offset(table, field);
4027
n_ptr = (const byte*) new_row + get_field_offset(table, field);
4029
/* Use new_mysql_row_col and col_pack_len save the values */
4031
new_mysql_row_col = n_ptr;
4032
col_pack_len = field->pack_length();
4034
o_len = col_pack_len;
4035
n_len = col_pack_len;
4037
/* We use o_ptr and n_ptr to dig up the actual data for
4040
field_mysql_type = field->type();
4042
col_type = prebuilt->table->cols[i].mtype;
4047
o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4048
n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4055
if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4056
/* This is a >= 5.0.3 type true VARCHAR where
4057
the real payload data length is stored in
4060
o_ptr = row_mysql_read_true_varchar(
4063
(((Field_varstring*)field)->length_bytes));
4065
n_ptr = row_mysql_read_true_varchar(
4068
(((Field_varstring*)field)->length_bytes));
4076
if (field->null_ptr) {
4077
if (field_in_record_is_null(table, field,
4079
o_len = UNIV_SQL_NULL;
4082
if (field_in_record_is_null(table, field,
4084
n_len = UNIV_SQL_NULL;
4088
if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4089
0 != memcmp(o_ptr, n_ptr, o_len))) {
4090
/* The field has changed */
4092
ufield = uvect->fields + n_changed;
4094
/* Let us use a dummy dfield to make the conversion
4095
from the MySQL column format to the InnoDB format */
4097
dict_col_copy_type(prebuilt->table->cols + i,
4100
if (n_len != UNIV_SQL_NULL) {
4101
buf = row_mysql_store_col_in_innobase_format(
4107
dict_table_is_comp(prebuilt->table));
4108
dfield_copy_data(&ufield->new_val, &dfield);
4110
dfield_set_null(&ufield->new_val);
4114
ufield->orig_len = 0;
4115
ufield->field_no = dict_col_get_clust_pos(
4116
&prebuilt->table->cols[i], clust_index);
4121
uvect->n_fields = n_changed;
4122
uvect->info_bits = 0;
4124
ut_a(buf <= (byte*)original_upd_buff + buff_len);
4129
/**********************************************************************//**
4130
Updates a row given as a parameter to a new value. Note that we are given
4131
whole rows, not just the fields which are updated: this incurs some
4132
overhead for CPU when we check which fields are actually updated.
4133
TODO: currently InnoDB does not prevent the 'Halloween problem':
4134
in a searched update a single row can get updated several times
4135
if its index columns are updated!
4136
@return error number or 0 */
4139
ha_innobase::update_row(
4140
/*====================*/
4141
const unsigned char* old_row,/*!< in: old row in MySQL format */
4142
unsigned char* new_row)/*!< in: new row in MySQL format */
4146
trx_t* trx = session_to_trx(user_session);
4148
ut_a(prebuilt->trx == trx);
4150
ha_statistic_increment(&system_status_var::ha_update_count);
4152
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
4153
table->timestamp_field->set_time();
4155
if (prebuilt->upd_node) {
4156
uvect = prebuilt->upd_node->update;
4158
uvect = row_get_prebuilt_update_vector(prebuilt);
4161
/* Build an update vector from the modified fields in the rows
4162
(uses upd_buff of the handle) */
4164
calc_row_difference(uvect, (unsigned char*) old_row, new_row, table,
4165
upd_buff, (ulint)upd_and_key_val_buff_len,
4166
prebuilt, user_session);
4168
/* This is not a delete */
4169
prebuilt->upd_node->is_delete = FALSE;
4171
ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4173
innodb_srv_conc_enter_innodb(trx);
4175
error = row_update_for_mysql((byte*) old_row, prebuilt);
4177
/* We need to do some special AUTOINC handling for the following case:
4179
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4181
We need to use the AUTOINC counter that was actually used by
4182
MySQL in the UPDATE statement, which can be different from the
4183
value used in the INSERT statement.*/
4185
if (error == DB_SUCCESS
4186
&& table->next_number_field
4187
&& new_row == table->record[0]
4188
&& session_sql_command(user_session) == SQLCOM_INSERT
4189
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
4190
== TRX_DUP_IGNORE) {
4193
uint64_t col_max_value;
4195
auto_inc = table->next_number_field->val_int();
4197
/* We need the upper limit of the col type to check for
4198
whether we update the table autoinc counter or not. */
4199
col_max_value = innobase_get_int_col_max_value(
4200
table->next_number_field);
4202
if (auto_inc <= col_max_value && auto_inc != 0) {
4207
offset = prebuilt->autoinc_offset;
4208
need = prebuilt->autoinc_increment;
4210
auto_inc = innobase_next_autoinc(
4211
auto_inc, need, offset, col_max_value);
4213
error = innobase_set_max_autoinc(auto_inc);
4217
innodb_srv_conc_exit_innodb(trx);
4219
error = convert_error_code_to_mysql(error,
4220
prebuilt->table->flags,
4223
if (error == 0 /* success */
4224
&& uvect->n_fields == 0 /* no columns were updated */) {
4226
/* This is the same as success, but instructs
4227
MySQL that the row is not really updated and it
4228
should not increase the count of updated rows.
4229
This is fix for http://bugs.mysql.com/29157 */
4230
error = HA_ERR_RECORD_IS_THE_SAME;
4233
/* Tell InnoDB server that there might be work for
4236
innobase_active_small();
4241
/**********************************************************************//**
4242
Deletes a row given as the parameter.
4243
@return error number or 0 */
4246
ha_innobase::delete_row(
4247
/*====================*/
4248
const unsigned char* record) /*!< in: a row in MySQL format */
4251
trx_t* trx = session_to_trx(user_session);
4253
ut_a(prebuilt->trx == trx);
4255
ha_statistic_increment(&system_status_var::ha_delete_count);
4257
if (!prebuilt->upd_node) {
4258
row_get_prebuilt_update_vector(prebuilt);
4261
/* This is a delete */
4263
prebuilt->upd_node->is_delete = TRUE;
4265
innodb_srv_conc_enter_innodb(trx);
4267
error = row_update_for_mysql((byte*) record, prebuilt);
4269
innodb_srv_conc_exit_innodb(trx);
4271
error = convert_error_code_to_mysql(
4272
error, prebuilt->table->flags, user_session);
4274
/* Tell the InnoDB server that there might be work for
4277
innobase_active_small();
4282
/**********************************************************************//**
4283
Removes a new lock set on a row, if it was not read optimistically. This can
4284
be called after a row has been read in the processing of an UPDATE or a DELETE
4285
query, if the option innodb_locks_unsafe_for_binlog is set. */
4288
ha_innobase::unlock_row(void)
4289
/*=========================*/
4291
/* Consistent read does not take any locks, thus there is
4292
nothing to unlock. */
4294
if (prebuilt->select_lock_type == LOCK_NONE) {
4298
switch (prebuilt->row_read_type) {
4299
case ROW_READ_WITH_LOCKS:
4300
if (!srv_locks_unsafe_for_binlog
4301
&& prebuilt->trx->isolation_level
4302
!= TRX_ISO_READ_COMMITTED) {
4306
case ROW_READ_TRY_SEMI_CONSISTENT:
4307
row_unlock_for_mysql(prebuilt, FALSE);
4309
case ROW_READ_DID_SEMI_CONSISTENT:
4310
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4317
/* See Cursor.h and row0mysql.h for docs on this function. */
4320
ha_innobase::was_semi_consistent_read(void)
4321
/*=======================================*/
4323
return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
4326
/* See Cursor.h and row0mysql.h for docs on this function. */
4329
ha_innobase::try_semi_consistent_read(bool yes)
4330
/*===========================================*/
4332
ut_a(prebuilt->trx == session_to_trx(ha_session()));
4334
/* Row read type is set to semi consistent read if this was
4335
requested by the MySQL and either innodb_locks_unsafe_for_binlog
4336
option is used or this session is using READ COMMITTED isolation
4340
&& (srv_locks_unsafe_for_binlog
4341
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
4342
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4344
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
4348
/******************************************************************//**
4349
Initializes a handle to use an index.
4350
@return 0 or error number */
4353
ha_innobase::index_init(
4354
/*====================*/
4355
uint keynr, /*!< in: key (index) number */
4356
bool ) /*!< in: 1 if result MUST be sorted according to index */
4358
return(change_active_index(keynr));
4361
/******************************************************************//**
4362
Currently does nothing.
4366
ha_innobase::index_end(void)
4367
/*========================*/
4370
active_index=MAX_KEY;
4374
/*********************************************************************//**
4375
Converts a search mode flag understood by MySQL to a flag understood
4379
convert_search_mode_to_innobase(
4380
/*============================*/
4381
enum ha_rkey_function find_flag)
4383
switch (find_flag) {
4384
case HA_READ_KEY_EXACT:
4385
/* this does not require the index to be UNIQUE */
4386
return(PAGE_CUR_GE);
4387
case HA_READ_KEY_OR_NEXT:
4388
return(PAGE_CUR_GE);
4389
case HA_READ_KEY_OR_PREV:
4390
return(PAGE_CUR_LE);
4391
case HA_READ_AFTER_KEY:
4393
case HA_READ_BEFORE_KEY:
4395
case HA_READ_PREFIX:
4396
return(PAGE_CUR_GE);
4397
case HA_READ_PREFIX_LAST:
4398
return(PAGE_CUR_LE);
4399
case HA_READ_PREFIX_LAST_OR_PREV:
4400
return(PAGE_CUR_LE);
4401
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
4402
pass a complete-field prefix of a key value as the search
4403
tuple. I.e., it is not allowed that the last field would
4404
just contain n first bytes of the full field value.
4405
MySQL uses a 'padding' trick to convert LIKE 'abc%'
4406
type queries so that it can use as a search tuple
4407
a complete-field-prefix of a key value. Thus, the InnoDB
4408
search mode PAGE_CUR_LE_OR_EXTENDS is never used.
4409
TODO: when/if MySQL starts to use also partial-field
4410
prefixes, we have to deal with stripping of spaces
4411
and comparison of non-latin1 char type fields in
4412
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
4414
case HA_READ_MBR_CONTAIN:
4415
case HA_READ_MBR_INTERSECT:
4416
case HA_READ_MBR_WITHIN:
4417
case HA_READ_MBR_DISJOINT:
4418
case HA_READ_MBR_EQUAL:
4419
return(PAGE_CUR_UNSUPP);
4420
/* do not use "default:" in order to produce a gcc warning:
4421
enumeration value '...' not handled in switch
4422
(if -Wswitch or -Wall is used) */
4425
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
4427
return(PAGE_CUR_UNSUPP);
4431
BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
4432
---------------------------------------------------
4433
The following does not cover all the details, but explains how we determine
4434
the start of a new SQL statement, and what is associated with it.
4436
For each table in the database the MySQL interpreter may have several
4437
table handle instances in use, also in a single SQL query. For each table
4438
handle instance there is an InnoDB 'prebuilt' struct which contains most
4439
of the InnoDB data associated with this table handle instance.
4441
A) if the user has not explicitly set any MySQL table level locks:
4443
1) Drizzle calls StorageEngine::doStartStatement(), indicating to
4444
InnoDB that a new SQL statement has begun.
4446
2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
4447
to set an 'intention' table level lock on the table of the Cursor instance.
4448
There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should
4449
be set true if we are taking this table handle instance to use in a new SQL
4450
statement issued by the user.
4452
2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
4453
instructions to prebuilt->template of the table handle instance in
4454
::index_read. The template is used to save CPU time in large joins.
4456
3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
4457
allocate a new consistent read view for the trx if it does not yet have one,
4458
or in the case of a locking read, set an InnoDB 'intention' table level
4461
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
4462
same table handle instance, if it is a join.
4464
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
4466
(a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter
4467
does NOT execute autocommit for pure read transactions, though it should.
4468
That is why we must execute the COMMIT in ::doEndStatement().
4469
(b) we also release possible 'SQL statement level resources' InnoDB may
4470
have for this SQL statement.
4474
Remove need for InnoDB to call autocommit for read-only trx
4476
@todo Check the below is still valid (I don't think it is...)
4478
B) If the user has explicitly set MySQL table level locks, then MySQL
4479
does NOT call ::external_lock at the start of the statement. To determine
4480
when we are at the start of a new SQL statement we at the start of
4481
::index_read also compare the query id to the latest query id where the
4482
table handle instance was used. If it has changed, we know we are at the
4483
start of a new SQL statement. Since the query id can theoretically
4484
overwrap, we use this test only as a secondary way of determining the
4485
start of a new SQL statement. */
4488
/**********************************************************************//**
4489
Positions an index cursor to the index specified in the handle. Fetches the
4491
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
4494
ha_innobase::index_read(
4495
/*====================*/
4496
unsigned char* buf, /*!< in/out: buffer for the returned
4498
const unsigned char* key_ptr,/*!< in: key value; if this is NULL
4499
we position the cursor at the
4500
start or end of index; this can
4501
also contain an InnoDB row id, in
4502
which case key_len is the InnoDB
4503
row id length; the key value can
4504
also be a prefix of a full key value,
4505
and the last column can be a prefix
4507
uint key_len,/*!< in: key value length */
4508
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4511
dict_index_t* index;
4512
ulint match_mode = 0;
4516
ut_a(prebuilt->trx == session_to_trx(user_session));
4518
ha_statistic_increment(&system_status_var::ha_read_key_count);
4520
index = prebuilt->index;
4522
/* Note that if the index for which the search template is built is not
4523
necessarily prebuilt->index, but can also be the clustered index */
4525
if (prebuilt->sql_stat_start) {
4526
build_template(prebuilt, user_session, table,
4527
ROW_MYSQL_REC_FIELDS);
4531
/* Convert the search key value to InnoDB format into
4532
prebuilt->search_tuple */
4534
row_sel_convert_mysql_key_to_innobase(
4535
prebuilt->search_tuple,
4536
(byte*) key_val_buff,
4537
(ulint)upd_and_key_val_buff_len,
4543
/* We position the cursor to the last or the first entry
4546
dtuple_set_n_fields(prebuilt->search_tuple, 0);
4549
mode = convert_search_mode_to_innobase(find_flag);
4553
if (find_flag == HA_READ_KEY_EXACT) {
4555
match_mode = ROW_SEL_EXACT;
4557
} else if (find_flag == HA_READ_PREFIX
4558
|| find_flag == HA_READ_PREFIX_LAST) {
4560
match_mode = ROW_SEL_EXACT_PREFIX;
4563
last_match_mode = (uint) match_mode;
4565
if (mode != PAGE_CUR_UNSUPP) {
4567
innodb_srv_conc_enter_innodb(prebuilt->trx);
4569
ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
4572
innodb_srv_conc_exit_innodb(prebuilt->trx);
4575
ret = DB_UNSUPPORTED;
4583
case DB_RECORD_NOT_FOUND:
4584
error = HA_ERR_KEY_NOT_FOUND;
4585
table->status = STATUS_NOT_FOUND;
4587
case DB_END_OF_INDEX:
4588
error = HA_ERR_KEY_NOT_FOUND;
4589
table->status = STATUS_NOT_FOUND;
4592
error = convert_error_code_to_mysql((int) ret,
4593
prebuilt->table->flags,
4595
table->status = STATUS_NOT_FOUND;
4602
/*******************************************************************//**
4603
The following functions works like index_read, but it find the last
4604
row with the current key value or prefix.
4605
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
4608
ha_innobase::index_read_last(
4609
/*=========================*/
4610
unsigned char* buf, /*!< out: fetched row */
4611
const unsigned char* key_ptr,/*!< in: key value, or a prefix of a full
4613
uint key_len)/*!< in: length of the key val or prefix
4616
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
4619
/********************************************************************//**
4620
Get the index for a handle. Does not change active index.
4621
@return NULL or index instance. */
4624
ha_innobase::innobase_get_index(
4625
/*============================*/
4626
uint keynr) /*!< in: use this index; MAX_KEY means always
4627
clustered index, even if it was internally
4628
generated by InnoDB */
4631
dict_index_t* index = 0;
4633
ha_statistic_increment(&system_status_var::ha_read_key_count);
4635
ut_ad(user_session == ha_session());
4636
ut_a(prebuilt->trx == session_to_trx(user_session));
4638
if (keynr != MAX_KEY && table->s->keys > 0) {
4639
key = table->key_info + keynr;
4641
index = dict_table_get_index_on_name(prebuilt->table,
4644
index = dict_table_get_first_index(prebuilt->table);
4648
errmsg_printf(ERRMSG_LVL_ERROR,
4649
"Innodb could not find key n:o %u with name %s "
4650
"from dict cache for table %s",
4651
keynr, key ? key->name : "NULL",
4652
prebuilt->table->name);
4658
/********************************************************************//**
4659
Changes the active index of a handle.
4660
@return 0 or error code */
4663
ha_innobase::change_active_index(
4664
/*=============================*/
4665
uint keynr) /*!< in: use this index; MAX_KEY means always clustered
4666
index, even if it was internally generated by
4669
ut_ad(user_session == ha_session());
4670
ut_a(prebuilt->trx == session_to_trx(user_session));
4672
active_index = keynr;
4674
prebuilt->index = innobase_get_index(keynr);
4676
if (UNIV_UNLIKELY(!prebuilt->index)) {
4677
errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
4682
prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
4685
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
4686
errmsg_printf(ERRMSG_LVL_WARN,
4687
"InnoDB: insufficient history for index %u",
4689
/* The caller seems to ignore this. Thus, we must check
4690
this again in row_search_for_mysql(). */
4694
ut_a(prebuilt->search_tuple != 0);
4696
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
4698
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
4699
prebuilt->index->n_fields);
4701
/* MySQL changes the active index for a handle also during some
4702
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
4703
and then calculates the sum. Previously we played safe and used
4704
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
4705
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
4707
build_template(prebuilt, user_session, table, ROW_MYSQL_REC_FIELDS);
4712
/**********************************************************************//**
4713
Positions an index cursor to the index specified in keynr. Fetches the
4715
??? This is only used to read whole keys ???
4716
@return error number or 0 */
4719
ha_innobase::index_read_idx(
4720
/*========================*/
4721
unsigned char* buf, /*!< in/out: buffer for the returned
4723
uint keynr, /*!< in: use this index */
4724
const unsigned char* key, /*!< in: key value; if this is NULL
4725
we position the cursor at the
4726
start or end of index */
4727
uint key_len, /*!< in: key value length */
4728
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4730
if (change_active_index(keynr)) {
4735
return(index_read(buf, key, key_len, find_flag));
4738
/***********************************************************************//**
4739
Reads the next or previous row from a cursor, which must have previously been
4740
positioned using index_read.
4741
@return 0, HA_ERR_END_OF_FILE, or error number */
4744
ha_innobase::general_fetch(
4745
/*=======================*/
4746
unsigned char* buf, /*!< in/out: buffer for next row in MySQL
4748
uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
4749
uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
4750
ROW_SEL_EXACT_PREFIX */
4755
ut_a(prebuilt->trx == session_to_trx(user_session));
4757
innodb_srv_conc_enter_innodb(prebuilt->trx);
4759
ret = row_search_for_mysql(
4760
(byte*)buf, 0, prebuilt, match_mode, direction);
4762
innodb_srv_conc_exit_innodb(prebuilt->trx);
4769
case DB_RECORD_NOT_FOUND:
4770
error = HA_ERR_END_OF_FILE;
4771
table->status = STATUS_NOT_FOUND;
4773
case DB_END_OF_INDEX:
4774
error = HA_ERR_END_OF_FILE;
4775
table->status = STATUS_NOT_FOUND;
4778
error = convert_error_code_to_mysql(
4779
(int) ret, prebuilt->table->flags, user_session);
4780
table->status = STATUS_NOT_FOUND;
4787
/***********************************************************************//**
4788
Reads the next row from a cursor, which must have previously been
4789
positioned using index_read.
4790
@return 0, HA_ERR_END_OF_FILE, or error number */
4793
ha_innobase::index_next(
4794
/*====================*/
4795
unsigned char* buf) /*!< in/out: buffer for next row in MySQL
4798
ha_statistic_increment(&system_status_var::ha_read_next_count);
4800
return(general_fetch(buf, ROW_SEL_NEXT, 0));
4803
/*******************************************************************//**
4804
Reads the next row matching to the key value given as the parameter.
4805
@return 0, HA_ERR_END_OF_FILE, or error number */
4808
ha_innobase::index_next_same(
4809
/*=========================*/
4810
unsigned char* buf, /*!< in/out: buffer for the row */
4811
const unsigned char* , /*!< in: key value */
4812
uint ) /*!< in: key value length */
4814
ha_statistic_increment(&system_status_var::ha_read_next_count);
4816
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
4819
/***********************************************************************//**
4820
Reads the previous row from a cursor, which must have previously been
4821
positioned using index_read.
4822
@return 0, HA_ERR_END_OF_FILE, or error number */
4825
ha_innobase::index_prev(
4826
/*====================*/
4827
unsigned char* buf) /*!< in/out: buffer for previous row in MySQL format */
4829
ha_statistic_increment(&system_status_var::ha_read_prev_count);
4831
return(general_fetch(buf, ROW_SEL_PREV, 0));
4834
/********************************************************************//**
4835
Positions a cursor on the first record in an index and reads the
4836
corresponding row to buf.
4837
@return 0, HA_ERR_END_OF_FILE, or error code */
4840
ha_innobase::index_first(
4841
/*=====================*/
4842
unsigned char* buf) /*!< in/out: buffer for the row */
4846
ha_statistic_increment(&system_status_var::ha_read_first_count);
4848
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
4850
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4852
if (error == HA_ERR_KEY_NOT_FOUND) {
4853
error = HA_ERR_END_OF_FILE;
4859
/********************************************************************//**
4860
Positions a cursor on the last record in an index and reads the
4861
corresponding row to buf.
4862
@return 0, HA_ERR_END_OF_FILE, or error code */
4865
ha_innobase::index_last(
4866
/*====================*/
4867
unsigned char* buf) /*!< in/out: buffer for the row */
4871
ha_statistic_increment(&system_status_var::ha_read_last_count);
4873
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
4875
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4877
if (error == HA_ERR_KEY_NOT_FOUND) {
4878
error = HA_ERR_END_OF_FILE;
4884
/****************************************************************//**
4885
Initialize a table scan.
4886
@return 0 or error number */
4889
ha_innobase::rnd_init(
4890
/*==================*/
4891
bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
4895
/* Store the active index value so that we can restore the original
4896
value after a scan */
4898
if (prebuilt->clust_index_was_generated) {
4899
err = change_active_index(MAX_KEY);
4901
err = change_active_index(primary_key);
4904
/* Don't use semi-consistent read in random row reads (by position).
4905
This means we must disable semi_consistent_read if scan is false */
4908
try_semi_consistent_read(0);
4916
/*****************************************************************//**
4918
@return 0 or error number */
4921
ha_innobase::rnd_end(void)
4922
/*======================*/
4924
return(index_end());
4927
/*****************************************************************//**
4928
Reads the next row in a table scan (also used to read the FIRST row
4930
@return 0, HA_ERR_END_OF_FILE, or error number */
4933
ha_innobase::rnd_next(
4934
/*==================*/
4935
unsigned char* buf) /*!< in/out: returns the row in this buffer,
4940
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
4942
if (start_of_scan) {
4943
error = index_first(buf);
4945
if (error == HA_ERR_KEY_NOT_FOUND) {
4946
error = HA_ERR_END_OF_FILE;
4951
error = general_fetch(buf, ROW_SEL_NEXT, 0);
4957
/**********************************************************************//**
4958
Fetches a row from the table based on a row reference.
4959
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
4962
ha_innobase::rnd_pos(
4963
/*=================*/
4964
unsigned char* buf, /*!< in/out: buffer for the row */
4965
unsigned char* pos) /*!< in: primary key value of the row in the
4966
MySQL format, or the row id if the clustered
4967
index was internally generated by InnoDB; the
4968
length of data in pos has to be ref_length */
4971
uint keynr = active_index;
4973
ha_statistic_increment(&system_status_var::ha_read_rnd_count);
4975
ut_a(prebuilt->trx == session_to_trx(ha_session()));
4977
if (prebuilt->clust_index_was_generated) {
4978
/* No primary key was defined for the table and we
4979
generated the clustered index from the row id: the
4980
row reference is the row id, not any key value
4981
that MySQL knows of */
4983
error = change_active_index(MAX_KEY);
4985
error = change_active_index(primary_key);
4992
/* Note that we assume the length of the row reference is fixed
4993
for the table, and it is == ref_length */
4995
error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5000
change_active_index(keynr);
5005
/*********************************************************************//**
5006
Stores a reference to the current row to 'ref' field of the handle. Note
5007
that in the case where we have generated the clustered index for the
5008
table, the function parameter is illogical: we MUST ASSUME that 'record'
5009
is the current 'position' of the handle, because if row ref is actually
5010
the row id internally generated in InnoDB, then 'record' does not contain
5011
it. We just guess that the row id must be for the record where the handle
5012
was positioned the last time. */
5015
ha_innobase::position(
5016
/*==================*/
5017
const unsigned char* record) /*!< in: row in MySQL format */
5021
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5023
if (prebuilt->clust_index_was_generated) {
5024
/* No primary key was defined for the table and we
5025
generated the clustered index from row id: the
5026
row reference will be the row id, not any key value
5027
that MySQL knows of */
5029
len = DATA_ROW_ID_LEN;
5031
memcpy(ref, prebuilt->row_id, len);
5033
len = store_key_val_for_row(primary_key, (char*)ref,
5034
ref_length, record);
5037
/* We assume that the 'ref' value len is always fixed for the same
5040
if (len != ref_length) {
5041
errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
5042
(ulong) len, (ulong) ref_length);
5047
/*****************************************************************//**
5048
Creates a table definition to an InnoDB database. */
5053
trx_t* trx, /*!< in: InnoDB transaction handle */
5054
Table* form, /*!< in: information on table
5055
columns and indexes */
5056
const char* table_name, /*!< in: table name */
5057
const char* path_of_temp_table,/*!< in: if this is a table explicitly
5058
created by the user with the
5059
TEMPORARY keyword, then this
5060
parameter is the dir path where the
5061
table should be placed if we create
5062
an .ibd file for it (no .ibd extension
5063
in the path, though); otherwise this
5065
ulint flags) /*!< in: table flags */
5068
dict_table_t* table;
5073
ulint nulls_allowed;
5074
ulint unsigned_type;
5076
ulint long_true_varchar;
5080
n_cols = form->s->fields;
5082
/* We pass 0 as the space id, and determine at a lower level the space
5083
id where to store the table */
5085
table = dict_mem_table_create(table_name, 0, n_cols, flags);
5087
if (path_of_temp_table) {
5088
table->dir_path_of_temp_table =
5089
mem_heap_strdup(table->heap, path_of_temp_table);
5092
for (i = 0; i < n_cols; i++) {
5093
field = form->field[i];
5095
col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5097
if (field->null_ptr) {
5100
nulls_allowed = DATA_NOT_NULL;
5103
if (field->binary()) {
5104
binary_type = DATA_BINARY_TYPE;
5111
if (dtype_is_string_type(col_type)) {
5113
charset_no = (ulint)field->charset()->number;
5115
if (UNIV_UNLIKELY(charset_no >= 256)) {
5116
/* in data0type.h we assume that the
5117
number fits in one byte in prtype */
5118
push_warning_printf(
5119
(Session*) trx->mysql_thd,
5120
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5121
ER_CANT_CREATE_TABLE,
5122
"In InnoDB, charset-collation codes"
5123
" must be below 256."
5124
" Unsupported code %lu.",
5125
(ulong) charset_no);
5126
return(ER_CANT_CREATE_TABLE);
5130
ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5131
that this fits in one byte */
5132
col_len = field->pack_length();
5134
/* The MySQL pack length contains 1 or 2 bytes length field
5135
for a true VARCHAR. Let us subtract that, so that the InnoDB
5136
column length in the InnoDB data dictionary is the real
5137
maximum byte length of the actual data. */
5139
long_true_varchar = 0;
5141
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5142
col_len -= ((Field_varstring*)field)->length_bytes;
5144
if (((Field_varstring*)field)->length_bytes == 2) {
5145
long_true_varchar = DATA_LONG_TRUE_VARCHAR;
5149
dict_mem_table_add_col(table, table->heap,
5150
(char*) field->field_name,
5153
(ulint)field->type()
5154
| nulls_allowed | unsigned_type
5155
| binary_type | long_true_varchar,
5160
error = row_create_table_for_mysql(table, trx);
5162
error = convert_error_code_to_mysql(error, flags, NULL);
5167
/*****************************************************************//**
5168
Creates an index in an InnoDB database. */
5173
trx_t* trx, /*!< in: InnoDB transaction handle */
5174
Table* form, /*!< in: information on table
5175
columns and indexes */
5176
ulint flags, /*!< in: InnoDB table flags */
5177
const char* table_name, /*!< in: table name */
5178
uint key_num) /*!< in: index number */
5181
dict_index_t* index;
5185
KEY_PART_INFO* key_part;
5192
ulint* field_lengths;
5194
key = form->key_info + key_num;
5196
n_fields = key->key_parts;
5200
if (key_num == form->s->primary_key) {
5201
ind_type = ind_type | DICT_CLUSTERED;
5204
if (key->flags & HA_NOSAME ) {
5205
ind_type = ind_type | DICT_UNIQUE;
5208
/* We pass 0 as the space id, and determine at a lower level the space
5209
id where to store the table */
5211
index = dict_mem_index_create(table_name, key->name, 0,
5212
ind_type, n_fields);
5214
field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
5216
for (i = 0; i < n_fields; i++) {
5217
key_part = key->key_part + i;
5219
/* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
5220
field in an index: we only store a specified number of first
5221
bytes of the column to the index field.) The flag does not
5222
seem to be properly set by MySQL. Let us fall back on testing
5223
the length of the key part versus the column. */
5226
for (j = 0; j < form->s->fields; j++) {
5228
field = form->field[j];
5230
if (0 == innobase_strcasecmp(
5232
key_part->field->field_name)) {
5233
/* Found the corresponding column */
5239
ut_a(j < form->s->fields);
5241
col_type = get_innobase_type_from_mysql_type(
5242
&is_unsigned, key_part->field);
5244
if (DATA_BLOB == col_type
5245
|| (key_part->length < field->pack_length()
5246
&& field->type() != DRIZZLE_TYPE_VARCHAR)
5247
|| (field->type() == DRIZZLE_TYPE_VARCHAR
5248
&& key_part->length < field->pack_length()
5249
- ((Field_varstring*)field)->length_bytes)) {
5251
prefix_len = key_part->length;
5253
if (col_type == DATA_INT
5254
|| col_type == DATA_FLOAT
5255
|| col_type == DATA_DOUBLE
5256
|| col_type == DATA_DECIMAL) {
5257
errmsg_printf(ERRMSG_LVL_ERROR,
5258
"MySQL is trying to create a column "
5259
"prefix index field, on an "
5260
"inappropriate data type. Table "
5261
"name %s, column name %s.",
5263
key_part->field->field_name);
5271
field_lengths[i] = key_part->length;
5273
dict_mem_index_add_field(index,
5274
(char*) key_part->field->field_name, prefix_len);
5277
/* Even though we've defined max_supported_key_part_length, we
5278
still do our own checking using field_lengths to be absolutely
5279
sure we don't create too long indexes. */
5280
error = row_create_index_for_mysql(index, trx, field_lengths);
5282
error = convert_error_code_to_mysql(error, flags, NULL);
5284
free(field_lengths);
5289
/*****************************************************************//**
5290
Creates an index to an InnoDB table when the user has defined no
5294
create_clustered_index_when_no_primary(
5295
/*===================================*/
5296
trx_t* trx, /*!< in: InnoDB transaction handle */
5297
ulint flags, /*!< in: InnoDB table flags */
5298
const char* table_name) /*!< in: table name */
5300
dict_index_t* index;
5303
/* We pass 0 as the space id, and determine at a lower level the space
5304
id where to store the table */
5306
index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
5307
0, DICT_CLUSTERED, 0);
5309
error = row_create_index_for_mysql(index, trx, NULL);
5311
error = convert_error_code_to_mysql(error, flags, NULL);
5316
/*****************************************************************//**
5317
Validates the create options. We may build on this function
5318
in future. For now, it checks two specifiers:
5319
KEY_BLOCK_SIZE and ROW_FORMAT
5320
If innodb_strict_mode is not set then this function is a no-op
5321
@return TRUE if valid. */
5324
create_options_are_valid(
5325
/*=====================*/
5326
Session* session, /*!< in: connection thread. */
5327
Table& form, /*!< in: information on table
5328
columns and indexes */
5329
message::Table& create_proto)
5331
ibool kbs_specified = FALSE;
5335
ut_ad(session != NULL);
5337
/* If innodb_strict_mode is not set don't do any validation. */
5338
if (!(SessionVAR(session, strict_mode))) {
5342
/* First check if KEY_BLOCK_SIZE was specified. */
5343
if (create_proto.options().has_key_block_size()) {
5345
kbs_specified = TRUE;
5346
switch (create_proto.options().key_block_size()) {
5355
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5356
ER_ILLEGAL_HA_CREATE_OPTION,
5358
" KEY_BLOCK_SIZE = %lu."
5360
" [1, 2, 4, 8, 16]",
5361
create_proto.options().key_block_size());
5366
/* If KEY_BLOCK_SIZE was specified, check for its
5368
if (kbs_specified && !srv_file_per_table) {
5369
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5370
ER_ILLEGAL_HA_CREATE_OPTION,
5371
"InnoDB: KEY_BLOCK_SIZE"
5372
" requires innodb_file_per_table.");
5376
if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
5377
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5378
ER_ILLEGAL_HA_CREATE_OPTION,
5379
"InnoDB: KEY_BLOCK_SIZE"
5380
" requires innodb_file_format >"
5385
/* Now check for ROW_FORMAT specifier. */
5386
if (create_proto.options().has_row_type()) {
5387
switch (form.s->row_type) {
5388
const char* row_format_name;
5389
case ROW_TYPE_COMPRESSED:
5390
case ROW_TYPE_DYNAMIC:
5392
= form.s->row_type == ROW_TYPE_COMPRESSED
5396
/* These two ROW_FORMATs require
5397
srv_file_per_table and srv_file_format */
5398
if (!srv_file_per_table) {
5399
push_warning_printf(
5401
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5402
ER_ILLEGAL_HA_CREATE_OPTION,
5403
"InnoDB: ROW_FORMAT=%s"
5404
" requires innodb_file_per_table.",
5410
if (srv_file_format < DICT_TF_FORMAT_ZIP) {
5411
push_warning_printf(
5413
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5414
ER_ILLEGAL_HA_CREATE_OPTION,
5415
"InnoDB: ROW_FORMAT=%s"
5416
" requires innodb_file_format >"
5422
/* Cannot specify KEY_BLOCK_SIZE with
5423
ROW_FORMAT = DYNAMIC.
5424
However, we do allow COMPRESSED to be
5425
specified with KEY_BLOCK_SIZE. */
5427
&& form.s->row_type == ROW_TYPE_DYNAMIC) {
5428
push_warning_printf(
5430
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5431
ER_ILLEGAL_HA_CREATE_OPTION,
5432
"InnoDB: cannot specify"
5433
" ROW_FORMAT = DYNAMIC with"
5434
" KEY_BLOCK_SIZE.");
5440
case ROW_TYPE_REDUNDANT:
5441
case ROW_TYPE_COMPACT:
5442
case ROW_TYPE_DEFAULT:
5443
/* Default is COMPACT. */
5445
= form.s->row_type == ROW_TYPE_REDUNDANT
5449
/* Cannot specify KEY_BLOCK_SIZE with these
5450
format specifiers. */
5451
if (kbs_specified) {
5452
push_warning_printf(
5454
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5455
ER_ILLEGAL_HA_CREATE_OPTION,
5456
"InnoDB: cannot specify"
5457
" ROW_FORMAT = %s with"
5466
push_warning(session,
5467
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5468
ER_ILLEGAL_HA_CREATE_OPTION,
5469
"InnoDB: invalid ROW_FORMAT specifier.");
5478
/*********************************************************************
5479
Creates a new table to an InnoDB database. */
5482
InnobaseEngine::doCreateTable(
5483
/*================*/
5484
Session* session, /*!< in: Session */
5485
const char* table_name, /*!< in: table name */
5486
Table& form, /*!< in: information on table
5487
columns and indexes */
5488
message::Table& create_proto)
5491
dict_table_t* innobase_table;
5496
char name2[FN_REFLEN];
5497
char norm_name[FN_REFLEN];
5498
ib_int64_t auto_inc_value;
5500
/* Cache the value of innodb_file_format, in case it is
5501
modified by another thread while the table is being created. */
5502
const ulint file_format = srv_file_format;
5503
bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
5505
assert(session != NULL);
5508
/* Names passed in from server are in two formats:
5509
1. <database_name>/<table_name>: for normal table creation
5510
2. full path: for temp table creation, or sym link
5512
When srv_file_per_table is on, check for full path pattern, i.e.
5513
X:\dir\..., X is a driver letter, or
5514
\\dir1\dir2\..., UNC path
5515
returns error if it is in full path format, but not creating a temp.
5516
table. Currently InnoDB does not support symbolic link on Windows. */
5518
if (srv_file_per_table
5519
&& (! lex_identified_temp_table)) {
5521
if ((table_name[1] == ':')
5522
|| (table_name[0] == '\\' && table_name[1] == '\\')) {
5523
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot create table %s\n", table_name);
5524
return(HA_ERR_GENERIC);
5529
if (form.s->fields > 1000) {
5530
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
5531
but we play safe here */
5533
return(HA_ERR_TO_BIG_ROW);
5536
/* Get the transaction associated with the current session, or create one
5537
if not yet created */
5539
parent_trx = check_trx_exists(session);
5541
/* In case MySQL calls this in the middle of a SELECT query, release
5542
possible adaptive hash latch to avoid deadlocks of threads */
5544
trx_search_latch_release_if_reserved(parent_trx);
5546
trx = innobase_trx_allocate(session);
5548
srv_lower_case_table_names = TRUE;
5550
strcpy(name2, table_name);
5552
normalize_table_name(norm_name, name2);
5554
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
5555
or lock waits can happen in it during a table create operation.
5556
Drop table etc. do this latching in row0mysql.c. */
5558
row_mysql_lock_data_dictionary(trx);
5560
/* Create the table definition in InnoDB */
5564
/* Validate create options if innodb_strict_mode is set. */
5565
if (! create_options_are_valid(session, form, create_proto)) {
5566
error = ER_ILLEGAL_HA_CREATE_OPTION;
5570
if (create_proto.options().has_key_block_size()) {
5571
/* Determine the page_zip.ssize corresponding to the
5572
requested page size (key_block_size) in kilobytes. */
5575
ulint key_block_size = create_proto.options().key_block_size();
5577
for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
5578
ssize++, ksize <<= 1) {
5579
if (key_block_size == ksize) {
5580
iflags = ssize << DICT_TF_ZSSIZE_SHIFT
5582
| DICT_TF_FORMAT_ZIP
5583
<< DICT_TF_FORMAT_SHIFT;
5588
if (!srv_file_per_table) {
5589
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5590
ER_ILLEGAL_HA_CREATE_OPTION,
5591
"InnoDB: KEY_BLOCK_SIZE"
5592
" requires innodb_file_per_table.");
5596
if (file_format < DICT_TF_FORMAT_ZIP) {
5597
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5598
ER_ILLEGAL_HA_CREATE_OPTION,
5599
"InnoDB: KEY_BLOCK_SIZE"
5600
" requires innodb_file_format >"
5606
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5607
ER_ILLEGAL_HA_CREATE_OPTION,
5609
" KEY_BLOCK_SIZE=%lu.",
5610
create_proto.options().key_block_size());
5614
if (create_proto.options().has_row_type()) {
5616
/* KEY_BLOCK_SIZE was specified. */
5617
if (form.s->row_type != ROW_TYPE_COMPRESSED) {
5618
/* ROW_FORMAT other than COMPRESSED
5619
ignores KEY_BLOCK_SIZE. It does not
5620
make sense to reject conflicting
5621
KEY_BLOCK_SIZE and ROW_FORMAT, because
5622
such combinations can be obtained
5623
with ALTER TABLE anyway. */
5624
push_warning_printf(
5626
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5627
ER_ILLEGAL_HA_CREATE_OPTION,
5628
"InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
5629
" unless ROW_FORMAT=COMPRESSED.",
5630
create_proto.options().key_block_size());
5634
/* No KEY_BLOCK_SIZE */
5635
if (form.s->row_type == ROW_TYPE_COMPRESSED) {
5636
/* ROW_FORMAT=COMPRESSED without
5637
KEY_BLOCK_SIZE implies half the
5638
maximum KEY_BLOCK_SIZE. */
5639
iflags = (DICT_TF_ZSSIZE_MAX - 1)
5640
<< DICT_TF_ZSSIZE_SHIFT
5642
| DICT_TF_FORMAT_ZIP
5643
<< DICT_TF_FORMAT_SHIFT;
5644
#if DICT_TF_ZSSIZE_MAX < 1
5645
# error "DICT_TF_ZSSIZE_MAX < 1"
5650
switch (form.s->row_type) {
5651
const char* row_format_name;
5652
case ROW_TYPE_REDUNDANT:
5654
case ROW_TYPE_COMPRESSED:
5655
case ROW_TYPE_DYNAMIC:
5657
= form.s->row_type == ROW_TYPE_COMPRESSED
5661
if (!srv_file_per_table) {
5662
push_warning_printf(
5664
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5665
ER_ILLEGAL_HA_CREATE_OPTION,
5666
"InnoDB: ROW_FORMAT=%s"
5667
" requires innodb_file_per_table.",
5669
} else if (file_format < DICT_TF_FORMAT_ZIP) {
5670
push_warning_printf(
5672
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5673
ER_ILLEGAL_HA_CREATE_OPTION,
5674
"InnoDB: ROW_FORMAT=%s"
5675
" requires innodb_file_format >"
5679
iflags |= DICT_TF_COMPACT
5680
| (DICT_TF_FORMAT_ZIP
5681
<< DICT_TF_FORMAT_SHIFT);
5686
case ROW_TYPE_NOT_USED:
5687
case ROW_TYPE_FIXED:
5689
error = ER_ILLEGAL_HA_CREATE_OPTION;
5691
case ROW_TYPE_DEFAULT:
5692
case ROW_TYPE_COMPACT:
5693
iflags = DICT_TF_COMPACT;
5696
} else if (!iflags) {
5697
/* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
5698
use ROW_FORMAT=COMPACT by default. */
5699
iflags = DICT_TF_COMPACT;
5702
error = create_table_def(trx, &form, norm_name,
5703
lex_identified_temp_table ? name2 : NULL,
5710
/* Look for a primary key */
5712
primary_key_no= (form.s->primary_key != MAX_KEY ?
5713
(int) form.s->primary_key :
5716
/* Our function row_get_mysql_key_number_for_index assumes
5717
the primary key is always number 0, if it exists */
5719
assert(primary_key_no == -1 || primary_key_no == 0);
5721
/* Create the keys */
5723
if (form.s->keys == 0 || primary_key_no == -1) {
5724
/* Create an index which is used as the clustered index;
5725
order the rows by their row id which is internally generated
5728
error = create_clustered_index_when_no_primary(
5729
trx, iflags, norm_name);
5735
if (primary_key_no != -1) {
5736
/* In InnoDB the clustered index must always be created
5738
if ((error = create_index(trx, &form, iflags, norm_name,
5739
(uint) primary_key_no))) {
5744
for (i = 0; i < form.s->keys; i++) {
5746
if (i != (uint) primary_key_no) {
5748
if ((error = create_index(trx, &form, iflags, norm_name,
5755
if (trx->mysql_query_str) {
5756
error = row_table_add_foreign_constraints(trx,
5757
trx->mysql_query_str, norm_name,
5758
lex_identified_temp_table);
5760
error = convert_error_code_to_mysql(error, iflags, NULL);
5767
innobase_commit_low(trx);
5769
row_mysql_unlock_data_dictionary(trx);
5771
/* Flush the log to reduce probability that the .frm files and
5772
the InnoDB data dictionary get out-of-sync if the user runs
5773
with innodb_flush_log_at_trx_commit = 0 */
5775
log_buffer_flush_to_disk();
5777
innobase_table = dict_table_get(norm_name, FALSE);
5779
assert(innobase_table != 0);
5781
if (innobase_table) {
5782
/* We update the highest file format in the system table
5783
space, if this table has higher file format setting. */
5785
trx_sys_file_format_max_upgrade(
5786
(const char**) &innobase_file_format_check,
5787
dict_table_get_format(innobase_table));
5790
/* Note: We can't call update_session() as prebuilt will not be
5791
setup at this stage and so we use session. */
5793
/* We need to copy the AUTOINC value from the old table if
5794
this is an ALTER TABLE. */
5796
if ((create_proto.options().has_auto_increment_value()
5797
|| session_sql_command(session) == SQLCOM_ALTER_TABLE)
5798
&& create_proto.options().auto_increment_value() != 0) {
5800
/* Query was ALTER TABLE...AUTO_INCREMENT = x; or
5801
CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
5802
definition from the dictionary and get the current value
5803
of the auto increment field. Set a new value to the
5804
auto increment field if the value is greater than the
5805
maximum value in the column. */
5807
auto_inc_value = create_proto.options().auto_increment_value();
5809
dict_table_autoinc_lock(innobase_table);
5810
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
5811
dict_table_autoinc_unlock(innobase_table);
5814
/* Tell the InnoDB server that there might be work for
5817
srv_active_wake_master_thread();
5819
trx_free_for_mysql(trx);
5824
innobase_commit_low(trx);
5826
row_mysql_unlock_data_dictionary(trx);
5828
trx_free_for_mysql(trx);
5833
/*****************************************************************//**
5834
Discards or imports an InnoDB tablespace.
5835
@return 0 == success, -1 == error */
5838
ha_innobase::discard_or_import_tablespace(
5839
/*======================================*/
5840
my_bool discard) /*!< in: TRUE if discard, else import */
5842
dict_table_t* dict_table;
5846
ut_a(prebuilt->trx);
5847
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
5848
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5850
dict_table = prebuilt->table;
5851
trx = prebuilt->trx;
5854
err = row_discard_tablespace_for_mysql(dict_table->name, trx);
5856
err = row_import_tablespace_for_mysql(dict_table->name, trx);
5859
err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
5864
/*****************************************************************//**
5865
Deletes all rows of an InnoDB table.
5866
@return error number */
5869
ha_innobase::delete_all_rows(void)
5870
/*==============================*/
5874
/* Get the transaction associated with the current session, or create one
5875
if not yet created, and update prebuilt->trx */
5877
update_session(ha_session());
5879
if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
5881
/* We only handle TRUNCATE TABLE t as a special case.
5882
DELETE FROM t will have to use ha_innobase::delete_row(),
5883
because DELETE is transactional while TRUNCATE is not. */
5884
return(errno=HA_ERR_WRONG_COMMAND);
5887
/* Truncate the table in InnoDB */
5889
error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
5890
if (error == DB_ERROR) {
5891
/* Cannot truncate; resort to ha_innobase::delete_row() */
5895
error = convert_error_code_to_mysql(error, prebuilt->table->flags,
5901
/*****************************************************************//**
5902
Drops a table from an InnoDB database. Before calling this function,
5903
MySQL calls innobase_commit to commit the transaction of the current user.
5904
Then the current user cannot have locks set on the table. Drop table
5905
operation inside InnoDB will remove all locks any user has on the table
5907
@return error number */
5910
InnobaseEngine::doDropTable(
5911
/*======================*/
5913
const string &table_path) /* in: table name */
5918
char norm_name[1000];
5920
ut_a(table_path.length() < 1000);
5922
/* Strangely, MySQL passes the table name without the '.frm'
5923
extension, in contrast to ::create */
5924
normalize_table_name(norm_name, table_path.c_str());
5926
/* Get the transaction associated with the current session, or create one
5927
if not yet created */
5929
parent_trx = check_trx_exists(&session);
5931
/* In case MySQL calls this in the middle of a SELECT query, release
5932
possible adaptive hash latch to avoid deadlocks of threads */
5934
trx_search_latch_release_if_reserved(parent_trx);
5936
trx = innobase_trx_allocate(&session);
5938
srv_lower_case_table_names = TRUE;
5940
/* Drop the table in InnoDB */
5942
error = row_drop_table_for_mysql(norm_name, trx,
5943
session_sql_command(&session)
5946
/* Flush the log to reduce probability that the .frm files and
5947
the InnoDB data dictionary get out-of-sync if the user runs
5948
with innodb_flush_log_at_trx_commit = 0 */
5950
log_buffer_flush_to_disk();
5952
/* Tell the InnoDB server that there might be work for
5955
srv_active_wake_master_thread();
5957
innobase_commit_low(trx);
5959
trx_free_for_mysql(trx);
5962
error = convert_error_code_to_mysql(error, 0, NULL);
5967
/*****************************************************************//**
5968
Removes all tables in the named database inside InnoDB. */
5970
InnobaseEngine::doDropSchema(
5971
/*===================*/
5972
const std::string &schema_name)
5973
/*!< in: database path; inside InnoDB the name
5974
of the last directory in the path is used as
5975
the database name: for example, in 'mysql/data/test'
5976
the database name is 'test' */
5980
string schema_path(schema_name);
5981
Session* session = current_session;
5983
/* Get the transaction associated with the current session, or create one
5984
if not yet created */
5986
assert(this == innodb_engine_ptr);
5988
/* In the Windows plugin, session = current_session is always NULL */
5990
trx_t* parent_trx = check_trx_exists(session);
5992
/* In case Drizzle calls this in the middle of a SELECT
5993
query, release possible adaptive hash latch to avoid
5994
deadlocks of threads */
5996
trx_search_latch_release_if_reserved(parent_trx);
5999
schema_path.append("/");
6000
trx = innobase_trx_allocate(session);
6001
error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6003
/* Flush the log to reduce probability that the .frm files and
6004
the InnoDB data dictionary get out-of-sync if the user runs
6005
with innodb_flush_log_at_trx_commit = 0 */
6007
log_buffer_flush_to_disk();
6009
/* Tell the InnoDB server that there might be work for
6012
srv_active_wake_master_thread();
6014
innobase_commit_low(trx);
6015
trx_free_for_mysql(trx);
6017
return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement.
6019
/*********************************************************************//**
6020
Renames an InnoDB table.
6021
@return 0 or error code */
6024
innobase_rename_table(
6025
/*==================*/
6026
trx_t* trx, /*!< in: transaction */
6027
const char* from, /*!< in: old name of the table */
6028
const char* to, /*!< in: new name of the table */
6029
ibool lock_and_commit)
6030
/*!< in: TRUE=lock data dictionary and commit */
6036
srv_lower_case_table_names = TRUE;
6038
// Magic number 64 arbitrary
6039
norm_to = (char*) malloc(strlen(to) + 64);
6040
norm_from = (char*) malloc(strlen(from) + 64);
6042
normalize_table_name(norm_to, to);
6043
normalize_table_name(norm_from, from);
6045
/* Serialize data dictionary operations with dictionary mutex:
6046
no deadlocks can occur then in these operations */
6048
if (lock_and_commit) {
6049
row_mysql_lock_data_dictionary(trx);
6052
error = row_rename_table_for_mysql(
6053
norm_from, norm_to, trx, lock_and_commit);
6055
if (error != DB_SUCCESS) {
6056
FILE* ef = dict_foreign_err_file;
6058
fputs("InnoDB: Renaming table ", ef);
6059
ut_print_name(ef, trx, TRUE, norm_from);
6061
ut_print_name(ef, trx, TRUE, norm_to);
6062
fputs(" failed!\n", ef);
6065
if (lock_and_commit) {
6066
row_mysql_unlock_data_dictionary(trx);
6068
/* Flush the log to reduce probability that the .frm
6069
files and the InnoDB data dictionary get out-of-sync
6070
if the user runs with innodb_flush_log_at_trx_commit = 0 */
6072
log_buffer_flush_to_disk();
6080
/*********************************************************************//**
6081
Renames an InnoDB table.
6082
@return 0 or error code */
6085
InnobaseEngine::doRenameTable(
6086
/*======================*/
6088
const char* from, /*!< in: old name of the table */
6089
const char* to) /*!< in: new name of the table */
6095
/* Get the transaction associated with the current session, or create one
6096
if not yet created */
6098
parent_trx = check_trx_exists(session);
6100
/* In case MySQL calls this in the middle of a SELECT query, release
6101
possible adaptive hash latch to avoid deadlocks of threads */
6103
trx_search_latch_release_if_reserved(parent_trx);
6105
trx = innobase_trx_allocate(session);
6107
error = innobase_rename_table(trx, from, to, TRUE);
6109
/* Tell the InnoDB server that there might be work for
6112
srv_active_wake_master_thread();
6114
innobase_commit_low(trx);
6115
trx_free_for_mysql(trx);
6117
error = convert_error_code_to_mysql(error, 0, NULL);
6122
/*********************************************************************//**
6123
Estimates the number of index records in a range.
6124
@return estimated number of rows */
6127
ha_innobase::records_in_range(
6128
/*==========================*/
6129
uint keynr, /*!< in: index number */
6130
key_range *min_key, /*!< in: start key value of the
6131
range, may also be 0 */
6132
key_range *max_key) /*!< in: range end key val, may
6136
dict_index_t* index;
6137
unsigned char* key_val_buff2 = (unsigned char*) malloc(
6138
table->s->stored_rec_length
6139
+ table->s->max_key_length + 100);
6140
ulint buff2_len = table->s->stored_rec_length
6141
+ table->s->max_key_length + 100;
6142
dtuple_t* range_start;
6143
dtuple_t* range_end;
6149
ut_a(prebuilt->trx == session_to_trx(ha_session()));
6151
prebuilt->trx->op_info = (char*)"estimating records in index range";
6153
/* In case MySQL calls this in the middle of a SELECT query, release
6154
possible adaptive hash latch to avoid deadlocks of threads */
6156
trx_search_latch_release_if_reserved(prebuilt->trx);
6158
active_index = keynr;
6160
key = table->key_info + active_index;
6162
index = dict_table_get_index_on_name(prebuilt->table, key->name);
6164
/* MySQL knows about this index and so we must be able to find it.*/
6167
heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6168
+ sizeof(dtuple_t)));
6170
range_start = dtuple_create(heap, key->key_parts);
6171
dict_index_copy_types(range_start, index, key->key_parts);
6173
range_end = dtuple_create(heap, key->key_parts);
6174
dict_index_copy_types(range_end, index, key->key_parts);
6176
row_sel_convert_mysql_key_to_innobase(
6177
range_start, (byte*) key_val_buff,
6178
(ulint)upd_and_key_val_buff_len,
6180
(byte*) (min_key ? min_key->key :
6181
(const unsigned char*) 0),
6182
(ulint) (min_key ? min_key->length : 0),
6185
row_sel_convert_mysql_key_to_innobase(
6186
range_end, (byte*) key_val_buff2,
6188
(byte*) (max_key ? max_key->key :
6189
(const unsigned char*) 0),
6190
(ulint) (max_key ? max_key->length : 0),
6193
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
6195
mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
6198
if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
6200
n_rows = btr_estimate_n_rows_in_range(index, range_start,
6205
n_rows = HA_POS_ERROR;
6208
mem_heap_free(heap);
6210
free(key_val_buff2);
6212
prebuilt->trx->op_info = (char*)"";
6214
/* The MySQL optimizer seems to believe an estimate of 0 rows is
6215
always accurate and may return the result 'Empty set' based on that.
6216
The accuracy is not guaranteed, and even if it were, for a locking
6217
read we should anyway perform the search to set the next-key lock.
6218
Add 1 to the value to make sure MySQL does not make the assumption! */
6224
return((ha_rows) n_rows);
6227
/*********************************************************************//**
6228
Gives an UPPER BOUND to the number of rows in a table. This is used in
6230
@return upper bound of rows */
6233
ha_innobase::estimate_rows_upper_bound(void)
6234
/*======================================*/
6236
dict_index_t* index;
6238
uint64_t local_data_file_length;
6240
/* We do not know if MySQL can call this function before calling
6241
external_lock(). To be safe, update the session of the current table
6244
update_session(ha_session());
6246
prebuilt->trx->op_info = (char*)
6247
"calculating upper bound for table rows";
6249
/* In case MySQL calls this in the middle of a SELECT query, release
6250
possible adaptive hash latch to avoid deadlocks of threads */
6252
trx_search_latch_release_if_reserved(prebuilt->trx);
6254
index = dict_table_get_first_index(prebuilt->table);
6256
ut_a(index->stat_n_leaf_pages > 0);
6258
local_data_file_length =
6259
((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
6262
/* Calculate a minimum length for a clustered index record and from
6263
that an upper bound for the number of rows. Since we only calculate
6264
new statistics in row0mysql.c when a table has grown by a threshold
6265
factor, we must add a safety factor 2 in front of the formula below. */
6267
estimate = 2 * local_data_file_length /
6268
dict_index_calc_min_rec_len(index);
6270
prebuilt->trx->op_info = (char*)"";
6272
return((ha_rows) estimate);
6275
/*********************************************************************//**
6276
How many seeks it will take to read through the table. This is to be
6277
comparable to the number returned by records_in_range so that we can
6278
decide if we should scan the table or use keys.
6279
@return estimated time measured in disk seeks */
6282
ha_innobase::scan_time()
6283
/*====================*/
6285
/* Since MySQL seems to favor table scans too much over index
6286
searches, we pretend that a sequential read takes the same time
6287
as a random disk read, that is, we do not divide the following
6288
by 10, which would be physically realistic. */
6290
return((double) (prebuilt->table->stat_clustered_index_size));
6293
/******************************************************************//**
6294
Calculate the time it takes to read a set of ranges through an index
6295
This enables us to optimise reads for clustered indexes.
6296
@return estimated time measured in disk seeks */
6299
ha_innobase::read_time(
6300
/*===================*/
6301
uint index, /*!< in: key number */
6302
uint ranges, /*!< in: how many ranges */
6303
ha_rows rows) /*!< in: estimated number of rows in the ranges */
6306
double time_for_scan;
6308
if (index != table->s->primary_key) {
6310
return(Cursor::read_time(index, ranges, rows));
6315
return((double) rows);
6318
/* Assume that the read time is proportional to the scan time for all
6319
rows + at most one seek per range. */
6321
time_for_scan = scan_time();
6323
if ((total_rows = estimate_rows_upper_bound()) < rows) {
6325
return(time_for_scan);
6328
return(ranges + (double) rows / (double) total_rows * time_for_scan);
6331
/*********************************************************************//**
6332
Returns statistics information of the table to the MySQL interpreter,
6333
in various fields of the handle object. */
6338
uint flag) /*!< in: what information MySQL requests */
6340
dict_table_t* ib_table;
6341
dict_index_t* index;
6342
ha_rows rec_per_key;
6346
char path[FN_REFLEN];
6347
os_file_stat_t stat_info;
6349
/* If we are forcing recovery at a high level, we will suppress
6350
statistics calculation on tables, because that may crash the
6351
server if an index is badly corrupted. */
6353
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
6355
/* We return success (0) instead of HA_ERR_CRASHED,
6356
because we want MySQL to process this query and not
6357
stop, like it would do if it received the error code
6363
/* We do not know if MySQL can call this function before calling
6364
external_lock(). To be safe, update the session of the current table
6367
update_session(ha_session());
6369
/* In case MySQL calls this in the middle of a SELECT query, release
6370
possible adaptive hash latch to avoid deadlocks of threads */
6372
prebuilt->trx->op_info = (char*)"returning various info to MySQL";
6374
trx_search_latch_release_if_reserved(prebuilt->trx);
6376
ib_table = prebuilt->table;
6378
if (flag & HA_STATUS_TIME) {
6379
if (innobase_stats_on_metadata) {
6380
/* In sql_show we call with this flag: update
6381
then statistics so that they are up-to-date */
6383
prebuilt->trx->op_info = "updating table statistics";
6385
dict_update_statistics(ib_table);
6387
prebuilt->trx->op_info = "returning various info to MySQL";
6390
snprintf(path, sizeof(path), "%s/%s%s",
6391
drizzle_data_home, ib_table->name, ".dfe");
6393
internal::unpack_filename(path,path);
6395
/* Note that we do not know the access time of the table,
6396
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
6398
if (os_file_get_status(path,&stat_info)) {
6399
stats.create_time = (ulong) stat_info.ctime;
6403
if (flag & HA_STATUS_VARIABLE) {
6404
n_rows = ib_table->stat_n_rows;
6406
/* Because we do not protect stat_n_rows by any mutex in a
6407
delete, it is theoretically possible that the value can be
6408
smaller than zero! TODO: fix this race.
6410
The MySQL optimizer seems to assume in a left join that n_rows
6411
is an accurate estimate if it is zero. Of course, it is not,
6412
since we do not have any locks on the rows yet at this phase.
6413
Since SHOW TABLE STATUS seems to call this function with the
6414
HA_STATUS_TIME flag set, while the left join optimizer does not
6415
set that flag, we add one to a zero value if the flag is not
6416
set. That way SHOW TABLE STATUS will show the best estimate,
6417
while the optimizer never sees the table empty. */
6423
if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
6427
/* Fix bug#40386: Not flushing query cache after truncate.
6428
n_rows can not be 0 unless the table is empty, set to 1
6429
instead. The original problem of bug#29507 is actually
6430
fixed in the server code. */
6431
if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
6435
/* We need to reset the prebuilt value too, otherwise
6436
checks for values greater than the last value written
6437
to the table will fail and the autoinc counter will
6438
not be updated. This will force write_row() into
6439
attempting an update of the table's AUTOINC counter. */
6441
prebuilt->autoinc_last_value = 0;
6444
stats.records = (ha_rows)n_rows;
6446
stats.data_file_length = ((uint64_t)
6447
ib_table->stat_clustered_index_size)
6449
stats.index_file_length = ((uint64_t)
6450
ib_table->stat_sum_of_other_index_sizes)
6453
/* Since fsp_get_available_space_in_free_extents() is
6454
acquiring latches inside InnoDB, we do not call it if we
6455
are asked by MySQL to avoid locking. Another reason to
6456
avoid the call is that it uses quite a lot of CPU.
6458
We do not update delete_length if no locking is requested
6459
so the "old" value can remain. delete_length is initialized
6460
to 0 in the ha_statistics' constructor. */
6461
if (!(flag & HA_STATUS_NO_LOCK)) {
6463
/* lock the data dictionary to avoid races with
6464
ibd_file_missing and tablespace_discarded */
6465
row_mysql_lock_data_dictionary(prebuilt->trx);
6467
/* ib_table->space must be an existent tablespace */
6468
if (!ib_table->ibd_file_missing
6469
&& !ib_table->tablespace_discarded) {
6471
stats.delete_length =
6472
fsp_get_available_space_in_free_extents(
6473
ib_table->space) * 1024;
6478
session = ha_session();
6480
push_warning_printf(
6482
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6484
"InnoDB: Trying to get the free "
6485
"space for table %s but its "
6486
"tablespace has been discarded or "
6487
"the .ibd file is missing. Setting "
6488
"the free space to zero.",
6491
stats.delete_length = 0;
6494
row_mysql_unlock_data_dictionary(prebuilt->trx);
6497
stats.check_time = 0;
6499
if (stats.records == 0) {
6500
stats.mean_rec_length = 0;
6502
stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
6506
if (flag & HA_STATUS_CONST) {
6507
index = dict_table_get_first_index(ib_table);
6509
if (prebuilt->clust_index_was_generated) {
6510
index = dict_table_get_next_index(index);
6513
for (i = 0; i < table->s->keys; i++) {
6514
if (index == NULL) {
6515
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
6516
"indexes inside InnoDB than "
6517
"are defined in the MySQL "
6518
".frm file. Have you mixed up "
6519
".frm files from different "
6520
"installations? See "
6522
"innodb-troubleshooting.html\n",
6527
for (j = 0; j < table->key_info[i].key_parts; j++) {
6529
if (j + 1 > index->n_uniq) {
6530
errmsg_printf(ERRMSG_LVL_ERROR,
6531
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
6532
"statistics for %lu columns. Have you mixed up .frm files from different "
6534
"See " REFMAN "innodb-troubleshooting.html\n",
6538
index->n_uniq, j + 1);
6542
if (index->stat_n_diff_key_vals[j + 1] == 0) {
6544
rec_per_key = stats.records;
6546
rec_per_key = (ha_rows)(stats.records /
6547
index->stat_n_diff_key_vals[j + 1]);
6550
/* Since MySQL seems to favor table scans
6551
too much over index searches, we pretend
6552
index selectivity is 2 times better than
6555
rec_per_key = rec_per_key / 2;
6557
if (rec_per_key == 0) {
6561
table->key_info[i].rec_per_key[j]=
6562
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
6563
(ulong) rec_per_key;
6566
index = dict_table_get_next_index(index);
6570
if (flag & HA_STATUS_ERRKEY) {
6571
const dict_index_t* err_index;
6573
ut_a(prebuilt->trx);
6574
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6576
err_index = trx_get_error_info(prebuilt->trx);
6579
errkey = (unsigned int)
6580
row_get_mysql_key_number_for_index(err_index);
6582
errkey = (unsigned int) prebuilt->trx->error_key_num;
6586
if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
6587
stats.auto_increment_value = innobase_peek_autoinc();
6590
prebuilt->trx->op_info = (char*)"";
6595
/**********************************************************************//**
6596
Updates index cardinalities of the table, based on 8 random dives into
6597
each index tree. This does NOT calculate exact statistics on the table.
6598
@return returns always 0 (success) */
6601
ha_innobase::analyze(
6602
/*=================*/
6603
Session*) /*!< in: connection thread handle */
6605
/* Simply call ::info() with all the flags */
6606
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
6611
/*******************************************************************//**
6612
Tries to check that an InnoDB table is not corrupted. If corruption is
6613
noticed, prints to stderr information about it. In case of corruption
6614
may also assert a failure and crash the server.
6615
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
6620
Session* session) /*!< in: user thread handle */
6624
assert(session == ha_session());
6625
ut_a(prebuilt->trx);
6626
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6627
ut_a(prebuilt->trx == session_to_trx(session));
6629
if (prebuilt->mysql_template == NULL) {
6630
/* Build the template; we will use a dummy template
6631
in index scans done in checking */
6633
build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
6636
ret = row_check_table_for_mysql(prebuilt);
6638
if (ret == DB_SUCCESS) {
6639
return(HA_ADMIN_OK);
6642
return(HA_ADMIN_CORRUPT);
6645
/*************************************************************//**
6646
Adds information about free space in the InnoDB tablespace to a table comment
6647
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
6649
@return table comment + InnoDB free space + info on foreign keys */
6652
ha_innobase::update_table_comment(
6653
/*==============================*/
6654
const char* comment)/*!< in: table comment defined by user */
6656
uint length = (uint) strlen(comment);
6660
/* We do not know if MySQL can call this function before calling
6661
external_lock(). To be safe, update the session of the current table
6664
if (length > 64000 - 3) {
6665
return((char*)comment); /* string too long */
6668
update_session(ha_session());
6670
prebuilt->trx->op_info = (char*)"returning table comment";
6672
/* In case MySQL calls this in the middle of a SELECT query, release
6673
possible adaptive hash latch to avoid deadlocks of threads */
6675
trx_search_latch_release_if_reserved(prebuilt->trx);
6678
/* output the data to a temporary file */
6680
mutex_enter(&srv_dict_tmpfile_mutex);
6681
rewind(srv_dict_tmpfile);
6683
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
6684
fsp_get_available_space_in_free_extents(
6685
prebuilt->table->space));
6687
dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
6688
prebuilt->trx, prebuilt->table);
6689
flen = ftell(srv_dict_tmpfile);
6692
} else if (length + flen + 3 > 64000) {
6693
flen = 64000 - 3 - length;
6696
/* allocate buffer for the full string, and
6697
read the contents of the temporary file */
6699
str = (char*) malloc(length + flen + 3);
6702
char* pos = str + length;
6704
memcpy(str, comment, length);
6708
rewind(srv_dict_tmpfile);
6709
flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
6713
mutex_exit(&srv_dict_tmpfile_mutex);
6715
prebuilt->trx->op_info = (char*)"";
6717
return(str ? str : (char*) comment);
6720
/*******************************************************************//**
6721
Gets the foreign key create info for a table stored in InnoDB.
6722
@return own: character string in the form which can be inserted to the
6723
CREATE TABLE statement, MUST be freed with
6724
ha_innobase::free_foreign_key_create_info */
6727
ha_innobase::get_foreign_key_create_info(void)
6728
/*==========================================*/
6733
ut_a(prebuilt != NULL);
6735
/* We do not know if MySQL can call this function before calling
6736
external_lock(). To be safe, update the session of the current table
6739
update_session(ha_session());
6741
prebuilt->trx->op_info = (char*)"getting info on foreign keys";
6743
/* In case MySQL calls this in the middle of a SELECT query,
6744
release possible adaptive hash latch to avoid
6745
deadlocks of threads */
6747
trx_search_latch_release_if_reserved(prebuilt->trx);
6749
mutex_enter(&srv_dict_tmpfile_mutex);
6750
rewind(srv_dict_tmpfile);
6752
/* output the data to a temporary file */
6753
dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
6754
prebuilt->trx, prebuilt->table);
6755
prebuilt->trx->op_info = (char*)"";
6757
flen = ftell(srv_dict_tmpfile);
6760
} else if (flen > 64000 - 1) {
6764
/* allocate buffer for the string, and
6765
read the contents of the temporary file */
6767
str = (char*) malloc(flen + 1);
6770
rewind(srv_dict_tmpfile);
6771
flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
6775
mutex_exit(&srv_dict_tmpfile_mutex);
6783
ha_innobase::get_foreign_key_list(Session *session, List<FOREIGN_KEY_INFO> *f_key_list)
6785
dict_foreign_t* foreign;
6787
ut_a(prebuilt != NULL);
6788
update_session(ha_session());
6789
prebuilt->trx->op_info = (char*)"getting list of foreign keys";
6790
trx_search_latch_release_if_reserved(prebuilt->trx);
6791
mutex_enter(&(dict_sys->mutex));
6792
foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
6794
while (foreign != NULL) {
6796
FOREIGN_KEY_INFO f_key_info;
6797
LEX_STRING *name= 0;
6799
char uname[NAME_LEN+1]; /* Unencoded name */
6800
char db_name[NAME_LEN+1];
6801
const char *tmp_buff;
6803
tmp_buff= foreign->id;
6805
while (tmp_buff[i] != '/')
6808
f_key_info.forein_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
6809
tmp_buff= foreign->referenced_table_name;
6813
while (tmp_buff[i] != '/')
6815
db_name[i]= tmp_buff[i];
6819
ulen= filename_to_tablename(db_name, uname, sizeof(uname));
6820
f_key_info.referenced_db = session->make_lex_string(NULL, uname, ulen, true);
6824
ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
6825
f_key_info.referenced_table = session->make_lex_string(NULL, uname, ulen, true);
6828
tmp_buff= foreign->foreign_col_names[i];
6829
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6830
f_key_info.foreign_fields.push_back(name);
6831
tmp_buff= foreign->referenced_col_names[i];
6832
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6833
f_key_info.referenced_fields.push_back(name);
6834
if (++i >= foreign->n_fields)
6839
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
6842
tmp_buff= "CASCADE";
6844
else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
6847
tmp_buff= "SET NULL";
6849
else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
6852
tmp_buff= "NO ACTION";
6857
tmp_buff= "RESTRICT";
6859
f_key_info.delete_method = session->make_lex_string(
6860
f_key_info.delete_method, tmp_buff, length, true);
6863
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
6866
tmp_buff= "CASCADE";
6868
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
6871
tmp_buff= "SET NULL";
6873
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
6876
tmp_buff= "NO ACTION";
6881
tmp_buff= "RESTRICT";
6883
f_key_info.update_method = session->make_lex_string(
6884
f_key_info.update_method, tmp_buff, length, true);
6885
if (foreign->referenced_index &&
6886
foreign->referenced_index->name)
6888
f_key_info.referenced_key_name = session->make_lex_string(
6889
f_key_info.referenced_key_name,
6890
foreign->referenced_index->name,
6891
strlen(foreign->referenced_index->name), true);
6894
f_key_info.referenced_key_name= 0;
6896
FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
6897
session_memdup(session, &f_key_info, sizeof(FOREIGN_KEY_INFO));
6898
f_key_list->push_back(pf_key_info);
6899
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
6901
mutex_exit(&(dict_sys->mutex));
6902
prebuilt->trx->op_info = (char*)"";
6907
/*****************************************************************//**
6908
Checks if ALTER TABLE may change the storage engine of the table.
6909
Changing storage engines is not allowed for tables for which there
6910
are foreign key constraints (parent or child tables).
6911
@return TRUE if can switch engines */
6914
ha_innobase::can_switch_engines(void)
6915
/*=================================*/
6919
ut_a(prebuilt->trx == session_to_trx(ha_session()));
6921
prebuilt->trx->op_info =
6922
"determining if there are foreign key constraints";
6923
row_mysql_lock_data_dictionary(prebuilt->trx);
6925
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
6926
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
6928
row_mysql_unlock_data_dictionary(prebuilt->trx);
6929
prebuilt->trx->op_info = "";
6934
/*******************************************************************//**
6935
Checks if a table is referenced by a foreign key. The MySQL manual states that
6936
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
6937
delete is then allowed internally to resolve a duplicate key conflict in
6938
REPLACE, not an update.
6939
@return > 0 if referenced by a FOREIGN KEY */
6942
ha_innobase::referenced_by_foreign_key(void)
6943
/*========================================*/
6945
if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
6953
/*******************************************************************//**
6954
Frees the foreign key create info for a table stored in InnoDB, if it is
6958
ha_innobase::free_foreign_key_create_info(
6959
/*======================================*/
6960
char* str) /*!< in, own: create info string to free */
6967
/*******************************************************************//**
6968
Tells something additional to the Cursor about how to do things.
6969
@return 0 or error number */
6974
enum ha_extra_function operation)
6975
/*!< in: HA_EXTRA_FLUSH or some other flag */
6977
/* Warning: since it is not sure that MySQL calls external_lock
6978
before calling this function, the trx field in prebuilt can be
6981
switch (operation) {
6982
case HA_EXTRA_FLUSH:
6983
if (prebuilt->blob_heap) {
6984
row_mysql_prebuilt_free_blob_heap(prebuilt);
6987
case HA_EXTRA_RESET_STATE:
6988
reset_template(prebuilt);
6990
case HA_EXTRA_NO_KEYREAD:
6991
prebuilt->read_just_key = 0;
6993
case HA_EXTRA_KEYREAD:
6994
prebuilt->read_just_key = 1;
6996
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
6997
prebuilt->keep_other_fields_on_keyread = 1;
7000
/* IMPORTANT: prebuilt->trx can be obsolete in
7001
this method, because it is not sure that MySQL
7002
calls external_lock before this method with the
7003
parameters below. We must not invoke update_session()
7004
either, because the calling threads may change.
7005
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
7006
case HA_EXTRA_IGNORE_DUP_KEY:
7007
session_to_trx(ha_session())->duplicates |= TRX_DUP_IGNORE;
7009
case HA_EXTRA_WRITE_CAN_REPLACE:
7010
session_to_trx(ha_session())->duplicates |= TRX_DUP_REPLACE;
7012
case HA_EXTRA_WRITE_CANNOT_REPLACE:
7013
session_to_trx(ha_session())->duplicates &= ~TRX_DUP_REPLACE;
7015
case HA_EXTRA_NO_IGNORE_DUP_KEY:
7016
session_to_trx(ha_session())->duplicates &=
7017
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
7019
default:/* Do nothing */
7028
ha_innobase::reset()
7030
if (prebuilt->blob_heap) {
7031
row_mysql_prebuilt_free_blob_heap(prebuilt);
7034
reset_template(prebuilt);
7036
/* TODO: This should really be reset in reset_template() but for now
7037
it's safer to do it explicitly here. */
7039
/* This is a statement level counter. */
7040
prebuilt->autoinc_last_value = 0;
7045
/******************************************************************//**
7046
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7047
@return InnoDB isolation level */
7050
innobase_map_isolation_level(
7051
/*=========================*/
7052
enum_tx_isolation iso) /*!< in: MySQL isolation level code */
7055
case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
7056
case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
7057
case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
7058
case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
7059
default: ut_a(0); return(0);
7063
/******************************************************************//**
7064
As MySQL will execute an external lock for every new table it uses when it
7065
starts to process an SQL statement. We can use this function to store the pointer to
7066
the Session in the handle.
7070
ha_innobase::external_lock(
7071
/*=======================*/
7072
Session* session, /*!< in: handle to the user thread */
7073
int lock_type) /*!< in: lock type */
7075
update_session(session);
7077
trx_t *trx= prebuilt->trx;
7079
prebuilt->sql_stat_start = TRUE;
7080
prebuilt->hint_need_to_fetch_extra_cols = 0;
7082
reset_template(prebuilt);
7084
if (lock_type == F_WRLCK) {
7086
/* If this is a SELECT, then it is in UPDATE TABLE ...
7087
or SELECT ... FOR UPDATE */
7088
prebuilt->select_lock_type = LOCK_X;
7089
prebuilt->stored_select_lock_type = LOCK_X;
7092
if (lock_type != F_UNLCK) {
7093
/* MySQL is setting a new table lock */
7095
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
7096
&& prebuilt->select_lock_type == LOCK_NONE
7097
&& session_test_options(session,
7098
OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7100
/* To get serializable execution, we let InnoDB
7101
conceptually add 'LOCK IN SHARE MODE' to all SELECTs
7102
which otherwise would have been consistent reads. An
7103
exception is consistent reads in the AUTOCOMMIT=1 mode:
7104
we know that they are read-only transactions, and they
7105
can be serialized also if performed as consistent
7108
prebuilt->select_lock_type = LOCK_S;
7109
prebuilt->stored_select_lock_type = LOCK_S;
7112
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
7113
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
7114
an InnoDB table lock if it is released immediately at the end
7115
of LOCK TABLES, and InnoDB's table locks in that case cause
7116
VERY easily deadlocks.
7118
We do not set InnoDB table locks if user has not explicitly
7119
requested a table lock. Note that session_in_lock_tables(session)
7120
can hold in some cases, e.g., at the start of a stored
7121
procedure call (SQLCOM_CALL). */
7123
if (prebuilt->select_lock_type != LOCK_NONE) {
7124
trx->mysql_n_tables_locked++;
7127
prebuilt->mysql_has_locked = TRUE;
7132
/* MySQL is releasing a table lock */
7133
prebuilt->mysql_has_locked = FALSE;
7134
trx->mysql_n_tables_locked= 0;
7139
/************************************************************************//**
7140
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
7141
Monitor to the client. */
7146
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7147
Session* session,/*!< in: the MySQL query thread of the caller */
7148
stat_print_fn *stat_print)
7151
static const char truncated_msg[] = "... truncated...\n";
7152
const long MAX_STATUS_SIZE = 64000;
7153
ulint trx_list_start = ULINT_UNDEFINED;
7154
ulint trx_list_end = ULINT_UNDEFINED;
7156
assert(engine == innodb_engine_ptr);
7158
trx = check_trx_exists(session);
7160
innobase_release_stat_resources(trx);
7162
/* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
7165
long flen, usable_len;
7168
mutex_enter(&srv_monitor_file_mutex);
7169
rewind(srv_monitor_file);
7170
srv_printf_innodb_monitor(srv_monitor_file,
7171
&trx_list_start, &trx_list_end);
7172
flen = ftell(srv_monitor_file);
7173
os_file_set_eof(srv_monitor_file);
7179
if (flen > MAX_STATUS_SIZE) {
7180
usable_len = MAX_STATUS_SIZE;
7185
/* allocate buffer for the string, and
7186
read the contents of the temporary file */
7188
if (!(str = (char*) malloc(usable_len + 1))) {
7189
mutex_exit(&srv_monitor_file_mutex);
7193
rewind(srv_monitor_file);
7194
if (flen < MAX_STATUS_SIZE) {
7195
/* Display the entire output. */
7196
flen = (long) fread(str, 1, flen, srv_monitor_file);
7197
} else if (trx_list_end < (ulint) flen
7198
&& trx_list_start < trx_list_end
7199
&& trx_list_start + (flen - trx_list_end)
7200
< MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
7201
/* Omit the beginning of the list of active transactions. */
7202
long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
7203
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
7204
len += sizeof truncated_msg - 1;
7205
usable_len = (MAX_STATUS_SIZE - 1) - len;
7206
fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
7207
len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
7210
/* Omit the end of the output. */
7211
flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
7214
mutex_exit(&srv_monitor_file_mutex);
7216
bool result = FALSE;
7218
if (stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
7219
STRING_WITH_LEN(""), str, flen)) {
7227
/************************************************************************//**
7228
Implements the SHOW MUTEX STATUS command. . */
7231
innodb_mutex_show_status(
7232
/*=====================*/
7233
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7234
Session* session, /*!< in: the MySQL query thread of the
7236
stat_print_fn* stat_print)
7238
char buf1[IO_SIZE], buf2[IO_SIZE];
7242
ulint rw_lock_count= 0;
7243
ulint rw_lock_count_spin_loop= 0;
7244
ulint rw_lock_count_spin_rounds= 0;
7245
ulint rw_lock_count_os_wait= 0;
7246
ulint rw_lock_count_os_yield= 0;
7247
uint64_t rw_lock_wait_time= 0;
7248
#endif /* UNIV_DEBUG */
7249
uint engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
7250
assert(engine == innodb_engine_ptr);
7252
mutex_enter(&mutex_list_mutex);
7254
mutex = UT_LIST_GET_FIRST(mutex_list);
7256
while (mutex != NULL) {
7257
if (mutex->count_os_wait == 0
7258
|| buf_pool_is_block_mutex(mutex)) {
7262
if (mutex->mutex_type != 1) {
7263
if (mutex->count_using > 0) {
7264
buf1len= my_snprintf(buf1, sizeof(buf1),
7266
mutex->cmutex_name, mutex->cfile_name);
7267
buf2len= my_snprintf(buf2, sizeof(buf2),
7268
"count=%lu, spin_waits=%lu,"
7269
" spin_rounds=%lu, "
7270
"os_waits=%lu, os_yields=%lu,"
7271
" os_wait_times=%lu",
7273
mutex->count_spin_loop,
7274
mutex->count_spin_rounds,
7275
mutex->count_os_wait,
7276
mutex->count_os_yield,
7277
(ulong) (mutex->lspent_time/1000));
7279
if (stat_print(session, innobase_engine_name,
7280
engine_name_len, buf1, buf1len,
7282
mutex_exit(&mutex_list_mutex);
7288
rw_lock_count += mutex->count_using;
7289
rw_lock_count_spin_loop += mutex->count_spin_loop;
7290
rw_lock_count_spin_rounds += mutex->count_spin_rounds;
7291
rw_lock_count_os_wait += mutex->count_os_wait;
7292
rw_lock_count_os_yield += mutex->count_os_yield;
7293
rw_lock_wait_time += mutex->lspent_time;
7295
#else /* UNIV_DEBUG */
7296
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7297
mutex->cfile_name, (ulong) mutex->cline);
7298
buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
7299
mutex->count_os_wait);
7301
if (stat_print(session, innobase_engine_name,
7302
engine_name_len, buf1, buf1len,
7304
mutex_exit(&mutex_list_mutex);
7307
#endif /* UNIV_DEBUG */
7310
mutex = UT_LIST_GET_NEXT(list, mutex);
7313
mutex_exit(&mutex_list_mutex);
7315
mutex_enter(&rw_lock_list_mutex);
7317
lock = UT_LIST_GET_FIRST(rw_lock_list);
7319
while (lock != NULL) {
7320
if (lock->count_os_wait
7321
&& !buf_pool_is_block_lock(lock)) {
7322
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7323
lock->cfile_name, (unsigned long) lock->cline);
7324
buf2len= snprintf(buf2, sizeof(buf2),
7325
"os_waits=%lu", lock->count_os_wait);
7327
if (stat_print(session, innobase_engine_name,
7328
engine_name_len, buf1, buf1len,
7330
mutex_exit(&rw_lock_list_mutex);
7334
lock = UT_LIST_GET_NEXT(list, lock);
7337
mutex_exit(&rw_lock_list_mutex);
7340
buf2len= my_snprintf(buf2, sizeof(buf2),
7341
"count=%lu, spin_waits=%lu, spin_rounds=%lu, "
7342
"os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
7343
rw_lock_count, rw_lock_count_spin_loop,
7344
rw_lock_count_spin_rounds,
7345
rw_lock_count_os_wait, rw_lock_count_os_yield,
7346
(ulong) (rw_lock_wait_time/1000));
7348
if (stat_print(session, innobase_engine_name, engine_name_len,
7349
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
7352
#endif /* UNIV_DEBUG */
7357
bool InnobaseEngine::show_status(Session* session,
7358
stat_print_fn* stat_print,
7359
enum ha_stat_type stat_type)
7361
assert(this == innodb_engine_ptr);
7363
switch (stat_type) {
7364
case HA_ENGINE_STATUS:
7365
return innodb_show_status(this, session, stat_print);
7366
case HA_ENGINE_MUTEX:
7367
return innodb_mutex_show_status(this, session, stat_print);
7373
/************************************************************************//**
7374
Handling the shared INNOBASE_SHARE structure that is needed to provide table
7376
****************************************************************************/
7378
static INNOBASE_SHARE* get_share(const char* table_name)
7380
INNOBASE_SHARE *share;
7381
pthread_mutex_lock(&innobase_share_mutex);
7383
ulint fold = ut_fold_string(table_name);
7385
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7386
INNOBASE_SHARE*, share,
7387
ut_ad(share->use_count > 0),
7388
!strcmp(share->table_name, table_name));
7392
uint length = (uint) strlen(table_name);
7394
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
7397
share = (INNOBASE_SHARE *) malloc(sizeof(*share)+length+1);
7398
memset(share, 0, sizeof(*share)+length+1);
7400
share->table_name = (char*) memcpy(share + 1,
7401
table_name, length + 1);
7403
HASH_INSERT(INNOBASE_SHARE, table_name_hash,
7404
innobase_open_tables, fold, share);
7406
thr_lock_init(&share->lock);
7410
pthread_mutex_unlock(&innobase_share_mutex);
7415
static void free_share(INNOBASE_SHARE* share)
7417
pthread_mutex_lock(&innobase_share_mutex);
7420
INNOBASE_SHARE* share2;
7421
ulint fold = ut_fold_string(share->table_name);
7423
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7424
INNOBASE_SHARE*, share2,
7425
ut_ad(share->use_count > 0),
7426
!strcmp(share->table_name, share2->table_name));
7428
ut_a(share2 == share);
7429
#endif /* UNIV_DEBUG */
7431
if (!--share->use_count) {
7432
ulint fold = ut_fold_string(share->table_name);
7434
HASH_DELETE(INNOBASE_SHARE, table_name_hash,
7435
innobase_open_tables, fold, share);
7436
thr_lock_delete(&share->lock);
7439
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
7443
pthread_mutex_unlock(&innobase_share_mutex);
7446
/*****************************************************************//**
7447
Converts a MySQL table lock stored in the 'lock' field of the handle to
7448
a proper type before storing pointer to the lock into an array of pointers.
7449
MySQL also calls this if it wants to reset some table locks to a not-locked
7450
state during the processing of an SQL query. An example is that during a
7451
SELECT the read lock is released early on the 'const' tables where we only
7452
fetch one row. MySQL does not call this when it releases all locks at the
7453
end of an SQL statement.
7454
@return pointer to the next element in the 'to' array */
7457
ha_innobase::store_lock(
7458
/*====================*/
7459
Session* session, /*!< in: user thread handle */
7460
THR_LOCK_DATA** to, /*!< in: pointer to an array
7461
of pointers to lock structs;
7462
pointer to the 'lock' field
7463
of current handle is stored
7464
next to this array */
7465
enum thr_lock_type lock_type) /*!< in: lock type to store in
7466
'lock'; this may also be
7471
/* Note that trx in this function is NOT necessarily prebuilt->trx
7472
because we call update_session() later, in ::external_lock()! Failure to
7473
understand this caused a serious memory corruption bug in 5.1.11. */
7475
trx = check_trx_exists(session);
7477
assert(EQ_CURRENT_SESSION(session));
7478
const uint32_t sql_command = session_sql_command(session);
7480
if (sql_command == SQLCOM_DROP_TABLE) {
7482
/* MySQL calls this function in DROP Table though this table
7483
handle may belong to another session that is running a query.
7484
Let us in that case skip any changes to the prebuilt struct. */
7486
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
7487
|| lock_type == TL_READ_NO_INSERT
7488
|| (lock_type != TL_IGNORE
7489
&& sql_command != SQLCOM_SELECT)) {
7491
/* The OR cases above are in this order:
7492
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
7493
are processing a stored procedure or function, or
7494
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
7495
3) this is a SELECT ... IN SHARE MODE, or
7496
4) we are doing a complex SQL statement like
7497
INSERT INTO ... SELECT ... and the logical logging (MySQL
7498
binlog) requires the use of a locking read, or
7499
MySQL is doing LOCK TABLES ... READ.
7500
5) we let InnoDB do locking reads for all SQL statements that
7501
are not simple SELECTs; note that select_lock_type in this
7502
case may get strengthened in ::external_lock() to LOCK_X.
7503
Note that we MUST use a locking read in all data modifying
7504
SQL statements, because otherwise the execution would not be
7505
serializable, and also the results from the update could be
7506
unexpected if an obsolete consistent read view would be
7509
ulint isolation_level;
7511
isolation_level = trx->isolation_level;
7513
if ((srv_locks_unsafe_for_binlog
7514
|| isolation_level == TRX_ISO_READ_COMMITTED)
7515
&& isolation_level != TRX_ISO_SERIALIZABLE
7516
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
7517
&& (sql_command == SQLCOM_INSERT_SELECT
7518
|| sql_command == SQLCOM_UPDATE
7519
|| sql_command == SQLCOM_CREATE_TABLE)) {
7521
/* If we either have innobase_locks_unsafe_for_binlog
7522
option set or this session is using READ COMMITTED
7523
isolation level and isolation level of the transaction
7524
is not set to serializable and MySQL is doing
7525
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
7526
CREATE ... SELECT... without FOR UPDATE or
7527
IN SHARE MODE in select, then we use consistent
7530
prebuilt->select_lock_type = LOCK_NONE;
7531
prebuilt->stored_select_lock_type = LOCK_NONE;
7532
} else if (sql_command == SQLCOM_CHECKSUM) {
7533
/* Use consistent read for checksum table */
7535
prebuilt->select_lock_type = LOCK_NONE;
7536
prebuilt->stored_select_lock_type = LOCK_NONE;
7538
prebuilt->select_lock_type = LOCK_S;
7539
prebuilt->stored_select_lock_type = LOCK_S;
7542
} else if (lock_type != TL_IGNORE) {
7544
/* We set possible LOCK_X value in external_lock, not yet
7545
here even if this would be SELECT ... FOR UPDATE */
7547
prebuilt->select_lock_type = LOCK_NONE;
7548
prebuilt->stored_select_lock_type = LOCK_NONE;
7551
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
7553
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
7554
TABLESPACE or TRUNCATE TABLE then allow multiple
7555
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
7556
< TL_WRITE_CONCURRENT_INSERT.
7559
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
7560
&& lock_type <= TL_WRITE)
7561
&& !session_tablespace_op(session)
7562
&& sql_command != SQLCOM_TRUNCATE
7563
&& sql_command != SQLCOM_CREATE_TABLE) {
7565
lock_type = TL_WRITE_ALLOW_WRITE;
7568
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
7569
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
7570
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
7571
to t2. Convert the lock to a normal read lock to allow
7572
concurrent inserts to t2.
7575
if (lock_type == TL_READ_NO_INSERT) {
7577
lock_type = TL_READ;
7580
lock.type = lock_type;
7588
/*********************************************************************//**
7589
Read the next autoinc value. Acquire the relevant locks before reading
7590
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
7591
on return and all relevant locks acquired.
7592
@return DB_SUCCESS or error code */
7595
ha_innobase::innobase_get_autoinc(
7596
/*==============================*/
7597
uint64_t* value) /*!< out: autoinc value */
7601
prebuilt->autoinc_error = innobase_lock_autoinc();
7603
if (prebuilt->autoinc_error == DB_SUCCESS) {
7605
/* Determine the first value of the interval */
7606
*value = dict_table_autoinc_read(prebuilt->table);
7608
/* It should have been initialized during open. */
7612
return(prebuilt->autoinc_error);
7615
/*******************************************************************//**
7616
This function reads the global auto-inc counter. It doesn't use the
7617
AUTOINC lock even if the lock mode is set to TRADITIONAL.
7618
@return the autoinc value */
7621
ha_innobase::innobase_peek_autoinc(void)
7622
/*====================================*/
7625
dict_table_t* innodb_table;
7627
ut_a(prebuilt != NULL);
7628
ut_a(prebuilt->table != NULL);
7630
innodb_table = prebuilt->table;
7632
dict_table_autoinc_lock(innodb_table);
7634
auto_inc = dict_table_autoinc_read(innodb_table);
7638
dict_table_autoinc_unlock(innodb_table);
7643
/*********************************************************************//**
7644
This function initializes the auto-inc counter if it has not been
7645
initialized yet. This function does not change the value of the auto-inc
7646
counter if it already has been initialized. Returns the value of the
7647
auto-inc counter in *first_value, and UINT64_T_MAX in *nb_reserved_values (as
7648
we have a table-level lock). offset, increment, nb_desired_values are ignored.
7649
*first_value is set to -1 if error (deadlock or lock wait timeout) */
7652
ha_innobase::get_auto_increment(
7653
/*============================*/
7654
uint64_t offset, /*!< in: table autoinc offset */
7655
uint64_t increment, /*!< in: table autoinc increment */
7656
uint64_t nb_desired_values, /*!< in: number of values reqd */
7657
uint64_t *first_value, /*!< out: the autoinc value */
7658
uint64_t *nb_reserved_values) /*!< out: count of reserved values */
7662
uint64_t autoinc = 0;
7664
/* Prepare prebuilt->trx in the table handle */
7665
update_session(ha_session());
7667
error = innobase_get_autoinc(&autoinc);
7669
if (error != DB_SUCCESS) {
7670
*first_value = (~(uint64_t) 0);
7674
/* This is a hack, since nb_desired_values seems to be accurate only
7675
for the first call to get_auto_increment() for multi-row INSERT and
7676
meaningless for other statements e.g, LOAD etc. Subsequent calls to
7677
this method for the same statement results in different values which
7678
don't make sense. Therefore we store the value the first time we are
7679
called and count down from that as rows are written (see write_row()).
7682
trx = prebuilt->trx;
7684
/* Note: We can't rely on *first_value since some MySQL engines,
7685
in particular the partition engine, don't initialize it to 0 when
7686
invoking this method. So we are not sure if it's guaranteed to
7689
/* Called for the first time ? */
7690
if (trx->n_autoinc_rows == 0) {
7692
trx->n_autoinc_rows = (ulint) nb_desired_values;
7694
/* It's possible for nb_desired_values to be 0:
7695
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
7696
if (nb_desired_values == 0) {
7698
trx->n_autoinc_rows = 1;
7701
set_if_bigger(*first_value, autoinc);
7702
/* Not in the middle of a mult-row INSERT. */
7703
} else if (prebuilt->autoinc_last_value == 0) {
7704
set_if_bigger(*first_value, autoinc);
7707
*nb_reserved_values = trx->n_autoinc_rows;
7709
/* With old style AUTOINC locking we only update the table's
7710
AUTOINC counter after attempting to insert the row. */
7711
if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
7713
uint64_t next_value;
7714
uint64_t col_max_value;
7716
/* We need the upper limit of the col type to check for
7717
whether we update the table autoinc counter or not. */
7718
col_max_value = innobase_get_int_col_max_value(
7719
table->next_number_field);
7721
need = *nb_reserved_values * increment;
7723
/* Compute the last value in the interval */
7724
next_value = innobase_next_autoinc(
7725
*first_value, need, offset, col_max_value);
7727
prebuilt->autoinc_last_value = next_value;
7729
if (prebuilt->autoinc_last_value < *first_value) {
7730
*first_value = (~(unsigned long long) 0);
7732
/* Update the table autoinc variable */
7733
dict_table_autoinc_update_if_greater(
7734
prebuilt->table, prebuilt->autoinc_last_value);
7737
/* This will force write_row() into attempting an update
7738
of the table's AUTOINC counter. */
7739
prebuilt->autoinc_last_value = 0;
7742
/* The increment to be used to increase the AUTOINC value, we use
7743
this in write_row() and update_row() to increase the autoinc counter
7744
for columns that are filled by the user. We need the offset and
7746
prebuilt->autoinc_offset = offset;
7747
prebuilt->autoinc_increment = increment;
7749
dict_table_autoinc_unlock(prebuilt->table);
7752
/*******************************************************************//**
7753
Reset the auto-increment counter to the given value, i.e. the next row
7754
inserted will get the given value. This is called e.g. after TRUNCATE
7755
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
7756
returned by storage engines that don't support this operation.
7757
@return 0 or error code */
7760
ha_innobase::reset_auto_increment(
7761
/*==============================*/
7762
uint64_t value) /*!< in: new value for table autoinc */
7766
update_session(ha_session());
7768
error = row_lock_table_autoinc_for_mysql(prebuilt);
7770
if (error != DB_SUCCESS) {
7771
error = convert_error_code_to_mysql(error,
7772
prebuilt->table->flags,
7778
/* The next value can never be 0. */
7783
innobase_reset_autoinc(value);
7788
/* See comment in Cursor.cc */
7791
InnobaseEngine::get_error_message(int, String *buf)
7793
trx_t* trx = check_trx_exists(current_session);
7795
buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
7796
system_charset_info);
7801
/*******************************************************************//**
7802
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
7803
If there is no explicitly declared non-null unique key or a primary key, then
7804
InnoDB internally uses the row id as the primary key.
7805
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
7808
ha_innobase::cmp_ref(
7809
/*=================*/
7810
const unsigned char* ref1, /*!< in: an (internal) primary key value in the
7811
MySQL key value format */
7812
const unsigned char* ref2) /*!< in: an (internal) primary key value in the
7813
MySQL key value format */
7815
enum_field_types mysql_type;
7817
KEY_PART_INFO* key_part;
7818
KEY_PART_INFO* key_part_end;
7823
if (prebuilt->clust_index_was_generated) {
7824
/* The 'ref' is an InnoDB row id */
7826
return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
7829
/* Do a type-aware comparison of primary key fields. PK fields
7830
are always NOT NULL, so no checks for NULL are performed. */
7832
key_part = table->key_info[table->s->primary_key].key_part;
7834
key_part_end = key_part
7835
+ table->key_info[table->s->primary_key].key_parts;
7837
for (; key_part != key_part_end; ++key_part) {
7838
field = key_part->field;
7839
mysql_type = field->type();
7841
if (mysql_type == DRIZZLE_TYPE_BLOB) {
7843
/* In the MySQL key value format, a column prefix of
7844
a BLOB is preceded by a 2-byte length field */
7846
len1 = innobase_read_from_2_little_endian(ref1);
7847
len2 = innobase_read_from_2_little_endian(ref2);
7851
result = ((Field_blob*)field)->cmp( ref1, len1,
7854
result = field->key_cmp(ref1, ref2);
7862
ref1 += key_part->store_length;
7863
ref2 += key_part->store_length;
7869
/**********************************************************************
7870
This function is used to find the storage length in bytes of the first n
7871
characters for prefix indexes using a multibyte character set. The function
7872
finds charset information and returns length of prefix_len characters in the
7873
index field in bytes.
7874
@return number of bytes occupied by the first n characters */
7875
extern "C" UNIV_INTERN
7877
innobase_get_at_most_n_mbchars(
7878
/*===========================*/
7879
ulint charset_id, /*!< in: character set id */
7880
ulint prefix_len, /*!< in: prefix length in bytes of the index
7881
(this has to be divided by mbmaxlen to get the
7882
number of CHARACTERS n in the prefix) */
7883
ulint data_len, /*!< in: length of the string in bytes */
7884
const char* str); /*!< in: character string */
7887
innobase_get_at_most_n_mbchars(
7888
/*===========================*/
7889
ulint charset_id, /*!< in: character set id */
7890
ulint prefix_len, /*!< in: prefix length in bytes of the index
7891
(this has to be divided by mbmaxlen to get the
7892
number of CHARACTERS n in the prefix) */
7893
ulint data_len, /*!< in: length of the string in bytes */
7894
const char* str) /*!< in: character string */
7896
ulint char_length; /*!< character length in bytes */
7897
ulint n_chars; /*!< number of characters in prefix */
7898
const CHARSET_INFO* charset; /*!< charset used in the field */
7900
charset = get_charset((uint) charset_id);
7903
ut_ad(charset->mbmaxlen);
7905
/* Calculate how many characters at most the prefix index contains */
7907
n_chars = prefix_len / charset->mbmaxlen;
7909
/* If the charset is multi-byte, then we must find the length of the
7910
first at most n chars in the string. If the string contains less
7911
characters than n, then we return the length to the end of the last
7914
if (charset->mbmaxlen > 1) {
7915
/* my_charpos() returns the byte length of the first n_chars
7916
characters, or a value bigger than the length of str, if
7917
there were not enough full characters in str.
7919
Why does the code below work:
7920
Suppose that we are looking for n UTF-8 characters.
7922
1) If the string is long enough, then the prefix contains at
7923
least n complete UTF-8 characters + maybe some extra
7924
characters + an incomplete UTF-8 character. No problem in
7925
this case. The function returns the pointer to the
7926
end of the nth character.
7928
2) If the string is not long enough, then the string contains
7929
the complete value of a column, that is, only complete UTF-8
7930
characters, and we can store in the column prefix index the
7933
char_length = my_charpos(charset, str,
7934
str + data_len, (int) n_chars);
7935
if (char_length > data_len) {
7936
char_length = data_len;
7939
if (data_len < prefix_len) {
7940
char_length = data_len;
7942
char_length = prefix_len;
7946
return(char_length);
7949
* We will also use this function to communicate
7950
* to InnoDB that a new SQL statement has started and that we must store a
7951
* savepoint to our transaction handle, so that we are able to roll back
7952
* the SQL statement in case of an error.
7955
InnobaseEngine::doStartStatement(
7956
Session *session) /*!< in: handle to the Drizzle session */
7959
* Create the InnoDB transaction structure
7962
trx_t *trx= check_trx_exists(session);
7964
/* "reset" the error message for the transaction */
7965
trx->detailed_error[0]= '\0';
7967
/* Set the isolation level of the transaction. */
7968
trx->isolation_level= innobase_map_isolation_level((enum_tx_isolation) session_tx_isolation(session));
7972
InnobaseEngine::doEndStatement(
7975
trx_t *trx= check_trx_exists(session);
7977
/* Release a possible FIFO ticket and search latch. Since we
7978
may reserve the kernel mutex, we have to release the search
7979
system latch first to obey the latching order. */
7981
innobase_release_stat_resources(trx);
7983
if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
7985
if (trx->conc_state != TRX_NOT_STARTED)
7987
commit(session, TRUE);
7992
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
7993
trx->global_read_view)
7995
/* At low transaction isolation levels we let
7996
each consistent read set its own snapshot */
7997
read_view_close_for_mysql(trx);
8002
/*******************************************************************//**
8003
This function is used to prepare an X/Open XA distributed transaction.
8004
@return 0 or error number */
8006
InnobaseEngine::doXaPrepare(
8007
/*================*/
8008
Session* session,/*!< in: handle to the MySQL thread of
8009
the user whose XA transaction should
8011
bool all) /*!< in: TRUE - commit transaction
8012
FALSE - the current SQL statement
8016
trx_t* trx = check_trx_exists(session);
8018
assert(this == innodb_engine_ptr);
8020
/* we use support_xa value as it was seen at transaction start
8021
time, not the current session variable value. Any possible changes
8022
to the session variable take effect only in the next transaction */
8023
if (!trx->support_xa) {
8028
session_get_xid(session, reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
8030
/* Release a possible FIFO ticket and search latch. Since we will
8031
reserve the kernel mutex, we have to release the search system latch
8032
first to obey the latching order. */
8034
innobase_release_stat_resources(trx);
8037
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
8039
/* We were instructed to prepare the whole transaction, or
8040
this is an SQL statement end and autocommit is on */
8042
ut_ad(trx->conc_state != TRX_NOT_STARTED);
8044
error = (int) trx_prepare_for_mysql(trx);
8046
/* We just mark the SQL statement ended and do not do a
8047
transaction prepare */
8049
/* If we had reserved the auto-inc lock for some
8050
table in this SQL statement we release it now */
8052
row_unlock_table_autoinc_for_mysql(trx);
8054
/* Store the current undo_no of the transaction so that we
8055
know where to roll back if we have to roll back the next
8058
trx_mark_sql_stat_end(trx);
8061
/* Tell the InnoDB server that there might be work for utility
8064
srv_active_wake_master_thread();
8066
if (all || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
8069
/* For ibbackup to work the order of transactions in binlog
8070
and InnoDB must be the same. Consider the situation
8072
thread1> prepare; write to binlog; ...
8074
thread2> prepare; write to binlog; commit
8077
To ensure this will not happen we're taking the mutex on
8078
prepare, and releasing it on commit.
8080
Note: only do it for normal commits, done via ha_commit_trans.
8081
If 2pc protocol is executed by external transaction
8082
coordinator, it will be just a regular MySQL client
8083
executing XA PREPARE and XA COMMIT commands.
8084
In this case we cannot know how many minutes or hours
8085
will be between XA PREPARE and XA COMMIT, and we don't want
8086
to block for undefined period of time.
8088
pthread_mutex_lock(&prepare_commit_mutex);
8089
trx->conc_state = TRX_PREPARED;
8094
/*******************************************************************//**
8095
This function is used to recover X/Open XA distributed transactions.
8096
@return number of prepared transactions stored in xid_list */
8098
InnobaseEngine::doXaRecover(
8099
/*================*/
8100
::drizzled::XID* xid_list,/*!< in/out: prepared transactions */
8101
size_t len) /*!< in: number of slots in xid_list */
8103
assert(this == innodb_engine_ptr);
8105
if (len == 0 || xid_list == NULL) {
8110
return(trx_recover_for_mysql((::XID *)xid_list, len));
8113
/*******************************************************************//**
8114
This function is used to commit one X/Open XA distributed transaction
8115
which is in the prepared state
8116
@return 0 or error number */
8118
InnobaseEngine::doXaCommitXid(
8119
/*===================*/
8120
::drizzled::XID* xid) /*!< in: X/Open XA transaction identification */
8124
assert(this == innodb_engine_ptr);
8126
trx = trx_get_trx_by_xid((::XID *)xid);
8129
innobase_commit_low(trx);
8137
/*******************************************************************//**
8138
This function is used to rollback one X/Open XA distributed transaction
8139
which is in the prepared state
8140
@return 0 or error number */
8142
InnobaseEngine::doXaRollbackXid(
8143
/*=====================*/
8144
::drizzled::XID* xid) /*!< in: X/Open XA transaction
8149
assert(this == innodb_engine_ptr);
8151
trx = trx_get_trx_by_xid((::XID *)xid);
8154
return(innobase_rollback_trx(trx));
8161
/************************************************************//**
8162
Validate the file format name and return its corresponding id.
8163
@return valid file format id */
8166
innobase_file_format_name_lookup(
8167
/*=============================*/
8168
const char* format_name) /*!< in: pointer to file format name */
8173
ut_a(format_name != NULL);
8175
/* The format name can contain the format id itself instead of
8176
the name and we check for that. */
8177
format_id = (uint) strtoul(format_name, &endp, 10);
8179
/* Check for valid parse. */
8180
if (*endp == '\0' && *format_name != '\0') {
8182
if (format_id <= DICT_TF_FORMAT_MAX) {
8188
for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
8192
name = trx_sys_file_format_id_to_name(format_id);
8194
if (!innobase_strcasecmp(format_name, name)) {
8201
return(DICT_TF_FORMAT_MAX + 1);
8204
/************************************************************//**
8205
Validate the file format check value, is it one of "on" or "off",
8206
as a side effect it sets the srv_check_file_format_at_startup variable.
8207
@return true if config value one of "on" or "off" */
8210
innobase_file_format_check_on_off(
8211
/*==============================*/
8212
const char* format_check) /*!< in: parameter value */
8216
if (!innobase_strcasecmp(format_check, "off")) {
8218
/* Set the value to disable checking. */
8219
srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
8221
} else if (!innobase_strcasecmp(format_check, "on")) {
8223
/* Set the value to the lowest supported format. */
8224
srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
8232
/************************************************************//**
8233
Validate the file format check config parameters, as a side effect it
8234
sets the srv_check_file_format_at_startup variable.
8235
@return true if valid config value */
8238
innobase_file_format_check_validate(
8239
/*================================*/
8240
const char* format_check) /*!< in: parameter value */
8245
format_id = innobase_file_format_name_lookup(format_check);
8247
if (format_id < DICT_TF_FORMAT_MAX + 1) {
8248
srv_check_file_format_at_startup = format_id;
8256
/*************************************************************//**
8257
Check if it is a valid file format. This function is registered as
8258
a callback with MySQL.
8259
@return 0 for valid file format */
8262
innodb_file_format_name_validate(
8263
/*=============================*/
8264
Session* , /*!< in: thread handle */
8265
drizzle_sys_var* , /*!< in: pointer to system
8267
void* save, /*!< out: immediate result
8268
for update function */
8269
drizzle_value* value) /*!< in: incoming string */
8271
const char* file_format_input;
8272
char buff[STRING_BUFFER_USUAL_SIZE];
8273
int len = sizeof(buff);
8276
ut_a(value != NULL);
8278
file_format_input = value->val_str(value, buff, &len);
8280
if (file_format_input != NULL) {
8283
format_id = innobase_file_format_name_lookup(
8286
if (format_id <= DICT_TF_FORMAT_MAX) {
8288
*static_cast<const char**>(save) = file_format_input;
8293
*static_cast<const char**>(save) = NULL;
8297
/****************************************************************//**
8298
Update the system variable innodb_file_format using the "saved"
8299
value. This function is registered as a callback with MySQL. */
8302
innodb_file_format_name_update(
8303
/*===========================*/
8304
Session* , /*!< in: thread handle */
8305
drizzle_sys_var* , /*!< in: pointer to
8307
void* var_ptr, /*!< out: where the
8308
formal string goes */
8309
const void* save) /*!< in: immediate result
8310
from check function */
8312
const char* format_name;
8314
ut_a(var_ptr != NULL);
8317
format_name = *static_cast<const char*const*>(save);
8322
format_id = innobase_file_format_name_lookup(format_name);
8324
if (format_id <= DICT_TF_FORMAT_MAX) {
8325
srv_file_format = format_id;
8329
*static_cast<const char**>(var_ptr)
8330
= trx_sys_file_format_id_to_name(srv_file_format);
8333
/*************************************************************//**
8334
Check if valid argument to innodb_file_format_check. This
8335
function is registered as a callback with MySQL.
8336
@return 0 for valid file format */
8339
innodb_file_format_check_validate(
8340
/*==============================*/
8341
Session* , /*!< in: thread handle */
8342
drizzle_sys_var* , /*!< in: pointer to system
8344
void* save, /*!< out: immediate result
8345
for update function */
8346
drizzle_value* value) /*!< in: incoming string */
8348
const char* file_format_input;
8349
char buff[STRING_BUFFER_USUAL_SIZE];
8350
int len = sizeof(buff);
8353
ut_a(value != NULL);
8355
file_format_input = value->val_str(value, buff, &len);
8357
if (file_format_input != NULL) {
8359
/* Check if user set on/off, we want to print a suitable
8360
message if they did so. */
8362
if (innobase_file_format_check_on_off(file_format_input)) {
8363
errmsg_printf(ERRMSG_LVL_WARN,
8364
"InnoDB: invalid innodb_file_format_check "
8365
"value; on/off can only be set at startup or "
8366
"in the configuration file");
8367
} else if (innobase_file_format_check_validate(
8368
file_format_input)) {
8370
*static_cast<const char**>(save) = file_format_input;
8375
errmsg_printf(ERRMSG_LVL_WARN,
8376
"InnoDB: invalid innodb_file_format_check "
8377
"value; can be any format up to %s "
8378
"or its equivalent numeric id",
8379
trx_sys_file_format_id_to_name(
8380
DICT_TF_FORMAT_MAX));
8384
*static_cast<const char**>(save) = NULL;
8388
/****************************************************************//**
8389
Update the system variable innodb_file_format_check using the "saved"
8390
value. This function is registered as a callback with MySQL. */
8393
innodb_file_format_check_update(
8394
/*============================*/
8395
Session* session, /*!< in: thread handle */
8396
drizzle_sys_var* , /*!< in: pointer to
8398
void* var_ptr, /*!< out: where the
8399
formal string goes */
8400
const void* save) /*!< in: immediate result
8401
from check function */
8403
const char* format_name_in;
8404
const char** format_name_out;
8408
ut_a(var_ptr != NULL);
8410
format_name_in = *static_cast<const char*const*>(save);
8412
if (!format_name_in) {
8417
format_id = innobase_file_format_name_lookup(format_name_in);
8419
if (format_id > DICT_TF_FORMAT_MAX) {
8420
/* DEFAULT is "on", which is invalid at runtime. */
8421
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
8423
"Ignoring SET innodb_file_format=%s",
8428
format_name_out = static_cast<const char**>(var_ptr);
8430
/* Update the max format id in the system tablespace. */
8431
if (trx_sys_file_format_max_set(format_id, format_name_out)) {
8432
ut_print_timestamp(stderr);
8434
" [Info] InnoDB: the file format in the system "
8435
"tablespace is now set to %s.\n", *format_name_out);
8439
/****************************************************************//**
8440
Update the system variable innodb_adaptive_hash_index using the "saved"
8441
value. This function is registered as a callback with MySQL. */
8444
innodb_adaptive_hash_index_update(
8445
/*==============================*/
8446
Session* , /*!< in: thread handle */
8447
drizzle_sys_var* , /*!< in: pointer to
8449
void* , /*!< out: where the
8450
formal string goes */
8451
const void* save) /*!< in: immediate result
8452
from check function */
8454
if (*(bool*) save) {
8455
btr_search_enable();
8457
btr_search_disable();
8461
/*************************************************************//**
8462
Check if it is a valid value of innodb_change_buffering. This function is
8463
registered as a callback with MySQL.
8464
@return 0 for valid innodb_change_buffering */
8467
innodb_change_buffering_validate(
8468
/*=============================*/
8469
Session* , /*!< in: thread handle */
8470
drizzle_sys_var* , /*!< in: pointer to system
8472
void* save, /*!< out: immediate result
8473
for update function */
8474
drizzle_value* value) /*!< in: incoming string */
8476
const char* change_buffering_input;
8477
char buff[STRING_BUFFER_USUAL_SIZE];
8478
int len = sizeof(buff);
8481
ut_a(value != NULL);
8483
change_buffering_input = value->val_str(value, buff, &len);
8485
if (change_buffering_input != NULL) {
8488
for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
8490
if (!innobase_strcasecmp(
8491
change_buffering_input,
8492
innobase_change_buffering_values[use])) {
8493
*(ibuf_use_t*) save = (ibuf_use_t) use;
8502
/****************************************************************//**
8503
Update the system variable innodb_change_buffering using the "saved"
8504
value. This function is registered as a callback with MySQL. */
8507
innodb_change_buffering_update(
8508
/*===========================*/
8509
Session* , /*!< in: thread handle */
8510
drizzle_sys_var* , /*!< in: pointer to
8512
void* var_ptr, /*!< out: where the
8513
formal string goes */
8514
const void* save) /*!< in: immediate result
8515
from check function */
8517
ut_a(var_ptr != NULL);
8519
ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
8521
ibuf_use = *(const ibuf_use_t*) save;
8523
*(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
8526
/* plugin options */
8527
static DRIZZLE_SYSVAR_BOOL(checksums, innobase_use_checksums,
8528
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8529
"Enable InnoDB checksums validation (enabled by default). "
8530
"Disable with --skip-innodb-checksums.",
8533
static DRIZZLE_SYSVAR_STR(data_home_dir, innobase_data_home_dir,
8534
PLUGIN_VAR_READONLY,
8535
"The common part for InnoDB table spaces.",
8538
static DRIZZLE_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
8539
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8540
"Enable InnoDB doublewrite buffer (enabled by default). "
8541
"Disable with --skip-innodb-doublewrite.",
8544
static DRIZZLE_SYSVAR_ULONG(io_capacity, srv_io_capacity,
8545
PLUGIN_VAR_RQCMDARG,
8546
"Number of IOPs the server can do. Tunes the background IO rate",
8547
NULL, NULL, 200, 100, ~0L, 0);
8549
static DRIZZLE_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
8550
PLUGIN_VAR_OPCMDARG,
8551
"Speeds up the shutdown process of the InnoDB storage engine. Possible "
8552
"values are 0, 1 (faster)"
8553
" or 2 (fastest - crash-like)"
8555
NULL, NULL, 1, 0, 2, 0);
8557
static DRIZZLE_SYSVAR_BOOL(file_per_table, srv_file_per_table,
8558
PLUGIN_VAR_NOCMDARG,
8559
"Stores each InnoDB table to an .ibd file in the database dir.",
8562
static DRIZZLE_SYSVAR_STR(file_format, innobase_file_format_name,
8563
PLUGIN_VAR_RQCMDARG,
8564
"File format to use for new tables in .ibd files.",
8565
innodb_file_format_name_validate,
8566
innodb_file_format_name_update, "Antelope");
8568
static DRIZZLE_SYSVAR_STR(file_format_check, innobase_file_format_check,
8569
PLUGIN_VAR_OPCMDARG,
8570
"The highest file format in the tablespace.",
8571
innodb_file_format_check_validate,
8572
innodb_file_format_check_update,
8575
static DRIZZLE_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
8576
PLUGIN_VAR_OPCMDARG,
8577
"Set to 0 (write and flush once per second),"
8578
" 1 (write and flush at each commit)"
8579
" or 2 (write at commit, flush once per second).",
8580
NULL, NULL, 1, 0, 2, 0);
8582
static DRIZZLE_SYSVAR_STR(flush_method, innobase_unix_file_flush_method,
8583
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8584
"With which method to flush data.", NULL, NULL, NULL);
8586
#ifdef UNIV_LOG_ARCHIVE
8587
static DRIZZLE_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
8588
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8589
"Where full logs should be archived.", NULL, NULL, NULL);
8591
static DRIZZLE_SYSVAR_BOOL(log_archive, innobase_log_archive,
8592
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
8593
"Set to 1 if you want to have logs archived.", NULL, NULL, FALSE);
8594
#endif /* UNIV_LOG_ARCHIVE */
8596
static DRIZZLE_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir,
8597
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8598
"Path to InnoDB log files.", NULL, NULL, NULL);
8600
static DRIZZLE_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
8601
PLUGIN_VAR_RQCMDARG,
8602
"Percentage of dirty pages allowed in bufferpool.",
8603
NULL, NULL, 75, 0, 99, 0);
8605
static DRIZZLE_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing,
8606
PLUGIN_VAR_NOCMDARG,
8607
"Attempt flushing dirty pages to avoid IO bursts at checkpoints.",
8610
static DRIZZLE_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
8611
PLUGIN_VAR_RQCMDARG,
8612
"Desired maximum length of the purge queue (0 = no limit)",
8613
NULL, NULL, 0, 0, ~0L, 0);
8615
static DRIZZLE_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
8616
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
8617
"Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
8620
static DRIZZLE_SYSVAR_BOOL(status_file, innobase_create_status_file,
8621
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR,
8622
"Enable SHOW INNODB STATUS output in the innodb_status.<pid> file",
8625
static DRIZZLE_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
8626
PLUGIN_VAR_OPCMDARG,
8627
"Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
8630
static DRIZZLE_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_sample_pages,
8631
PLUGIN_VAR_RQCMDARG,
8632
"The number of index pages to sample when calculating statistics (default 8)",
8633
NULL, NULL, 8, 1, ~0ULL, 0);
8635
static DRIZZLE_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
8636
PLUGIN_VAR_OPCMDARG,
8637
"Enable InnoDB adaptive hash index (enabled by default). "
8638
"Disable with --skip-innodb-adaptive-hash-index.",
8639
NULL, innodb_adaptive_hash_index_update, TRUE);
8641
static DRIZZLE_SYSVAR_ULONG(replication_delay, srv_replication_delay,
8642
PLUGIN_VAR_RQCMDARG,
8643
"Replication thread delay (ms) on the slave server if "
8644
"innodb_thread_concurrency is reached (0 by default)",
8645
NULL, NULL, 0, 0, ~0UL, 0);
8647
static DRIZZLE_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
8648
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8649
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
8650
NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024);
8652
static DRIZZLE_SYSVAR_UINT(autoextend_increment, srv_auto_extend_increment,
8653
PLUGIN_VAR_RQCMDARG,
8654
"Data file autoextend increment in megabytes",
8655
NULL, NULL, 8L, 1L, 1000L, 0);
8657
static DRIZZLE_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
8658
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8659
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
8660
NULL, NULL, 128*1024*1024L, 5*1024*1024L, INT64_MAX, 1024*1024L);
8662
static DRIZZLE_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
8663
PLUGIN_VAR_RQCMDARG,
8664
"Helps in performance tuning in heavily concurrent environments.",
8665
innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0);
8667
static DRIZZLE_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter,
8668
PLUGIN_VAR_RQCMDARG,
8669
"Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
8670
NULL, NULL, 500L, 1L, ~0L, 0);
8672
static DRIZZLE_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
8673
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8674
"Number of file I/O threads in InnoDB.",
8675
NULL, NULL, 4, 4, 64, 0);
8677
static DRIZZLE_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
8678
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8679
"Number of background read I/O threads in InnoDB.",
8680
NULL, NULL, 4, 1, 64, 0);
8682
static DRIZZLE_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
8683
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8684
"Number of background write I/O threads in InnoDB.",
8685
NULL, NULL, 4, 1, 64, 0);
8687
static DRIZZLE_SYSVAR_LONG(force_recovery, innobase_force_recovery,
8688
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8689
"Helps to save your data in case the disk image of the database becomes corrupt.",
8690
NULL, NULL, 0, 0, 6, 0);
8692
static DRIZZLE_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
8693
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8694
"The size of the buffer which InnoDB uses to write log to the log files on disk.",
8695
NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
8697
static DRIZZLE_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
8698
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8699
"Size of each log file in a log group.",
8700
NULL, NULL, 5*1024*1024L, 1*1024*1024L, INT64_MAX, 1024*1024L);
8702
static DRIZZLE_SYSVAR_LONG(log_files_in_group, innobase_log_files_in_group,
8703
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8704
"Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.",
8705
NULL, NULL, 2, 2, 100, 0);
8707
static DRIZZLE_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
8708
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8709
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
8710
NULL, NULL, 1, 1, 10, 0);
8712
static DRIZZLE_SYSVAR_LONG(open_files, innobase_open_files,
8713
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8714
"How many files at the maximum InnoDB keeps open at the same time.",
8715
NULL, NULL, 300L, 10L, LONG_MAX, 0);
8717
static DRIZZLE_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
8718
PLUGIN_VAR_RQCMDARG,
8719
"Count of spin-loop rounds in InnoDB mutexes (30 by default)",
8720
NULL, NULL, 30L, 0L, ~0L, 0);
8722
static DRIZZLE_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay,
8723
PLUGIN_VAR_OPCMDARG,
8724
"Maximum delay between polling for a spin lock (6 by default)",
8725
NULL, NULL, 6L, 0L, ~0L, 0);
8727
static DRIZZLE_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
8728
PLUGIN_VAR_RQCMDARG,
8729
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
8730
NULL, NULL, 0, 0, 1000, 0);
8732
static DRIZZLE_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
8733
PLUGIN_VAR_RQCMDARG,
8734
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep",
8735
NULL, NULL, 10000L, 0L, ~0L, 0);
8737
static DRIZZLE_SYSVAR_STR(data_file_path, innobase_data_file_path,
8738
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8739
"Path to individual files and their sizes.",
8742
static DRIZZLE_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
8743
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8744
"The AUTOINC lock modes supported by InnoDB: "
8745
"0 => Old style AUTOINC locking (for backward"
8747
"1 => New style AUTOINC locking "
8748
"2 => No AUTOINC locking (unsafe for SBR)",
8750
AUTOINC_NO_LOCKING, /* Default setting */
8751
AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */
8752
AUTOINC_NO_LOCKING, 0); /* Maximum value */
8754
static DRIZZLE_SYSVAR_STR(version, innodb_version_str,
8755
PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
8756
"InnoDB version", NULL, NULL, INNODB_VERSION_STR);
8758
static DRIZZLE_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
8759
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8760
"Use OS memory allocator instead of InnoDB's internal memory allocator",
8763
static DRIZZLE_SYSVAR_STR(change_buffering, innobase_change_buffering,
8764
PLUGIN_VAR_RQCMDARG,
8765
"Buffer changes to reduce random access: "
8766
"OFF, ON, inserting, deleting, changing, or purging.",
8767
innodb_change_buffering_validate,
8768
innodb_change_buffering_update, NULL);
8770
static DRIZZLE_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
8771
PLUGIN_VAR_RQCMDARG,
8772
"Number of pages that must be accessed sequentially for InnoDB to"
8773
"trigger a readahead.",
8774
NULL, NULL, 56, 0, 64, 0);
8776
static drizzle_sys_var* innobase_system_variables[]= {
8777
DRIZZLE_SYSVAR(additional_mem_pool_size),
8778
DRIZZLE_SYSVAR(autoextend_increment),
8779
DRIZZLE_SYSVAR(buffer_pool_size),
8780
DRIZZLE_SYSVAR(checksums),
8781
DRIZZLE_SYSVAR(commit_concurrency),
8782
DRIZZLE_SYSVAR(concurrency_tickets),
8783
DRIZZLE_SYSVAR(data_file_path),
8784
DRIZZLE_SYSVAR(data_home_dir),
8785
DRIZZLE_SYSVAR(doublewrite),
8786
DRIZZLE_SYSVAR(fast_shutdown),
8787
DRIZZLE_SYSVAR(file_io_threads),
8788
DRIZZLE_SYSVAR(read_io_threads),
8789
DRIZZLE_SYSVAR(write_io_threads),
8790
DRIZZLE_SYSVAR(file_per_table),
8791
DRIZZLE_SYSVAR(file_format),
8792
DRIZZLE_SYSVAR(file_format_check),
8793
DRIZZLE_SYSVAR(flush_log_at_trx_commit),
8794
DRIZZLE_SYSVAR(flush_method),
8795
DRIZZLE_SYSVAR(force_recovery),
8796
DRIZZLE_SYSVAR(lock_wait_timeout),
8797
#ifdef UNIV_LOG_ARCHIVE
8798
DRIZZLE_SYSVAR(log_arch_dir),
8799
DRIZZLE_SYSVAR(log_archive),
8800
#endif /* UNIV_LOG_ARCHIVE */
8801
DRIZZLE_SYSVAR(log_buffer_size),
8802
DRIZZLE_SYSVAR(log_file_size),
8803
DRIZZLE_SYSVAR(log_files_in_group),
8804
DRIZZLE_SYSVAR(log_group_home_dir),
8805
DRIZZLE_SYSVAR(max_dirty_pages_pct),
8806
DRIZZLE_SYSVAR(max_purge_lag),
8807
DRIZZLE_SYSVAR(adaptive_flushing),
8808
DRIZZLE_SYSVAR(mirrored_log_groups),
8809
DRIZZLE_SYSVAR(open_files),
8810
DRIZZLE_SYSVAR(rollback_on_timeout),
8811
DRIZZLE_SYSVAR(stats_on_metadata),
8812
DRIZZLE_SYSVAR(stats_sample_pages),
8813
DRIZZLE_SYSVAR(adaptive_hash_index),
8814
DRIZZLE_SYSVAR(replication_delay),
8815
DRIZZLE_SYSVAR(status_file),
8816
DRIZZLE_SYSVAR(strict_mode),
8817
DRIZZLE_SYSVAR(support_xa),
8818
DRIZZLE_SYSVAR(sync_spin_loops),
8819
DRIZZLE_SYSVAR(spin_wait_delay),
8820
DRIZZLE_SYSVAR(table_locks),
8821
DRIZZLE_SYSVAR(thread_concurrency),
8822
DRIZZLE_SYSVAR(thread_sleep_delay),
8823
DRIZZLE_SYSVAR(autoinc_lock_mode),
8824
DRIZZLE_SYSVAR(version),
8825
DRIZZLE_SYSVAR(use_sys_malloc),
8826
DRIZZLE_SYSVAR(change_buffering),
8827
DRIZZLE_SYSVAR(read_ahead_threshold),
8828
DRIZZLE_SYSVAR(io_capacity),
8832
DRIZZLE_DECLARE_PLUGIN
8835
innobase_engine_name,
8838
"Supports transactions, row-level locking, and foreign keys",
8840
innobase_init, /* Plugin Init */
8841
innobase_deinit, /* Plugin Deinit */
8842
innobase_system_variables, /* system variables */
8845
DRIZZLE_DECLARE_PLUGIN_END;
8847
int ha_innobase::read_range_first(const key_range *start_key,
8848
const key_range *end_key,
8853
//if (!eq_range_arg)
8854
//in_range_read= TRUE;
8855
res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
8857
// in_range_read= FALSE;
8862
int ha_innobase::read_range_next()
8864
int res= Cursor::read_range_next();
8866
// in_range_read= FALSE;
8870
/** @brief Initialize the default value of innodb_commit_concurrency.
8872
Once InnoDB is running, the innodb_commit_concurrency must not change
8873
from zero to nonzero. (Bug #42101)
8875
The initial default value is 0, and without this extra initialization,
8876
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
8877
to 0, even if it was initially set to nonzero at the command line
8878
or configuration file. */
8881
innobase_commit_concurrency_init_default(void)
8882
/*==========================================*/
8884
DRIZZLE_SYSVAR_NAME(commit_concurrency).def_val
8885
= innobase_commit_concurrency;
8888
#ifdef UNIV_COMPILE_TEST_FUNCS
8890
typedef struct innobase_convert_name_test_struct {
8898
const char* expected;
8899
} innobase_convert_name_test_t;
8902
test_innobase_convert_name()
8907
innobase_convert_name_test_t test_input[] = {
8908
{buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
8909
{buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
8910
{buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
8911
{buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
8912
{buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
8914
{buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8915
{buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8916
{buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8917
{buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8918
{buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
8919
{buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
8920
{buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
8922
{buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
8923
"\"#mysql50#ab\"\"cd\""},
8924
{buf, 17, "ab\"cd", 5, NULL, TRUE,
8925
"\"#mysql50#ab\"\"cd\""},
8926
{buf, 16, "ab\"cd", 5, NULL, TRUE,
8927
"\"#mysql50#ab\"\"c\""},
8928
{buf, 15, "ab\"cd", 5, NULL, TRUE,
8929
"\"#mysql50#ab\"\"\""},
8930
{buf, 14, "ab\"cd", 5, NULL, TRUE,
8932
{buf, 13, "ab\"cd", 5, NULL, TRUE,
8934
{buf, 12, "ab\"cd", 5, NULL, TRUE,
8936
{buf, 11, "ab\"cd", 5, NULL, TRUE,
8938
{buf, 10, "ab\"cd", 5, NULL, TRUE,
8941
{buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
8942
{buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
8943
{buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
8944
{buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
8945
{buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
8946
{buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
8947
{buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
8948
{buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
8949
{buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
8950
/* XXX probably "" is a better result in this case
8951
{buf, 1, "ab/cd", 5, NULL, TRUE, "."},
8953
{buf, 0, "ab/cd", 5, NULL, TRUE, ""},
8956
for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
8962
fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
8963
test_input[i].buflen,
8965
test_input[i].idlen,
8966
test_input[i].expected);
8968
end = innobase_convert_name(
8970
test_input[i].buflen,
8972
test_input[i].idlen,
8973
test_input[i].session,
8974
test_input[i].file_id);
8976
res_len = (size_t) (end - test_input[i].buf);
8978
if (res_len != strlen(test_input[i].expected)) {
8980
fprintf(stderr, "unexpected len of the result: %u, "
8981
"expected: %u\n", (unsigned) res_len,
8982
(unsigned) strlen(test_input[i].expected));
8986
if (memcmp(test_input[i].buf,
8987
test_input[i].expected,
8988
strlen(test_input[i].expected)) != 0
8991
fprintf(stderr, "unexpected result: %.*s, "
8992
"expected: %s\n", (int) res_len,
8994
test_input[i].expected);
8999
fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9002
fprintf(stderr, "FAILED\n\n");
9008
#endif /* UNIV_COMPILE_TEST_FUNCS */