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
- Remove the flag trx->active_trans and look at trx->conc_state
54
- fix savepoint functions to use savepoint storage area
55
- Find out what kind of problems the OS X case-insensitivity causes to
56
table and database names; should we 'normalize' the names like we do
65
#include "drizzled/error.h"
66
#include "drizzled/errmsg_print.h"
67
#include "drizzled/charset_info.h"
68
#include "drizzled/internal/m_string.h"
69
#include "drizzled/internal/my_sys.h"
70
#include "drizzled/my_hash.h"
71
#include "drizzled/my_error.h"
72
#include "drizzled/plugin.h"
73
#include "drizzled/show.h"
74
#include "drizzled/data_home.h"
75
#include "drizzled/error.h"
76
#include "drizzled/field.h"
77
#include "drizzled/charset.h"
78
#include "drizzled/session.h"
79
#include "drizzled/current_session.h"
80
#include "drizzled/table.h"
81
#include "drizzled/field/blob.h"
82
#include "drizzled/field/varstring.h"
83
#include "drizzled/field/timestamp.h"
84
#include "drizzled/plugin/storage_engine.h"
85
#include "drizzled/plugin/info_schema_table.h"
86
#include "drizzled/memory/multi_malloc.h"
87
#include "drizzled/pthread_globals.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"
126
#include "handler0vars.h"
133
#ifndef DRIZZLE_SERVER
134
/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t
135
is defined the same in both builds: the MySQL server and the InnoDB plugin. */
136
extern pthread_mutex_t LOCK_thread_count;
138
#endif /* DRIZZLE_SERVER */
140
/** to protect innobase_open_files */
141
static pthread_mutex_t innobase_share_mutex;
142
/** to force correct commit order in binlog */
143
static pthread_mutex_t prepare_commit_mutex;
144
static ulong commit_threads = 0;
145
static pthread_mutex_t commit_threads_m;
146
static pthread_cond_t commit_cond;
147
static pthread_mutex_t commit_cond_m;
148
static bool innodb_inited = 0;
150
#define INSIDE_HA_INNOBASE_CC
152
/* In the Windows plugin, the return value of current_session is
153
undefined. Map it to NULL. */
154
#if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
155
# undef current_session
156
# define current_session NULL
157
# define EQ_CURRENT_SESSION(session) TRUE
158
#else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
159
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
160
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
162
static drizzled::plugin::StorageEngine* innodb_engine_ptr= NULL;
164
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
165
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
166
static const long AUTOINC_NO_LOCKING = 2;
168
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
169
innobase_log_buffer_size,
170
innobase_additional_mem_pool_size, innobase_file_io_threads,
171
innobase_force_recovery, innobase_open_files,
172
innobase_autoinc_lock_mode;
173
static ulong innobase_commit_concurrency = 0;
174
static ulong innobase_read_io_threads;
175
static ulong innobase_write_io_threads;
178
* @TODO: Turn this into size_t as soon as we have a Variable<size_t>
180
static int64_t innobase_buffer_pool_size, innobase_log_file_size;
182
/* The default values for the following char* start-up parameters
183
are determined in innobase_init below: */
185
static char* innobase_data_home_dir = NULL;
186
static char* innobase_data_file_path = NULL;
187
static char* innobase_log_group_home_dir = NULL;
188
static char* innobase_file_format_name = NULL;
189
static char* innobase_change_buffering = NULL;
191
/* Note: This variable can be set to on/off and any of the supported
192
file formats in the configuration file, but can only be set to any
193
of the supported file formats during runtime. */
194
static char* innobase_file_format_check = NULL;
196
/* The following has a misleading name: starting from 4.0.5, this also
198
static char* innobase_unix_file_flush_method = NULL;
200
/* Below we have boolean-valued start-up parameters, and their default
203
static ulong innobase_fast_shutdown = 1;
204
#ifdef UNIV_LOG_ARCHIVE
205
static my_bool innobase_log_archive = FALSE;
206
static char* innobase_log_arch_dir = NULL;
207
#endif /* UNIV_LOG_ARCHIVE */
208
static my_bool innobase_use_doublewrite = TRUE;
209
static my_bool innobase_use_checksums = TRUE;
210
static my_bool innobase_locks_unsafe_for_binlog = TRUE;
211
static my_bool innobase_rollback_on_timeout = FALSE;
212
static my_bool innobase_create_status_file = FALSE;
213
static my_bool innobase_stats_on_metadata = TRUE;
215
static char* internal_innobase_data_file_path = NULL;
217
static char* innodb_version_str = (char*) INNODB_VERSION_STR;
219
/* The following counter is used to convey information to InnoDB
220
about server activity: in selects it is not sensible to call
221
srv_active_wake_master_thread after each fetch or search, we only do
222
it every INNOBASE_WAKE_INTERVAL'th step. */
224
#define INNOBASE_WAKE_INTERVAL 32
225
static ulong innobase_active_counter = 0;
227
static hash_table_t* innobase_open_tables;
229
#ifdef __NETWARE__ /* some special cleanup for NetWare */
230
bool nw_panic = FALSE;
233
/** Allowed values of innodb_change_buffering */
234
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
235
"none", /* IBUF_USE_NONE */
236
"inserts" /* IBUF_USE_INSERT */
239
/********************************************************************
240
Gives the file extension of an InnoDB single-table tablespace. */
241
static const char* ha_innobase_exts[] = {
246
static INNOBASE_SHARE *get_share(const char *table_name);
247
static void free_share(INNOBASE_SHARE *share);
249
class InnobaseEngine : public drizzled::plugin::StorageEngine
252
InnobaseEngine(string name_arg)
253
: drizzled::plugin::StorageEngine(name_arg,
255
HTON_CAN_INDEX_BLOBS |
256
HTON_PRIMARY_KEY_REQUIRED_FOR_POSITION |
257
HTON_PRIMARY_KEY_IN_READ_INDEX |
258
HTON_PARTIAL_COLUMN_READ |
259
HTON_TABLE_SCAN_ON_INDEX |
261
HTON_HAS_DOES_TRANSACTIONS, sizeof(trx_named_savept_t))
263
table_definition_ext= drizzled::plugin::DEFAULT_DEFINITION_FILE_EXT;
264
addAlias("INNOBASE");
270
/*======================*/
271
/* out: 0 or error number */
272
Session* session); /* in: handle to the MySQL thread of the user
273
whose resources should be free'd */
275
virtual int savepoint_set_hook(Session* session,
277
virtual int savepoint_rollback_hook(Session* session,
279
virtual int savepoint_release_hook(Session* session,
281
virtual int commit(Session* session, bool all);
282
virtual int rollback(Session* session, bool all);
284
/***********************************************************************
285
This function is used to prepare X/Open XA distributed transaction */
290
/* out: 0 or error number */
291
Session* session, /* in: handle to the MySQL thread of the user
292
whose XA transaction should be prepared */
293
bool all); /* in: TRUE - commit transaction
294
FALSE - the current SQL statement ended */
295
/***********************************************************************
296
This function is used to recover X/Open XA distributed transactions */
301
/* out: number of prepared transactions
302
stored in xid_list */
303
XID* xid_list, /* in/out: prepared transactions */
304
uint len); /* in: number of slots in xid_list */
305
/***********************************************************************
306
This function is used to commit one X/Open XA distributed transaction
307
which is in the prepared state */
311
/*===================*/
312
/* out: 0 or error number */
313
XID* xid); /* in: X/Open XA transaction identification */
314
/***********************************************************************
315
This function is used to rollback one X/Open XA distributed transaction
316
which is in the prepared state */
320
/*=====================*/
321
/* out: 0 or error number */
322
XID *xid); /* in: X/Open XA transaction identification */
324
virtual Cursor *create(TableShare &table,
325
drizzled::memory::Root *mem_root)
327
return new (mem_root) ha_innobase(*this, table);
330
/*********************************************************************
331
Removes all tables in the named database inside InnoDB. */
335
/*===================*/
336
/* out: error number */
337
char* path); /* in: database path; inside InnoDB the name
338
of the last directory in the path is used as
339
the database name: for example, in 'mysql/data/test'
340
the database name is 'test' */
342
/*********************************************************************
343
Creates an InnoDB transaction struct for the session if it does not yet have one.
344
Starts a new InnoDB transaction if a transaction is not yet started. And
345
assigns a new snapshot for a consistent read if the transaction does not yet
349
start_consistent_snapshot(
350
/*====================================*/
352
Session* session); /* in: MySQL thread handle of the user for whom
353
the transaction should be committed */
354
/********************************************************************
355
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
356
the logs, and the name of this function should be innobase_checkpoint. */
361
/* out: TRUE if error */
363
/****************************************************************************
364
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
365
Monitor to the client. */
370
Session* session, /* in: the MySQL query thread of the caller */
371
stat_print_fn *stat_print,
372
enum ha_stat_type stat_type);
376
release_temporary_latches(
377
/*===============================*/
379
Session* session); /* in: MySQL thread */
382
const char** bas_ext() const {
383
return(ha_innobase_exts);
386
UNIV_INTERN int doCreateTable(Session *session,
387
const char *table_name,
389
drizzled::message::Table&);
390
UNIV_INTERN int doRenameTable(Session* session,
393
UNIV_INTERN int doDropTable(Session& session, const string table_path);
395
UNIV_INTERN virtual bool get_error_message(int error, String *buf);
397
UNIV_INTERN uint32_t max_supported_keys() const;
398
UNIV_INTERN uint32_t max_supported_key_length() const;
399
UNIV_INTERN uint32_t max_supported_key_part_length() const;
402
UNIV_INTERN uint32_t index_flags(enum ha_key_alg) const
404
return (HA_READ_NEXT |
412
/** @brief Initialize the default value of innodb_commit_concurrency.
414
Once InnoDB is running, the innodb_commit_concurrency must not change
415
from zero to nonzero. (Bug #42101)
417
The initial default value is 0, and without this extra initialization,
418
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
419
to 0, even if it was initially set to nonzero at the command line
420
or configuration file. */
423
innobase_commit_concurrency_init_default(void);
424
/*==========================================*/
426
/************************************************************//**
427
Validate the file format name and return its corresponding id.
428
@return valid file format id */
431
innobase_file_format_name_lookup(
432
/*=============================*/
433
const char* format_name); /*!< in: pointer to file format
435
/************************************************************//**
436
Validate the file format check config parameters, as a side effect it
437
sets the srv_check_file_format_at_startup variable.
438
@return true if one of "on" or "off" */
441
innobase_file_format_check_on_off(
442
/*==============================*/
443
const char* format_check); /*!< in: parameter value */
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 valid config value */
450
innobase_file_format_check_validate(
451
/*================================*/
452
const char* format_check); /*!< in: parameter value */
454
static const char innobase_engine_name[]= "InnoDB";
456
/*************************************************************//**
457
Check for a valid value of innobase_commit_concurrency.
458
@return 0 for valid innodb_commit_concurrency */
461
innobase_commit_concurrency_validate(
462
/*=================================*/
463
Session* , /*!< in: thread handle */
464
drizzle_sys_var* , /*!< in: pointer to system
466
void* save, /*!< out: immediate result
467
for update function */
468
drizzle_value* value) /*!< in: incoming string */
471
ulong commit_concurrency;
473
if (value->val_int(value, &intbuf)) {
474
/* The value is NULL. That is invalid. */
478
*reinterpret_cast<ulong*>(save) = commit_concurrency
479
= static_cast<ulong>(intbuf);
481
/* Allow the value to be updated, as long as it remains zero
483
return(!(!commit_concurrency == !innobase_commit_concurrency));
486
static DRIZZLE_SessionVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
487
"Enable InnoDB support for the XA two-phase commit",
488
/* check_func */ NULL, /* update_func */ NULL,
491
static DRIZZLE_SessionVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
492
"Enable InnoDB locking in LOCK TABLES",
493
/* check_func */ NULL, /* update_func */ NULL,
496
static DRIZZLE_SessionVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
497
"Use strict mode when evaluating create options.",
500
static DRIZZLE_SessionVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
501
"Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
502
NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
505
/***********************************************************************
506
Closes an InnoDB database. */
509
innobase_deinit(drizzled::plugin::Registry ®istry);
511
/*****************************************************************//**
512
Commits a transaction in an InnoDB database. */
517
trx_t* trx); /*!< in: transaction handle */
519
static SHOW_VAR innodb_status_variables[]= {
520
{"buffer_pool_pages_data",
521
(char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
522
{"buffer_pool_pages_dirty",
523
(char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
524
{"buffer_pool_pages_flushed",
525
(char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
526
{"buffer_pool_pages_free",
527
(char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
529
{"buffer_pool_pages_latched",
530
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
531
#endif /* UNIV_DEBUG */
532
{"buffer_pool_pages_misc",
533
(char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
534
{"buffer_pool_pages_total",
535
(char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
536
{"buffer_pool_read_ahead_rnd",
537
(char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
538
{"buffer_pool_read_ahead_seq",
539
(char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG},
540
{"buffer_pool_read_requests",
541
(char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
542
{"buffer_pool_reads",
543
(char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
544
{"buffer_pool_wait_free",
545
(char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
546
{"buffer_pool_write_requests",
547
(char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
549
(char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
550
{"data_pending_fsyncs",
551
(char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
552
{"data_pending_reads",
553
(char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
554
{"data_pending_writes",
555
(char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
557
(char*) &export_vars.innodb_data_read, SHOW_LONG},
559
(char*) &export_vars.innodb_data_reads, SHOW_LONG},
561
(char*) &export_vars.innodb_data_writes, SHOW_LONG},
563
(char*) &export_vars.innodb_data_written, SHOW_LONG},
564
{"dblwr_pages_written",
565
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
567
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
568
{"have_atomic_builtins",
569
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
571
(char*) &export_vars.innodb_log_waits, SHOW_LONG},
572
{"log_write_requests",
573
(char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
575
(char*) &export_vars.innodb_log_writes, SHOW_LONG},
577
(char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
578
{"os_log_pending_fsyncs",
579
(char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
580
{"os_log_pending_writes",
581
(char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
583
(char*) &export_vars.innodb_os_log_written, SHOW_LONG},
585
(char*) &export_vars.innodb_page_size, SHOW_LONG},
587
(char*) &export_vars.innodb_pages_created, SHOW_LONG},
589
(char*) &export_vars.innodb_pages_read, SHOW_LONG},
591
(char*) &export_vars.innodb_pages_written, SHOW_LONG},
592
{"row_lock_current_waits",
593
(char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
595
(char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
596
{"row_lock_time_avg",
597
(char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
598
{"row_lock_time_max",
599
(char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
601
(char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
603
(char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
605
(char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
607
(char*) &export_vars.innodb_rows_read, SHOW_LONG},
609
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
610
{NULL, NULL, SHOW_LONG}
613
/* General functions */
615
/******************************************************************//**
616
Returns true if the thread is the replication thread on the slave
617
server. Used in srv_conc_enter_innodb() to determine if the thread
618
should be allowed to enter InnoDB - the replication thread is treated
619
differently than other threads. Also used in
620
srv_conc_force_exit_innodb().
622
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
624
@return true if session is the replication thread */
625
extern "C" UNIV_INTERN
627
thd_is_replication_slave_thread(
628
/*============================*/
629
void* ) /*!< in: thread handle (Session*) */
634
/******************************************************************//**
635
Save some CPU by testing the value of srv_thread_concurrency in inline
639
innodb_srv_conc_enter_innodb(
640
/*=========================*/
641
trx_t* trx) /*!< in: transaction handle */
643
if (UNIV_LIKELY(!srv_thread_concurrency)) {
648
srv_conc_enter_innodb(trx);
651
/******************************************************************//**
652
Save some CPU by testing the value of srv_thread_concurrency in inline
656
innodb_srv_conc_exit_innodb(
657
/*========================*/
658
trx_t* trx) /*!< in: transaction handle */
660
if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
665
srv_conc_exit_innodb(trx);
668
/******************************************************************//**
669
Releases possible search latch and InnoDB thread FIFO ticket. These should
670
be released at each SQL statement end, and also when mysqld passes the
671
control to the client. It does no harm to release these also in the middle
672
of an SQL statement. */
675
innobase_release_stat_resources(
676
/*============================*/
677
trx_t* trx) /*!< in: transaction object */
679
if (trx->has_search_latch) {
680
trx_search_latch_release_if_reserved(trx);
683
if (trx->declared_to_be_inside_innodb) {
684
/* Release our possible ticket in the FIFO */
686
srv_conc_force_exit_innodb(trx);
690
/******************************************************************//**
691
Returns true if the transaction this thread is processing has edited
692
non-transactional tables. Used by the deadlock detector when deciding
693
which transaction to rollback in case of a deadlock - we try to avoid
694
rolling back transactions that have edited non-transactional tables.
696
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
698
@return true if non-transactional tables have been edited */
699
extern "C" UNIV_INTERN
701
thd_has_edited_nontrans_tables(
702
/*===========================*/
703
void* session) /*!< in: thread handle (Session*) */
705
return((ibool) session_non_transactional_update((Session*) session));
708
/******************************************************************//**
709
Returns true if the thread is executing a SELECT statement.
710
@return true if session is executing SELECT */
711
extern "C" UNIV_INTERN
715
const void* session) /*!< in: thread handle (Session*) */
717
return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
720
/******************************************************************//**
721
Returns true if the thread supports XA,
722
global value of innodb_supports_xa if session is NULL.
723
@return true if session has XA support */
724
extern "C" UNIV_INTERN
728
void* session) /*!< in: thread handle (Session*), or NULL to query
729
the global innodb_supports_xa */
731
return(SessionVAR((Session*) session, support_xa));
734
/******************************************************************//**
735
Returns the lock wait timeout for the current connection.
736
@return the lock wait timeout, in seconds */
737
extern "C" UNIV_INTERN
739
thd_lock_wait_timeout(
740
/*==================*/
741
void* session) /*!< in: thread handle (Session*), or NULL to query
742
the global innodb_lock_wait_timeout */
744
/* According to <drizzle/plugin.h>, passing session == NULL
745
returns the global value of the session variable. */
746
return(SessionVAR((Session*) session, lock_wait_timeout));
749
/********************************************************************//**
750
Obtain the InnoDB transaction of a MySQL thread.
751
@return reference to transaction pointer */
756
Session* session) /*!< in: Drizzle Session */
758
return *(trx_t**) session->getEngineData(innodb_engine_ptr);
761
/********************************************************************//**
762
Call this function when mysqld passes control to the client. That is to
763
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
764
documentation, see Cursor.cc.
767
InnobaseEngine::release_temporary_latches(
768
/*===============================*/
769
Session* session) /*!< in: MySQL thread */
773
assert(this == innodb_engine_ptr);
775
if (!innodb_inited) {
780
trx = session_to_trx(session);
783
innobase_release_stat_resources(trx);
788
/********************************************************************//**
789
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
790
time calls srv_active_wake_master_thread. This function should be used
791
when a single database operation may introduce a small need for
792
server utility activity, like checkpointing. */
795
innobase_active_small(void)
796
/*=======================*/
798
innobase_active_counter++;
800
if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
801
srv_active_wake_master_thread();
805
/********************************************************************//**
806
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
807
about a possible transaction rollback inside InnoDB caused by a lock wait
808
timeout or a deadlock.
809
@return MySQL error code */
810
extern "C" UNIV_INTERN
812
convert_error_code_to_mysql(
813
/*========================*/
814
int error, /*!< in: InnoDB error code */
815
ulint flags, /*!< in: InnoDB table flags, or 0 */
816
Session* session)/*!< in: user thread handle or NULL */
824
return(-1); /* unspecified error */
826
case DB_DUPLICATE_KEY:
827
return(HA_ERR_FOUND_DUPP_KEY);
829
case DB_FOREIGN_DUPLICATE_KEY:
830
return(HA_ERR_FOREIGN_DUPLICATE_KEY);
832
case DB_MISSING_HISTORY:
833
return(HA_ERR_TABLE_DEF_CHANGED);
835
case DB_RECORD_NOT_FOUND:
836
return(HA_ERR_NO_ACTIVE_RECORD);
839
/* Since we rolled back the whole transaction, we must
840
tell it also to MySQL so that MySQL knows to empty the
841
cached binlog for this transaction */
843
session_mark_transaction_to_rollback(session, TRUE);
845
return(HA_ERR_LOCK_DEADLOCK);
847
case DB_LOCK_WAIT_TIMEOUT:
848
/* Starting from 5.0.13, we let MySQL just roll back the
849
latest SQL statement in a lock wait timeout. Previously, we
850
rolled back the whole transaction. */
852
session_mark_transaction_to_rollback(session,
853
(bool)row_rollback_on_timeout);
855
return(HA_ERR_LOCK_WAIT_TIMEOUT);
857
case DB_NO_REFERENCED_ROW:
858
return(HA_ERR_NO_REFERENCED_ROW);
860
case DB_ROW_IS_REFERENCED:
861
return(HA_ERR_ROW_IS_REFERENCED);
863
case DB_CANNOT_ADD_CONSTRAINT:
864
return(HA_ERR_CANNOT_ADD_FOREIGN);
866
case DB_CANNOT_DROP_CONSTRAINT:
868
return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
869
misleading, a new MySQL error
870
code should be introduced */
872
case DB_COL_APPEARS_TWICE_IN_INDEX:
874
return(HA_ERR_CRASHED);
876
case DB_OUT_OF_FILE_SPACE:
877
return(HA_ERR_RECORD_FILE_FULL);
879
case DB_TABLE_IS_BEING_USED:
880
return(HA_ERR_WRONG_COMMAND);
882
case DB_TABLE_NOT_FOUND:
883
return(HA_ERR_NO_SUCH_TABLE);
885
case DB_TOO_BIG_RECORD:
886
my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
887
page_get_free_space_of_empty(flags
888
& DICT_TF_COMPACT) / 2);
889
return(HA_ERR_TO_BIG_ROW);
891
case DB_NO_SAVEPOINT:
892
return(HA_ERR_NO_SAVEPOINT);
894
case DB_LOCK_TABLE_FULL:
895
/* Since we rolled back the whole transaction, we must
896
tell it also to MySQL so that MySQL knows to empty the
897
cached binlog for this transaction */
899
session_mark_transaction_to_rollback(session, TRUE);
901
return(HA_ERR_LOCK_TABLE_FULL);
903
case DB_PRIMARY_KEY_IS_NULL:
904
return(ER_PRIMARY_CANT_HAVE_NULL);
906
case DB_TOO_MANY_CONCURRENT_TRXS:
908
/* Once MySQL add the appropriate code to errmsg.txt then
909
we can get rid of this #ifdef. NOTE: The code checked by
910
the #ifdef is the suggested name for the error condition
911
and the actual error code name could very well be different.
912
This will require some monitoring, ie. the status
913
of this request on our part.*/
914
#ifdef ER_TOO_MANY_CONCURRENT_TRXS
915
return(ER_TOO_MANY_CONCURRENT_TRXS);
917
return(HA_ERR_RECORD_FILE_FULL);
920
return(HA_ERR_UNSUPPORTED);
924
/*************************************************************//**
925
If you want to print a session that is not associated with the current thread,
926
you must call this function before reserving the InnoDB kernel_mutex, to
927
protect Drizzle from setting session->query NULL. If you print a session of the
928
current thread, we know that Drizzle cannot modify sesion->query, and it is
929
not necessary to call this. Call innobase_mysql_end_print_arbitrary_thd()
930
after you release the kernel_mutex.
932
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
935
extern "C" UNIV_INTERN
937
innobase_mysql_prepare_print_arbitrary_thd(void)
938
/*============================================*/
940
ut_ad(!mutex_own(&kernel_mutex));
941
pthread_mutex_lock(&LOCK_thread_count);
944
/*************************************************************//**
945
Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd().
946
In the InnoDB latching order, the mutex sits right above the
947
kernel_mutex. In debug builds, we assert that the kernel_mutex is
948
released before this function is invoked.
950
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking
953
extern "C" UNIV_INTERN
955
innobase_mysql_end_print_arbitrary_thd(void)
956
/*========================================*/
958
ut_ad(!mutex_own(&kernel_mutex));
959
pthread_mutex_unlock(&LOCK_thread_count);
962
/*************************************************************//**
963
Prints info of a Session object (== user session thread) to the given file. */
964
extern "C" UNIV_INTERN
966
innobase_mysql_print_thd(
967
/*=====================*/
968
FILE* f, /*!< in: output stream */
969
void * in_session, /*!< in: pointer to a Drizzle Session object */
970
uint ) /*!< in: max query length to print, or 0 to
971
use the default max length */
973
Session *session= reinterpret_cast<Session *>(in_session);
975
"Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
976
static_cast<uint64_t>(session_get_thread_id( session)),
977
static_cast<uint64_t>(session->getQueryId()),
979
session->security_ctx.ip.c_str(),
980
session->security_ctx.user.c_str()
983
"\n%s", session->getQueryString()
988
/******************************************************************//**
989
Get the variable length bounds of the given character set. */
990
extern "C" UNIV_INTERN
992
innobase_get_cset_width(
993
/*====================*/
994
ulint cset, /*!< in: MySQL charset-collation code */
995
ulint* mbminlen, /*!< out: minimum length of a char (in bytes) */
996
ulint* mbmaxlen) /*!< out: maximum length of a char (in bytes) */
1003
cs = all_charsets[cset];
1005
*mbminlen = cs->mbminlen;
1006
*mbmaxlen = cs->mbmaxlen;
1009
*mbminlen = *mbmaxlen = 0;
1013
/******************************************************************//**
1014
Converts an identifier to a table name. */
1015
extern "C" UNIV_INTERN
1017
innobase_convert_from_table_id(
1018
/*===========================*/
1019
const struct charset_info_st*, /*!< in: the 'from' character set */
1020
char* to, /*!< out: converted identifier */
1021
const char* from, /*!< in: identifier to convert */
1022
ulint len) /*!< in: length of 'to', in bytes */
1024
strncpy(to, from, len);
1027
/******************************************************************//**
1028
Converts an identifier to UTF-8. */
1029
extern "C" UNIV_INTERN
1031
innobase_convert_from_id(
1032
/*=====================*/
1033
const struct charset_info_st*, /*!< in: the 'from' character set */
1034
char* to, /*!< out: converted identifier */
1035
const char* from, /*!< in: identifier to convert */
1036
ulint len) /*!< in: length of 'to', in bytes */
1038
strncpy(to, from, len);
1041
/******************************************************************//**
1042
Compares NUL-terminated UTF-8 strings case insensitively.
1043
@return 0 if a=b, <0 if a<b, >1 if a>b */
1044
extern "C" UNIV_INTERN
1046
innobase_strcasecmp(
1047
/*================*/
1048
const char* a, /*!< in: first string to compare */
1049
const char* b) /*!< in: second string to compare */
1051
return(my_strcasecmp(system_charset_info, a, b));
1054
/******************************************************************//**
1055
Makes all characters in a NUL-terminated UTF-8 string lower case. */
1056
extern "C" UNIV_INTERN
1058
innobase_casedn_str(
1059
/*================*/
1060
char* a) /*!< in/out: string to put in lower case */
1062
my_casedn_str(system_charset_info, a);
1065
/**********************************************************************//**
1066
Determines the connection character set.
1067
@return connection character set */
1068
extern "C" UNIV_INTERN
1069
const charset_info_st*
1070
innobase_get_charset(
1071
/*=================*/
1072
void* mysql_session) /*!< in: MySQL thread handle */
1074
return(session_charset(static_cast<Session*>(mysql_session)));
1077
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1078
/*******************************************************************//**
1079
Map an OS error to an errno value. The OS error number is stored in
1080
_doserrno and the mapped value is stored in errno) */
1084
unsigned long); /*!< in: OS error value */
1086
/*********************************************************************//**
1087
Creates a temporary file.
1088
@return temporary file descriptor, or < 0 on error */
1089
extern "C" UNIV_INTERN
1091
innobase_mysql_tmpfile(void)
1092
/*========================*/
1094
int fd; /* handle of opened file */
1095
HANDLE osfh; /* OS handle of opened file */
1096
char* tmpdir; /* point to the directory
1097
where to create file */
1098
TCHAR path_buf[MAX_PATH - 14]; /* buffer for tmp file path.
1099
The length cannot be longer
1100
than MAX_PATH - 14, or
1101
GetTempFileName will fail. */
1102
char filename[MAX_PATH]; /* name of the tmpfile */
1103
DWORD fileaccess = GENERIC_READ /* OS file access */
1106
DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
1108
| FILE_SHARE_DELETE;
1109
DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
1110
DWORD fileattrib = /* OS file attribute flags */
1111
FILE_ATTRIBUTE_NORMAL
1112
| FILE_FLAG_DELETE_ON_CLOSE
1113
| FILE_ATTRIBUTE_TEMPORARY
1114
| FILE_FLAG_SEQUENTIAL_SCAN;
1116
tmpdir = my_tmpdir(&mysql_tmpdir_list);
1118
/* The tmpdir parameter can not be NULL for GetTempFileName. */
1122
/* Use GetTempPath to determine path for temporary files. */
1123
ret = GetTempPath(sizeof(path_buf), path_buf);
1124
if (ret > sizeof(path_buf) || (ret == 0)) {
1126
_dosmaperr(GetLastError()); /* map error */
1133
/* Use GetTempFileName to generate a unique filename. */
1134
if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
1136
_dosmaperr(GetLastError()); /* map error */
1140
/* Open/Create the file. */
1141
osfh = CreateFile(filename, fileaccess, fileshare, NULL,
1142
filecreate, fileattrib, NULL);
1143
if (osfh == INVALID_HANDLE_VALUE) {
1145
/* open/create file failed! */
1146
_dosmaperr(GetLastError()); /* map error */
1151
/* Associates a CRT file descriptor with the OS file handle. */
1152
fd = _open_osfhandle((intptr_t) osfh, 0);
1153
} while (fd == -1 && errno == EINTR);
1156
/* Open failed, close the file handle. */
1158
_dosmaperr(GetLastError()); /* map error */
1159
CloseHandle(osfh); /* no need to check if
1160
CloseHandle fails */
1166
/*********************************************************************//**
1167
Creates a temporary file.
1168
@return temporary file descriptor, or < 0 on error */
1169
extern "C" UNIV_INTERN
1171
innobase_mysql_tmpfile(void)
1172
/*========================*/
1175
int fd = mysql_tmpfile("ib");
1177
/* Copy the file descriptor, so that the additional resources
1178
allocated by create_temp_file() can be freed by invoking
1181
Because the file descriptor returned by this function
1182
will be passed to fdopen(), it will be closed by invoking
1183
fclose(), which in turn will invoke close() instead of
1188
my_error(EE_OUT_OF_FILERESOURCES,
1189
MYF(ME_BELL+ME_WAITTANG),
1192
my_close(fd, MYF(MY_WME));
1196
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
1199
/*******************************************************************//**
1200
Formats the raw data in "data" (in InnoDB on-disk format) that is of
1201
type DATA_(CHAR|VARCHAR|DRIZZLE|VARDRIZZLE) using "charset_coll" and writes
1202
the result to "buf". The result is converted to "system_charset_info".
1203
Not more than "buf_size" bytes are written to "buf".
1204
The result is always NUL-terminated (provided buf_size > 0) and the
1205
number of bytes that were written to "buf" is returned (including the
1207
@return number of bytes that were written */
1208
extern "C" UNIV_INTERN
1210
innobase_raw_format(
1211
/*================*/
1212
const char* data, /*!< in: raw data */
1213
ulint data_len, /*!< in: raw data length
1215
ulint , /*!< in: charset collation */
1216
char* buf, /*!< out: output buffer */
1217
ulint buf_size) /*!< in: output buffer size
1220
return(ut_str_sql_format(data, data_len, buf, buf_size));
1223
/*********************************************************************//**
1224
Compute the next autoinc value.
1226
For MySQL replication the autoincrement values can be partitioned among
1227
the nodes. The offset is the start or origin of the autoincrement value
1228
for a particular node. For n nodes the increment will be n and the offset
1229
will be in the interval [1, n]. The formula tries to allocate the next
1230
value for a particular node.
1232
Note: This function is also called with increment set to the number of
1233
values we want to reserve for multi-value inserts e.g.,
1235
INSERT INTO T VALUES(), (), ();
1237
innobase_next_autoinc() will be called with increment set to
1238
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
1239
to reserve 3 values for the multi-value INSERT above.
1240
@return the next value */
1243
innobase_next_autoinc(
1244
/*==================*/
1245
uint64_t current, /*!< in: Current value */
1246
uint64_t increment, /*!< in: increment current by */
1247
uint64_t offset, /*!< in: AUTOINC offset */
1248
uint64_t max_value) /*!< in: max value for type */
1250
uint64_t next_value;
1252
/* Should never be 0. */
1253
ut_a(increment > 0);
1255
/* According to MySQL documentation, if the offset is greater than
1256
the increment then the offset is ignored. */
1257
if (offset > increment) {
1261
if (max_value <= current) {
1262
next_value = max_value;
1263
} else if (offset <= 1) {
1264
/* Offset 0 and 1 are the same, because there must be at
1265
least one node in the system. */
1266
if (max_value - current <= increment) {
1267
next_value = max_value;
1269
next_value = current + increment;
1271
} else if (max_value > current) {
1272
if (current > offset) {
1273
next_value = ((current - offset) / increment) + 1;
1275
next_value = ((offset - current) / increment) + 1;
1278
ut_a(increment > 0);
1279
ut_a(next_value > 0);
1281
/* Check for multiplication overflow. */
1282
if (increment > (max_value / next_value)) {
1284
next_value = max_value;
1286
next_value *= increment;
1288
ut_a(max_value >= next_value);
1290
/* Check for overflow. */
1291
if (max_value - next_value <= offset) {
1292
next_value = max_value;
1294
next_value += offset;
1298
next_value = max_value;
1301
ut_a(next_value <= max_value);
1306
/*********************************************************************//**
1307
Initializes some fields in an InnoDB transaction object. */
1312
Session* session, /*!< in: user thread handle */
1313
trx_t* trx) /*!< in/out: InnoDB transaction handle */
1315
assert(session == trx->mysql_thd);
1317
trx->check_foreigns = !session_test_options(
1318
session, OPTION_NO_FOREIGN_KEY_CHECKS);
1320
trx->check_unique_secondary = !session_test_options(
1321
session, OPTION_RELAXED_UNIQUE_CHECKS);
1326
/*********************************************************************//**
1327
Allocates an InnoDB transaction for a MySQL Cursor object.
1328
@return InnoDB transaction handle */
1329
extern "C" UNIV_INTERN
1331
innobase_trx_allocate(
1332
/*==================*/
1333
Session* session) /*!< in: user thread handle */
1337
assert(session != NULL);
1338
assert(EQ_CURRENT_SESSION(session));
1340
trx = trx_allocate_for_mysql();
1342
trx->mysql_thd = session;
1343
trx->mysql_query_str = session_query(session);
1345
innobase_trx_init(session, trx);
1350
/*********************************************************************//**
1351
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1352
an InnoDB transaction struct if the corresponding MySQL thread struct still
1354
@return InnoDB transaction handle */
1359
Session* session) /*!< in: user thread handle */
1361
trx_t*& trx = session_to_trx(session);
1363
ut_ad(EQ_CURRENT_SESSION(session));
1366
trx = innobase_trx_allocate(session);
1367
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1368
mem_analyze_corruption(trx);
1372
innobase_trx_init(session, trx);
1378
/*********************************************************************//**
1379
Construct ha_innobase Cursor. */
1381
ha_innobase::ha_innobase(drizzled::plugin::StorageEngine &engine_arg,
1382
TableShare &table_arg)
1383
:Cursor(engine_arg, table_arg),
1384
primary_key(0), /* needs initialization because index_flags() may be called
1385
before this is set to the real value. It's ok to have any
1386
value here because it doesn't matter if we return the
1387
HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
1392
/*********************************************************************//**
1393
Destruct ha_innobase Cursor. */
1395
ha_innobase::~ha_innobase()
1399
/*********************************************************************//**
1400
Updates the user_thd field in a handle and also allocates a new InnoDB
1401
transaction handle if needed, and updates the transaction fields in the
1405
ha_innobase::update_session(
1406
/*====================*/
1407
Session* session) /*!< in: thd to use the handle */
1411
trx = check_trx_exists(session);
1413
if (prebuilt->trx != trx) {
1415
row_update_prebuilt_trx(prebuilt, trx);
1418
user_session = session;
1421
/*********************************************************************//**
1422
Updates the user_thd field in a handle and also allocates a new InnoDB
1423
transaction handle if needed, and updates the transaction fields in the
1427
ha_innobase::update_session()
1428
/*=====================*/
1430
Session* session = ha_session();
1431
ut_ad(EQ_CURRENT_SESSION(session));
1432
update_session(session);
1435
/*********************************************************************//**
1436
Registers that InnoDB takes part in an SQL statement, so that MySQL knows to
1437
roll back the statement if the statement results in an error. This MUST be
1438
called for every SQL statement that may be rolled back by MySQL. Calling this
1439
several times to register the same statement is allowed, too. */
1442
innobase_register_stmt(
1443
/*===================*/
1444
drizzled::plugin::StorageEngine* engine, /*!< in: Innobase hton */
1445
Session* session) /*!< in: MySQL thd (connection) object */
1447
assert(engine == innodb_engine_ptr);
1448
/* Register the statement */
1449
trans_register_ha(session, FALSE, engine);
1452
/*********************************************************************//**
1453
Registers an InnoDB transaction in MySQL, so that the MySQL XA code knows
1454
to call the InnoDB prepare and commit, or rollback for the transaction. This
1455
MUST be called for every transaction for which the user may call commit or
1456
rollback. Calling this several times to register the same transaction is
1458
This function also registers the current SQL statement. */
1461
innobase_register_trx_and_stmt(
1462
/*===========================*/
1463
drizzled::plugin::StorageEngine *engine, /*!< in: Innobase StorageEngine */
1464
Session* session) /*!< in: MySQL thd (connection) object */
1466
/* NOTE that actually innobase_register_stmt() registers also
1467
the transaction in the AUTOCOMMIT=1 mode. */
1469
innobase_register_stmt(engine, session);
1471
if (session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
1473
/* No autocommit mode, register for a transaction */
1474
trans_register_ha(session, TRUE, engine);
1478
/*****************************************************************//**
1479
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1480
and quote it if needed.
1481
@return pointer to the end of buf */
1484
innobase_convert_identifier(
1485
/*========================*/
1486
char* buf, /*!< out: buffer for converted identifier */
1487
ulint buflen, /*!< in: length of buf, in bytes */
1488
const char* id, /*!< in: identifier to convert */
1489
ulint idlen, /*!< in: length of id, in bytes */
1490
void* session,/*!< in: MySQL connection thread, or NULL */
1491
ibool file_id)/*!< in: TRUE=id is a table or database name;
1492
FALSE=id is an UTF-8 string */
1494
char nz[NAME_LEN + 1];
1495
char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
1501
/* Decode the table name. The filename_to_tablename()
1502
function expects a NUL-terminated string. The input and
1503
output strings buffers must not be shared. */
1505
if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1506
idlen = (sizeof nz) - 1;
1509
memcpy(nz, id, idlen);
1513
idlen = filename_to_tablename(nz, nz2, sizeof nz2);
1516
/* See if the identifier needs to be quoted. */
1517
if (UNIV_UNLIKELY(!session)) {
1520
q = get_quote_char_for_identifier();
1524
if (UNIV_UNLIKELY(idlen > buflen)) {
1527
memcpy(buf, s, idlen);
1528
return(buf + idlen);
1531
/* Quote the identifier. */
1539
for (; idlen; idlen--) {
1541
if (UNIV_UNLIKELY(c == q)) {
1542
if (UNIV_UNLIKELY(buflen < 3)) {
1550
if (UNIV_UNLIKELY(buflen < 2)) {
1563
/*****************************************************************//**
1564
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1565
and quote it if needed.
1566
@return pointer to the end of buf */
1567
extern "C" UNIV_INTERN
1569
innobase_convert_name(
1570
/*==================*/
1571
char* buf, /*!< out: buffer for converted identifier */
1572
ulint buflen, /*!< in: length of buf, in bytes */
1573
const char* id, /*!< in: identifier to convert */
1574
ulint idlen, /*!< in: length of id, in bytes */
1575
void* session,/*!< in: MySQL connection thread, or NULL */
1576
ibool table_id)/*!< in: TRUE=id is a table or database name;
1577
FALSE=id is an index name */
1580
const char* bufend = buf + buflen;
1583
const char* slash = (const char*) memchr(id, '/', idlen);
1589
/* Print the database name and table name separately. */
1590
s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1592
if (UNIV_LIKELY(s < bufend)) {
1594
s = innobase_convert_identifier(s, bufend - s,
1599
} else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1600
/* Temporary index name (smart ALTER TABLE) */
1601
const char temp_index_suffix[]= "--temporary--";
1603
s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1605
if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1606
memcpy(s, temp_index_suffix,
1607
sizeof temp_index_suffix - 1);
1608
s += sizeof temp_index_suffix - 1;
1612
s = innobase_convert_identifier(buf, buflen, id, idlen,
1620
/**********************************************************************//**
1621
Determines if the currently running transaction has been interrupted.
1622
@return TRUE if interrupted */
1623
extern "C" UNIV_INTERN
1627
trx_t* trx) /*!< in: transaction */
1629
return(trx && trx->mysql_thd && session_killed((Session*) trx->mysql_thd));
1632
/**************************************************************//**
1633
Resets some fields of a prebuilt struct. The template is used in fast
1634
retrieval of just those column values MySQL needs in its processing. */
1639
row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1641
prebuilt->keep_other_fields_on_keyread = 0;
1642
prebuilt->read_just_key = 0;
1645
/*****************************************************************//**
1646
Call this when you have opened a new table handle in HANDLER, before you
1647
call index_read_idx() etc. Actually, we can let the cursor stay open even
1648
over a transaction commit! Then you should call this before every operation,
1649
fetch next etc. This function inits the necessary things even after a
1650
transaction commit. */
1653
ha_innobase::init_table_handle_for_HANDLER(void)
1654
/*============================================*/
1656
/* If current session does not yet have a trx struct, create one.
1657
If the current handle does not yet have a prebuilt struct, create
1658
one. Update the trx pointers in the prebuilt struct. Normally
1659
this operation is done in external_lock. */
1661
update_session(ha_session());
1663
/* Initialize the prebuilt struct much like it would be inited in
1666
innobase_release_stat_resources(prebuilt->trx);
1668
/* If the transaction is not started yet, start it */
1670
trx_start_if_not_started(prebuilt->trx);
1672
/* Assign a read view if the transaction does not have it yet */
1674
trx_assign_read_view(prebuilt->trx);
1676
/* Set the MySQL flag to mark that there is an active transaction */
1678
if (prebuilt->trx->active_trans == 0) {
1680
innobase_register_trx_and_stmt(engine, user_session);
1682
prebuilt->trx->active_trans = 1;
1685
/* We did the necessary inits in this function, no need to repeat them
1686
in row_search_for_mysql */
1688
prebuilt->sql_stat_start = FALSE;
1690
/* We let HANDLER always to do the reads as consistent reads, even
1691
if the trx isolation level would have been specified as SERIALIZABLE */
1693
prebuilt->select_lock_type = LOCK_NONE;
1694
prebuilt->stored_select_lock_type = LOCK_NONE;
1696
/* Always fetch all columns in the index record */
1698
prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
1700
/* We want always to fetch all columns in the whole row? Or do
1703
prebuilt->used_in_HANDLER = TRUE;
1704
reset_template(prebuilt);
1707
/*********************************************************************//**
1708
Opens an InnoDB database.
1709
@return 0 on success, error code on failure */
1714
drizzled::plugin::Registry ®istry) /*!< in: Drizzle Plugin Registry */
1716
static char current_dir[3]; /*!< Set if using current lib */
1722
innodb_engine_ptr= new InnobaseEngine(innobase_engine_name);
1725
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
1728
static const char test_filename[] = "-@";
1729
char test_tablename[sizeof test_filename
1730
+ sizeof srv_mysql50_table_name_prefix];
1731
if ((sizeof test_tablename) - 1
1732
!= filename_to_tablename(test_filename, test_tablename,
1733
sizeof test_tablename)
1734
|| strncmp(test_tablename,
1735
srv_mysql50_table_name_prefix,
1736
sizeof srv_mysql50_table_name_prefix)
1737
|| strcmp(test_tablename
1738
+ sizeof srv_mysql50_table_name_prefix,
1740
errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
1743
#endif /* UNIV_DEBUG */
1745
/* Check that values don't overflow on 32-bit systems. */
1746
if (sizeof(ulint) == 4) {
1747
if (innobase_buffer_pool_size > UINT32_MAX) {
1748
errmsg_printf(ERRMSG_LVL_ERROR,
1749
"innobase_buffer_pool_size can't be over 4GB"
1750
" on 32-bit systems");
1755
if (innobase_log_file_size > UINT32_MAX) {
1756
errmsg_printf(ERRMSG_LVL_ERROR,
1757
"innobase_log_file_size can't be over 4GB"
1758
" on 32-bit systems");
1764
os_innodb_umask = (ulint)my_umask;
1766
/* First calculate the default path for innodb_data_home_dir etc.,
1767
in case the user has not given any value.
1769
Note that when using the embedded server, the datadirectory is not
1770
necessarily the current directory of this program. */
1772
/* It's better to use current lib, to keep paths short */
1773
current_dir[0] = FN_CURLIB;
1774
current_dir[1] = FN_LIBCHAR;
1776
default_path = current_dir;
1780
srv_set_thread_priorities = TRUE;
1781
srv_query_thread_priority = QUERY_PRIOR;
1783
/* Set InnoDB initialization parameters according to the values
1784
read from MySQL .cnf file */
1786
/*--------------- Data files -------------------------*/
1788
/* The default dir for data files is the datadir of MySQL */
1790
srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
1793
/* Set default InnoDB data file size to 10 MB and let it be
1794
auto-extending. Thus users can use InnoDB in >= 4.0 without having
1795
to specify any startup options. */
1797
if (!innobase_data_file_path) {
1798
innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
1801
/* Since InnoDB edits the argument in the next call, we make another
1804
internal_innobase_data_file_path = strdup(innobase_data_file_path);
1806
ret = (bool) srv_parse_data_file_paths_and_sizes(
1807
internal_innobase_data_file_path);
1809
errmsg_printf(ERRMSG_LVL_ERROR,
1810
"InnoDB: syntax error in innodb_data_file_path");
1812
srv_free_paths_and_sizes();
1813
if (internal_innobase_data_file_path)
1814
free(internal_innobase_data_file_path);
1818
/* -------------- Log files ---------------------------*/
1820
/* The default dir for log files is the datadir of MySQL */
1822
if (!innobase_log_group_home_dir) {
1823
innobase_log_group_home_dir = default_path;
1826
#ifdef UNIV_LOG_ARCHIVE
1827
/* Since innodb_log_arch_dir has no relevance under MySQL,
1828
starting from 4.0.6 we always set it the same as
1829
innodb_log_group_home_dir: */
1831
innobase_log_arch_dir = innobase_log_group_home_dir;
1833
srv_arch_dir = innobase_log_arch_dir;
1834
#endif /* UNIG_LOG_ARCHIVE */
1837
srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
1839
if (ret == FALSE || innobase_mirrored_log_groups != 1) {
1840
errmsg_printf(ERRMSG_LVL_ERROR, "syntax error in innodb_log_group_home_dir, or a "
1841
"wrong number of mirrored log groups");
1843
goto mem_free_and_error;
1846
/* Validate the file format by animal name */
1847
if (innobase_file_format_name != NULL) {
1849
format_id = innobase_file_format_name_lookup(
1850
innobase_file_format_name);
1852
if (format_id > DICT_TF_FORMAT_MAX) {
1854
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
1856
goto mem_free_and_error;
1859
/* Set it to the default file format id. Though this
1860
should never happen. */
1864
srv_file_format = format_id;
1866
/* Given the type of innobase_file_format_name we have little
1867
choice but to cast away the constness from the returned name.
1868
innobase_file_format_name is used in the MySQL set variable
1869
interface and so can't be const. */
1871
innobase_file_format_name =
1872
(char*) trx_sys_file_format_id_to_name(format_id);
1874
/* Process innobase_file_format_check variable */
1875
ut_a(innobase_file_format_check != NULL);
1877
/* As a side effect it will set srv_check_file_format_at_startup
1878
on valid input. First we check for "on"/"off". */
1879
if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
1881
/* Did the user specify a format name that we support ?
1882
As a side effect it will update the variable
1883
srv_check_file_format_at_startup */
1884
if (!innobase_file_format_check_validate(
1885
innobase_file_format_check)) {
1887
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: invalid "
1888
"innodb_file_format_check value: "
1889
"should be either 'on' or 'off' or "
1890
"any value up to %s or its "
1891
"equivalent numeric id",
1892
trx_sys_file_format_id_to_name(
1893
DICT_TF_FORMAT_MAX));
1895
goto mem_free_and_error;
1899
if (innobase_change_buffering) {
1903
use < UT_ARR_SIZE(innobase_change_buffering_values);
1905
if (!innobase_strcasecmp(
1906
innobase_change_buffering,
1907
innobase_change_buffering_values[use])) {
1908
ibuf_use = (ibuf_use_t) use;
1909
goto innobase_change_buffering_inited_ok;
1913
errmsg_printf(ERRMSG_LVL_ERROR,
1914
"InnoDB: invalid value "
1915
"innodb_file_format_check=%s",
1916
innobase_change_buffering);
1917
goto mem_free_and_error;
1920
innobase_change_buffering_inited_ok:
1921
ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
1922
innobase_change_buffering = (char*)
1923
innobase_change_buffering_values[ibuf_use];
1925
/* --------------------------------------------------*/
1927
srv_file_flush_method_str = innobase_unix_file_flush_method;
1929
srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
1930
srv_n_log_files = (ulint) innobase_log_files_in_group;
1931
srv_log_file_size = (ulint) innobase_log_file_size;
1933
#ifdef UNIV_LOG_ARCHIVE
1934
srv_log_archive_on = (ulint) innobase_log_archive;
1935
#endif /* UNIV_LOG_ARCHIVE */
1936
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
1938
srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
1940
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
1942
srv_n_file_io_threads = (ulint) innobase_file_io_threads;
1943
srv_n_read_io_threads = (ulint) innobase_read_io_threads;
1944
srv_n_write_io_threads = (ulint) innobase_write_io_threads;
1946
srv_force_recovery = (ulint) innobase_force_recovery;
1948
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
1949
srv_use_checksums = (ibool) innobase_use_checksums;
1951
#ifdef HAVE_LARGE_PAGES
1952
if ((os_use_large_pages = (ibool) my_use_large_pages))
1953
os_large_page_size = (ulint) opt_large_page_size;
1956
row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
1958
srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
1960
srv_max_n_open_files = (ulint) innobase_open_files;
1961
srv_innodb_status = (ibool) innobase_create_status_file;
1963
srv_print_verbose_log = true;
1965
/* Store the default charset-collation number of this MySQL
1968
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
1971
innobase_commit_concurrency_init_default();
1973
/* Since we in this module access directly the fields of a trx
1974
struct, and due to different headers and flags it might happen that
1975
mutex_t has a different size in this module and in InnoDB
1976
modules, we check at run time that the size is the same in
1977
these compilation modules. */
1979
err = innobase_start_or_create_for_mysql();
1981
if (err != DB_SUCCESS) {
1982
goto mem_free_and_error;
1985
innobase_open_tables = hash_create(200);
1986
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
1987
pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
1988
pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
1989
pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
1990
pthread_cond_init(&commit_cond, NULL);
1993
if (innodb_locks_init() ||
1994
innodb_trx_init() ||
1995
innodb_lock_waits_init() ||
1997
i_s_cmp_reset_init() ||
1998
i_s_cmpmem_init() ||
1999
i_s_cmpmem_reset_init())
2002
registry.add(innodb_engine_ptr);
2004
registry.add(innodb_trx_schema_table);
2005
registry.add(innodb_locks_schema_table);
2006
registry.add(innodb_lock_waits_schema_table);
2007
registry.add(innodb_cmp_schema_table);
2008
registry.add(innodb_cmp_reset_schema_table);
2009
registry.add(innodb_cmpmem_schema_table);
2010
registry.add(innodb_cmpmem_reset_schema_table);
2012
/* Get the current high water mark format. */
2013
innobase_file_format_check = (char*) trx_sys_file_format_max_get();
2020
/*******************************************************************//**
2021
Closes an InnoDB database.
2022
@return TRUE if error */
2025
innobase_deinit(drizzled::plugin::Registry ®istry)
2028
i_s_common_deinit(registry);
2029
registry.remove(innodb_engine_ptr);
2030
delete innodb_engine_ptr;
2032
if (innodb_inited) {
2034
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
2036
hash_table_free(innobase_open_tables);
2037
innobase_open_tables = NULL;
2038
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
2041
srv_free_paths_and_sizes();
2042
if (internal_innobase_data_file_path)
2043
free(internal_innobase_data_file_path);
2044
pthread_mutex_destroy(&innobase_share_mutex);
2045
pthread_mutex_destroy(&prepare_commit_mutex);
2046
pthread_mutex_destroy(&commit_threads_m);
2047
pthread_mutex_destroy(&commit_cond_m);
2048
pthread_cond_destroy(&commit_cond);
2054
/****************************************************************//**
2055
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2056
the logs, and the name of this function should be innobase_checkpoint.
2057
@return TRUE if error */
2059
InnobaseEngine::flush_logs()
2060
/*=====================*/
2064
assert(this == innodb_engine_ptr);
2066
log_buffer_flush_to_disk();
2071
/*****************************************************************//**
2072
Commits a transaction in an InnoDB database. */
2075
innobase_commit_low(
2076
/*================*/
2077
trx_t* trx) /*!< in: transaction handle */
2079
if (trx->conc_state == TRX_NOT_STARTED) {
2084
trx_commit_for_mysql(trx);
2087
/*****************************************************************//**
2088
Creates an InnoDB transaction struct for the thd if it does not yet have one.
2089
Starts a new InnoDB transaction if a transaction is not yet started. And
2090
assigns a new snapshot for a consistent read if the transaction does not yet
2094
InnobaseEngine::start_consistent_snapshot(
2095
/*====================================*/
2096
Session* session) /*!< in: MySQL thread handle of the user for whom
2097
the transaction should be committed */
2101
assert(this == innodb_engine_ptr);
2103
/* Create a new trx struct for session, if it does not yet have one */
2105
trx = check_trx_exists(session);
2107
/* This is just to play safe: release a possible FIFO ticket and
2108
search latch. Since we will reserve the kernel mutex, we have to
2109
release the search system latch first to obey the latching order. */
2111
innobase_release_stat_resources(trx);
2113
/* If the transaction is not started yet, start it */
2115
trx_start_if_not_started(trx);
2117
/* Assign a read view if the transaction does not have it yet */
2119
trx_assign_read_view(trx);
2121
/* Set the MySQL flag to mark that there is an active transaction */
2123
if (trx->active_trans == 0) {
2124
innobase_register_trx_and_stmt(this, current_session);
2125
trx->active_trans = 1;
2131
/*****************************************************************//**
2132
Commits a transaction in an InnoDB database or marks an SQL statement
2136
InnobaseEngine::commit(
2138
Session* session, /*!< in: MySQL thread handle of the user for whom
2139
the transaction should be committed */
2140
bool all) /*!< in: TRUE - commit transaction
2141
FALSE - the current SQL statement ended */
2145
assert(this == innodb_engine_ptr);
2147
trx = check_trx_exists(session);
2149
/* Since we will reserve the kernel mutex, we have to release
2150
the search system latch first to obey the latching order. */
2152
if (trx->has_search_latch) {
2153
trx_search_latch_release_if_reserved(trx);
2156
/* The flag trx->active_trans is set to 1 in
2158
1. ::external_lock(),
2160
3. innobase_query_caching_of_table_permitted(),
2161
4. InnobaseEngine::savepoint_set(),
2162
5. ::init_table_handle_for_HANDLER(),
2163
6. InnobaseEngine::start_consistent_snapshot(),
2165
and it is only set to 0 in a commit or a rollback. If it is 0 we know
2166
there cannot be resources to be freed and we could return immediately.
2167
For the time being, we play safe and do the cleanup though there should
2168
be nothing to clean up. */
2170
if (trx->active_trans == 0
2171
&& trx->conc_state != TRX_NOT_STARTED) {
2173
errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
2174
" trx->conc_state != TRX_NOT_STARTED");
2177
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
2179
/* We were instructed to commit the whole transaction, or
2180
this is an SQL statement end and autocommit is on */
2182
/* We need current binlog position for ibbackup to work.
2183
Note, the position is current because of
2184
prepare_commit_mutex */
2186
if (innobase_commit_concurrency > 0) {
2187
pthread_mutex_lock(&commit_cond_m);
2190
if (commit_threads > innobase_commit_concurrency) {
2192
pthread_cond_wait(&commit_cond,
2194
pthread_mutex_unlock(&commit_cond_m);
2198
pthread_mutex_unlock(&commit_cond_m);
2202
/* Store transaction point for binlog
2203
Later logic tests that this is set to _something_. We need
2204
that logic to fire, even though we do not have a real name. */
2205
trx->mysql_log_file_name = "UNUSED";
2206
trx->mysql_log_offset = 0;
2208
/* Don't do write + flush right now. For group commit
2209
to work we want to do the flush after releasing the
2210
prepare_commit_mutex. */
2211
trx->flush_log_later = TRUE;
2212
innobase_commit_low(trx);
2213
trx->flush_log_later = FALSE;
2215
if (innobase_commit_concurrency > 0) {
2216
pthread_mutex_lock(&commit_cond_m);
2218
pthread_cond_signal(&commit_cond);
2219
pthread_mutex_unlock(&commit_cond_m);
2222
if (trx->active_trans == 2) {
2224
pthread_mutex_unlock(&prepare_commit_mutex);
2227
/* Now do a write + flush of logs. */
2228
trx_commit_complete_for_mysql(trx);
2229
trx->active_trans = 0;
2232
/* We just mark the SQL statement ended and do not do a
2233
transaction commit */
2235
/* If we had reserved the auto-inc lock for some
2236
table in this SQL statement we release it now */
2238
row_unlock_table_autoinc_for_mysql(trx);
2240
/* Store the current undo_no of the transaction so that we
2241
know where to roll back if we have to roll back the next
2244
trx_mark_sql_stat_end(trx);
2247
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2249
if (trx->declared_to_be_inside_innodb) {
2250
/* Release our possible ticket in the FIFO */
2252
srv_conc_force_exit_innodb(trx);
2255
/* Tell the InnoDB server that there might be work for utility
2257
srv_active_wake_master_thread();
2262
/*****************************************************************//**
2263
Rolls back a transaction or the latest SQL statement.
2264
@return 0 or error number */
2266
InnobaseEngine::rollback(
2268
Session* session,/*!< in: handle to the MySQL thread of the user
2269
whose transaction should be rolled back */
2270
bool all) /*!< in: TRUE - commit transaction
2271
FALSE - the current SQL statement ended */
2276
assert(this == innodb_engine_ptr);
2278
trx = check_trx_exists(session);
2280
/* Release a possible FIFO ticket and search latch. Since we will
2281
reserve the kernel mutex, we have to release the search system latch
2282
first to obey the latching order. */
2284
innobase_release_stat_resources(trx);
2286
/* If we had reserved the auto-inc lock for some table (if
2287
we come here to roll back the latest SQL statement) we
2288
release it now before a possibly lengthy rollback */
2290
row_unlock_table_autoinc_for_mysql(trx);
2293
|| !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
2295
error = trx_rollback_for_mysql(trx);
2296
trx->active_trans = 0;
2298
error = trx_rollback_last_sql_stat_for_mysql(trx);
2301
return(convert_error_code_to_mysql(error, 0, NULL));
2304
/*****************************************************************//**
2305
Rolls back a transaction
2306
@return 0 or error number */
2309
innobase_rollback_trx(
2310
/*==================*/
2311
trx_t* trx) /*!< in: transaction */
2315
/* Release a possible FIFO ticket and search latch. Since we will
2316
reserve the kernel mutex, we have to release the search system latch
2317
first to obey the latching order. */
2319
innobase_release_stat_resources(trx);
2321
/* If we had reserved the auto-inc lock for some table (if
2322
we come here to roll back the latest SQL statement) we
2323
release it now before a possibly lengthy rollback */
2325
row_unlock_table_autoinc_for_mysql(trx);
2327
error = trx_rollback_for_mysql(trx);
2329
return(convert_error_code_to_mysql(error, 0, NULL));
2332
/*****************************************************************//**
2333
Rolls back a transaction to a savepoint.
2334
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2337
InnobaseEngine::savepoint_rollback_hook(
2338
/*===========================*/
2339
Session* session, /*!< in: handle to the MySQL thread of the user
2340
whose transaction should be rolled back */
2341
void* savepoint) /*!< in: savepoint data */
2343
ib_int64_t mysql_binlog_cache_pos;
2348
assert(this == innodb_engine_ptr);
2350
trx = check_trx_exists(session);
2352
/* Release a possible FIFO ticket and search latch. Since we will
2353
reserve the kernel mutex, we have to release the search system latch
2354
first to obey the latching order. */
2356
innobase_release_stat_resources(trx);
2358
/* TODO: use provided savepoint data area to store savepoint data */
2360
int64_t2str((ulint)savepoint, sp_name, 36);
2362
error = (int) trx_rollback_to_savepoint_for_mysql(trx, sp_name,
2363
&mysql_binlog_cache_pos);
2364
return(convert_error_code_to_mysql(error, 0, NULL));
2367
/*****************************************************************//**
2368
Release transaction savepoint name.
2369
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2372
InnobaseEngine::savepoint_release_hook(
2373
/*=======================*/
2374
Session* session, /*!< in: handle to the MySQL thread of the user
2375
whose transaction should be rolled back */
2376
void* savepoint) /*!< in: savepoint data */
2382
assert(this == innodb_engine_ptr);
2384
trx = check_trx_exists(session);
2386
/* TODO: use provided savepoint data area to store savepoint data */
2388
int64_t2str((ulint)savepoint, sp_name, 36);
2390
error = (int) trx_release_savepoint_for_mysql(trx, sp_name);
2392
return(convert_error_code_to_mysql(error, 0, NULL));
2395
/*****************************************************************//**
2396
Sets a transaction savepoint.
2397
@return always 0, that is, always succeeds */
2399
InnobaseEngine::savepoint_set_hook(
2401
Session* session,/*!< in: handle to the MySQL thread */
2402
void* savepoint) /*!< in: savepoint data */
2407
assert(this == innodb_engine_ptr);
2410
In the autocommit mode there is no sense to set a savepoint
2411
(unless we are in sub-statement), so SQL layer ensures that
2412
this method is never called in such situation.
2415
trx = check_trx_exists(session);
2417
/* Release a possible FIFO ticket and search latch. Since we will
2418
reserve the kernel mutex, we have to release the search system latch
2419
first to obey the latching order. */
2421
innobase_release_stat_resources(trx);
2423
/* cannot happen outside of transaction */
2424
assert(trx->active_trans);
2426
/* TODO: use provided savepoint data area to store savepoint data */
2428
int64_t2str((ulint)savepoint,sp_name,36);
2430
error = (int) trx_savepoint_for_mysql(trx, sp_name, (ib_int64_t)0);
2432
return(convert_error_code_to_mysql(error, 0, NULL));
2435
/*****************************************************************//**
2436
Frees a possible InnoDB trx object associated with the current Session.
2437
@return 0 or error number */
2439
InnobaseEngine::close_connection(
2440
/*======================*/
2441
Session* session)/*!< in: handle to the MySQL thread of the user
2442
whose resources should be free'd */
2446
assert(this == innodb_engine_ptr);
2447
trx = session_to_trx(session);
2451
if (trx->active_trans == 0
2452
&& trx->conc_state != TRX_NOT_STARTED) {
2454
errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
2455
" trx->conc_state != TRX_NOT_STARTED");
2459
if (trx->conc_state != TRX_NOT_STARTED &&
2460
global_system_variables.log_warnings) {
2461
errmsg_printf(ERRMSG_LVL_WARN,
2462
"MySQL is closing a connection that has an active "
2463
"InnoDB transaction. %lu row modifications will "
2465
(ulong) trx->undo_no.low);
2468
innobase_rollback_trx(trx);
2470
thr_local_free(trx->mysql_thread_id);
2471
trx_free_for_mysql(trx);
2477
/*************************************************************************//**
2478
** InnoDB database tables
2479
*****************************************************************************/
2481
/****************************************************************//**
2482
Get the record format from the data dictionary.
2483
@return one of ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT,
2484
ROW_TYPE_COMPRESSED, ROW_TYPE_DYNAMIC */
2487
ha_innobase::get_row_type() const
2488
/*=============================*/
2490
if (prebuilt && prebuilt->table) {
2491
const ulint flags = prebuilt->table->flags;
2493
if (UNIV_UNLIKELY(!flags)) {
2494
return(ROW_TYPE_REDUNDANT);
2497
ut_ad(flags & DICT_TF_COMPACT);
2499
switch (flags & DICT_TF_FORMAT_MASK) {
2500
case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
2501
return(ROW_TYPE_COMPACT);
2502
case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
2503
if (flags & DICT_TF_ZSSIZE_MASK) {
2504
return(ROW_TYPE_COMPRESSED);
2506
return(ROW_TYPE_DYNAMIC);
2508
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
2509
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
2514
return(ROW_TYPE_NOT_USED);
2518
/****************************************************************//**
2519
Returns the index type. */
2522
ha_innobase::index_type(
2523
/*====================*/
2525
/*!< out: index type */
2530
/****************************************************************//**
2531
Returns the maximum number of keys.
2535
InnobaseEngine::max_supported_keys() const
2536
/*===================================*/
2541
/****************************************************************//**
2542
Returns the maximum key length.
2543
@return maximum supported key length, in bytes */
2546
InnobaseEngine::max_supported_key_length() const
2547
/*=========================================*/
2549
/* An InnoDB page must store >= 2 keys; a secondary key record
2550
must also contain the primary key value: max key length is
2551
therefore set to slightly less than 1 / 4 of page size which
2552
is 16 kB; but currently MySQL does not work with keys whose
2553
size is > MAX_KEY_LENGTH */
2557
/****************************************************************//**
2558
Returns the key map of keys that are usable for scanning.
2559
@return key_map_full */
2562
ha_innobase::keys_to_use_for_scanning()
2564
return(&key_map_full);
2568
/****************************************************************//**
2569
Determines if the primary key is clustered index.
2573
ha_innobase::primary_key_is_clustered()
2578
/*****************************************************************//**
2579
Normalizes a table name string. A normalized name consists of the
2580
database name catenated to '/' and table name. An example:
2581
test/mytable. On Windows normalization puts both the database name and the
2582
table name always to lower case. */
2585
normalize_table_name(
2586
/*=================*/
2587
char* norm_name, /*!< out: normalized name as a
2588
null-terminated string */
2589
const char* name) /*!< in: table name string */
2591
const char* name_ptr;
2595
/* Scan name from the end */
2597
ptr = strchr(name, '\0')-1;
2599
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2609
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2615
memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
2617
norm_name[name_ptr - db_ptr - 1] = '/';
2620
innobase_casedn_str(norm_name);
2624
/********************************************************************//**
2625
Set the autoinc column max value. This should only be called once from
2626
ha_innobase::open(). Therefore there's no need for a covering lock.
2627
@return DB_SUCCESS or error code */
2630
ha_innobase::innobase_initialize_autoinc()
2631
/*======================================*/
2633
dict_index_t* index;
2635
const char* col_name;
2638
col_name = table->found_next_number_field->field_name;
2639
index = innobase_get_index(table->s->next_number_index);
2641
/* Execute SELECT MAX(col_name) FROM TABLE; */
2642
error = row_search_max_autoinc(index, col_name, &auto_inc);
2647
/* At the this stage we don't know the increment
2648
or the offset, so use default inrement of 1. */
2652
case DB_RECORD_NOT_FOUND:
2653
ut_print_timestamp(stderr);
2654
fprintf(stderr, " InnoDB: MySQL and InnoDB data "
2655
"dictionaries are out of sync.\n"
2656
"InnoDB: Unable to find the AUTOINC column %s in the "
2657
"InnoDB table %s.\n"
2658
"InnoDB: We set the next AUTOINC column value to the "
2659
"maximum possible value,\n"
2660
"InnoDB: in effect disabling the AUTOINC next value "
2662
"InnoDB: You can either set the next AUTOINC value "
2663
"explicitly using ALTER TABLE\n"
2664
"InnoDB: or fix the data dictionary by recreating "
2666
col_name, index->table->name);
2668
auto_inc = 0xFFFFFFFFFFFFFFFFULL;
2675
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
2680
/*****************************************************************//**
2681
Creates and opens a handle to a table which already exists in an InnoDB
2683
@return 1 if error, 0 if success */
2688
const char* name, /*!< in: table name */
2689
int mode, /*!< in: not used */
2690
uint test_if_locked) /*!< in: not used */
2692
dict_table_t* ib_table;
2693
char norm_name[1000];
2696
char* is_part = NULL;
2699
UT_NOT_USED(test_if_locked);
2701
session = ha_session();
2703
/* Under some cases Drizzle seems to call this function while
2704
holding btr_search_latch. This breaks the latching order as
2705
we acquire dict_sys->mutex below and leads to a deadlock. */
2706
if (session != NULL) {
2707
engine->release_temporary_latches(session);
2710
normalize_table_name(norm_name, name);
2712
user_session = NULL;
2714
if (!(share=get_share(name))) {
2719
/* Create buffers for packing the fields of a record. Why
2720
table->stored_rec_length did not work here? Obviously, because char
2721
fields when packed actually became 1 byte longer, when we also
2722
stored the string length as the first byte. */
2724
upd_and_key_val_buff_len =
2725
table->s->stored_rec_length
2726
+ table->s->max_key_length
2727
+ MAX_REF_PARTS * 3;
2728
if (!(unsigned char*) drizzled::memory::multi_malloc(false,
2729
&upd_buff, upd_and_key_val_buff_len,
2730
&key_val_buff, upd_and_key_val_buff_len,
2737
/* We look for pattern #P# to see if the table is partitioned
2738
MySQL table. The retry logic for partitioned tables is a
2739
workaround for http://bugs.mysql.com/bug.php?id=33349. Look
2740
at support issue https://support.mysql.com/view.php?id=21080
2741
for more details. */
2742
is_part = strstr(norm_name, "#P#");
2744
/* Get pointer to a table object in InnoDB dictionary cache */
2745
ib_table = dict_table_get(norm_name, TRUE);
2747
if (NULL == ib_table) {
2748
if (is_part && retries < 10) {
2750
os_thread_sleep(100000);
2755
errmsg_printf(ERRMSG_LVL_ERROR, "Failed to open table %s after "
2756
"%lu attemtps.\n", norm_name,
2760
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
2761
"the internal data dictionary of InnoDB "
2762
"though the .frm file for the\n"
2763
"table exists. Maybe you have deleted and "
2764
"recreated InnoDB data\n"
2765
"files but have forgotten to delete the "
2766
"corresponding .frm files\n"
2767
"of InnoDB tables, or you have moved .frm "
2768
"files to another database?\n"
2769
"or, the table contains indexes that this "
2770
"version of the engine\n"
2771
"doesn't support.\n"
2772
"See " REFMAN "innodb-troubleshooting.html\n"
2773
"how you can resolve the problem.\n",
2779
return(HA_ERR_NO_SUCH_TABLE);
2782
if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
2783
errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
2784
"the .ibd file for\ntable %s does not exist.\n"
2785
"Have you deleted the .ibd file from the "
2786
"database directory under\nthe MySQL datadir, "
2787
"or have you used DISCARD TABLESPACE?\n"
2788
"See " REFMAN "innodb-troubleshooting.html\n"
2789
"how you can resolve the problem.\n",
2795
dict_table_decrement_handle_count(ib_table, FALSE);
2796
return(HA_ERR_NO_SUCH_TABLE);
2799
prebuilt = row_create_prebuilt(ib_table);
2801
prebuilt->mysql_row_len = table->s->stored_rec_length;
2802
prebuilt->default_rec = table->s->default_values;
2803
ut_ad(prebuilt->default_rec);
2805
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
2807
primary_key = table->s->primary_key;
2808
key_used_on_scan = primary_key;
2810
/* Allocate a buffer for a 'row reference'. A row reference is
2811
a string of bytes of length ref_length which uniquely specifies
2812
a row in our table. Note that MySQL may also compare two row
2813
references for equality by doing a simple memcmp on the strings
2814
of length ref_length! */
2816
if (!row_table_got_default_clust_index(ib_table)) {
2817
if (primary_key >= MAX_KEY) {
2818
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in InnoDB data "
2819
"dictionary, but not in MySQL!", name);
2822
prebuilt->clust_index_was_generated = FALSE;
2824
/* MySQL allocates the buffer for ref. key_info->key_length
2825
includes space for all key columns + one byte for each column
2826
that may be NULL. ref_length must be as exact as possible to
2827
save space, because all row reference buffers are allocated
2828
based on ref_length. */
2830
ref_length = table->key_info[primary_key].key_length;
2832
if (primary_key != MAX_KEY) {
2833
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has no primary key in InnoDB data "
2834
"dictionary, but has one in MySQL! If you "
2835
"created the table with a MySQL version < "
2836
"3.23.54 and did not define a primary key, "
2837
"but defined a unique key with all non-NULL "
2838
"columns, then MySQL internally treats that "
2839
"key as the primary key. You can fix this "
2840
"error by dump + DROP + CREATE + reimport "
2841
"of the table.", name);
2844
prebuilt->clust_index_was_generated = TRUE;
2846
ref_length = DATA_ROW_ID_LEN;
2848
/* If we automatically created the clustered index, then
2849
MySQL does not know about it, and MySQL must NOT be aware
2850
of the index used on scan, to make it avoid checking if we
2851
update the column of the index. That is why we assert below
2852
that key_used_on_scan is the undefined value MAX_KEY.
2853
The column is the row id in the automatical generation case,
2854
and it will never be updated anyway. */
2856
if (key_used_on_scan != MAX_KEY) {
2857
errmsg_printf(ERRMSG_LVL_WARN,
2858
"Table %s key_used_on_scan is %lu even "
2859
"though there is no primary key inside "
2860
"InnoDB.", name, (ulong) key_used_on_scan);
2864
/* Index block size in InnoDB: used by MySQL in query optimization */
2865
stats.block_size = 16 * 1024;
2867
/* Init table lock structure */
2868
thr_lock_data_init(&share->lock,&lock,(void*) 0);
2870
if (prebuilt->table) {
2871
/* We update the highest file format in the system table
2872
space, if this table has higher file format setting. */
2874
trx_sys_file_format_max_upgrade(
2875
(const char**) &innobase_file_format_check,
2876
dict_table_get_format(prebuilt->table));
2879
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
2881
/* Only if the table has an AUTOINC column. */
2882
if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
2885
dict_table_autoinc_lock(prebuilt->table);
2887
/* Since a table can already be "open" in InnoDB's internal
2888
data dictionary, we only init the autoinc counter once, the
2889
first time the table is loaded. We can safely reuse the
2890
autoinc value from a previous Drizzle open. */
2891
if (dict_table_autoinc_read(prebuilt->table) == 0) {
2893
error = innobase_initialize_autoinc();
2894
ut_a(error == DB_SUCCESS);
2897
dict_table_autoinc_unlock(prebuilt->table);
2905
InnobaseEngine::max_supported_key_part_length() const
2907
return(DICT_MAX_INDEX_COL_LEN - 1);
2910
/******************************************************************//**
2911
Closes a handle to an InnoDB table.
2915
ha_innobase::close(void)
2916
/*====================*/
2920
session = ha_session();
2921
if (session != NULL) {
2922
engine->release_temporary_latches(session);
2925
row_prebuilt_free(prebuilt, FALSE);
2930
/* Tell InnoDB server that there might be work for
2933
srv_active_wake_master_thread();
2938
/* The following accessor functions should really be inside MySQL code! */
2940
/**************************************************************//**
2941
Gets field offset for a field in a table.
2947
Table* table, /*!< in: MySQL table object */
2948
Field* field) /*!< in: MySQL field object */
2950
return((uint) (field->ptr - table->record[0]));
2953
/**************************************************************//**
2954
Checks if a field in a record is SQL NULL. Uses the record format
2955
information in table to track the null bit in record.
2956
@return 1 if NULL, 0 otherwise */
2959
field_in_record_is_null(
2960
/*====================*/
2961
Table* table, /*!< in: MySQL table object */
2962
Field* field, /*!< in: MySQL field object */
2963
char* record) /*!< in: a row in MySQL format */
2967
if (!field->null_ptr) {
2972
null_offset = (uint) ((char*) field->null_ptr
2973
- (char*) table->record[0]);
2975
if (record[null_offset] & field->null_bit) {
2983
/**************************************************************//**
2984
Sets a field in a record to SQL NULL. Uses the record format
2985
information in table to track the null bit in record. */
2988
set_field_in_record_to_null(
2989
/*========================*/
2990
Table* table, /*!< in: MySQL table object */
2991
Field* field, /*!< in: MySQL field object */
2992
char* record) /*!< in: a row in MySQL format */
2996
null_offset = (uint) ((char*) field->null_ptr
2997
- (char*) table->record[0]);
2999
record[null_offset] = record[null_offset] | field->null_bit;
3002
/*************************************************************//**
3003
InnoDB uses this function to compare two data fields for which the data type
3004
is such that we must use MySQL code to compare them. NOTE that the prototype
3005
of this function is in rem0cmp.c in InnoDB source code! If you change this
3006
function, remember to update the prototype there!
3007
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
3008
extern "C" UNIV_INTERN
3012
int mysql_type, /*!< in: MySQL type */
3013
uint charset_number, /*!< in: number of the charset */
3014
const unsigned char* a, /*!< in: data field */
3015
unsigned int a_length, /*!< in: data field length,
3016
not UNIV_SQL_NULL */
3017
const unsigned char* b, /* in: data field */
3018
unsigned int b_length); /* in: data field length,
3019
not UNIV_SQL_NULL */
3024
/* out: 1, 0, -1, if a is greater,
3025
equal, less than b, respectively */
3026
int mysql_type, /* in: MySQL type */
3027
uint charset_number, /* in: number of the charset */
3028
const unsigned char* a, /* in: data field */
3029
unsigned int a_length, /* in: data field length,
3030
not UNIV_SQL_NULL */
3031
const unsigned char* b, /* in: data field */
3032
unsigned int b_length) /* in: data field length,
3033
not UNIV_SQL_NULL */
3035
const CHARSET_INFO* charset;
3036
enum_field_types mysql_tp;
3039
assert(a_length != UNIV_SQL_NULL);
3040
assert(b_length != UNIV_SQL_NULL);
3042
mysql_tp = (enum_field_types) mysql_type;
3046
case DRIZZLE_TYPE_BLOB:
3047
case DRIZZLE_TYPE_VARCHAR:
3048
/* Use the charset number to pick the right charset struct for
3049
the comparison. Since the MySQL function get_charset may be
3050
slow before Bar removes the mutex operation there, we first
3051
look at 2 common charsets directly. */
3053
if (charset_number == default_charset_info->number) {
3054
charset = default_charset_info;
3056
charset = get_charset(charset_number);
3058
if (charset == NULL) {
3059
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
3060
"a comparison, but MySQL cannot "
3061
"find that charset.",
3062
(ulong) charset_number);
3067
/* Starting from 4.1.3, we use strnncollsp() in comparisons of
3068
non-latin1_swedish_ci strings. NOTE that the collation order
3069
changes then: 'b\0\0...' is ordered BEFORE 'b ...'. Users
3070
having indexes on such data need to rebuild their tables! */
3072
ret = charset->coll->strnncollsp(charset,
3077
} else if (ret > 0) {
3089
/**************************************************************//**
3090
Converts a MySQL type to an InnoDB type. Note that this function returns
3091
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3092
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3093
@return DATA_BINARY, DATA_VARCHAR, ... */
3094
extern "C" UNIV_INTERN
3096
get_innobase_type_from_mysql_type(
3097
/*==============================*/
3098
ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
3100
at least ENUM and SET,
3101
and unsigned integer
3102
types are 'unsigned types' */
3103
const void* f) /*!< in: MySQL Field */
3105
const class Field* field = reinterpret_cast<const class Field*>(f);
3107
/* The following asserts try to check that the MySQL type code fits in
3108
8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3111
assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3113
if (field->flags & UNSIGNED_FLAG) {
3115
*unsigned_flag = DATA_UNSIGNED;
3120
if (field->real_type() == DRIZZLE_TYPE_ENUM)
3122
/* MySQL has field->type() a string type for these, but the
3123
data is actually internally stored as an unsigned integer
3126
*unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3127
flag set to zero, even though
3128
internally this is an unsigned
3133
switch (field->type()) {
3134
/* NOTE that we only allow string types in DATA_DRIZZLE and
3136
case DRIZZLE_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
3137
if (field->binary()) {
3138
return(DATA_BINARY);
3140
return(DATA_VARMYSQL);
3142
case DRIZZLE_TYPE_DECIMAL:
3143
return(DATA_FIXBINARY);
3144
case DRIZZLE_TYPE_LONG:
3145
case DRIZZLE_TYPE_LONGLONG:
3146
case DRIZZLE_TYPE_DATETIME:
3147
case DRIZZLE_TYPE_DATE:
3148
case DRIZZLE_TYPE_TIMESTAMP:
3150
case DRIZZLE_TYPE_DOUBLE:
3151
return(DATA_DOUBLE);
3152
case DRIZZLE_TYPE_BLOB:
3161
/*******************************************************************//**
3162
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
3166
innobase_write_to_2_little_endian(
3167
/*==============================*/
3168
byte* buf, /*!< in: where to store */
3169
ulint val) /*!< in: value to write, must be < 64k */
3171
ut_a(val < 256 * 256);
3173
buf[0] = (byte)(val & 0xFF);
3174
buf[1] = (byte)(val / 256);
3177
/*******************************************************************//**
3178
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
3183
innobase_read_from_2_little_endian(
3184
/*===============================*/
3185
const unsigned char* buf) /*!< in: from where to read */
3187
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
3190
/*******************************************************************//**
3191
Stores a key value for a row to a buffer.
3192
@return key value length as stored in buff */
3195
ha_innobase::store_key_val_for_row(
3196
/*===============================*/
3197
uint keynr, /*!< in: key number */
3198
char* buff, /*!< in/out: buffer for the key value (in MySQL
3200
uint buff_len,/*!< in: buffer length */
3201
const unsigned char* record)/*!< in: row in MySQL format */
3203
KEY* key_info = table->key_info + keynr;
3204
KEY_PART_INFO* key_part = key_info->key_part;
3205
KEY_PART_INFO* end = key_part + key_info->key_parts;
3206
char* buff_start = buff;
3207
enum_field_types mysql_type;
3211
/* The format for storing a key field in MySQL is the following:
3213
1. If the column can be NULL, then in the first byte we put 1 if the
3214
field value is NULL, 0 otherwise.
3216
2. If the column is of a BLOB type (it must be a column prefix field
3217
in this case), then we put the length of the data in the field to the
3218
next 2 bytes, in the little-endian format. If the field is SQL NULL,
3219
then these 2 bytes are set to 0. Note that the length of data in the
3220
field is <= column prefix length.
3222
3. In a column prefix field, prefix_len next bytes are reserved for
3223
data. In a normal field the max field length next bytes are reserved
3224
for data. For a VARCHAR(n) the max field length is n. If the stored
3225
value is the SQL NULL then these data bytes are set to 0.
3227
4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
3228
in the MySQL row format, the length is stored in 1 or 2 bytes,
3229
depending on the maximum allowed length. But in the MySQL key value
3230
format, the length always takes 2 bytes.
3232
We have to zero-fill the buffer so that MySQL is able to use a
3233
simple memcmp to compare two key values to determine if they are
3234
equal. MySQL does this to compare contents of two 'ref' values. */
3236
bzero(buff, buff_len);
3238
for (; key_part != end; key_part++) {
3241
if (key_part->null_bit) {
3242
if (record[key_part->null_offset]
3243
& key_part->null_bit) {
3252
field = key_part->field;
3253
mysql_type = field->type();
3255
if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
3256
/* >= 5.0.3 true VARCHAR */
3262
const CHARSET_INFO* cs;
3265
key_len = key_part->length;
3268
buff += key_len + 2;
3272
cs = field->charset();
3275
(((Field_varstring*)field)->length_bytes);
3277
data = row_mysql_read_true_varchar(&len,
3279
+ (ulint)get_field_offset(table, field)),
3284
/* For multi byte character sets we need to calculate
3285
the true length of the key */
3287
if (len > 0 && cs->mbmaxlen > 1) {
3288
true_len = (ulint) cs->cset->well_formed_len(cs,
3289
(const char *) data,
3290
(const char *) data + len,
3296
/* In a column prefix index, we may need to truncate
3297
the stored value: */
3299
if (true_len > key_len) {
3303
/* The length in a key value is always stored in 2
3306
row_mysql_store_true_var_len((byte*)buff, true_len, 2);
3309
memcpy(buff, data, true_len);
3311
/* Note that we always reserve the maximum possible
3312
length of the true VARCHAR in the key value, though
3313
only len first bytes after the 2 length bytes contain
3314
actual data. The rest of the space was reset to zero
3315
in the bzero() call above. */
3319
} else if (mysql_type == DRIZZLE_TYPE_BLOB) {
3321
const CHARSET_INFO* cs;
3326
const byte* blob_data;
3328
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
3330
key_len = key_part->length;
3333
buff += key_len + 2;
3338
cs = field->charset();
3340
blob_data = row_mysql_read_blob_ref(&blob_len,
3342
+ (ulint)get_field_offset(table, field)),
3343
(ulint) field->pack_length());
3345
true_len = blob_len;
3347
ut_a(get_field_offset(table, field)
3348
== key_part->offset);
3350
/* For multi byte character sets we need to calculate
3351
the true length of the key */
3353
if (blob_len > 0 && cs->mbmaxlen > 1) {
3354
true_len = (ulint) cs->cset->well_formed_len(cs,
3355
(const char *) blob_data,
3356
(const char *) blob_data
3363
/* All indexes on BLOB and TEXT are column prefix
3364
indexes, and we may need to truncate the data to be
3365
stored in the key value: */
3367
if (true_len > key_len) {
3371
/* MySQL reserves 2 bytes for the length and the
3372
storage of the number is little-endian */
3374
innobase_write_to_2_little_endian(
3375
(byte*)buff, true_len);
3378
memcpy(buff, blob_data, true_len);
3380
/* Note that we always reserve the maximum possible
3381
length of the BLOB prefix in the key value. */
3385
/* Here we handle all other data types except the
3386
true VARCHAR, BLOB and TEXT. Note that the column
3387
value we store may be also in a column prefix
3392
const unsigned char* src_start;
3393
enum_field_types real_type;
3395
key_len = key_part->length;
3403
src_start = record + key_part->offset;
3404
real_type = field->real_type();
3407
/* Character set for the field is defined only
3408
to fields whose type is string and real field
3409
type is not enum or set. For these fields check
3410
if character set is multi byte. */
3412
memcpy(buff, src_start, true_len);
3415
/* Pad the unused space with spaces. Note that no
3416
padding is ever needed for UCS-2 because in MySQL,
3417
all UCS2 characters are 2 bytes, as MySQL does not
3418
support surrogate pairs, which are needed to represent
3419
characters in the range U+10000 to U+10FFFF. */
3421
if (true_len < key_len) {
3422
ulint pad_len = key_len - true_len;
3423
memset(buff, ' ', pad_len);
3429
ut_a(buff <= buff_start + buff_len);
3431
return((uint)(buff - buff_start));
3434
/**************************************************************//**
3435
Builds a 'template' to the prebuilt struct. The template is used in fast
3436
retrieval of just those column values MySQL needs in its processing. */
3441
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
3442
Session* , /*!< in: current user thread, used
3443
only if templ_type is
3444
ROW_DRIZZLE_REC_FIELDS */
3445
Table* table, /*!< in: MySQL table */
3446
uint templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
3447
ROW_DRIZZLE_REC_FIELDS */
3449
dict_index_t* index;
3450
dict_index_t* clust_index;
3451
mysql_row_templ_t* templ;
3454
ulint n_requested_fields = 0;
3455
ibool fetch_all_in_key = FALSE;
3456
ibool fetch_primary_key_cols = FALSE;
3458
/* byte offset of the end of last requested column */
3459
ulint mysql_prefix_len = 0;
3461
if (prebuilt->select_lock_type == LOCK_X) {
3462
/* We always retrieve the whole clustered index record if we
3463
use exclusive row level locks, for example, if the read is
3464
done in an UPDATE statement. */
3466
templ_type = ROW_MYSQL_WHOLE_ROW;
3469
if (templ_type == ROW_MYSQL_REC_FIELDS) {
3470
if (prebuilt->hint_need_to_fetch_extra_cols
3471
== ROW_RETRIEVE_ALL_COLS) {
3473
/* We know we must at least fetch all columns in the
3474
key, or all columns in the table */
3476
if (prebuilt->read_just_key) {
3477
/* MySQL has instructed us that it is enough
3478
to fetch the columns in the key; looks like
3479
MySQL can set this flag also when there is
3480
only a prefix of the column in the key: in
3481
that case we retrieve the whole column from
3482
the clustered index */
3484
fetch_all_in_key = TRUE;
3486
templ_type = ROW_MYSQL_WHOLE_ROW;
3488
} else if (prebuilt->hint_need_to_fetch_extra_cols
3489
== ROW_RETRIEVE_PRIMARY_KEY) {
3490
/* We must at least fetch all primary key cols. Note
3491
that if the clustered index was internally generated
3492
by InnoDB on the row id (no primary key was
3493
defined), then row_search_for_mysql() will always
3494
retrieve the row id to a special buffer in the
3497
fetch_primary_key_cols = TRUE;
3501
clust_index = dict_table_get_first_index(prebuilt->table);
3503
if (templ_type == ROW_MYSQL_REC_FIELDS) {
3504
index = prebuilt->index;
3506
index = clust_index;
3509
if (index == clust_index) {
3510
prebuilt->need_to_access_clustered = TRUE;
3512
prebuilt->need_to_access_clustered = FALSE;
3513
/* Below we check column by column if we need to access
3514
the clustered index */
3517
n_fields = (ulint)table->s->fields; /* number of columns */
3519
if (!prebuilt->mysql_template) {
3520
prebuilt->mysql_template = (mysql_row_templ_t*)
3521
mem_alloc(n_fields * sizeof(mysql_row_templ_t));
3524
prebuilt->template_type = templ_type;
3525
prebuilt->null_bitmap_len = table->s->null_bytes;
3527
prebuilt->templ_contains_blob = FALSE;
3529
/* Note that in InnoDB, i is the column number. MySQL calls columns
3531
for (i = 0; i < n_fields; i++) {
3532
templ = prebuilt->mysql_template + n_requested_fields;
3533
field = table->field[i];
3535
if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
3536
/* Decide which columns we should fetch
3537
and which we can skip. */
3538
register const ibool index_contains_field =
3539
dict_index_contains_col_or_prefix(index, i);
3541
if (!index_contains_field && prebuilt->read_just_key) {
3542
/* If this is a 'key read', we do not need
3543
columns that are not in the key */
3548
if (index_contains_field && fetch_all_in_key) {
3549
/* This field is needed in the query */
3554
if (field->isReadSet() || field->isWriteSet())
3555
/* This field is needed in the query */
3558
assert(table->isReadSet(i) == field->isReadSet());
3559
assert(table->isWriteSet(i) == field->isWriteSet());
3561
if (fetch_primary_key_cols
3562
&& dict_table_col_in_clustered_key(
3564
/* This field is needed in the query */
3569
/* This field is not needed in the query, skip it */
3574
n_requested_fields++;
3578
if (index == clust_index) {
3579
templ->rec_field_no = dict_col_get_clust_pos(
3580
&index->table->cols[i], index);
3582
templ->rec_field_no = dict_index_get_nth_col_pos(
3586
if (templ->rec_field_no == ULINT_UNDEFINED) {
3587
prebuilt->need_to_access_clustered = TRUE;
3590
if (field->null_ptr) {
3591
templ->mysql_null_byte_offset =
3592
(ulint) ((char*) field->null_ptr
3593
- (char*) table->record[0]);
3595
templ->mysql_null_bit_mask = (ulint) field->null_bit;
3597
templ->mysql_null_bit_mask = 0;
3600
templ->mysql_col_offset = (ulint)
3601
get_field_offset(table, field);
3603
templ->mysql_col_len = (ulint) field->pack_length();
3604
if (mysql_prefix_len < templ->mysql_col_offset
3605
+ templ->mysql_col_len) {
3606
mysql_prefix_len = templ->mysql_col_offset
3607
+ templ->mysql_col_len;
3609
templ->type = index->table->cols[i].mtype;
3610
templ->mysql_type = (ulint)field->type();
3612
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
3613
templ->mysql_length_bytes = (ulint)
3614
(((Field_varstring*)field)->length_bytes);
3617
templ->charset = dtype_get_charset_coll(
3618
index->table->cols[i].prtype);
3619
templ->mbminlen = index->table->cols[i].mbminlen;
3620
templ->mbmaxlen = index->table->cols[i].mbmaxlen;
3621
templ->is_unsigned = index->table->cols[i].prtype
3623
if (templ->type == DATA_BLOB) {
3624
prebuilt->templ_contains_blob = TRUE;
3630
prebuilt->n_template = n_requested_fields;
3631
prebuilt->mysql_prefix_len = mysql_prefix_len;
3633
if (index != clust_index && prebuilt->need_to_access_clustered) {
3634
/* Change rec_field_no's to correspond to the clustered index
3636
for (i = 0; i < n_requested_fields; i++) {
3637
templ = prebuilt->mysql_template + i;
3639
templ->rec_field_no = dict_col_get_clust_pos(
3640
&index->table->cols[templ->col_no],
3646
/********************************************************************//**
3647
Get the upper limit of the MySQL integral and floating-point type. */
3650
ha_innobase::innobase_get_int_col_max_value(
3651
/*========================================*/
3654
uint64_t max_value = 0;
3656
switch(field->key_type()) {
3658
case HA_KEYTYPE_BINARY:
3659
max_value = 0xFFULL;
3662
case HA_KEYTYPE_UINT24:
3663
max_value = 0xFFFFFFULL;
3666
case HA_KEYTYPE_ULONG_INT:
3667
max_value = 0xFFFFFFFFULL;
3669
case HA_KEYTYPE_LONG_INT:
3670
max_value = 0x7FFFFFFFULL;
3673
case HA_KEYTYPE_ULONGLONG:
3674
max_value = 0xFFFFFFFFFFFFFFFFULL;
3676
case HA_KEYTYPE_LONGLONG:
3677
max_value = 0x7FFFFFFFFFFFFFFFULL;
3679
case HA_KEYTYPE_DOUBLE:
3680
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
3681
max_value = 0x20000000000000ULL;
3690
/********************************************************************//**
3691
This special handling is really to overcome the limitations of MySQL's
3692
binlogging. We need to eliminate the non-determinism that will arise in
3693
INSERT ... SELECT type of statements, since MySQL binlog only stores the
3694
min value of the autoinc interval. Once that is fixed we can get rid of
3695
the special lock handling.
3696
@return DB_SUCCESS if all OK else error code */
3699
ha_innobase::innobase_lock_autoinc(void)
3700
/*====================================*/
3702
ulint error = DB_SUCCESS;
3704
switch (innobase_autoinc_lock_mode) {
3705
case AUTOINC_NO_LOCKING:
3706
/* Acquire only the AUTOINC mutex. */
3707
dict_table_autoinc_lock(prebuilt->table);
3710
case AUTOINC_NEW_STYLE_LOCKING:
3711
/* For simple (single/multi) row INSERTs, we fallback to the
3712
old style only if another transaction has already acquired
3713
the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
3714
etc. type of statement. */
3715
if (session_sql_command(user_session) == SQLCOM_INSERT
3716
|| session_sql_command(user_session) == SQLCOM_REPLACE) {
3717
dict_table_t* d_table = prebuilt->table;
3719
/* Acquire the AUTOINC mutex. */
3720
dict_table_autoinc_lock(d_table);
3722
/* We need to check that another transaction isn't
3723
already holding the AUTOINC lock on the table. */
3724
if (d_table->n_waiting_or_granted_auto_inc_locks) {
3725
/* Release the mutex to avoid deadlocks. */
3726
dict_table_autoinc_unlock(d_table);
3731
/* Fall through to old style locking. */
3733
case AUTOINC_OLD_STYLE_LOCKING:
3734
error = row_lock_table_autoinc_for_mysql(prebuilt);
3736
if (error == DB_SUCCESS) {
3738
/* Acquire the AUTOINC mutex. */
3739
dict_table_autoinc_lock(prebuilt->table);
3747
return(ulong(error));
3750
/********************************************************************//**
3751
Reset the autoinc value in the table.
3752
@return DB_SUCCESS if all went well else error code */
3755
ha_innobase::innobase_reset_autoinc(
3756
/*================================*/
3757
uint64_t autoinc) /*!< in: value to store */
3761
error = innobase_lock_autoinc();
3763
if (error == DB_SUCCESS) {
3765
dict_table_autoinc_initialize(prebuilt->table, autoinc);
3767
dict_table_autoinc_unlock(prebuilt->table);
3770
return(ulong(error));
3773
/********************************************************************//**
3774
Store the autoinc value in the table. The autoinc value is only set if
3775
it's greater than the existing autoinc value in the table.
3776
@return DB_SUCCESS if all went well else error code */
3779
ha_innobase::innobase_set_max_autoinc(
3780
/*==================================*/
3781
uint64_t auto_inc) /*!< in: value to store */
3785
error = innobase_lock_autoinc();
3787
if (error == DB_SUCCESS) {
3789
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
3791
dict_table_autoinc_unlock(prebuilt->table);
3794
return(ulong(error));
3797
/********************************************************************//**
3798
Stores a row in an InnoDB database, to the table specified in this
3800
@return error code */
3803
ha_innobase::write_row(
3804
/*===================*/
3805
unsigned char* record) /*!< in: a row in MySQL format */
3808
int error_result= 0;
3809
ibool auto_inc_used= FALSE;
3811
trx_t* trx = session_to_trx(user_session);
3813
if (prebuilt->trx != trx) {
3814
errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
3815
"%p, but for the current thread it is at %p",
3816
(const void*) prebuilt->trx, (const void*) trx);
3818
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
3819
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
3821
"InnoDB: Dump of 200 bytes around ha_data: ",
3823
ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
3828
ha_statistic_increment(&SSV::ha_write_count);
3830
sql_command = session_sql_command(user_session);
3832
if ((sql_command == SQLCOM_ALTER_TABLE
3833
|| sql_command == SQLCOM_CREATE_INDEX
3834
|| sql_command == SQLCOM_DROP_INDEX)
3835
&& num_write_row >= 10000) {
3836
/* ALTER TABLE is COMMITted at every 10000 copied rows.
3837
The IX table lock for the original table has to be re-issued.
3838
As this method will be called on a temporary table where the
3839
contents of the original table is being copied to, it is
3840
a bit tricky to determine the source table. The cursor
3841
position in the source table need not be adjusted after the
3842
intermediate COMMIT, since writes by other transactions are
3843
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
3845
dict_table_t* src_table;
3846
enum lock_mode mode;
3850
/* Commit the transaction. This will release the table
3851
locks, so they have to be acquired again. */
3853
/* Altering an InnoDB table */
3854
/* Get the source table. */
3855
src_table = lock_get_src_table(
3856
prebuilt->trx, prebuilt->table, &mode);
3859
/* Unknown situation: do not commit */
3861
ut_print_timestamp(stderr);
3863
" InnoDB: ALTER TABLE is holding lock"
3864
" on %lu tables!\n",
3865
prebuilt->trx->mysql_n_tables_locked);
3868
} else if (src_table == prebuilt->table) {
3869
/* Source table is not in InnoDB format:
3870
no need to re-acquire locks on it. */
3872
/* Altering to InnoDB format */
3873
engine->commit(user_session, 1);
3874
/* Note that this transaction is still active. */
3875
prebuilt->trx->active_trans = 1;
3876
/* We will need an IX lock on the destination table. */
3877
prebuilt->sql_stat_start = TRUE;
3879
/* Ensure that there are no other table locks than
3880
LOCK_IX and LOCK_AUTO_INC on the destination table. */
3882
if (!lock_is_table_exclusive(prebuilt->table,
3887
/* Commit the transaction. This will release the table
3888
locks, so they have to be acquired again. */
3889
engine->commit(user_session, 1);
3890
/* Note that this transaction is still active. */
3891
prebuilt->trx->active_trans = 1;
3892
/* Re-acquire the table lock on the source table. */
3893
row_lock_table_for_mysql(prebuilt, src_table, mode);
3894
/* We will need an IX lock on the destination table. */
3895
prebuilt->sql_stat_start = TRUE;
3901
/* This is the case where the table has an auto-increment column */
3902
if (table->next_number_field && record == table->record[0]) {
3904
/* Reset the error code before calling
3905
innobase_get_auto_increment(). */
3906
prebuilt->autoinc_error = DB_SUCCESS;
3908
if ((error = update_auto_increment())) {
3910
/* We don't want to mask autoinc overflow errors. */
3911
if (prebuilt->autoinc_error != DB_SUCCESS) {
3912
error = (int) prebuilt->autoinc_error;
3917
/* MySQL errors are passed straight back. */
3918
error_result = (int) error;
3922
auto_inc_used = TRUE;
3925
if (prebuilt->mysql_template == NULL
3926
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
3928
/* Build the template used in converting quickly between
3929
the two database formats */
3931
build_template(prebuilt, NULL, table,
3932
ROW_MYSQL_WHOLE_ROW);
3935
innodb_srv_conc_enter_innodb(prebuilt->trx);
3937
error = row_insert_for_mysql((byte*) record, prebuilt);
3939
/* Handle duplicate key errors */
3940
if (auto_inc_used) {
3943
uint64_t col_max_value;
3945
/* Note the number of rows processed for this statement, used
3946
by get_auto_increment() to determine the number of AUTO-INC
3947
values to reserve. This is only useful for a mult-value INSERT
3948
and is a statement level counter.*/
3949
if (trx->n_autoinc_rows > 0) {
3950
--trx->n_autoinc_rows;
3953
/* We need the upper limit of the col type to check for
3954
whether we update the table autoinc counter or not. */
3955
col_max_value = innobase_get_int_col_max_value(
3956
table->next_number_field);
3958
/* Get the value that MySQL attempted to store in the table.*/
3959
auto_inc = table->next_number_field->val_int();
3962
case DB_DUPLICATE_KEY:
3964
/* A REPLACE command and LOAD DATA INFILE REPLACE
3965
handle a duplicate key error themselves, but we
3966
must update the autoinc counter if we are performing
3967
those statements. */
3969
switch (sql_command) {
3971
if ((trx->duplicates
3972
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
3974
goto set_max_autoinc;
3978
case SQLCOM_REPLACE:
3979
case SQLCOM_INSERT_SELECT:
3980
case SQLCOM_REPLACE_SELECT:
3981
goto set_max_autoinc;
3990
/* If the actual value inserted is greater than
3991
the upper limit of the interval, then we try and
3992
update the table upper limit. Note: last_value
3993
will be 0 if get_auto_increment() was not called.*/
3995
if (auto_inc <= col_max_value
3996
&& auto_inc >= prebuilt->autoinc_last_value) {
3998
ut_a(prebuilt->autoinc_increment > 0);
4003
offset = prebuilt->autoinc_offset;
4004
need = prebuilt->autoinc_increment;
4006
auto_inc = innobase_next_autoinc(
4007
auto_inc, need, offset, col_max_value);
4009
err = innobase_set_max_autoinc(auto_inc);
4011
if (err != DB_SUCCESS) {
4019
innodb_srv_conc_exit_innodb(prebuilt->trx);
4022
error_result = convert_error_code_to_mysql((int) error,
4023
prebuilt->table->flags,
4027
innobase_active_small();
4029
return(error_result);
4032
/**********************************************************************//**
4033
Checks which fields have changed in a row and stores information
4034
of them to an update vector.
4035
@return error number or 0 */
4038
calc_row_difference(
4039
/*================*/
4040
upd_t* uvect, /*!< in/out: update vector */
4041
unsigned char* old_row, /*!< in: old row in MySQL format */
4042
unsigned char* new_row, /*!< in: new row in MySQL format */
4043
Table* table, /*!< in: table in MySQL data
4045
unsigned char* upd_buff, /*!< in: buffer to use */
4046
ulint buff_len, /*!< in: buffer length */
4047
row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
4048
Session* ) /*!< in: user thread */
4050
unsigned char* original_upd_buff = upd_buff;
4052
enum_field_types field_mysql_type;
4057
const byte* new_mysql_row_col;
4061
upd_field_t* ufield;
4063
ulint n_changed = 0;
4065
dict_index_t* clust_index;
4068
n_fields = table->s->fields;
4069
clust_index = dict_table_get_first_index(prebuilt->table);
4071
/* We use upd_buff to convert changed fields */
4072
buf = (byte*) upd_buff;
4074
for (i = 0; i < n_fields; i++) {
4075
field = table->field[i];
4077
o_ptr = (const byte*) old_row + get_field_offset(table, field);
4078
n_ptr = (const byte*) new_row + get_field_offset(table, field);
4080
/* Use new_mysql_row_col and col_pack_len save the values */
4082
new_mysql_row_col = n_ptr;
4083
col_pack_len = field->pack_length();
4085
o_len = col_pack_len;
4086
n_len = col_pack_len;
4088
/* We use o_ptr and n_ptr to dig up the actual data for
4091
field_mysql_type = field->type();
4093
col_type = prebuilt->table->cols[i].mtype;
4098
o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4099
n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4106
if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4107
/* This is a >= 5.0.3 type true VARCHAR where
4108
the real payload data length is stored in
4111
o_ptr = row_mysql_read_true_varchar(
4114
(((Field_varstring*)field)->length_bytes));
4116
n_ptr = row_mysql_read_true_varchar(
4119
(((Field_varstring*)field)->length_bytes));
4127
if (field->null_ptr) {
4128
if (field_in_record_is_null(table, field,
4130
o_len = UNIV_SQL_NULL;
4133
if (field_in_record_is_null(table, field,
4135
n_len = UNIV_SQL_NULL;
4139
if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4140
0 != memcmp(o_ptr, n_ptr, o_len))) {
4141
/* The field has changed */
4143
ufield = uvect->fields + n_changed;
4145
/* Let us use a dummy dfield to make the conversion
4146
from the MySQL column format to the InnoDB format */
4148
dict_col_copy_type(prebuilt->table->cols + i,
4151
if (n_len != UNIV_SQL_NULL) {
4152
buf = row_mysql_store_col_in_innobase_format(
4158
dict_table_is_comp(prebuilt->table));
4159
dfield_copy_data(&ufield->new_val, &dfield);
4161
dfield_set_null(&ufield->new_val);
4165
ufield->orig_len = 0;
4166
ufield->field_no = dict_col_get_clust_pos(
4167
&prebuilt->table->cols[i], clust_index);
4172
uvect->n_fields = n_changed;
4173
uvect->info_bits = 0;
4175
ut_a(buf <= (byte*)original_upd_buff + buff_len);
4180
/**********************************************************************//**
4181
Updates a row given as a parameter to a new value. Note that we are given
4182
whole rows, not just the fields which are updated: this incurs some
4183
overhead for CPU when we check which fields are actually updated.
4184
TODO: currently InnoDB does not prevent the 'Halloween problem':
4185
in a searched update a single row can get updated several times
4186
if its index columns are updated!
4187
@return error number or 0 */
4190
ha_innobase::update_row(
4191
/*====================*/
4192
const unsigned char* old_row,/*!< in: old row in MySQL format */
4193
unsigned char* new_row)/*!< in: new row in MySQL format */
4197
trx_t* trx = session_to_trx(user_session);
4199
ut_a(prebuilt->trx == trx);
4201
ha_statistic_increment(&SSV::ha_update_count);
4203
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
4204
table->timestamp_field->set_time();
4206
if (prebuilt->upd_node) {
4207
uvect = prebuilt->upd_node->update;
4209
uvect = row_get_prebuilt_update_vector(prebuilt);
4212
/* Build an update vector from the modified fields in the rows
4213
(uses upd_buff of the handle) */
4215
calc_row_difference(uvect, (unsigned char*) old_row, new_row, table,
4216
upd_buff, (ulint)upd_and_key_val_buff_len,
4217
prebuilt, user_session);
4219
/* This is not a delete */
4220
prebuilt->upd_node->is_delete = FALSE;
4222
ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4224
innodb_srv_conc_enter_innodb(trx);
4226
error = row_update_for_mysql((byte*) old_row, prebuilt);
4228
/* We need to do some special AUTOINC handling for the following case:
4230
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4232
We need to use the AUTOINC counter that was actually used by
4233
MySQL in the UPDATE statement, which can be different from the
4234
value used in the INSERT statement.*/
4236
if (error == DB_SUCCESS
4237
&& table->next_number_field
4238
&& new_row == table->record[0]
4239
&& session_sql_command(user_session) == SQLCOM_INSERT
4240
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
4241
== TRX_DUP_IGNORE) {
4244
uint64_t col_max_value;
4246
auto_inc = table->next_number_field->val_int();
4248
/* We need the upper limit of the col type to check for
4249
whether we update the table autoinc counter or not. */
4250
col_max_value = innobase_get_int_col_max_value(
4251
table->next_number_field);
4253
if (auto_inc <= col_max_value && auto_inc != 0) {
4258
offset = prebuilt->autoinc_offset;
4259
need = prebuilt->autoinc_increment;
4261
auto_inc = innobase_next_autoinc(
4262
auto_inc, need, offset, col_max_value);
4264
error = innobase_set_max_autoinc(auto_inc);
4268
innodb_srv_conc_exit_innodb(trx);
4270
error = convert_error_code_to_mysql(error,
4271
prebuilt->table->flags,
4274
if (error == 0 /* success */
4275
&& uvect->n_fields == 0 /* no columns were updated */) {
4277
/* This is the same as success, but instructs
4278
MySQL that the row is not really updated and it
4279
should not increase the count of updated rows.
4280
This is fix for http://bugs.mysql.com/29157 */
4281
error = HA_ERR_RECORD_IS_THE_SAME;
4284
/* Tell InnoDB server that there might be work for
4287
innobase_active_small();
4292
/**********************************************************************//**
4293
Deletes a row given as the parameter.
4294
@return error number or 0 */
4297
ha_innobase::delete_row(
4298
/*====================*/
4299
const unsigned char* record) /*!< in: a row in MySQL format */
4302
trx_t* trx = session_to_trx(user_session);
4304
ut_a(prebuilt->trx == trx);
4306
ha_statistic_increment(&SSV::ha_delete_count);
4308
if (!prebuilt->upd_node) {
4309
row_get_prebuilt_update_vector(prebuilt);
4312
/* This is a delete */
4314
prebuilt->upd_node->is_delete = TRUE;
4316
innodb_srv_conc_enter_innodb(trx);
4318
error = row_update_for_mysql((byte*) record, prebuilt);
4320
innodb_srv_conc_exit_innodb(trx);
4322
error = convert_error_code_to_mysql(
4323
error, prebuilt->table->flags, user_session);
4325
/* Tell the InnoDB server that there might be work for
4328
innobase_active_small();
4333
/**********************************************************************//**
4334
Removes a new lock set on a row, if it was not read optimistically. This can
4335
be called after a row has been read in the processing of an UPDATE or a DELETE
4336
query, if the option innodb_locks_unsafe_for_binlog is set. */
4339
ha_innobase::unlock_row(void)
4340
/*=========================*/
4342
/* Consistent read does not take any locks, thus there is
4343
nothing to unlock. */
4345
if (prebuilt->select_lock_type == LOCK_NONE) {
4349
switch (prebuilt->row_read_type) {
4350
case ROW_READ_WITH_LOCKS:
4351
if (!srv_locks_unsafe_for_binlog
4352
&& prebuilt->trx->isolation_level
4353
!= TRX_ISO_READ_COMMITTED) {
4357
case ROW_READ_TRY_SEMI_CONSISTENT:
4358
row_unlock_for_mysql(prebuilt, FALSE);
4360
case ROW_READ_DID_SEMI_CONSISTENT:
4361
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4368
/* See Cursor.h and row0mysql.h for docs on this function. */
4371
ha_innobase::was_semi_consistent_read(void)
4372
/*=======================================*/
4374
return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
4377
/* See Cursor.h and row0mysql.h for docs on this function. */
4380
ha_innobase::try_semi_consistent_read(bool yes)
4381
/*===========================================*/
4383
ut_a(prebuilt->trx == session_to_trx(ha_session()));
4385
/* Row read type is set to semi consistent read if this was
4386
requested by the MySQL and either innodb_locks_unsafe_for_binlog
4387
option is used or this session is using READ COMMITTED isolation
4391
&& (srv_locks_unsafe_for_binlog
4392
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
4393
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4395
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
4399
/******************************************************************//**
4400
Initializes a handle to use an index.
4401
@return 0 or error number */
4404
ha_innobase::index_init(
4405
/*====================*/
4406
uint keynr, /*!< in: key (index) number */
4407
bool ) /*!< in: 1 if result MUST be sorted according to index */
4409
return(change_active_index(keynr));
4412
/******************************************************************//**
4413
Currently does nothing.
4417
ha_innobase::index_end(void)
4418
/*========================*/
4421
active_index=MAX_KEY;
4425
/*********************************************************************//**
4426
Converts a search mode flag understood by MySQL to a flag understood
4430
convert_search_mode_to_innobase(
4431
/*============================*/
4432
enum ha_rkey_function find_flag)
4434
switch (find_flag) {
4435
case HA_READ_KEY_EXACT:
4436
/* this does not require the index to be UNIQUE */
4437
return(PAGE_CUR_GE);
4438
case HA_READ_KEY_OR_NEXT:
4439
return(PAGE_CUR_GE);
4440
case HA_READ_KEY_OR_PREV:
4441
return(PAGE_CUR_LE);
4442
case HA_READ_AFTER_KEY:
4444
case HA_READ_BEFORE_KEY:
4446
case HA_READ_PREFIX:
4447
return(PAGE_CUR_GE);
4448
case HA_READ_PREFIX_LAST:
4449
return(PAGE_CUR_LE);
4450
case HA_READ_PREFIX_LAST_OR_PREV:
4451
return(PAGE_CUR_LE);
4452
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
4453
pass a complete-field prefix of a key value as the search
4454
tuple. I.e., it is not allowed that the last field would
4455
just contain n first bytes of the full field value.
4456
MySQL uses a 'padding' trick to convert LIKE 'abc%'
4457
type queries so that it can use as a search tuple
4458
a complete-field-prefix of a key value. Thus, the InnoDB
4459
search mode PAGE_CUR_LE_OR_EXTENDS is never used.
4460
TODO: when/if MySQL starts to use also partial-field
4461
prefixes, we have to deal with stripping of spaces
4462
and comparison of non-latin1 char type fields in
4463
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
4465
case HA_READ_MBR_CONTAIN:
4466
case HA_READ_MBR_INTERSECT:
4467
case HA_READ_MBR_WITHIN:
4468
case HA_READ_MBR_DISJOINT:
4469
case HA_READ_MBR_EQUAL:
4470
return(PAGE_CUR_UNSUPP);
4471
/* do not use "default:" in order to produce a gcc warning:
4472
enumeration value '...' not handled in switch
4473
(if -Wswitch or -Wall is used) */
4476
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
4478
return(PAGE_CUR_UNSUPP);
4482
BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
4483
---------------------------------------------------
4484
The following does not cover all the details, but explains how we determine
4485
the start of a new SQL statement, and what is associated with it.
4487
For each table in the database the MySQL interpreter may have several
4488
table handle instances in use, also in a single SQL query. For each table
4489
handle instance there is an InnoDB 'prebuilt' struct which contains most
4490
of the InnoDB data associated with this table handle instance.
4492
A) if the user has not explicitly set any MySQL table level locks:
4494
1) MySQL calls ::external_lock to set an 'intention' table level lock on
4495
the table of the handle instance. There we set
4496
prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set
4497
true if we are taking this table handle instance to use in a new SQL
4498
statement issued by the user. We also increment trx->n_mysql_tables_in_use.
4500
2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
4501
instructions to prebuilt->template of the table handle instance in
4502
::index_read. The template is used to save CPU time in large joins.
4504
3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
4505
allocate a new consistent read view for the trx if it does not yet have one,
4506
or in the case of a locking read, set an InnoDB 'intention' table level
4509
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
4510
same table handle instance, if it is a join.
4512
5) When the SELECT ends, MySQL removes its intention table level locks
4513
in ::external_lock. When trx->n_mysql_tables_in_use drops to zero,
4514
(a) we execute a COMMIT there if the autocommit is on,
4515
(b) we also release possible 'SQL statement level resources' InnoDB may
4516
have for this SQL statement. The MySQL interpreter does NOT execute
4517
autocommit for pure read transactions, though it should. That is why the
4518
table Cursor in that case has to execute the COMMIT in ::external_lock.
4520
B) If the user has explicitly set MySQL table level locks, then MySQL
4521
does NOT call ::external_lock at the start of the statement. To determine
4522
when we are at the start of a new SQL statement we at the start of
4523
::index_read also compare the query id to the latest query id where the
4524
table handle instance was used. If it has changed, we know we are at the
4525
start of a new SQL statement. Since the query id can theoretically
4526
overwrap, we use this test only as a secondary way of determining the
4527
start of a new SQL statement. */
4530
/**********************************************************************//**
4531
Positions an index cursor to the index specified in the handle. Fetches the
4533
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
4536
ha_innobase::index_read(
4537
/*====================*/
4538
unsigned char* buf, /*!< in/out: buffer for the returned
4540
const unsigned char* key_ptr,/*!< in: key value; if this is NULL
4541
we position the cursor at the
4542
start or end of index; this can
4543
also contain an InnoDB row id, in
4544
which case key_len is the InnoDB
4545
row id length; the key value can
4546
also be a prefix of a full key value,
4547
and the last column can be a prefix
4549
uint key_len,/*!< in: key value length */
4550
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4553
dict_index_t* index;
4554
ulint match_mode = 0;
4558
ut_a(prebuilt->trx == session_to_trx(user_session));
4560
ha_statistic_increment(&SSV::ha_read_key_count);
4562
index = prebuilt->index;
4564
/* Note that if the index for which the search template is built is not
4565
necessarily prebuilt->index, but can also be the clustered index */
4567
if (prebuilt->sql_stat_start) {
4568
build_template(prebuilt, user_session, table,
4569
ROW_MYSQL_REC_FIELDS);
4573
/* Convert the search key value to InnoDB format into
4574
prebuilt->search_tuple */
4576
row_sel_convert_mysql_key_to_innobase(
4577
prebuilt->search_tuple,
4578
(byte*) key_val_buff,
4579
(ulint)upd_and_key_val_buff_len,
4585
/* We position the cursor to the last or the first entry
4588
dtuple_set_n_fields(prebuilt->search_tuple, 0);
4591
mode = convert_search_mode_to_innobase(find_flag);
4595
if (find_flag == HA_READ_KEY_EXACT) {
4597
match_mode = ROW_SEL_EXACT;
4599
} else if (find_flag == HA_READ_PREFIX
4600
|| find_flag == HA_READ_PREFIX_LAST) {
4602
match_mode = ROW_SEL_EXACT_PREFIX;
4605
last_match_mode = (uint) match_mode;
4607
if (mode != PAGE_CUR_UNSUPP) {
4609
innodb_srv_conc_enter_innodb(prebuilt->trx);
4611
ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
4614
innodb_srv_conc_exit_innodb(prebuilt->trx);
4617
ret = DB_UNSUPPORTED;
4625
case DB_RECORD_NOT_FOUND:
4626
error = HA_ERR_KEY_NOT_FOUND;
4627
table->status = STATUS_NOT_FOUND;
4629
case DB_END_OF_INDEX:
4630
error = HA_ERR_KEY_NOT_FOUND;
4631
table->status = STATUS_NOT_FOUND;
4634
error = convert_error_code_to_mysql((int) ret,
4635
prebuilt->table->flags,
4637
table->status = STATUS_NOT_FOUND;
4644
/*******************************************************************//**
4645
The following functions works like index_read, but it find the last
4646
row with the current key value or prefix.
4647
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
4650
ha_innobase::index_read_last(
4651
/*=========================*/
4652
unsigned char* buf, /*!< out: fetched row */
4653
const unsigned char* key_ptr,/*!< in: key value, or a prefix of a full
4655
uint key_len)/*!< in: length of the key val or prefix
4658
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
4661
/********************************************************************//**
4662
Get the index for a handle. Does not change active index.
4663
@return NULL or index instance. */
4666
ha_innobase::innobase_get_index(
4667
/*============================*/
4668
uint keynr) /*!< in: use this index; MAX_KEY means always
4669
clustered index, even if it was internally
4670
generated by InnoDB */
4673
dict_index_t* index = 0;
4675
ha_statistic_increment(&SSV::ha_read_key_count);
4677
ut_ad(user_session == ha_session());
4678
ut_a(prebuilt->trx == session_to_trx(user_session));
4680
if (keynr != MAX_KEY && table->s->keys > 0) {
4681
key = table->key_info + keynr;
4683
index = dict_table_get_index_on_name(prebuilt->table,
4686
index = dict_table_get_first_index(prebuilt->table);
4690
errmsg_printf(ERRMSG_LVL_ERROR,
4691
"Innodb could not find key n:o %u with name %s "
4692
"from dict cache for table %s",
4693
keynr, key ? key->name : "NULL",
4694
prebuilt->table->name);
4700
/********************************************************************//**
4701
Changes the active index of a handle.
4702
@return 0 or error code */
4705
ha_innobase::change_active_index(
4706
/*=============================*/
4707
uint keynr) /*!< in: use this index; MAX_KEY means always clustered
4708
index, even if it was internally generated by
4711
ut_ad(user_session == ha_session());
4712
ut_a(prebuilt->trx == session_to_trx(user_session));
4714
active_index = keynr;
4716
prebuilt->index = innobase_get_index(keynr);
4718
if (UNIV_UNLIKELY(!prebuilt->index)) {
4719
errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
4724
prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
4727
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
4728
errmsg_printf(ERRMSG_LVL_WARN,
4729
"InnoDB: insufficient history for index %u",
4731
/* The caller seems to ignore this. Thus, we must check
4732
this again in row_search_for_mysql(). */
4736
ut_a(prebuilt->search_tuple != 0);
4738
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
4740
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
4741
prebuilt->index->n_fields);
4743
/* MySQL changes the active index for a handle also during some
4744
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
4745
and then calculates the sum. Previously we played safe and used
4746
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
4747
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
4749
build_template(prebuilt, user_session, table, ROW_MYSQL_REC_FIELDS);
4754
/**********************************************************************//**
4755
Positions an index cursor to the index specified in keynr. Fetches the
4757
??? This is only used to read whole keys ???
4758
@return error number or 0 */
4761
ha_innobase::index_read_idx(
4762
/*========================*/
4763
unsigned char* buf, /*!< in/out: buffer for the returned
4765
uint keynr, /*!< in: use this index */
4766
const unsigned char* key, /*!< in: key value; if this is NULL
4767
we position the cursor at the
4768
start or end of index */
4769
uint key_len, /*!< in: key value length */
4770
enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4772
if (change_active_index(keynr)) {
4777
return(index_read(buf, key, key_len, find_flag));
4780
/***********************************************************************//**
4781
Reads the next or previous row from a cursor, which must have previously been
4782
positioned using index_read.
4783
@return 0, HA_ERR_END_OF_FILE, or error number */
4786
ha_innobase::general_fetch(
4787
/*=======================*/
4788
unsigned char* buf, /*!< in/out: buffer for next row in MySQL
4790
uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
4791
uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
4792
ROW_SEL_EXACT_PREFIX */
4797
ut_a(prebuilt->trx == session_to_trx(user_session));
4799
innodb_srv_conc_enter_innodb(prebuilt->trx);
4801
ret = row_search_for_mysql(
4802
(byte*)buf, 0, prebuilt, match_mode, direction);
4804
innodb_srv_conc_exit_innodb(prebuilt->trx);
4811
case DB_RECORD_NOT_FOUND:
4812
error = HA_ERR_END_OF_FILE;
4813
table->status = STATUS_NOT_FOUND;
4815
case DB_END_OF_INDEX:
4816
error = HA_ERR_END_OF_FILE;
4817
table->status = STATUS_NOT_FOUND;
4820
error = convert_error_code_to_mysql(
4821
(int) ret, prebuilt->table->flags, user_session);
4822
table->status = STATUS_NOT_FOUND;
4829
/***********************************************************************//**
4830
Reads the next row from a cursor, which must have previously been
4831
positioned using index_read.
4832
@return 0, HA_ERR_END_OF_FILE, or error number */
4835
ha_innobase::index_next(
4836
/*====================*/
4837
unsigned char* buf) /*!< in/out: buffer for next row in MySQL
4840
ha_statistic_increment(&SSV::ha_read_next_count);
4842
return(general_fetch(buf, ROW_SEL_NEXT, 0));
4845
/*******************************************************************//**
4846
Reads the next row matching to the key value given as the parameter.
4847
@return 0, HA_ERR_END_OF_FILE, or error number */
4850
ha_innobase::index_next_same(
4851
/*=========================*/
4852
unsigned char* buf, /*!< in/out: buffer for the row */
4853
const unsigned char* , /*!< in: key value */
4854
uint ) /*!< in: key value length */
4856
ha_statistic_increment(&SSV::ha_read_next_count);
4858
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
4861
/***********************************************************************//**
4862
Reads the previous row from a cursor, which must have previously been
4863
positioned using index_read.
4864
@return 0, HA_ERR_END_OF_FILE, or error number */
4867
ha_innobase::index_prev(
4868
/*====================*/
4869
unsigned char* buf) /*!< in/out: buffer for previous row in MySQL format */
4871
ha_statistic_increment(&SSV::ha_read_prev_count);
4873
return(general_fetch(buf, ROW_SEL_PREV, 0));
4876
/********************************************************************//**
4877
Positions a cursor on the first record in an index and reads the
4878
corresponding row to buf.
4879
@return 0, HA_ERR_END_OF_FILE, or error code */
4882
ha_innobase::index_first(
4883
/*=====================*/
4884
unsigned char* buf) /*!< in/out: buffer for the row */
4888
ha_statistic_increment(&SSV::ha_read_first_count);
4890
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
4892
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4894
if (error == HA_ERR_KEY_NOT_FOUND) {
4895
error = HA_ERR_END_OF_FILE;
4901
/********************************************************************//**
4902
Positions a cursor on the last record in an index and reads the
4903
corresponding row to buf.
4904
@return 0, HA_ERR_END_OF_FILE, or error code */
4907
ha_innobase::index_last(
4908
/*====================*/
4909
unsigned char* buf) /*!< in/out: buffer for the row */
4913
ha_statistic_increment(&SSV::ha_read_last_count);
4915
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
4917
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4919
if (error == HA_ERR_KEY_NOT_FOUND) {
4920
error = HA_ERR_END_OF_FILE;
4926
/****************************************************************//**
4927
Initialize a table scan.
4928
@return 0 or error number */
4931
ha_innobase::rnd_init(
4932
/*==================*/
4933
bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
4937
/* Store the active index value so that we can restore the original
4938
value after a scan */
4940
if (prebuilt->clust_index_was_generated) {
4941
err = change_active_index(MAX_KEY);
4943
err = change_active_index(primary_key);
4946
/* Don't use semi-consistent read in random row reads (by position).
4947
This means we must disable semi_consistent_read if scan is false */
4950
try_semi_consistent_read(0);
4958
/*****************************************************************//**
4960
@return 0 or error number */
4963
ha_innobase::rnd_end(void)
4964
/*======================*/
4966
return(index_end());
4969
/*****************************************************************//**
4970
Reads the next row in a table scan (also used to read the FIRST row
4972
@return 0, HA_ERR_END_OF_FILE, or error number */
4975
ha_innobase::rnd_next(
4976
/*==================*/
4977
unsigned char* buf) /*!< in/out: returns the row in this buffer,
4982
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
4984
if (start_of_scan) {
4985
error = index_first(buf);
4987
if (error == HA_ERR_KEY_NOT_FOUND) {
4988
error = HA_ERR_END_OF_FILE;
4993
error = general_fetch(buf, ROW_SEL_NEXT, 0);
4999
/**********************************************************************//**
5000
Fetches a row from the table based on a row reference.
5001
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
5004
ha_innobase::rnd_pos(
5005
/*=================*/
5006
unsigned char* buf, /*!< in/out: buffer for the row */
5007
unsigned char* pos) /*!< in: primary key value of the row in the
5008
MySQL format, or the row id if the clustered
5009
index was internally generated by InnoDB; the
5010
length of data in pos has to be ref_length */
5013
uint keynr = active_index;
5015
ha_statistic_increment(&SSV::ha_read_rnd_count);
5017
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5019
if (prebuilt->clust_index_was_generated) {
5020
/* No primary key was defined for the table and we
5021
generated the clustered index from the row id: the
5022
row reference is the row id, not any key value
5023
that MySQL knows of */
5025
error = change_active_index(MAX_KEY);
5027
error = change_active_index(primary_key);
5034
/* Note that we assume the length of the row reference is fixed
5035
for the table, and it is == ref_length */
5037
error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5042
change_active_index(keynr);
5047
/*********************************************************************//**
5048
Stores a reference to the current row to 'ref' field of the handle. Note
5049
that in the case where we have generated the clustered index for the
5050
table, the function parameter is illogical: we MUST ASSUME that 'record'
5051
is the current 'position' of the handle, because if row ref is actually
5052
the row id internally generated in InnoDB, then 'record' does not contain
5053
it. We just guess that the row id must be for the record where the handle
5054
was positioned the last time. */
5057
ha_innobase::position(
5058
/*==================*/
5059
const unsigned char* record) /*!< in: row in MySQL format */
5063
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5065
if (prebuilt->clust_index_was_generated) {
5066
/* No primary key was defined for the table and we
5067
generated the clustered index from row id: the
5068
row reference will be the row id, not any key value
5069
that MySQL knows of */
5071
len = DATA_ROW_ID_LEN;
5073
memcpy(ref, prebuilt->row_id, len);
5075
len = store_key_val_for_row(primary_key, (char*)ref,
5076
ref_length, record);
5079
/* We assume that the 'ref' value len is always fixed for the same
5082
if (len != ref_length) {
5083
errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
5084
(ulong) len, (ulong) ref_length);
5089
/*****************************************************************//**
5090
Creates a table definition to an InnoDB database. */
5095
trx_t* trx, /*!< in: InnoDB transaction handle */
5096
Table* form, /*!< in: information on table
5097
columns and indexes */
5098
const char* table_name, /*!< in: table name */
5099
const char* path_of_temp_table,/*!< in: if this is a table explicitly
5100
created by the user with the
5101
TEMPORARY keyword, then this
5102
parameter is the dir path where the
5103
table should be placed if we create
5104
an .ibd file for it (no .ibd extension
5105
in the path, though); otherwise this
5107
ulint flags) /*!< in: table flags */
5110
dict_table_t* table;
5115
ulint nulls_allowed;
5116
ulint unsigned_type;
5118
ulint long_true_varchar;
5122
n_cols = form->s->fields;
5124
/* We pass 0 as the space id, and determine at a lower level the space
5125
id where to store the table */
5127
table = dict_mem_table_create(table_name, 0, n_cols, flags);
5129
if (path_of_temp_table) {
5130
table->dir_path_of_temp_table =
5131
mem_heap_strdup(table->heap, path_of_temp_table);
5134
for (i = 0; i < n_cols; i++) {
5135
field = form->field[i];
5137
col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5139
if (field->null_ptr) {
5142
nulls_allowed = DATA_NOT_NULL;
5145
if (field->binary()) {
5146
binary_type = DATA_BINARY_TYPE;
5153
if (dtype_is_string_type(col_type)) {
5155
charset_no = (ulint)field->charset()->number;
5157
if (UNIV_UNLIKELY(charset_no >= 256)) {
5158
/* in data0type.h we assume that the
5159
number fits in one byte in prtype */
5160
push_warning_printf(
5161
(Session*) trx->mysql_thd,
5162
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5163
ER_CANT_CREATE_TABLE,
5164
"In InnoDB, charset-collation codes"
5165
" must be below 256."
5166
" Unsupported code %lu.",
5167
(ulong) charset_no);
5168
return(ER_CANT_CREATE_TABLE);
5172
ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5173
that this fits in one byte */
5174
col_len = field->pack_length();
5176
/* The MySQL pack length contains 1 or 2 bytes length field
5177
for a true VARCHAR. Let us subtract that, so that the InnoDB
5178
column length in the InnoDB data dictionary is the real
5179
maximum byte length of the actual data. */
5181
long_true_varchar = 0;
5183
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5184
col_len -= ((Field_varstring*)field)->length_bytes;
5186
if (((Field_varstring*)field)->length_bytes == 2) {
5187
long_true_varchar = DATA_LONG_TRUE_VARCHAR;
5191
dict_mem_table_add_col(table, table->heap,
5192
(char*) field->field_name,
5195
(ulint)field->type()
5196
| nulls_allowed | unsigned_type
5197
| binary_type | long_true_varchar,
5202
error = row_create_table_for_mysql(table, trx);
5204
error = convert_error_code_to_mysql(error, flags, NULL);
5209
/*****************************************************************//**
5210
Creates an index in an InnoDB database. */
5215
trx_t* trx, /*!< in: InnoDB transaction handle */
5216
Table* form, /*!< in: information on table
5217
columns and indexes */
5218
ulint flags, /*!< in: InnoDB table flags */
5219
const char* table_name, /*!< in: table name */
5220
uint key_num) /*!< in: index number */
5223
dict_index_t* index;
5227
KEY_PART_INFO* key_part;
5234
ulint* field_lengths;
5236
key = form->key_info + key_num;
5238
n_fields = key->key_parts;
5242
if (key_num == form->s->primary_key) {
5243
ind_type = ind_type | DICT_CLUSTERED;
5246
if (key->flags & HA_NOSAME ) {
5247
ind_type = ind_type | DICT_UNIQUE;
5250
/* We pass 0 as the space id, and determine at a lower level the space
5251
id where to store the table */
5253
index = dict_mem_index_create(table_name, key->name, 0,
5254
ind_type, n_fields);
5256
field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
5258
for (i = 0; i < n_fields; i++) {
5259
key_part = key->key_part + i;
5261
/* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
5262
field in an index: we only store a specified number of first
5263
bytes of the column to the index field.) The flag does not
5264
seem to be properly set by MySQL. Let us fall back on testing
5265
the length of the key part versus the column. */
5268
for (j = 0; j < form->s->fields; j++) {
5270
field = form->field[j];
5272
if (0 == innobase_strcasecmp(
5274
key_part->field->field_name)) {
5275
/* Found the corresponding column */
5281
ut_a(j < form->s->fields);
5283
col_type = get_innobase_type_from_mysql_type(
5284
&is_unsigned, key_part->field);
5286
if (DATA_BLOB == col_type
5287
|| (key_part->length < field->pack_length()
5288
&& field->type() != DRIZZLE_TYPE_VARCHAR)
5289
|| (field->type() == DRIZZLE_TYPE_VARCHAR
5290
&& key_part->length < field->pack_length()
5291
- ((Field_varstring*)field)->length_bytes)) {
5293
prefix_len = key_part->length;
5295
if (col_type == DATA_INT
5296
|| col_type == DATA_FLOAT
5297
|| col_type == DATA_DOUBLE
5298
|| col_type == DATA_DECIMAL) {
5299
errmsg_printf(ERRMSG_LVL_ERROR,
5300
"MySQL is trying to create a column "
5301
"prefix index field, on an "
5302
"inappropriate data type. Table "
5303
"name %s, column name %s.",
5305
key_part->field->field_name);
5313
field_lengths[i] = key_part->length;
5315
dict_mem_index_add_field(index,
5316
(char*) key_part->field->field_name, prefix_len);
5319
/* Even though we've defined max_supported_key_part_length, we
5320
still do our own checking using field_lengths to be absolutely
5321
sure we don't create too long indexes. */
5322
error = row_create_index_for_mysql(index, trx, field_lengths);
5324
error = convert_error_code_to_mysql(error, flags, NULL);
5326
free(field_lengths);
5331
/*****************************************************************//**
5332
Creates an index to an InnoDB table when the user has defined no
5336
create_clustered_index_when_no_primary(
5337
/*===================================*/
5338
trx_t* trx, /*!< in: InnoDB transaction handle */
5339
ulint flags, /*!< in: InnoDB table flags */
5340
const char* table_name) /*!< in: table name */
5342
dict_index_t* index;
5345
/* We pass 0 as the space id, and determine at a lower level the space
5346
id where to store the table */
5348
index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
5349
0, DICT_CLUSTERED, 0);
5351
error = row_create_index_for_mysql(index, trx, NULL);
5353
error = convert_error_code_to_mysql(error, flags, NULL);
5358
/*****************************************************************//**
5359
Validates the create options. We may build on this function
5360
in future. For now, it checks two specifiers:
5361
KEY_BLOCK_SIZE and ROW_FORMAT
5362
If innodb_strict_mode is not set then this function is a no-op
5363
@return TRUE if valid. */
5366
create_options_are_valid(
5367
/*=====================*/
5368
Session* session, /*!< in: connection thread. */
5369
Table& form, /*!< in: information on table
5370
columns and indexes */
5371
drizzled::message::Table& create_proto)
5373
ibool kbs_specified = FALSE;
5377
ut_ad(session != NULL);
5379
/* If innodb_strict_mode is not set don't do any validation. */
5380
if (!(SessionVAR(session, strict_mode))) {
5384
/* First check if KEY_BLOCK_SIZE was specified. */
5385
if (create_proto.options().has_key_block_size()) {
5387
kbs_specified = TRUE;
5388
switch (create_proto.options().key_block_size()) {
5397
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5398
ER_ILLEGAL_HA_CREATE_OPTION,
5400
" KEY_BLOCK_SIZE = %lu."
5402
" [1, 2, 4, 8, 16]",
5403
create_proto.options().key_block_size());
5408
/* If KEY_BLOCK_SIZE was specified, check for its
5410
if (kbs_specified && !srv_file_per_table) {
5411
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5412
ER_ILLEGAL_HA_CREATE_OPTION,
5413
"InnoDB: KEY_BLOCK_SIZE"
5414
" requires innodb_file_per_table.");
5418
if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
5419
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5420
ER_ILLEGAL_HA_CREATE_OPTION,
5421
"InnoDB: KEY_BLOCK_SIZE"
5422
" requires innodb_file_format >"
5427
/* Now check for ROW_FORMAT specifier. */
5428
if (create_proto.options().has_row_type()) {
5429
switch (form.s->row_type) {
5430
const char* row_format_name;
5431
case ROW_TYPE_COMPRESSED:
5432
case ROW_TYPE_DYNAMIC:
5434
= form.s->row_type == ROW_TYPE_COMPRESSED
5438
/* These two ROW_FORMATs require
5439
srv_file_per_table and srv_file_format */
5440
if (!srv_file_per_table) {
5441
push_warning_printf(
5443
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5444
ER_ILLEGAL_HA_CREATE_OPTION,
5445
"InnoDB: ROW_FORMAT=%s"
5446
" requires innodb_file_per_table.",
5452
if (srv_file_format < DICT_TF_FORMAT_ZIP) {
5453
push_warning_printf(
5455
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5456
ER_ILLEGAL_HA_CREATE_OPTION,
5457
"InnoDB: ROW_FORMAT=%s"
5458
" requires innodb_file_format >"
5464
/* Cannot specify KEY_BLOCK_SIZE with
5465
ROW_FORMAT = DYNAMIC.
5466
However, we do allow COMPRESSED to be
5467
specified with KEY_BLOCK_SIZE. */
5469
&& form.s->row_type == ROW_TYPE_DYNAMIC) {
5470
push_warning_printf(
5472
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5473
ER_ILLEGAL_HA_CREATE_OPTION,
5474
"InnoDB: cannot specify"
5475
" ROW_FORMAT = DYNAMIC with"
5476
" KEY_BLOCK_SIZE.");
5482
case ROW_TYPE_REDUNDANT:
5483
case ROW_TYPE_COMPACT:
5484
case ROW_TYPE_DEFAULT:
5485
/* Default is COMPACT. */
5487
= form.s->row_type == ROW_TYPE_REDUNDANT
5491
/* Cannot specify KEY_BLOCK_SIZE with these
5492
format specifiers. */
5493
if (kbs_specified) {
5494
push_warning_printf(
5496
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5497
ER_ILLEGAL_HA_CREATE_OPTION,
5498
"InnoDB: cannot specify"
5499
" ROW_FORMAT = %s with"
5508
push_warning(session,
5509
DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5510
ER_ILLEGAL_HA_CREATE_OPTION,
5511
"InnoDB: invalid ROW_FORMAT specifier.");
5520
/*********************************************************************
5521
Creates a new table to an InnoDB database. */
5524
InnobaseEngine::doCreateTable(
5525
/*================*/
5526
Session* session, /*!< in: Session */
5527
const char* table_name, /*!< in: table name */
5528
Table& form, /*!< in: information on table
5529
columns and indexes */
5530
drizzled::message::Table& create_proto)
5533
dict_table_t* innobase_table;
5538
char name2[FN_REFLEN];
5539
char norm_name[FN_REFLEN];
5540
ib_int64_t auto_inc_value;
5542
/* Cache the value of innodb_file_format, in case it is
5543
modified by another thread while the table is being created. */
5544
const ulint file_format = srv_file_format;
5545
bool lex_identified_temp_table= (create_proto.type() == drizzled::message::Table::TEMPORARY);
5547
assert(session != NULL);
5550
/* Names passed in from server are in two formats:
5551
1. <database_name>/<table_name>: for normal table creation
5552
2. full path: for temp table creation, or sym link
5554
When srv_file_per_table is on, check for full path pattern, i.e.
5555
X:\dir\..., X is a driver letter, or
5556
\\dir1\dir2\..., UNC path
5557
returns error if it is in full path format, but not creating a temp.
5558
table. Currently InnoDB does not support symbolic link on Windows. */
5560
if (srv_file_per_table
5561
&& (! lex_identified_temp_table)) {
5563
if ((table_name[1] == ':')
5564
|| (table_name[0] == '\\' && table_name[1] == '\\')) {
5565
errmsg_printf(ERRMSG_LVL_ERROR, "Cannot create table %s\n", table_name);
5566
return(HA_ERR_GENERIC);
5571
if (form.s->fields > 1000) {
5572
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
5573
but we play safe here */
5575
return(HA_ERR_TO_BIG_ROW);
5578
/* Get the transaction associated with the current session, or create one
5579
if not yet created */
5581
parent_trx = check_trx_exists(session);
5583
/* In case MySQL calls this in the middle of a SELECT query, release
5584
possible adaptive hash latch to avoid deadlocks of threads */
5586
trx_search_latch_release_if_reserved(parent_trx);
5588
trx = innobase_trx_allocate(session);
5590
srv_lower_case_table_names = TRUE;
5592
strcpy(name2, table_name);
5594
normalize_table_name(norm_name, name2);
5596
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
5597
or lock waits can happen in it during a table create operation.
5598
Drop table etc. do this latching in row0mysql.c. */
5600
row_mysql_lock_data_dictionary(trx);
5602
/* Create the table definition in InnoDB */
5606
/* Validate create options if innodb_strict_mode is set. */
5607
if (! create_options_are_valid(session, form, create_proto)) {
5608
error = ER_ILLEGAL_HA_CREATE_OPTION;
5612
if (create_proto.options().has_key_block_size()) {
5613
/* Determine the page_zip.ssize corresponding to the
5614
requested page size (key_block_size) in kilobytes. */
5617
ulint key_block_size = create_proto.options().key_block_size();
5619
for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
5620
ssize++, ksize <<= 1) {
5621
if (key_block_size == ksize) {
5622
iflags = ssize << DICT_TF_ZSSIZE_SHIFT
5624
| DICT_TF_FORMAT_ZIP
5625
<< DICT_TF_FORMAT_SHIFT;
5630
if (!srv_file_per_table) {
5631
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5632
ER_ILLEGAL_HA_CREATE_OPTION,
5633
"InnoDB: KEY_BLOCK_SIZE"
5634
" requires innodb_file_per_table.");
5638
if (file_format < DICT_TF_FORMAT_ZIP) {
5639
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5640
ER_ILLEGAL_HA_CREATE_OPTION,
5641
"InnoDB: KEY_BLOCK_SIZE"
5642
" requires innodb_file_format >"
5648
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5649
ER_ILLEGAL_HA_CREATE_OPTION,
5651
" KEY_BLOCK_SIZE=%lu.",
5652
create_proto.options().key_block_size());
5656
if (create_proto.options().has_row_type()) {
5658
/* KEY_BLOCK_SIZE was specified. */
5659
if (form.s->row_type != ROW_TYPE_COMPRESSED) {
5660
/* ROW_FORMAT other than COMPRESSED
5661
ignores KEY_BLOCK_SIZE. It does not
5662
make sense to reject conflicting
5663
KEY_BLOCK_SIZE and ROW_FORMAT, because
5664
such combinations can be obtained
5665
with ALTER TABLE anyway. */
5666
push_warning_printf(
5668
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5669
ER_ILLEGAL_HA_CREATE_OPTION,
5670
"InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
5671
" unless ROW_FORMAT=COMPRESSED.",
5672
create_proto.options().key_block_size());
5676
/* No KEY_BLOCK_SIZE */
5677
if (form.s->row_type == ROW_TYPE_COMPRESSED) {
5678
/* ROW_FORMAT=COMPRESSED without
5679
KEY_BLOCK_SIZE implies half the
5680
maximum KEY_BLOCK_SIZE. */
5681
iflags = (DICT_TF_ZSSIZE_MAX - 1)
5682
<< DICT_TF_ZSSIZE_SHIFT
5684
| DICT_TF_FORMAT_ZIP
5685
<< DICT_TF_FORMAT_SHIFT;
5686
#if DICT_TF_ZSSIZE_MAX < 1
5687
# error "DICT_TF_ZSSIZE_MAX < 1"
5692
switch (form.s->row_type) {
5693
const char* row_format_name;
5694
case ROW_TYPE_REDUNDANT:
5696
case ROW_TYPE_COMPRESSED:
5697
case ROW_TYPE_DYNAMIC:
5699
= form.s->row_type == ROW_TYPE_COMPRESSED
5703
if (!srv_file_per_table) {
5704
push_warning_printf(
5706
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5707
ER_ILLEGAL_HA_CREATE_OPTION,
5708
"InnoDB: ROW_FORMAT=%s"
5709
" requires innodb_file_per_table.",
5711
} else if (file_format < DICT_TF_FORMAT_ZIP) {
5712
push_warning_printf(
5714
DRIZZLE_ERROR::WARN_LEVEL_WARN,
5715
ER_ILLEGAL_HA_CREATE_OPTION,
5716
"InnoDB: ROW_FORMAT=%s"
5717
" requires innodb_file_format >"
5721
iflags |= DICT_TF_COMPACT
5722
| (DICT_TF_FORMAT_ZIP
5723
<< DICT_TF_FORMAT_SHIFT);
5728
case ROW_TYPE_NOT_USED:
5729
case ROW_TYPE_FIXED:
5731
error = ER_ILLEGAL_HA_CREATE_OPTION;
5733
case ROW_TYPE_DEFAULT:
5734
case ROW_TYPE_COMPACT:
5735
iflags = DICT_TF_COMPACT;
5738
} else if (!iflags) {
5739
/* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
5740
use ROW_FORMAT=COMPACT by default. */
5741
iflags = DICT_TF_COMPACT;
5744
error = create_table_def(trx, &form, norm_name,
5745
lex_identified_temp_table ? name2 : NULL,
5752
/* Look for a primary key */
5754
primary_key_no= (form.s->primary_key != MAX_KEY ?
5755
(int) form.s->primary_key :
5758
/* Our function row_get_mysql_key_number_for_index assumes
5759
the primary key is always number 0, if it exists */
5761
assert(primary_key_no == -1 || primary_key_no == 0);
5763
/* Create the keys */
5765
if (form.s->keys == 0 || primary_key_no == -1) {
5766
/* Create an index which is used as the clustered index;
5767
order the rows by their row id which is internally generated
5770
error = create_clustered_index_when_no_primary(
5771
trx, iflags, norm_name);
5777
if (primary_key_no != -1) {
5778
/* In InnoDB the clustered index must always be created
5780
if ((error = create_index(trx, &form, iflags, norm_name,
5781
(uint) primary_key_no))) {
5786
for (i = 0; i < form.s->keys; i++) {
5788
if (i != (uint) primary_key_no) {
5790
if ((error = create_index(trx, &form, iflags, norm_name,
5797
if (*trx->mysql_query_str) {
5798
error = row_table_add_foreign_constraints(trx,
5799
*trx->mysql_query_str, norm_name,
5800
lex_identified_temp_table);
5802
error = convert_error_code_to_mysql(error, iflags, NULL);
5809
innobase_commit_low(trx);
5811
row_mysql_unlock_data_dictionary(trx);
5813
/* Flush the log to reduce probability that the .frm files and
5814
the InnoDB data dictionary get out-of-sync if the user runs
5815
with innodb_flush_log_at_trx_commit = 0 */
5817
log_buffer_flush_to_disk();
5819
innobase_table = dict_table_get(norm_name, FALSE);
5821
assert(innobase_table != 0);
5823
if (innobase_table) {
5824
/* We update the highest file format in the system table
5825
space, if this table has higher file format setting. */
5827
trx_sys_file_format_max_upgrade(
5828
(const char**) &innobase_file_format_check,
5829
dict_table_get_format(innobase_table));
5832
/* Note: We can't call update_session() as prebuilt will not be
5833
setup at this stage and so we use session. */
5835
/* We need to copy the AUTOINC value from the old table if
5836
this is an ALTER TABLE. */
5838
if ((create_proto.options().has_auto_increment_value()
5839
|| session_sql_command(session) == SQLCOM_ALTER_TABLE)
5840
&& create_proto.options().auto_increment_value() != 0) {
5842
/* Query was ALTER TABLE...AUTO_INCREMENT = x; or
5843
CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
5844
definition from the dictionary and get the current value
5845
of the auto increment field. Set a new value to the
5846
auto increment field if the value is greater than the
5847
maximum value in the column. */
5849
auto_inc_value = create_proto.options().auto_increment_value();
5851
dict_table_autoinc_lock(innobase_table);
5852
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
5853
dict_table_autoinc_unlock(innobase_table);
5856
/* Tell the InnoDB server that there might be work for
5859
srv_active_wake_master_thread();
5861
trx_free_for_mysql(trx);
5866
innobase_commit_low(trx);
5868
row_mysql_unlock_data_dictionary(trx);
5870
trx_free_for_mysql(trx);
5875
/*****************************************************************//**
5876
Discards or imports an InnoDB tablespace.
5877
@return 0 == success, -1 == error */
5880
ha_innobase::discard_or_import_tablespace(
5881
/*======================================*/
5882
my_bool discard) /*!< in: TRUE if discard, else import */
5884
dict_table_t* dict_table;
5888
ut_a(prebuilt->trx);
5889
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
5890
ut_a(prebuilt->trx == session_to_trx(ha_session()));
5892
dict_table = prebuilt->table;
5893
trx = prebuilt->trx;
5896
err = row_discard_tablespace_for_mysql(dict_table->name, trx);
5898
err = row_import_tablespace_for_mysql(dict_table->name, trx);
5901
err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
5906
/*****************************************************************//**
5907
Deletes all rows of an InnoDB table.
5908
@return error number */
5911
ha_innobase::delete_all_rows(void)
5912
/*==============================*/
5916
/* Get the transaction associated with the current session, or create one
5917
if not yet created, and update prebuilt->trx */
5919
update_session(ha_session());
5921
if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
5923
/* We only handle TRUNCATE TABLE t as a special case.
5924
DELETE FROM t will have to use ha_innobase::delete_row(),
5925
because DELETE is transactional while TRUNCATE is not. */
5926
return(errno=HA_ERR_WRONG_COMMAND);
5929
/* Truncate the table in InnoDB */
5931
error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
5932
if (error == DB_ERROR) {
5933
/* Cannot truncate; resort to ha_innobase::delete_row() */
5937
error = convert_error_code_to_mysql(error, prebuilt->table->flags,
5943
/*****************************************************************//**
5944
Drops a table from an InnoDB database. Before calling this function,
5945
MySQL calls innobase_commit to commit the transaction of the current user.
5946
Then the current user cannot have locks set on the table. Drop table
5947
operation inside InnoDB will remove all locks any user has on the table
5949
@return error number */
5952
InnobaseEngine::doDropTable(
5953
/*======================*/
5955
const string table_path) /* in: table name */
5960
char norm_name[1000];
5962
ut_a(table_path.length() < 1000);
5964
/* Strangely, MySQL passes the table name without the '.frm'
5965
extension, in contrast to ::create */
5966
normalize_table_name(norm_name, table_path.c_str());
5968
/* Get the transaction associated with the current session, or create one
5969
if not yet created */
5971
parent_trx = check_trx_exists(&session);
5973
/* In case MySQL calls this in the middle of a SELECT query, release
5974
possible adaptive hash latch to avoid deadlocks of threads */
5976
trx_search_latch_release_if_reserved(parent_trx);
5978
trx = innobase_trx_allocate(&session);
5980
srv_lower_case_table_names = TRUE;
5982
/* Drop the table in InnoDB */
5984
error = row_drop_table_for_mysql(norm_name, trx,
5985
session_sql_command(&session)
5988
/* Flush the log to reduce probability that the .frm files and
5989
the InnoDB data dictionary get out-of-sync if the user runs
5990
with innodb_flush_log_at_trx_commit = 0 */
5992
log_buffer_flush_to_disk();
5994
/* Tell the InnoDB server that there might be work for
5997
srv_active_wake_master_thread();
5999
innobase_commit_low(trx);
6001
trx_free_for_mysql(trx);
6004
error = convert_error_code_to_mysql(error, 0, NULL);
6009
/*****************************************************************//**
6010
Removes all tables in the named database inside InnoDB. */
6012
InnobaseEngine::drop_database(
6013
/*===================*/
6014
char* path) /*!< in: database path; inside InnoDB the name
6015
of the last directory in the path is used as
6016
the database name: for example, in 'mysql/data/test'
6017
the database name is 'test' */
6024
Session* session = current_session;
6026
/* Get the transaction associated with the current session, or create one
6027
if not yet created */
6029
assert(this == innodb_engine_ptr);
6031
/* In the Windows plugin, session = current_session is always NULL */
6033
trx_t* parent_trx = check_trx_exists(session);
6035
/* In case Drizzle calls this in the middle of a SELECT
6036
query, release possible adaptive hash latch to avoid
6037
deadlocks of threads */
6039
trx_search_latch_release_if_reserved(parent_trx);
6042
ptr = strchr(path, '\0') - 2;
6044
while (ptr >= path && *ptr != '\\' && *ptr != '/') {
6050
namebuf = (char*) malloc((uint) len + 2);
6052
memcpy(namebuf, ptr, len);
6054
namebuf[len + 1] = '\0';
6056
innobase_casedn_str(namebuf);
6058
#if defined __WIN__ && !defined MYSQL_SERVER
6059
/* In the Windows plugin, thd = current_thd is always NULL */
6060
trx = trx_allocate_for_mysql();
6061
trx->mysql_thd = NULL;
6062
trx->mysql_query_str = NULL;
6064
trx = innobase_trx_allocate(session);
6066
error = row_drop_database_for_mysql(namebuf, trx);
6069
/* Flush the log to reduce probability that the .frm files and
6070
the InnoDB data dictionary get out-of-sync if the user runs
6071
with innodb_flush_log_at_trx_commit = 0 */
6073
log_buffer_flush_to_disk();
6075
/* Tell the InnoDB server that there might be work for
6078
srv_active_wake_master_thread();
6080
innobase_commit_low(trx);
6081
trx_free_for_mysql(trx);
6083
/*********************************************************************//**
6084
Renames an InnoDB table.
6085
@return 0 or error code */
6088
innobase_rename_table(
6089
/*==================*/
6090
trx_t* trx, /*!< in: transaction */
6091
const char* from, /*!< in: old name of the table */
6092
const char* to, /*!< in: new name of the table */
6093
ibool lock_and_commit)
6094
/*!< in: TRUE=lock data dictionary and commit */
6100
srv_lower_case_table_names = TRUE;
6102
// Magic number 64 arbitrary
6103
norm_to = (char*) malloc(strlen(to) + 64);
6104
norm_from = (char*) malloc(strlen(from) + 64);
6106
normalize_table_name(norm_to, to);
6107
normalize_table_name(norm_from, from);
6109
/* Serialize data dictionary operations with dictionary mutex:
6110
no deadlocks can occur then in these operations */
6112
if (lock_and_commit) {
6113
row_mysql_lock_data_dictionary(trx);
6116
error = row_rename_table_for_mysql(
6117
norm_from, norm_to, trx, lock_and_commit);
6119
if (error != DB_SUCCESS) {
6120
FILE* ef = dict_foreign_err_file;
6122
fputs("InnoDB: Renaming table ", ef);
6123
ut_print_name(ef, trx, TRUE, norm_from);
6125
ut_print_name(ef, trx, TRUE, norm_to);
6126
fputs(" failed!\n", ef);
6129
if (lock_and_commit) {
6130
row_mysql_unlock_data_dictionary(trx);
6132
/* Flush the log to reduce probability that the .frm
6133
files and the InnoDB data dictionary get out-of-sync
6134
if the user runs with innodb_flush_log_at_trx_commit = 0 */
6136
log_buffer_flush_to_disk();
6144
/*********************************************************************//**
6145
Renames an InnoDB table.
6146
@return 0 or error code */
6149
InnobaseEngine::doRenameTable(
6150
/*======================*/
6152
const char* from, /*!< in: old name of the table */
6153
const char* to) /*!< in: new name of the table */
6159
/* Get the transaction associated with the current session, or create one
6160
if not yet created */
6162
parent_trx = check_trx_exists(session);
6164
/* In case MySQL calls this in the middle of a SELECT query, release
6165
possible adaptive hash latch to avoid deadlocks of threads */
6167
trx_search_latch_release_if_reserved(parent_trx);
6169
trx = innobase_trx_allocate(session);
6171
error = innobase_rename_table(trx, from, to, TRUE);
6173
/* Tell the InnoDB server that there might be work for
6176
srv_active_wake_master_thread();
6178
innobase_commit_low(trx);
6179
trx_free_for_mysql(trx);
6181
error = convert_error_code_to_mysql(error, 0, NULL);
6186
/*********************************************************************//**
6187
Estimates the number of index records in a range.
6188
@return estimated number of rows */
6191
ha_innobase::records_in_range(
6192
/*==========================*/
6193
uint keynr, /*!< in: index number */
6194
key_range *min_key, /*!< in: start key value of the
6195
range, may also be 0 */
6196
key_range *max_key) /*!< in: range end key val, may
6200
dict_index_t* index;
6201
unsigned char* key_val_buff2 = (unsigned char*) malloc(
6202
table->s->stored_rec_length
6203
+ table->s->max_key_length + 100);
6204
ulint buff2_len = table->s->stored_rec_length
6205
+ table->s->max_key_length + 100;
6206
dtuple_t* range_start;
6207
dtuple_t* range_end;
6213
ut_a(prebuilt->trx == session_to_trx(ha_session()));
6215
prebuilt->trx->op_info = (char*)"estimating records in index range";
6217
/* In case MySQL calls this in the middle of a SELECT query, release
6218
possible adaptive hash latch to avoid deadlocks of threads */
6220
trx_search_latch_release_if_reserved(prebuilt->trx);
6222
active_index = keynr;
6224
key = table->key_info + active_index;
6226
index = dict_table_get_index_on_name(prebuilt->table, key->name);
6228
/* MySQL knows about this index and so we must be able to find it.*/
6231
heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6232
+ sizeof(dtuple_t)));
6234
range_start = dtuple_create(heap, key->key_parts);
6235
dict_index_copy_types(range_start, index, key->key_parts);
6237
range_end = dtuple_create(heap, key->key_parts);
6238
dict_index_copy_types(range_end, index, key->key_parts);
6240
row_sel_convert_mysql_key_to_innobase(
6241
range_start, (byte*) key_val_buff,
6242
(ulint)upd_and_key_val_buff_len,
6244
(byte*) (min_key ? min_key->key :
6245
(const unsigned char*) 0),
6246
(ulint) (min_key ? min_key->length : 0),
6249
row_sel_convert_mysql_key_to_innobase(
6250
range_end, (byte*) key_val_buff2,
6252
(byte*) (max_key ? max_key->key :
6253
(const unsigned char*) 0),
6254
(ulint) (max_key ? max_key->length : 0),
6257
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
6259
mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
6262
if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
6264
n_rows = btr_estimate_n_rows_in_range(index, range_start,
6269
n_rows = HA_POS_ERROR;
6272
mem_heap_free(heap);
6274
free(key_val_buff2);
6276
prebuilt->trx->op_info = (char*)"";
6278
/* The MySQL optimizer seems to believe an estimate of 0 rows is
6279
always accurate and may return the result 'Empty set' based on that.
6280
The accuracy is not guaranteed, and even if it were, for a locking
6281
read we should anyway perform the search to set the next-key lock.
6282
Add 1 to the value to make sure MySQL does not make the assumption! */
6288
return((ha_rows) n_rows);
6291
/*********************************************************************//**
6292
Gives an UPPER BOUND to the number of rows in a table. This is used in
6294
@return upper bound of rows */
6297
ha_innobase::estimate_rows_upper_bound(void)
6298
/*======================================*/
6300
dict_index_t* index;
6302
uint64_t local_data_file_length;
6304
/* We do not know if MySQL can call this function before calling
6305
external_lock(). To be safe, update the session of the current table
6308
update_session(ha_session());
6310
prebuilt->trx->op_info = (char*)
6311
"calculating upper bound for table rows";
6313
/* In case MySQL calls this in the middle of a SELECT query, release
6314
possible adaptive hash latch to avoid deadlocks of threads */
6316
trx_search_latch_release_if_reserved(prebuilt->trx);
6318
index = dict_table_get_first_index(prebuilt->table);
6320
ut_a(index->stat_n_leaf_pages > 0);
6322
local_data_file_length =
6323
((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
6326
/* Calculate a minimum length for a clustered index record and from
6327
that an upper bound for the number of rows. Since we only calculate
6328
new statistics in row0mysql.c when a table has grown by a threshold
6329
factor, we must add a safety factor 2 in front of the formula below. */
6331
estimate = 2 * local_data_file_length /
6332
dict_index_calc_min_rec_len(index);
6334
prebuilt->trx->op_info = (char*)"";
6336
return((ha_rows) estimate);
6339
/*********************************************************************//**
6340
How many seeks it will take to read through the table. This is to be
6341
comparable to the number returned by records_in_range so that we can
6342
decide if we should scan the table or use keys.
6343
@return estimated time measured in disk seeks */
6346
ha_innobase::scan_time()
6347
/*====================*/
6349
/* Since MySQL seems to favor table scans too much over index
6350
searches, we pretend that a sequential read takes the same time
6351
as a random disk read, that is, we do not divide the following
6352
by 10, which would be physically realistic. */
6354
return((double) (prebuilt->table->stat_clustered_index_size));
6357
/******************************************************************//**
6358
Calculate the time it takes to read a set of ranges through an index
6359
This enables us to optimise reads for clustered indexes.
6360
@return estimated time measured in disk seeks */
6363
ha_innobase::read_time(
6364
/*===================*/
6365
uint index, /*!< in: key number */
6366
uint ranges, /*!< in: how many ranges */
6367
ha_rows rows) /*!< in: estimated number of rows in the ranges */
6370
double time_for_scan;
6372
if (index != table->s->primary_key) {
6374
return(Cursor::read_time(index, ranges, rows));
6379
return((double) rows);
6382
/* Assume that the read time is proportional to the scan time for all
6383
rows + at most one seek per range. */
6385
time_for_scan = scan_time();
6387
if ((total_rows = estimate_rows_upper_bound()) < rows) {
6389
return(time_for_scan);
6392
return(ranges + (double) rows / (double) total_rows * time_for_scan);
6395
/*********************************************************************//**
6396
Returns statistics information of the table to the MySQL interpreter,
6397
in various fields of the handle object. */
6402
uint flag) /*!< in: what information MySQL requests */
6404
dict_table_t* ib_table;
6405
dict_index_t* index;
6406
ha_rows rec_per_key;
6410
char path[FN_REFLEN];
6411
os_file_stat_t stat_info;
6413
/* If we are forcing recovery at a high level, we will suppress
6414
statistics calculation on tables, because that may crash the
6415
server if an index is badly corrupted. */
6417
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
6419
/* We return success (0) instead of HA_ERR_CRASHED,
6420
because we want MySQL to process this query and not
6421
stop, like it would do if it received the error code
6427
/* We do not know if MySQL can call this function before calling
6428
external_lock(). To be safe, update the session of the current table
6431
update_session(ha_session());
6433
/* In case MySQL calls this in the middle of a SELECT query, release
6434
possible adaptive hash latch to avoid deadlocks of threads */
6436
prebuilt->trx->op_info = (char*)"returning various info to MySQL";
6438
trx_search_latch_release_if_reserved(prebuilt->trx);
6440
ib_table = prebuilt->table;
6442
if (flag & HA_STATUS_TIME) {
6443
if (innobase_stats_on_metadata) {
6444
/* In sql_show we call with this flag: update
6445
then statistics so that they are up-to-date */
6447
prebuilt->trx->op_info = "updating table statistics";
6449
dict_update_statistics(ib_table);
6451
prebuilt->trx->op_info = "returning various info to MySQL";
6454
snprintf(path, sizeof(path), "%s/%s%s",
6455
drizzle_data_home, ib_table->name, ".dfe");
6457
unpack_filename(path,path);
6459
/* Note that we do not know the access time of the table,
6460
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
6462
if (os_file_get_status(path,&stat_info)) {
6463
stats.create_time = (ulong) stat_info.ctime;
6467
if (flag & HA_STATUS_VARIABLE) {
6468
n_rows = ib_table->stat_n_rows;
6470
/* Because we do not protect stat_n_rows by any mutex in a
6471
delete, it is theoretically possible that the value can be
6472
smaller than zero! TODO: fix this race.
6474
The MySQL optimizer seems to assume in a left join that n_rows
6475
is an accurate estimate if it is zero. Of course, it is not,
6476
since we do not have any locks on the rows yet at this phase.
6477
Since SHOW TABLE STATUS seems to call this function with the
6478
HA_STATUS_TIME flag set, while the left join optimizer does not
6479
set that flag, we add one to a zero value if the flag is not
6480
set. That way SHOW TABLE STATUS will show the best estimate,
6481
while the optimizer never sees the table empty. */
6487
if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
6491
/* Fix bug#40386: Not flushing query cache after truncate.
6492
n_rows can not be 0 unless the table is empty, set to 1
6493
instead. The original problem of bug#29507 is actually
6494
fixed in the server code. */
6495
if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
6499
/* We need to reset the prebuilt value too, otherwise
6500
checks for values greater than the last value written
6501
to the table will fail and the autoinc counter will
6502
not be updated. This will force write_row() into
6503
attempting an update of the table's AUTOINC counter. */
6505
prebuilt->autoinc_last_value = 0;
6508
stats.records = (ha_rows)n_rows;
6510
stats.data_file_length = ((uint64_t)
6511
ib_table->stat_clustered_index_size)
6513
stats.index_file_length = ((uint64_t)
6514
ib_table->stat_sum_of_other_index_sizes)
6517
/* Since fsp_get_available_space_in_free_extents() is
6518
acquiring latches inside InnoDB, we do not call it if we
6519
are asked by MySQL to avoid locking. Another reason to
6520
avoid the call is that it uses quite a lot of CPU.
6522
We do not update delete_length if no locking is requested
6523
so the "old" value can remain. delete_length is initialized
6524
to 0 in the ha_statistics' constructor. */
6525
if (!(flag & HA_STATUS_NO_LOCK)) {
6527
/* lock the data dictionary to avoid races with
6528
ibd_file_missing and tablespace_discarded */
6529
row_mysql_lock_data_dictionary(prebuilt->trx);
6531
/* ib_table->space must be an existent tablespace */
6532
if (!ib_table->ibd_file_missing
6533
&& !ib_table->tablespace_discarded) {
6535
stats.delete_length =
6536
fsp_get_available_space_in_free_extents(
6537
ib_table->space) * 1024;
6542
session = ha_session();
6544
push_warning_printf(
6546
DRIZZLE_ERROR::WARN_LEVEL_WARN,
6548
"InnoDB: Trying to get the free "
6549
"space for table %s but its "
6550
"tablespace has been discarded or "
6551
"the .ibd file is missing. Setting "
6552
"the free space to zero.",
6555
stats.delete_length = 0;
6558
row_mysql_unlock_data_dictionary(prebuilt->trx);
6561
stats.check_time = 0;
6563
if (stats.records == 0) {
6564
stats.mean_rec_length = 0;
6566
stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
6570
if (flag & HA_STATUS_CONST) {
6571
index = dict_table_get_first_index(ib_table);
6573
if (prebuilt->clust_index_was_generated) {
6574
index = dict_table_get_next_index(index);
6577
for (i = 0; i < table->s->keys; i++) {
6578
if (index == NULL) {
6579
errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
6580
"indexes inside InnoDB than "
6581
"are defined in the MySQL "
6582
".frm file. Have you mixed up "
6583
".frm files from different "
6584
"installations? See "
6586
"innodb-troubleshooting.html\n",
6591
for (j = 0; j < table->key_info[i].key_parts; j++) {
6593
if (j + 1 > index->n_uniq) {
6594
errmsg_printf(ERRMSG_LVL_ERROR,
6595
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
6596
"statistics for %lu columns. Have you mixed up .frm files from different "
6598
"See " REFMAN "innodb-troubleshooting.html\n",
6602
index->n_uniq, j + 1);
6606
if (index->stat_n_diff_key_vals[j + 1] == 0) {
6608
rec_per_key = stats.records;
6610
rec_per_key = (ha_rows)(stats.records /
6611
index->stat_n_diff_key_vals[j + 1]);
6614
/* Since MySQL seems to favor table scans
6615
too much over index searches, we pretend
6616
index selectivity is 2 times better than
6619
rec_per_key = rec_per_key / 2;
6621
if (rec_per_key == 0) {
6625
table->key_info[i].rec_per_key[j]=
6626
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
6627
(ulong) rec_per_key;
6630
index = dict_table_get_next_index(index);
6634
if (flag & HA_STATUS_ERRKEY) {
6635
const dict_index_t* err_index;
6637
ut_a(prebuilt->trx);
6638
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6640
err_index = trx_get_error_info(prebuilt->trx);
6643
errkey = (unsigned int)
6644
row_get_mysql_key_number_for_index(err_index);
6646
errkey = (unsigned int) prebuilt->trx->error_key_num;
6650
if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
6651
stats.auto_increment_value = innobase_peek_autoinc();
6654
prebuilt->trx->op_info = (char*)"";
6659
/**********************************************************************//**
6660
Updates index cardinalities of the table, based on 8 random dives into
6661
each index tree. This does NOT calculate exact statistics on the table.
6662
@return returns always 0 (success) */
6665
ha_innobase::analyze(
6666
/*=================*/
6667
Session*) /*!< in: connection thread handle */
6669
/* Simply call ::info() with all the flags */
6670
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
6675
/*******************************************************************//**
6676
Tries to check that an InnoDB table is not corrupted. If corruption is
6677
noticed, prints to stderr information about it. In case of corruption
6678
may also assert a failure and crash the server.
6679
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
6684
Session* session) /*!< in: user thread handle */
6688
assert(session == ha_session());
6689
ut_a(prebuilt->trx);
6690
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6691
ut_a(prebuilt->trx == session_to_trx(session));
6693
if (prebuilt->mysql_template == NULL) {
6694
/* Build the template; we will use a dummy template
6695
in index scans done in checking */
6697
build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
6700
ret = row_check_table_for_mysql(prebuilt);
6702
if (ret == DB_SUCCESS) {
6703
return(HA_ADMIN_OK);
6706
return(HA_ADMIN_CORRUPT);
6709
/*************************************************************//**
6710
Adds information about free space in the InnoDB tablespace to a table comment
6711
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
6713
@return table comment + InnoDB free space + info on foreign keys */
6716
ha_innobase::update_table_comment(
6717
/*==============================*/
6718
const char* comment)/*!< in: table comment defined by user */
6720
uint length = (uint) strlen(comment);
6724
/* We do not know if MySQL can call this function before calling
6725
external_lock(). To be safe, update the session of the current table
6728
if (length > 64000 - 3) {
6729
return((char*)comment); /* string too long */
6732
update_session(ha_session());
6734
prebuilt->trx->op_info = (char*)"returning table comment";
6736
/* In case MySQL calls this in the middle of a SELECT query, release
6737
possible adaptive hash latch to avoid deadlocks of threads */
6739
trx_search_latch_release_if_reserved(prebuilt->trx);
6742
/* output the data to a temporary file */
6744
mutex_enter(&srv_dict_tmpfile_mutex);
6745
rewind(srv_dict_tmpfile);
6747
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
6748
fsp_get_available_space_in_free_extents(
6749
prebuilt->table->space));
6751
dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
6752
prebuilt->trx, prebuilt->table);
6753
flen = ftell(srv_dict_tmpfile);
6756
} else if (length + flen + 3 > 64000) {
6757
flen = 64000 - 3 - length;
6760
/* allocate buffer for the full string, and
6761
read the contents of the temporary file */
6763
str = (char*) malloc(length + flen + 3);
6766
char* pos = str + length;
6768
memcpy(str, comment, length);
6772
rewind(srv_dict_tmpfile);
6773
flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
6777
mutex_exit(&srv_dict_tmpfile_mutex);
6779
prebuilt->trx->op_info = (char*)"";
6781
return(str ? str : (char*) comment);
6784
/*******************************************************************//**
6785
Gets the foreign key create info for a table stored in InnoDB.
6786
@return own: character string in the form which can be inserted to the
6787
CREATE TABLE statement, MUST be freed with
6788
ha_innobase::free_foreign_key_create_info */
6791
ha_innobase::get_foreign_key_create_info(void)
6792
/*==========================================*/
6797
ut_a(prebuilt != NULL);
6799
/* We do not know if MySQL can call this function before calling
6800
external_lock(). To be safe, update the session of the current table
6803
update_session(ha_session());
6805
prebuilt->trx->op_info = (char*)"getting info on foreign keys";
6807
/* In case MySQL calls this in the middle of a SELECT query,
6808
release possible adaptive hash latch to avoid
6809
deadlocks of threads */
6811
trx_search_latch_release_if_reserved(prebuilt->trx);
6813
mutex_enter(&srv_dict_tmpfile_mutex);
6814
rewind(srv_dict_tmpfile);
6816
/* output the data to a temporary file */
6817
dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
6818
prebuilt->trx, prebuilt->table);
6819
prebuilt->trx->op_info = (char*)"";
6821
flen = ftell(srv_dict_tmpfile);
6824
} else if (flen > 64000 - 1) {
6828
/* allocate buffer for the string, and
6829
read the contents of the temporary file */
6831
str = (char*) malloc(flen + 1);
6834
rewind(srv_dict_tmpfile);
6835
flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
6839
mutex_exit(&srv_dict_tmpfile_mutex);
6847
ha_innobase::get_foreign_key_list(Session *session, List<FOREIGN_KEY_INFO> *f_key_list)
6849
dict_foreign_t* foreign;
6851
ut_a(prebuilt != NULL);
6852
update_session(ha_session());
6853
prebuilt->trx->op_info = (char*)"getting list of foreign keys";
6854
trx_search_latch_release_if_reserved(prebuilt->trx);
6855
mutex_enter(&(dict_sys->mutex));
6856
foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
6858
while (foreign != NULL) {
6860
FOREIGN_KEY_INFO f_key_info;
6861
LEX_STRING *name= 0;
6863
char uname[NAME_LEN+1]; /* Unencoded name */
6864
char db_name[NAME_LEN+1];
6865
const char *tmp_buff;
6867
tmp_buff= foreign->id;
6869
while (tmp_buff[i] != '/')
6872
f_key_info.forein_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
6873
tmp_buff= foreign->referenced_table_name;
6877
while (tmp_buff[i] != '/')
6879
db_name[i]= tmp_buff[i];
6883
ulen= filename_to_tablename(db_name, uname, sizeof(uname));
6884
f_key_info.referenced_db = session->make_lex_string(NULL, uname, ulen, true);
6888
ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
6889
f_key_info.referenced_table = session->make_lex_string(NULL, uname, ulen, true);
6892
tmp_buff= foreign->foreign_col_names[i];
6893
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6894
f_key_info.foreign_fields.push_back(name);
6895
tmp_buff= foreign->referenced_col_names[i];
6896
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6897
f_key_info.referenced_fields.push_back(name);
6898
if (++i >= foreign->n_fields)
6903
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
6906
tmp_buff= "CASCADE";
6908
else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
6911
tmp_buff= "SET NULL";
6913
else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
6916
tmp_buff= "NO ACTION";
6921
tmp_buff= "RESTRICT";
6923
f_key_info.delete_method = session->make_lex_string(
6924
f_key_info.delete_method, tmp_buff, length, true);
6927
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
6930
tmp_buff= "CASCADE";
6932
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
6935
tmp_buff= "SET NULL";
6937
else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
6940
tmp_buff= "NO ACTION";
6945
tmp_buff= "RESTRICT";
6947
f_key_info.update_method = session->make_lex_string(
6948
f_key_info.update_method, tmp_buff, length, true);
6949
if (foreign->referenced_index &&
6950
foreign->referenced_index->name)
6952
f_key_info.referenced_key_name = session->make_lex_string(
6953
f_key_info.referenced_key_name,
6954
foreign->referenced_index->name,
6955
strlen(foreign->referenced_index->name), true);
6958
f_key_info.referenced_key_name= 0;
6960
FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
6961
session_memdup(session, &f_key_info, sizeof(FOREIGN_KEY_INFO));
6962
f_key_list->push_back(pf_key_info);
6963
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
6965
mutex_exit(&(dict_sys->mutex));
6966
prebuilt->trx->op_info = (char*)"";
6971
/*****************************************************************//**
6972
Checks if ALTER TABLE may change the storage engine of the table.
6973
Changing storage engines is not allowed for tables for which there
6974
are foreign key constraints (parent or child tables).
6975
@return TRUE if can switch engines */
6978
ha_innobase::can_switch_engines(void)
6979
/*=================================*/
6983
ut_a(prebuilt->trx == session_to_trx(ha_session()));
6985
prebuilt->trx->op_info =
6986
"determining if there are foreign key constraints";
6987
row_mysql_lock_data_dictionary(prebuilt->trx);
6989
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
6990
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
6992
row_mysql_unlock_data_dictionary(prebuilt->trx);
6993
prebuilt->trx->op_info = "";
6998
/*******************************************************************//**
6999
Checks if a table is referenced by a foreign key. The MySQL manual states that
7000
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
7001
delete is then allowed internally to resolve a duplicate key conflict in
7002
REPLACE, not an update.
7003
@return > 0 if referenced by a FOREIGN KEY */
7006
ha_innobase::referenced_by_foreign_key(void)
7007
/*========================================*/
7009
if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
7017
/*******************************************************************//**
7018
Frees the foreign key create info for a table stored in InnoDB, if it is
7022
ha_innobase::free_foreign_key_create_info(
7023
/*======================================*/
7024
char* str) /*!< in, own: create info string to free */
7031
/*******************************************************************//**
7032
Tells something additional to the Cursor about how to do things.
7033
@return 0 or error number */
7038
enum ha_extra_function operation)
7039
/*!< in: HA_EXTRA_FLUSH or some other flag */
7041
/* Warning: since it is not sure that MySQL calls external_lock
7042
before calling this function, the trx field in prebuilt can be
7045
switch (operation) {
7046
case HA_EXTRA_FLUSH:
7047
if (prebuilt->blob_heap) {
7048
row_mysql_prebuilt_free_blob_heap(prebuilt);
7051
case HA_EXTRA_RESET_STATE:
7052
reset_template(prebuilt);
7054
case HA_EXTRA_NO_KEYREAD:
7055
prebuilt->read_just_key = 0;
7057
case HA_EXTRA_KEYREAD:
7058
prebuilt->read_just_key = 1;
7060
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
7061
prebuilt->keep_other_fields_on_keyread = 1;
7064
/* IMPORTANT: prebuilt->trx can be obsolete in
7065
this method, because it is not sure that MySQL
7066
calls external_lock before this method with the
7067
parameters below. We must not invoke update_session()
7068
either, because the calling threads may change.
7069
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
7070
case HA_EXTRA_IGNORE_DUP_KEY:
7071
session_to_trx(ha_session())->duplicates |= TRX_DUP_IGNORE;
7073
case HA_EXTRA_WRITE_CAN_REPLACE:
7074
session_to_trx(ha_session())->duplicates |= TRX_DUP_REPLACE;
7076
case HA_EXTRA_WRITE_CANNOT_REPLACE:
7077
session_to_trx(ha_session())->duplicates &= ~TRX_DUP_REPLACE;
7079
case HA_EXTRA_NO_IGNORE_DUP_KEY:
7080
session_to_trx(ha_session())->duplicates &=
7081
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
7083
default:/* Do nothing */
7092
ha_innobase::reset()
7094
if (prebuilt->blob_heap) {
7095
row_mysql_prebuilt_free_blob_heap(prebuilt);
7098
reset_template(prebuilt);
7100
/* TODO: This should really be reset in reset_template() but for now
7101
it's safer to do it explicitly here. */
7103
/* This is a statement level counter. */
7104
prebuilt->autoinc_last_value = 0;
7109
/******************************************************************//**
7110
MySQL calls this function at the start of each SQL statement inside LOCK
7111
TABLES. Inside LOCK TABLES the ::external_lock method does not work to
7112
mark SQL statement borders. Note also a special case: if a temporary table
7113
is created inside LOCK TABLES, MySQL has not called external_lock() at all
7115
MySQL-5.0 also calls this before each statement in an execution of a stored
7116
procedure. To make the execution more deterministic for binlogging, MySQL-5.0
7117
locks all tables involved in a stored procedure with full explicit table
7118
locks (session_in_lock_tables(session) holds in store_lock()) before executing
7120
@return 0 or error code */
7123
ha_innobase::start_stmt(
7124
/*====================*/
7125
Session* session, /*!< in: handle to the user thread */
7126
thr_lock_type lock_type)
7130
update_session(session);
7132
trx = prebuilt->trx;
7134
/* Here we release the search latch and the InnoDB thread FIFO ticket
7135
if they were reserved. They should have been released already at the
7136
end of the previous statement, but because inside LOCK TABLES the
7137
lock count method does not work to mark the end of a SELECT statement,
7138
that may not be the case. We MUST release the search latch before an
7139
INSERT, for example. */
7141
innobase_release_stat_resources(trx);
7143
/* Reset the AUTOINC statement level counter for multi-row INSERTs. */
7144
trx->n_autoinc_rows = 0;
7146
prebuilt->sql_stat_start = TRUE;
7147
prebuilt->hint_need_to_fetch_extra_cols = 0;
7148
reset_template(prebuilt);
7150
if (!prebuilt->mysql_has_locked) {
7151
/* This handle is for a temporary table created inside
7152
this same LOCK TABLES; since MySQL does NOT call external_lock
7153
in this case, we must use x-row locks inside InnoDB to be
7154
prepared for an update of a row */
7156
prebuilt->select_lock_type = LOCK_X;
7158
if (trx->isolation_level != TRX_ISO_SERIALIZABLE
7159
&& session_sql_command(session) == SQLCOM_SELECT
7160
&& lock_type == TL_READ) {
7162
/* For other than temporary tables, we obtain
7163
no lock for consistent read (plain SELECT). */
7165
prebuilt->select_lock_type = LOCK_NONE;
7167
/* Not a consistent read: restore the
7168
select_lock_type value. The value of
7169
stored_select_lock_type was decided in:
7171
2) ::external_lock(),
7172
3) ::init_table_handle_for_HANDLER(), and
7175
prebuilt->select_lock_type =
7176
prebuilt->stored_select_lock_type;
7180
trx->detailed_error[0] = '\0';
7182
/* Set the MySQL flag to mark that there is an active transaction */
7183
if (trx->active_trans == 0) {
7185
innobase_register_trx_and_stmt(engine, session);
7186
trx->active_trans = 1;
7188
innobase_register_stmt(engine, session);
7194
/******************************************************************//**
7195
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7196
@return InnoDB isolation level */
7199
innobase_map_isolation_level(
7200
/*=========================*/
7201
enum_tx_isolation iso) /*!< in: MySQL isolation level code */
7204
case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
7205
case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
7206
case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
7207
case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
7208
default: ut_a(0); return(0);
7212
/******************************************************************//**
7213
As MySQL will execute an external lock for every new table it uses when it
7214
starts to process an SQL statement (an exception is when MySQL calls
7215
start_stmt for the handle) we can use this function to store the pointer to
7216
the Session in the handle. We will also use this function to communicate
7217
to InnoDB that a new SQL statement has started and that we must store a
7218
savepoint to our transaction handle, so that we are able to roll back
7219
the SQL statement in case of an error.
7223
ha_innobase::external_lock(
7224
/*=======================*/
7225
Session* session, /*!< in: handle to the user thread */
7226
int lock_type) /*!< in: lock type */
7231
update_session(session);
7233
trx = prebuilt->trx;
7235
prebuilt->sql_stat_start = TRUE;
7236
prebuilt->hint_need_to_fetch_extra_cols = 0;
7238
reset_template(prebuilt);
7240
if (lock_type == F_WRLCK) {
7242
/* If this is a SELECT, then it is in UPDATE TABLE ...
7243
or SELECT ... FOR UPDATE */
7244
prebuilt->select_lock_type = LOCK_X;
7245
prebuilt->stored_select_lock_type = LOCK_X;
7248
if (lock_type != F_UNLCK) {
7249
/* MySQL is setting a new table lock */
7251
trx->detailed_error[0] = '\0';
7253
/* Set the MySQL flag to mark that there is an active
7255
if (trx->active_trans == 0) {
7257
innobase_register_trx_and_stmt(engine, session);
7258
trx->active_trans = 1;
7259
} else if (trx->n_mysql_tables_in_use == 0) {
7260
innobase_register_stmt(engine, session);
7263
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
7264
&& prebuilt->select_lock_type == LOCK_NONE
7265
&& session_test_options(session,
7266
OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7268
/* To get serializable execution, we let InnoDB
7269
conceptually add 'LOCK IN SHARE MODE' to all SELECTs
7270
which otherwise would have been consistent reads. An
7271
exception is consistent reads in the AUTOCOMMIT=1 mode:
7272
we know that they are read-only transactions, and they
7273
can be serialized also if performed as consistent
7276
prebuilt->select_lock_type = LOCK_S;
7277
prebuilt->stored_select_lock_type = LOCK_S;
7280
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
7281
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
7282
an InnoDB table lock if it is released immediately at the end
7283
of LOCK TABLES, and InnoDB's table locks in that case cause
7284
VERY easily deadlocks.
7286
We do not set InnoDB table locks if user has not explicitly
7287
requested a table lock. Note that session_in_lock_tables(session)
7288
can hold in some cases, e.g., at the start of a stored
7289
procedure call (SQLCOM_CALL). */
7291
if (prebuilt->select_lock_type != LOCK_NONE) {
7292
trx->mysql_n_tables_locked++;
7295
trx->n_mysql_tables_in_use++;
7296
prebuilt->mysql_has_locked = TRUE;
7301
/* MySQL is releasing a table lock */
7303
trx->n_mysql_tables_in_use--;
7304
prebuilt->mysql_has_locked = FALSE;
7306
/* Release a possible FIFO ticket and search latch. Since we
7307
may reserve the kernel mutex, we have to release the search
7308
system latch first to obey the latching order. */
7310
innobase_release_stat_resources(trx);
7312
/* If the MySQL lock count drops to zero we know that the current SQL
7313
statement has ended */
7315
if (trx->n_mysql_tables_in_use == 0) {
7317
trx->mysql_n_tables_locked = 0;
7318
prebuilt->used_in_HANDLER = FALSE;
7320
if (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7321
if (trx->active_trans != 0) {
7322
engine->commit(session, TRUE);
7325
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
7326
&& trx->global_read_view) {
7328
/* At low transaction isolation levels we let
7329
each consistent read set its own snapshot */
7331
read_view_close_for_mysql(trx);
7339
/************************************************************************//**
7340
Here we export InnoDB status variables to MySQL. */
7343
innodb_export_status(void)
7344
/*======================*/
7346
if (innodb_inited) {
7347
srv_export_innodb_status();
7351
/************************************************************************//**
7352
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
7353
Monitor to the client. */
7358
drizzled::plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7359
Session* session,/*!< in: the MySQL query thread of the caller */
7360
stat_print_fn *stat_print)
7363
static const char truncated_msg[] = "... truncated...\n";
7364
const long MAX_STATUS_SIZE = 64000;
7365
ulint trx_list_start = ULINT_UNDEFINED;
7366
ulint trx_list_end = ULINT_UNDEFINED;
7368
assert(engine == innodb_engine_ptr);
7370
trx = check_trx_exists(session);
7372
innobase_release_stat_resources(trx);
7374
/* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
7377
long flen, usable_len;
7380
mutex_enter(&srv_monitor_file_mutex);
7381
rewind(srv_monitor_file);
7382
srv_printf_innodb_monitor(srv_monitor_file,
7383
&trx_list_start, &trx_list_end);
7384
flen = ftell(srv_monitor_file);
7385
os_file_set_eof(srv_monitor_file);
7391
if (flen > MAX_STATUS_SIZE) {
7392
usable_len = MAX_STATUS_SIZE;
7397
/* allocate buffer for the string, and
7398
read the contents of the temporary file */
7400
if (!(str = (char*) malloc(usable_len + 1))) {
7401
mutex_exit(&srv_monitor_file_mutex);
7405
rewind(srv_monitor_file);
7406
if (flen < MAX_STATUS_SIZE) {
7407
/* Display the entire output. */
7408
flen = (long) fread(str, 1, flen, srv_monitor_file);
7409
} else if (trx_list_end < (ulint) flen
7410
&& trx_list_start < trx_list_end
7411
&& trx_list_start + (flen - trx_list_end)
7412
< MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
7413
/* Omit the beginning of the list of active transactions. */
7414
long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
7415
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
7416
len += sizeof truncated_msg - 1;
7417
usable_len = (MAX_STATUS_SIZE - 1) - len;
7418
fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
7419
len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
7422
/* Omit the end of the output. */
7423
flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
7426
mutex_exit(&srv_monitor_file_mutex);
7428
bool result = FALSE;
7430
if (stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
7431
STRING_WITH_LEN(""), str, flen)) {
7439
/************************************************************************//**
7440
Implements the SHOW MUTEX STATUS command. . */
7443
innodb_mutex_show_status(
7444
/*=====================*/
7445
drizzled::plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7446
Session* session, /*!< in: the MySQL query thread of the
7448
stat_print_fn* stat_print)
7450
char buf1[IO_SIZE], buf2[IO_SIZE];
7454
ulint rw_lock_count= 0;
7455
ulint rw_lock_count_spin_loop= 0;
7456
ulint rw_lock_count_spin_rounds= 0;
7457
ulint rw_lock_count_os_wait= 0;
7458
ulint rw_lock_count_os_yield= 0;
7459
uint64_t rw_lock_wait_time= 0;
7460
#endif /* UNIV_DEBUG */
7461
uint engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
7462
assert(engine == innodb_engine_ptr);
7464
mutex_enter(&mutex_list_mutex);
7466
mutex = UT_LIST_GET_FIRST(mutex_list);
7468
while (mutex != NULL) {
7469
if (mutex->count_os_wait == 0
7470
|| buf_pool_is_block_mutex(mutex)) {
7474
if (mutex->mutex_type != 1) {
7475
if (mutex->count_using > 0) {
7476
buf1len= my_snprintf(buf1, sizeof(buf1),
7478
mutex->cmutex_name, mutex->cfile_name);
7479
buf2len= my_snprintf(buf2, sizeof(buf2),
7480
"count=%lu, spin_waits=%lu,"
7481
" spin_rounds=%lu, "
7482
"os_waits=%lu, os_yields=%lu,"
7483
" os_wait_times=%lu",
7485
mutex->count_spin_loop,
7486
mutex->count_spin_rounds,
7487
mutex->count_os_wait,
7488
mutex->count_os_yield,
7489
(ulong) (mutex->lspent_time/1000));
7491
if (stat_print(session, innobase_engine_name,
7492
engine_name_len, buf1, buf1len,
7494
mutex_exit(&mutex_list_mutex);
7500
rw_lock_count += mutex->count_using;
7501
rw_lock_count_spin_loop += mutex->count_spin_loop;
7502
rw_lock_count_spin_rounds += mutex->count_spin_rounds;
7503
rw_lock_count_os_wait += mutex->count_os_wait;
7504
rw_lock_count_os_yield += mutex->count_os_yield;
7505
rw_lock_wait_time += mutex->lspent_time;
7507
#else /* UNIV_DEBUG */
7508
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7509
mutex->cfile_name, (ulong) mutex->cline);
7510
buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
7511
mutex->count_os_wait);
7513
if (stat_print(session, innobase_engine_name,
7514
engine_name_len, buf1, buf1len,
7516
mutex_exit(&mutex_list_mutex);
7519
#endif /* UNIV_DEBUG */
7522
mutex = UT_LIST_GET_NEXT(list, mutex);
7525
mutex_exit(&mutex_list_mutex);
7527
mutex_enter(&rw_lock_list_mutex);
7529
lock = UT_LIST_GET_FIRST(rw_lock_list);
7531
while (lock != NULL) {
7532
if (lock->count_os_wait
7533
&& !buf_pool_is_block_lock(lock)) {
7534
buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7535
lock->cfile_name, (unsigned long) lock->cline);
7536
buf2len= snprintf(buf2, sizeof(buf2),
7537
"os_waits=%lu", lock->count_os_wait);
7539
if (stat_print(session, innobase_engine_name,
7540
engine_name_len, buf1, buf1len,
7542
mutex_exit(&rw_lock_list_mutex);
7546
lock = UT_LIST_GET_NEXT(list, lock);
7549
mutex_exit(&rw_lock_list_mutex);
7552
buf2len= my_snprintf(buf2, sizeof(buf2),
7553
"count=%lu, spin_waits=%lu, spin_rounds=%lu, "
7554
"os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
7555
rw_lock_count, rw_lock_count_spin_loop,
7556
rw_lock_count_spin_rounds,
7557
rw_lock_count_os_wait, rw_lock_count_os_yield,
7558
(ulong) (rw_lock_wait_time/1000));
7560
if (stat_print(session, innobase_engine_name, engine_name_len,
7561
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
7564
#endif /* UNIV_DEBUG */
7569
bool InnobaseEngine::show_status(Session* session,
7570
stat_print_fn* stat_print,
7571
enum ha_stat_type stat_type)
7573
assert(this == innodb_engine_ptr);
7575
switch (stat_type) {
7576
case HA_ENGINE_STATUS:
7577
return innodb_show_status(this, session, stat_print);
7578
case HA_ENGINE_MUTEX:
7579
return innodb_mutex_show_status(this, session, stat_print);
7585
/************************************************************************//**
7586
Handling the shared INNOBASE_SHARE structure that is needed to provide table
7588
****************************************************************************/
7590
static INNOBASE_SHARE* get_share(const char* table_name)
7592
INNOBASE_SHARE *share;
7593
pthread_mutex_lock(&innobase_share_mutex);
7595
ulint fold = ut_fold_string(table_name);
7597
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7598
INNOBASE_SHARE*, share,
7599
ut_ad(share->use_count > 0),
7600
!strcmp(share->table_name, table_name));
7604
uint length = (uint) strlen(table_name);
7606
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
7609
share = (INNOBASE_SHARE *) malloc(sizeof(*share)+length+1);
7610
memset(share, 0, sizeof(*share)+length+1);
7612
share->table_name = (char*) memcpy(share + 1,
7613
table_name, length + 1);
7615
HASH_INSERT(INNOBASE_SHARE, table_name_hash,
7616
innobase_open_tables, fold, share);
7618
thr_lock_init(&share->lock);
7622
pthread_mutex_unlock(&innobase_share_mutex);
7627
static void free_share(INNOBASE_SHARE* share)
7629
pthread_mutex_lock(&innobase_share_mutex);
7632
INNOBASE_SHARE* share2;
7633
ulint fold = ut_fold_string(share->table_name);
7635
HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7636
INNOBASE_SHARE*, share2,
7637
ut_ad(share->use_count > 0),
7638
!strcmp(share->table_name, share2->table_name));
7640
ut_a(share2 == share);
7641
#endif /* UNIV_DEBUG */
7643
if (!--share->use_count) {
7644
ulint fold = ut_fold_string(share->table_name);
7646
HASH_DELETE(INNOBASE_SHARE, table_name_hash,
7647
innobase_open_tables, fold, share);
7648
thr_lock_delete(&share->lock);
7651
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
7655
pthread_mutex_unlock(&innobase_share_mutex);
7658
/*****************************************************************//**
7659
Converts a MySQL table lock stored in the 'lock' field of the handle to
7660
a proper type before storing pointer to the lock into an array of pointers.
7661
MySQL also calls this if it wants to reset some table locks to a not-locked
7662
state during the processing of an SQL query. An example is that during a
7663
SELECT the read lock is released early on the 'const' tables where we only
7664
fetch one row. MySQL does not call this when it releases all locks at the
7665
end of an SQL statement.
7666
@return pointer to the next element in the 'to' array */
7669
ha_innobase::store_lock(
7670
/*====================*/
7671
Session* session, /*!< in: user thread handle */
7672
THR_LOCK_DATA** to, /*!< in: pointer to an array
7673
of pointers to lock structs;
7674
pointer to the 'lock' field
7675
of current handle is stored
7676
next to this array */
7677
enum thr_lock_type lock_type) /*!< in: lock type to store in
7678
'lock'; this may also be
7683
/* Note that trx in this function is NOT necessarily prebuilt->trx
7684
because we call update_session() later, in ::external_lock()! Failure to
7685
understand this caused a serious memory corruption bug in 5.1.11. */
7687
trx = check_trx_exists(session);
7689
/* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
7690
Be careful to ignore TL_IGNORE if we are going to do something with
7691
only 'real' locks! */
7693
/* If no MySQL table is in use, we need to set the isolation level
7694
of the transaction. */
7696
if (lock_type != TL_IGNORE
7697
&& trx->n_mysql_tables_in_use == 0) {
7698
trx->isolation_level = innobase_map_isolation_level(
7699
(enum_tx_isolation) session_tx_isolation(session));
7701
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
7702
&& trx->global_read_view) {
7704
/* At low transaction isolation levels we let
7705
each consistent read set its own snapshot */
7707
read_view_close_for_mysql(trx);
7711
assert(EQ_CURRENT_SESSION(session));
7712
const uint32_t sql_command = session_sql_command(session);
7714
if (sql_command == SQLCOM_DROP_TABLE) {
7716
/* MySQL calls this function in DROP Table though this table
7717
handle may belong to another session that is running a query.
7718
Let us in that case skip any changes to the prebuilt struct. */
7720
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
7721
|| lock_type == TL_READ_NO_INSERT
7722
|| (lock_type != TL_IGNORE
7723
&& sql_command != SQLCOM_SELECT)) {
7725
/* The OR cases above are in this order:
7726
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
7727
are processing a stored procedure or function, or
7728
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
7729
3) this is a SELECT ... IN SHARE MODE, or
7730
4) we are doing a complex SQL statement like
7731
INSERT INTO ... SELECT ... and the logical logging (MySQL
7732
binlog) requires the use of a locking read, or
7733
MySQL is doing LOCK TABLES ... READ.
7734
5) we let InnoDB do locking reads for all SQL statements that
7735
are not simple SELECTs; note that select_lock_type in this
7736
case may get strengthened in ::external_lock() to LOCK_X.
7737
Note that we MUST use a locking read in all data modifying
7738
SQL statements, because otherwise the execution would not be
7739
serializable, and also the results from the update could be
7740
unexpected if an obsolete consistent read view would be
7743
ulint isolation_level;
7745
isolation_level = trx->isolation_level;
7747
if ((srv_locks_unsafe_for_binlog
7748
|| isolation_level == TRX_ISO_READ_COMMITTED)
7749
&& isolation_level != TRX_ISO_SERIALIZABLE
7750
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
7751
&& (sql_command == SQLCOM_INSERT_SELECT
7752
|| sql_command == SQLCOM_UPDATE
7753
|| sql_command == SQLCOM_CREATE_TABLE)) {
7755
/* If we either have innobase_locks_unsafe_for_binlog
7756
option set or this session is using READ COMMITTED
7757
isolation level and isolation level of the transaction
7758
is not set to serializable and MySQL is doing
7759
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
7760
CREATE ... SELECT... without FOR UPDATE or
7761
IN SHARE MODE in select, then we use consistent
7764
prebuilt->select_lock_type = LOCK_NONE;
7765
prebuilt->stored_select_lock_type = LOCK_NONE;
7766
} else if (sql_command == SQLCOM_CHECKSUM) {
7767
/* Use consistent read for checksum table */
7769
prebuilt->select_lock_type = LOCK_NONE;
7770
prebuilt->stored_select_lock_type = LOCK_NONE;
7772
prebuilt->select_lock_type = LOCK_S;
7773
prebuilt->stored_select_lock_type = LOCK_S;
7776
} else if (lock_type != TL_IGNORE) {
7778
/* We set possible LOCK_X value in external_lock, not yet
7779
here even if this would be SELECT ... FOR UPDATE */
7781
prebuilt->select_lock_type = LOCK_NONE;
7782
prebuilt->stored_select_lock_type = LOCK_NONE;
7785
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
7787
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
7788
TABLESPACE or TRUNCATE TABLE then allow multiple
7789
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
7790
< TL_WRITE_CONCURRENT_INSERT.
7792
We especially allow multiple writers if MySQL is at the
7793
start of a stored procedure call (SQLCOM_CALL) or a
7794
stored function call (MySQL does have in_lock_tables
7797
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
7798
&& lock_type <= TL_WRITE)
7799
&& !session_tablespace_op(session)
7800
&& sql_command != SQLCOM_TRUNCATE
7801
&& sql_command != SQLCOM_CREATE_TABLE) {
7803
lock_type = TL_WRITE_ALLOW_WRITE;
7806
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
7807
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
7808
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
7809
to t2. Convert the lock to a normal read lock to allow
7810
concurrent inserts to t2.
7812
We especially allow concurrent inserts if MySQL is at the
7813
start of a stored procedure call (SQLCOM_CALL)
7814
(MySQL does have session_in_lock_tables() TRUE there). */
7816
if (lock_type == TL_READ_NO_INSERT) {
7818
lock_type = TL_READ;
7821
lock.type = lock_type;
7829
/*********************************************************************//**
7830
Read the next autoinc value. Acquire the relevant locks before reading
7831
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
7832
on return and all relevant locks acquired.
7833
@return DB_SUCCESS or error code */
7836
ha_innobase::innobase_get_autoinc(
7837
/*==============================*/
7838
uint64_t* value) /*!< out: autoinc value */
7842
prebuilt->autoinc_error = innobase_lock_autoinc();
7844
if (prebuilt->autoinc_error == DB_SUCCESS) {
7846
/* Determine the first value of the interval */
7847
*value = dict_table_autoinc_read(prebuilt->table);
7849
/* It should have been initialized during open. */
7853
return(prebuilt->autoinc_error);
7856
/*******************************************************************//**
7857
This function reads the global auto-inc counter. It doesn't use the
7858
AUTOINC lock even if the lock mode is set to TRADITIONAL.
7859
@return the autoinc value */
7862
ha_innobase::innobase_peek_autoinc(void)
7863
/*====================================*/
7866
dict_table_t* innodb_table;
7868
ut_a(prebuilt != NULL);
7869
ut_a(prebuilt->table != NULL);
7871
innodb_table = prebuilt->table;
7873
dict_table_autoinc_lock(innodb_table);
7875
auto_inc = dict_table_autoinc_read(innodb_table);
7879
dict_table_autoinc_unlock(innodb_table);
7884
/*********************************************************************//**
7885
This function initializes the auto-inc counter if it has not been
7886
initialized yet. This function does not change the value of the auto-inc
7887
counter if it already has been initialized. Returns the value of the
7888
auto-inc counter in *first_value, and UINT64_T_MAX in *nb_reserved_values (as
7889
we have a table-level lock). offset, increment, nb_desired_values are ignored.
7890
*first_value is set to -1 if error (deadlock or lock wait timeout) */
7893
ha_innobase::get_auto_increment(
7894
/*============================*/
7895
uint64_t offset, /*!< in: table autoinc offset */
7896
uint64_t increment, /*!< in: table autoinc increment */
7897
uint64_t nb_desired_values, /*!< in: number of values reqd */
7898
uint64_t *first_value, /*!< out: the autoinc value */
7899
uint64_t *nb_reserved_values) /*!< out: count of reserved values */
7903
uint64_t autoinc = 0;
7905
/* Prepare prebuilt->trx in the table handle */
7906
update_session(ha_session());
7908
error = innobase_get_autoinc(&autoinc);
7910
if (error != DB_SUCCESS) {
7911
*first_value = (~(uint64_t) 0);
7915
/* This is a hack, since nb_desired_values seems to be accurate only
7916
for the first call to get_auto_increment() for multi-row INSERT and
7917
meaningless for other statements e.g, LOAD etc. Subsequent calls to
7918
this method for the same statement results in different values which
7919
don't make sense. Therefore we store the value the first time we are
7920
called and count down from that as rows are written (see write_row()).
7923
trx = prebuilt->trx;
7925
/* Note: We can't rely on *first_value since some MySQL engines,
7926
in particular the partition engine, don't initialize it to 0 when
7927
invoking this method. So we are not sure if it's guaranteed to
7930
/* Called for the first time ? */
7931
if (trx->n_autoinc_rows == 0) {
7933
trx->n_autoinc_rows = (ulint) nb_desired_values;
7935
/* It's possible for nb_desired_values to be 0:
7936
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
7937
if (nb_desired_values == 0) {
7939
trx->n_autoinc_rows = 1;
7942
set_if_bigger(*first_value, autoinc);
7943
/* Not in the middle of a mult-row INSERT. */
7944
} else if (prebuilt->autoinc_last_value == 0) {
7945
set_if_bigger(*first_value, autoinc);
7948
*nb_reserved_values = trx->n_autoinc_rows;
7950
/* With old style AUTOINC locking we only update the table's
7951
AUTOINC counter after attempting to insert the row. */
7952
if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
7954
uint64_t next_value;
7955
uint64_t col_max_value;
7957
/* We need the upper limit of the col type to check for
7958
whether we update the table autoinc counter or not. */
7959
col_max_value = innobase_get_int_col_max_value(
7960
table->next_number_field);
7962
need = *nb_reserved_values * increment;
7964
/* Compute the last value in the interval */
7965
next_value = innobase_next_autoinc(
7966
*first_value, need, offset, col_max_value);
7968
prebuilt->autoinc_last_value = next_value;
7970
if (prebuilt->autoinc_last_value < *first_value) {
7971
*first_value = (~(unsigned long long) 0);
7973
/* Update the table autoinc variable */
7974
dict_table_autoinc_update_if_greater(
7975
prebuilt->table, prebuilt->autoinc_last_value);
7978
/* This will force write_row() into attempting an update
7979
of the table's AUTOINC counter. */
7980
prebuilt->autoinc_last_value = 0;
7983
/* The increment to be used to increase the AUTOINC value, we use
7984
this in write_row() and update_row() to increase the autoinc counter
7985
for columns that are filled by the user. We need the offset and
7987
prebuilt->autoinc_offset = offset;
7988
prebuilt->autoinc_increment = increment;
7990
dict_table_autoinc_unlock(prebuilt->table);
7993
/*******************************************************************//**
7994
Reset the auto-increment counter to the given value, i.e. the next row
7995
inserted will get the given value. This is called e.g. after TRUNCATE
7996
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
7997
returned by storage engines that don't support this operation.
7998
@return 0 or error code */
8001
ha_innobase::reset_auto_increment(
8002
/*==============================*/
8003
uint64_t value) /*!< in: new value for table autoinc */
8007
update_session(ha_session());
8009
error = row_lock_table_autoinc_for_mysql(prebuilt);
8011
if (error != DB_SUCCESS) {
8012
error = convert_error_code_to_mysql(error,
8013
prebuilt->table->flags,
8019
/* The next value can never be 0. */
8024
innobase_reset_autoinc(value);
8029
/* See comment in Cursor.cc */
8032
InnobaseEngine::get_error_message(int, String *buf)
8034
trx_t* trx = check_trx_exists(current_session);
8036
buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
8037
system_charset_info);
8042
/*******************************************************************//**
8043
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
8044
If there is no explicitly declared non-null unique key or a primary key, then
8045
InnoDB internally uses the row id as the primary key.
8046
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
8049
ha_innobase::cmp_ref(
8050
/*=================*/
8051
const unsigned char* ref1, /*!< in: an (internal) primary key value in the
8052
MySQL key value format */
8053
const unsigned char* ref2) /*!< in: an (internal) primary key value in the
8054
MySQL key value format */
8056
enum_field_types mysql_type;
8058
KEY_PART_INFO* key_part;
8059
KEY_PART_INFO* key_part_end;
8064
if (prebuilt->clust_index_was_generated) {
8065
/* The 'ref' is an InnoDB row id */
8067
return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
8070
/* Do a type-aware comparison of primary key fields. PK fields
8071
are always NOT NULL, so no checks for NULL are performed. */
8073
key_part = table->key_info[table->s->primary_key].key_part;
8075
key_part_end = key_part
8076
+ table->key_info[table->s->primary_key].key_parts;
8078
for (; key_part != key_part_end; ++key_part) {
8079
field = key_part->field;
8080
mysql_type = field->type();
8082
if (mysql_type == DRIZZLE_TYPE_BLOB) {
8084
/* In the MySQL key value format, a column prefix of
8085
a BLOB is preceded by a 2-byte length field */
8087
len1 = innobase_read_from_2_little_endian(ref1);
8088
len2 = innobase_read_from_2_little_endian(ref2);
8092
result = ((Field_blob*)field)->cmp( ref1, len1,
8095
result = field->key_cmp(ref1, ref2);
8103
ref1 += key_part->store_length;
8104
ref2 += key_part->store_length;
8110
/**********************************************************************
8111
This function is used to find the storage length in bytes of the first n
8112
characters for prefix indexes using a multibyte character set. The function
8113
finds charset information and returns length of prefix_len characters in the
8114
index field in bytes.
8115
@return number of bytes occupied by the first n characters */
8116
extern "C" UNIV_INTERN
8118
innobase_get_at_most_n_mbchars(
8119
/*===========================*/
8120
ulint charset_id, /*!< in: character set id */
8121
ulint prefix_len, /*!< in: prefix length in bytes of the index
8122
(this has to be divided by mbmaxlen to get the
8123
number of CHARACTERS n in the prefix) */
8124
ulint data_len, /*!< in: length of the string in bytes */
8125
const char* str); /*!< in: character string */
8128
innobase_get_at_most_n_mbchars(
8129
/*===========================*/
8130
ulint charset_id, /*!< in: character set id */
8131
ulint prefix_len, /*!< in: prefix length in bytes of the index
8132
(this has to be divided by mbmaxlen to get the
8133
number of CHARACTERS n in the prefix) */
8134
ulint data_len, /*!< in: length of the string in bytes */
8135
const char* str) /*!< in: character string */
8137
ulint char_length; /*!< character length in bytes */
8138
ulint n_chars; /*!< number of characters in prefix */
8139
const CHARSET_INFO* charset; /*!< charset used in the field */
8141
charset = get_charset((uint) charset_id);
8144
ut_ad(charset->mbmaxlen);
8146
/* Calculate how many characters at most the prefix index contains */
8148
n_chars = prefix_len / charset->mbmaxlen;
8150
/* If the charset is multi-byte, then we must find the length of the
8151
first at most n chars in the string. If the string contains less
8152
characters than n, then we return the length to the end of the last
8155
if (charset->mbmaxlen > 1) {
8156
/* my_charpos() returns the byte length of the first n_chars
8157
characters, or a value bigger than the length of str, if
8158
there were not enough full characters in str.
8160
Why does the code below work:
8161
Suppose that we are looking for n UTF-8 characters.
8163
1) If the string is long enough, then the prefix contains at
8164
least n complete UTF-8 characters + maybe some extra
8165
characters + an incomplete UTF-8 character. No problem in
8166
this case. The function returns the pointer to the
8167
end of the nth character.
8169
2) If the string is not long enough, then the string contains
8170
the complete value of a column, that is, only complete UTF-8
8171
characters, and we can store in the column prefix index the
8174
char_length = my_charpos(charset, str,
8175
str + data_len, (int) n_chars);
8176
if (char_length > data_len) {
8177
char_length = data_len;
8180
if (data_len < prefix_len) {
8181
char_length = data_len;
8183
char_length = prefix_len;
8187
return(char_length);
8190
/*******************************************************************//**
8191
This function is used to prepare an X/Open XA distributed transaction.
8192
@return 0 or error number */
8194
InnobaseEngine::prepare(
8195
/*================*/
8196
Session* session,/*!< in: handle to the MySQL thread of
8197
the user whose XA transaction should
8199
bool all) /*!< in: TRUE - commit transaction
8200
FALSE - the current SQL statement
8204
trx_t* trx = check_trx_exists(session);
8206
assert(this == innodb_engine_ptr);
8208
/* we use support_xa value as it was seen at transaction start
8209
time, not the current session variable value. Any possible changes
8210
to the session variable take effect only in the next transaction */
8211
if (!trx->support_xa) {
8216
session_get_xid(session, reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
8218
/* Release a possible FIFO ticket and search latch. Since we will
8219
reserve the kernel mutex, we have to release the search system latch
8220
first to obey the latching order. */
8222
innobase_release_stat_resources(trx);
8224
if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) {
8226
errmsg_printf(ERRMSG_LVL_ERROR,
8227
"trx->active_trans == 0, but trx->conc_state != "
8232
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
8234
/* We were instructed to prepare the whole transaction, or
8235
this is an SQL statement end and autocommit is on */
8237
ut_ad(trx->active_trans);
8239
error = (int) trx_prepare_for_mysql(trx);
8241
/* We just mark the SQL statement ended and do not do a
8242
transaction prepare */
8244
/* If we had reserved the auto-inc lock for some
8245
table in this SQL statement we release it now */
8247
row_unlock_table_autoinc_for_mysql(trx);
8249
/* Store the current undo_no of the transaction so that we
8250
know where to roll back if we have to roll back the next
8253
trx_mark_sql_stat_end(trx);
8256
/* Tell the InnoDB server that there might be work for utility
8259
srv_active_wake_master_thread();
8261
if (all || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
8264
/* For ibbackup to work the order of transactions in binlog
8265
and InnoDB must be the same. Consider the situation
8267
thread1> prepare; write to binlog; ...
8269
thread2> prepare; write to binlog; commit
8272
To ensure this will not happen we're taking the mutex on
8273
prepare, and releasing it on commit.
8275
Note: only do it for normal commits, done via ha_commit_trans.
8276
If 2pc protocol is executed by external transaction
8277
coordinator, it will be just a regular MySQL client
8278
executing XA PREPARE and XA COMMIT commands.
8279
In this case we cannot know how many minutes or hours
8280
will be between XA PREPARE and XA COMMIT, and we don't want
8281
to block for undefined period of time.
8283
pthread_mutex_lock(&prepare_commit_mutex);
8284
trx->active_trans = 2;
8289
/*******************************************************************//**
8290
This function is used to recover X/Open XA distributed transactions.
8291
@return number of prepared transactions stored in xid_list */
8293
InnobaseEngine::recover(
8294
/*================*/
8295
XID* xid_list,/*!< in/out: prepared transactions */
8296
uint len) /*!< in: number of slots in xid_list */
8298
assert(this == innodb_engine_ptr);
8300
if (len == 0 || xid_list == NULL) {
8305
return(trx_recover_for_mysql(xid_list, len));
8308
/*******************************************************************//**
8309
This function is used to commit one X/Open XA distributed transaction
8310
which is in the prepared state
8311
@return 0 or error number */
8313
InnobaseEngine::commit_by_xid(
8314
/*===================*/
8315
XID* xid) /*!< in: X/Open XA transaction identification */
8319
assert(this == innodb_engine_ptr);
8321
trx = trx_get_trx_by_xid(xid);
8324
innobase_commit_low(trx);
8332
/*******************************************************************//**
8333
This function is used to rollback one X/Open XA distributed transaction
8334
which is in the prepared state
8335
@return 0 or error number */
8337
InnobaseEngine::rollback_by_xid(
8338
/*=====================*/
8339
XID* xid) /*!< in: X/Open XA transaction
8344
assert(this == innodb_engine_ptr);
8346
trx = trx_get_trx_by_xid(xid);
8349
return(innobase_rollback_trx(trx));
8356
/************************************************************//**
8357
Validate the file format name and return its corresponding id.
8358
@return valid file format id */
8361
innobase_file_format_name_lookup(
8362
/*=============================*/
8363
const char* format_name) /*!< in: pointer to file format name */
8368
ut_a(format_name != NULL);
8370
/* The format name can contain the format id itself instead of
8371
the name and we check for that. */
8372
format_id = (uint) strtoul(format_name, &endp, 10);
8374
/* Check for valid parse. */
8375
if (*endp == '\0' && *format_name != '\0') {
8377
if (format_id <= DICT_TF_FORMAT_MAX) {
8383
for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
8387
name = trx_sys_file_format_id_to_name(format_id);
8389
if (!innobase_strcasecmp(format_name, name)) {
8396
return(DICT_TF_FORMAT_MAX + 1);
8399
/************************************************************//**
8400
Validate the file format check value, is it one of "on" or "off",
8401
as a side effect it sets the srv_check_file_format_at_startup variable.
8402
@return true if config value one of "on" or "off" */
8405
innobase_file_format_check_on_off(
8406
/*==============================*/
8407
const char* format_check) /*!< in: parameter value */
8411
if (!innobase_strcasecmp(format_check, "off")) {
8413
/* Set the value to disable checking. */
8414
srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
8416
} else if (!innobase_strcasecmp(format_check, "on")) {
8418
/* Set the value to the lowest supported format. */
8419
srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
8427
/************************************************************//**
8428
Validate the file format check config parameters, as a side effect it
8429
sets the srv_check_file_format_at_startup variable.
8430
@return true if valid config value */
8433
innobase_file_format_check_validate(
8434
/*================================*/
8435
const char* format_check) /*!< in: parameter value */
8440
format_id = innobase_file_format_name_lookup(format_check);
8442
if (format_id < DICT_TF_FORMAT_MAX + 1) {
8443
srv_check_file_format_at_startup = format_id;
8451
/*************************************************************//**
8452
Check if it is a valid file format. This function is registered as
8453
a callback with MySQL.
8454
@return 0 for valid file format */
8457
innodb_file_format_name_validate(
8458
/*=============================*/
8459
Session* , /*!< in: thread handle */
8460
drizzle_sys_var* , /*!< in: pointer to system
8462
void* save, /*!< out: immediate result
8463
for update function */
8464
drizzle_value* value) /*!< in: incoming string */
8466
const char* file_format_input;
8467
char buff[STRING_BUFFER_USUAL_SIZE];
8468
int len = sizeof(buff);
8471
ut_a(value != NULL);
8473
file_format_input = value->val_str(value, buff, &len);
8475
if (file_format_input != NULL) {
8478
format_id = innobase_file_format_name_lookup(
8481
if (format_id <= DICT_TF_FORMAT_MAX) {
8483
*static_cast<const char**>(save) = file_format_input;
8488
*static_cast<const char**>(save) = NULL;
8492
/****************************************************************//**
8493
Update the system variable innodb_file_format using the "saved"
8494
value. This function is registered as a callback with MySQL. */
8497
innodb_file_format_name_update(
8498
/*===========================*/
8499
Session* , /*!< in: thread handle */
8500
drizzle_sys_var* , /*!< in: pointer to
8502
void* var_ptr, /*!< out: where the
8503
formal string goes */
8504
const void* save) /*!< in: immediate result
8505
from check function */
8507
const char* format_name;
8509
ut_a(var_ptr != NULL);
8512
format_name = *static_cast<const char*const*>(save);
8517
format_id = innobase_file_format_name_lookup(format_name);
8519
if (format_id <= DICT_TF_FORMAT_MAX) {
8520
srv_file_format = format_id;
8524
*static_cast<const char**>(var_ptr)
8525
= trx_sys_file_format_id_to_name(srv_file_format);
8528
/*************************************************************//**
8529
Check if valid argument to innodb_file_format_check. This
8530
function is registered as a callback with MySQL.
8531
@return 0 for valid file format */
8534
innodb_file_format_check_validate(
8535
/*==============================*/
8536
Session* , /*!< in: thread handle */
8537
drizzle_sys_var* , /*!< in: pointer to system
8539
void* save, /*!< out: immediate result
8540
for update function */
8541
drizzle_value* value) /*!< in: incoming string */
8543
const char* file_format_input;
8544
char buff[STRING_BUFFER_USUAL_SIZE];
8545
int len = sizeof(buff);
8548
ut_a(value != NULL);
8550
file_format_input = value->val_str(value, buff, &len);
8552
if (file_format_input != NULL) {
8554
/* Check if user set on/off, we want to print a suitable
8555
message if they did so. */
8557
if (innobase_file_format_check_on_off(file_format_input)) {
8558
errmsg_printf(ERRMSG_LVL_WARN,
8559
"InnoDB: invalid innodb_file_format_check "
8560
"value; on/off can only be set at startup or "
8561
"in the configuration file");
8562
} else if (innobase_file_format_check_validate(
8563
file_format_input)) {
8565
*static_cast<const char**>(save) = file_format_input;
8570
errmsg_printf(ERRMSG_LVL_WARN,
8571
"InnoDB: invalid innodb_file_format_check "
8572
"value; can be any format up to %s "
8573
"or its equivalent numeric id",
8574
trx_sys_file_format_id_to_name(
8575
DICT_TF_FORMAT_MAX));
8579
*static_cast<const char**>(save) = NULL;
8583
/****************************************************************//**
8584
Update the system variable innodb_file_format_check using the "saved"
8585
value. This function is registered as a callback with MySQL. */
8588
innodb_file_format_check_update(
8589
/*============================*/
8590
Session* session, /*!< in: thread handle */
8591
drizzle_sys_var* , /*!< in: pointer to
8593
void* var_ptr, /*!< out: where the
8594
formal string goes */
8595
const void* save) /*!< in: immediate result
8596
from check function */
8598
const char* format_name_in;
8599
const char** format_name_out;
8603
ut_a(var_ptr != NULL);
8605
format_name_in = *static_cast<const char*const*>(save);
8607
if (!format_name_in) {
8612
format_id = innobase_file_format_name_lookup(format_name_in);
8614
if (format_id > DICT_TF_FORMAT_MAX) {
8615
/* DEFAULT is "on", which is invalid at runtime. */
8616
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
8618
"Ignoring SET innodb_file_format=%s",
8623
format_name_out = static_cast<const char**>(var_ptr);
8625
/* Update the max format id in the system tablespace. */
8626
if (trx_sys_file_format_max_set(format_id, format_name_out)) {
8627
ut_print_timestamp(stderr);
8629
" [Info] InnoDB: the file format in the system "
8630
"tablespace is now set to %s.\n", *format_name_out);
8634
/****************************************************************//**
8635
Update the system variable innodb_adaptive_hash_index using the "saved"
8636
value. This function is registered as a callback with MySQL. */
8639
innodb_adaptive_hash_index_update(
8640
/*==============================*/
8641
Session* , /*!< in: thread handle */
8642
drizzle_sys_var* , /*!< in: pointer to
8644
void* , /*!< out: where the
8645
formal string goes */
8646
const void* save) /*!< in: immediate result
8647
from check function */
8649
if (*(bool*) save) {
8650
btr_search_enable();
8652
btr_search_disable();
8656
/*************************************************************//**
8657
Check if it is a valid value of innodb_change_buffering. This function is
8658
registered as a callback with MySQL.
8659
@return 0 for valid innodb_change_buffering */
8662
innodb_change_buffering_validate(
8663
/*=============================*/
8664
Session* , /*!< in: thread handle */
8665
drizzle_sys_var* , /*!< in: pointer to system
8667
void* save, /*!< out: immediate result
8668
for update function */
8669
drizzle_value* value) /*!< in: incoming string */
8671
const char* change_buffering_input;
8672
char buff[STRING_BUFFER_USUAL_SIZE];
8673
int len = sizeof(buff);
8676
ut_a(value != NULL);
8678
change_buffering_input = value->val_str(value, buff, &len);
8680
if (change_buffering_input != NULL) {
8683
for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
8685
if (!innobase_strcasecmp(
8686
change_buffering_input,
8687
innobase_change_buffering_values[use])) {
8688
*(ibuf_use_t*) save = (ibuf_use_t) use;
8697
/****************************************************************//**
8698
Update the system variable innodb_change_buffering using the "saved"
8699
value. This function is registered as a callback with MySQL. */
8702
innodb_change_buffering_update(
8703
/*===========================*/
8704
Session* , /*!< in: thread handle */
8705
drizzle_sys_var* , /*!< in: pointer to
8707
void* var_ptr, /*!< out: where the
8708
formal string goes */
8709
const void* save) /*!< in: immediate result
8710
from check function */
8712
ut_a(var_ptr != NULL);
8714
ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
8716
ibuf_use = *(const ibuf_use_t*) save;
8718
*(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
8721
static int show_innodb_vars(SHOW_VAR *var, char *)
8723
innodb_export_status();
8724
var->type= SHOW_ARRAY;
8725
var->value= (char *) &innodb_status_variables;
8729
static st_show_var_func_container
8730
show_innodb_vars_cont = { &show_innodb_vars };
8732
static SHOW_VAR innodb_status_variables_export[]= {
8733
{"Innodb", (char*) &show_innodb_vars_cont, SHOW_FUNC},
8734
{NULL, NULL, SHOW_LONG}
8738
/* plugin options */
8739
static DRIZZLE_SYSVAR_BOOL(checksums, innobase_use_checksums,
8740
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8741
"Enable InnoDB checksums validation (enabled by default). "
8742
"Disable with --skip-innodb-checksums.",
8745
static DRIZZLE_SYSVAR_STR(data_home_dir, innobase_data_home_dir,
8746
PLUGIN_VAR_READONLY,
8747
"The common part for InnoDB table spaces.",
8750
static DRIZZLE_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
8751
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8752
"Enable InnoDB doublewrite buffer (enabled by default). "
8753
"Disable with --skip-innodb-doublewrite.",
8756
static DRIZZLE_SYSVAR_ULONG(io_capacity, srv_io_capacity,
8757
PLUGIN_VAR_RQCMDARG,
8758
"Number of IOPs the server can do. Tunes the background IO rate",
8759
NULL, NULL, 200, 100, ~0L, 0);
8761
static DRIZZLE_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
8762
PLUGIN_VAR_OPCMDARG,
8763
"Speeds up the shutdown process of the InnoDB storage engine. Possible "
8764
"values are 0, 1 (faster)"
8765
" or 2 (fastest - crash-like)"
8767
NULL, NULL, 1, 0, 2, 0);
8769
static DRIZZLE_SYSVAR_BOOL(file_per_table, srv_file_per_table,
8770
PLUGIN_VAR_NOCMDARG,
8771
"Stores each InnoDB table to an .ibd file in the database dir.",
8774
static DRIZZLE_SYSVAR_STR(file_format, innobase_file_format_name,
8775
PLUGIN_VAR_RQCMDARG,
8776
"File format to use for new tables in .ibd files.",
8777
innodb_file_format_name_validate,
8778
innodb_file_format_name_update, "Antelope");
8780
static DRIZZLE_SYSVAR_STR(file_format_check, innobase_file_format_check,
8781
PLUGIN_VAR_OPCMDARG,
8782
"The highest file format in the tablespace.",
8783
innodb_file_format_check_validate,
8784
innodb_file_format_check_update,
8787
static DRIZZLE_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
8788
PLUGIN_VAR_OPCMDARG,
8789
"Set to 0 (write and flush once per second),"
8790
" 1 (write and flush at each commit)"
8791
" or 2 (write at commit, flush once per second).",
8792
NULL, NULL, 1, 0, 2, 0);
8794
static DRIZZLE_SYSVAR_STR(flush_method, innobase_unix_file_flush_method,
8795
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8796
"With which method to flush data.", NULL, NULL, NULL);
8798
static DRIZZLE_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binlog,
8799
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8800
"Force InnoDB to not use next-key locking, to use only row-level locking.",
8803
#ifdef UNIV_LOG_ARCHIVE
8804
static DRIZZLE_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
8805
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8806
"Where full logs should be archived.", NULL, NULL, NULL);
8808
static DRIZZLE_SYSVAR_BOOL(log_archive, innobase_log_archive,
8809
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
8810
"Set to 1 if you want to have logs archived.", NULL, NULL, FALSE);
8811
#endif /* UNIV_LOG_ARCHIVE */
8813
static DRIZZLE_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir,
8814
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8815
"Path to InnoDB log files.", NULL, NULL, NULL);
8817
static DRIZZLE_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
8818
PLUGIN_VAR_RQCMDARG,
8819
"Percentage of dirty pages allowed in bufferpool.",
8820
NULL, NULL, 75, 0, 99, 0);
8822
static DRIZZLE_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing,
8823
PLUGIN_VAR_NOCMDARG,
8824
"Attempt flushing dirty pages to avoid IO bursts at checkpoints.",
8827
static DRIZZLE_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
8828
PLUGIN_VAR_RQCMDARG,
8829
"Desired maximum length of the purge queue (0 = no limit)",
8830
NULL, NULL, 0, 0, ~0L, 0);
8832
static DRIZZLE_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
8833
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
8834
"Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
8837
static DRIZZLE_SYSVAR_BOOL(status_file, innobase_create_status_file,
8838
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR,
8839
"Enable SHOW INNODB STATUS output in the innodb_status.<pid> file",
8842
static DRIZZLE_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
8843
PLUGIN_VAR_OPCMDARG,
8844
"Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
8847
static DRIZZLE_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_sample_pages,
8848
PLUGIN_VAR_RQCMDARG,
8849
"The number of index pages to sample when calculating statistics (default 8)",
8850
NULL, NULL, 8, 1, ~0ULL, 0);
8852
static DRIZZLE_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
8853
PLUGIN_VAR_OPCMDARG,
8854
"Enable InnoDB adaptive hash index (enabled by default). "
8855
"Disable with --skip-innodb-adaptive-hash-index.",
8856
NULL, innodb_adaptive_hash_index_update, TRUE);
8858
static DRIZZLE_SYSVAR_ULONG(replication_delay, srv_replication_delay,
8859
PLUGIN_VAR_RQCMDARG,
8860
"Replication thread delay (ms) on the slave server if "
8861
"innodb_thread_concurrency is reached (0 by default)",
8862
NULL, NULL, 0, 0, ~0UL, 0);
8864
static DRIZZLE_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
8865
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8866
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
8867
NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024);
8869
static DRIZZLE_SYSVAR_UINT(autoextend_increment, srv_auto_extend_increment,
8870
PLUGIN_VAR_RQCMDARG,
8871
"Data file autoextend increment in megabytes",
8872
NULL, NULL, 8L, 1L, 1000L, 0);
8874
static DRIZZLE_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
8875
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8876
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
8877
NULL, NULL, 128*1024*1024L, 5*1024*1024L, INT64_MAX, 1024*1024L);
8879
static DRIZZLE_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
8880
PLUGIN_VAR_RQCMDARG,
8881
"Helps in performance tuning in heavily concurrent environments.",
8882
innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0);
8884
static DRIZZLE_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter,
8885
PLUGIN_VAR_RQCMDARG,
8886
"Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
8887
NULL, NULL, 500L, 1L, ~0L, 0);
8889
static DRIZZLE_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
8890
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8891
"Number of file I/O threads in InnoDB.",
8892
NULL, NULL, 4, 4, 64, 0);
8894
static DRIZZLE_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
8895
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8896
"Number of background read I/O threads in InnoDB.",
8897
NULL, NULL, 4, 1, 64, 0);
8899
static DRIZZLE_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
8900
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8901
"Number of background write I/O threads in InnoDB.",
8902
NULL, NULL, 4, 1, 64, 0);
8904
static DRIZZLE_SYSVAR_LONG(force_recovery, innobase_force_recovery,
8905
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8906
"Helps to save your data in case the disk image of the database becomes corrupt.",
8907
NULL, NULL, 0, 0, 6, 0);
8909
static DRIZZLE_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
8910
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8911
"The size of the buffer which InnoDB uses to write log to the log files on disk.",
8912
NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
8914
static DRIZZLE_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
8915
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8916
"Size of each log file in a log group.",
8917
NULL, NULL, 5*1024*1024L, 1*1024*1024L, INT64_MAX, 1024*1024L);
8919
static DRIZZLE_SYSVAR_LONG(log_files_in_group, innobase_log_files_in_group,
8920
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8921
"Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.",
8922
NULL, NULL, 2, 2, 100, 0);
8924
static DRIZZLE_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
8925
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8926
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
8927
NULL, NULL, 1, 1, 10, 0);
8929
static DRIZZLE_SYSVAR_LONG(open_files, innobase_open_files,
8930
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8931
"How many files at the maximum InnoDB keeps open at the same time.",
8932
NULL, NULL, 300L, 10L, LONG_MAX, 0);
8934
static DRIZZLE_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
8935
PLUGIN_VAR_RQCMDARG,
8936
"Count of spin-loop rounds in InnoDB mutexes (30 by default)",
8937
NULL, NULL, 30L, 0L, ~0L, 0);
8939
static DRIZZLE_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay,
8940
PLUGIN_VAR_OPCMDARG,
8941
"Maximum delay between polling for a spin lock (6 by default)",
8942
NULL, NULL, 6L, 0L, ~0L, 0);
8944
static DRIZZLE_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
8945
PLUGIN_VAR_RQCMDARG,
8946
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
8947
NULL, NULL, 0, 0, 1000, 0);
8949
static DRIZZLE_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
8950
PLUGIN_VAR_RQCMDARG,
8951
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep",
8952
NULL, NULL, 10000L, 0L, ~0L, 0);
8954
static DRIZZLE_SYSVAR_STR(data_file_path, innobase_data_file_path,
8955
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8956
"Path to individual files and their sizes.",
8959
static DRIZZLE_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
8960
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8961
"The AUTOINC lock modes supported by InnoDB: "
8962
"0 => Old style AUTOINC locking (for backward"
8964
"1 => New style AUTOINC locking "
8965
"2 => No AUTOINC locking (unsafe for SBR)",
8967
AUTOINC_NO_LOCKING, /* Default setting */
8968
AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */
8969
AUTOINC_NO_LOCKING, 0); /* Maximum value */
8971
static DRIZZLE_SYSVAR_STR(version, innodb_version_str,
8972
PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
8973
"InnoDB version", NULL, NULL, INNODB_VERSION_STR);
8975
static DRIZZLE_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
8976
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8977
"Use OS memory allocator instead of InnoDB's internal memory allocator",
8980
static DRIZZLE_SYSVAR_STR(change_buffering, innobase_change_buffering,
8981
PLUGIN_VAR_RQCMDARG,
8982
"Buffer changes to reduce random access: "
8983
"OFF, ON, inserting, deleting, changing, or purging.",
8984
innodb_change_buffering_validate,
8985
innodb_change_buffering_update, NULL);
8987
static DRIZZLE_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
8988
PLUGIN_VAR_RQCMDARG,
8989
"Number of pages that must be accessed sequentially for InnoDB to"
8990
"trigger a readahead.",
8991
NULL, NULL, 56, 0, 64, 0);
8993
static drizzle_sys_var* innobase_system_variables[]= {
8994
DRIZZLE_SYSVAR(additional_mem_pool_size),
8995
DRIZZLE_SYSVAR(autoextend_increment),
8996
DRIZZLE_SYSVAR(buffer_pool_size),
8997
DRIZZLE_SYSVAR(checksums),
8998
DRIZZLE_SYSVAR(commit_concurrency),
8999
DRIZZLE_SYSVAR(concurrency_tickets),
9000
DRIZZLE_SYSVAR(data_file_path),
9001
DRIZZLE_SYSVAR(data_home_dir),
9002
DRIZZLE_SYSVAR(doublewrite),
9003
DRIZZLE_SYSVAR(fast_shutdown),
9004
DRIZZLE_SYSVAR(file_io_threads),
9005
DRIZZLE_SYSVAR(read_io_threads),
9006
DRIZZLE_SYSVAR(write_io_threads),
9007
DRIZZLE_SYSVAR(file_per_table),
9008
DRIZZLE_SYSVAR(file_format),
9009
DRIZZLE_SYSVAR(file_format_check),
9010
DRIZZLE_SYSVAR(flush_log_at_trx_commit),
9011
DRIZZLE_SYSVAR(flush_method),
9012
DRIZZLE_SYSVAR(force_recovery),
9013
DRIZZLE_SYSVAR(locks_unsafe_for_binlog),
9014
DRIZZLE_SYSVAR(lock_wait_timeout),
9015
#ifdef UNIV_LOG_ARCHIVE
9016
DRIZZLE_SYSVAR(log_arch_dir),
9017
DRIZZLE_SYSVAR(log_archive),
9018
#endif /* UNIV_LOG_ARCHIVE */
9019
DRIZZLE_SYSVAR(log_buffer_size),
9020
DRIZZLE_SYSVAR(log_file_size),
9021
DRIZZLE_SYSVAR(log_files_in_group),
9022
DRIZZLE_SYSVAR(log_group_home_dir),
9023
DRIZZLE_SYSVAR(max_dirty_pages_pct),
9024
DRIZZLE_SYSVAR(max_purge_lag),
9025
DRIZZLE_SYSVAR(adaptive_flushing),
9026
DRIZZLE_SYSVAR(mirrored_log_groups),
9027
DRIZZLE_SYSVAR(open_files),
9028
DRIZZLE_SYSVAR(rollback_on_timeout),
9029
DRIZZLE_SYSVAR(stats_on_metadata),
9030
DRIZZLE_SYSVAR(stats_sample_pages),
9031
DRIZZLE_SYSVAR(adaptive_hash_index),
9032
DRIZZLE_SYSVAR(replication_delay),
9033
DRIZZLE_SYSVAR(status_file),
9034
DRIZZLE_SYSVAR(strict_mode),
9035
DRIZZLE_SYSVAR(support_xa),
9036
DRIZZLE_SYSVAR(sync_spin_loops),
9037
DRIZZLE_SYSVAR(spin_wait_delay),
9038
DRIZZLE_SYSVAR(table_locks),
9039
DRIZZLE_SYSVAR(thread_concurrency),
9040
DRIZZLE_SYSVAR(thread_sleep_delay),
9041
DRIZZLE_SYSVAR(autoinc_lock_mode),
9042
DRIZZLE_SYSVAR(version),
9043
DRIZZLE_SYSVAR(use_sys_malloc),
9044
DRIZZLE_SYSVAR(change_buffering),
9045
DRIZZLE_SYSVAR(read_ahead_threshold),
9046
DRIZZLE_SYSVAR(io_capacity),
9050
DRIZZLE_DECLARE_PLUGIN
9053
innobase_engine_name,
9056
"Supports transactions, row-level locking, and foreign keys",
9058
innobase_init, /* Plugin Init */
9059
innobase_deinit, /* Plugin Deinit */
9060
innodb_status_variables_export,/* status variables */
9061
innobase_system_variables, /* system variables */
9064
DRIZZLE_DECLARE_PLUGIN_END;
9066
int ha_innobase::read_range_first(const key_range *start_key,
9067
const key_range *end_key,
9072
//if (!eq_range_arg)
9073
//in_range_read= TRUE;
9074
res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
9076
// in_range_read= FALSE;
9081
int ha_innobase::read_range_next()
9083
int res= Cursor::read_range_next();
9085
// in_range_read= FALSE;
9089
/** @brief Initialize the default value of innodb_commit_concurrency.
9091
Once InnoDB is running, the innodb_commit_concurrency must not change
9092
from zero to nonzero. (Bug #42101)
9094
The initial default value is 0, and without this extra initialization,
9095
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
9096
to 0, even if it was initially set to nonzero at the command line
9097
or configuration file. */
9100
innobase_commit_concurrency_init_default(void)
9101
/*==========================================*/
9103
DRIZZLE_SYSVAR_NAME(commit_concurrency).def_val
9104
= innobase_commit_concurrency;
9107
#ifdef UNIV_COMPILE_TEST_FUNCS
9109
typedef struct innobase_convert_name_test_struct {
9117
const char* expected;
9118
} innobase_convert_name_test_t;
9121
test_innobase_convert_name()
9126
innobase_convert_name_test_t test_input[] = {
9127
{buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
9128
{buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
9129
{buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
9130
{buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
9131
{buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
9133
{buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9134
{buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9135
{buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9136
{buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9137
{buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
9138
{buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
9139
{buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
9141
{buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
9142
"\"#mysql50#ab\"\"cd\""},
9143
{buf, 17, "ab\"cd", 5, NULL, TRUE,
9144
"\"#mysql50#ab\"\"cd\""},
9145
{buf, 16, "ab\"cd", 5, NULL, TRUE,
9146
"\"#mysql50#ab\"\"c\""},
9147
{buf, 15, "ab\"cd", 5, NULL, TRUE,
9148
"\"#mysql50#ab\"\"\""},
9149
{buf, 14, "ab\"cd", 5, NULL, TRUE,
9151
{buf, 13, "ab\"cd", 5, NULL, TRUE,
9153
{buf, 12, "ab\"cd", 5, NULL, TRUE,
9155
{buf, 11, "ab\"cd", 5, NULL, TRUE,
9157
{buf, 10, "ab\"cd", 5, NULL, TRUE,
9160
{buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9161
{buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9162
{buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
9163
{buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
9164
{buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9165
{buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9166
{buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
9167
{buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
9168
{buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
9169
/* XXX probably "" is a better result in this case
9170
{buf, 1, "ab/cd", 5, NULL, TRUE, "."},
9172
{buf, 0, "ab/cd", 5, NULL, TRUE, ""},
9175
for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
9181
fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
9182
test_input[i].buflen,
9184
test_input[i].idlen,
9185
test_input[i].expected);
9187
end = innobase_convert_name(
9189
test_input[i].buflen,
9191
test_input[i].idlen,
9192
test_input[i].session,
9193
test_input[i].file_id);
9195
res_len = (size_t) (end - test_input[i].buf);
9197
if (res_len != strlen(test_input[i].expected)) {
9199
fprintf(stderr, "unexpected len of the result: %u, "
9200
"expected: %u\n", (unsigned) res_len,
9201
(unsigned) strlen(test_input[i].expected));
9205
if (memcmp(test_input[i].buf,
9206
test_input[i].expected,
9207
strlen(test_input[i].expected)) != 0
9210
fprintf(stderr, "unexpected result: %.*s, "
9211
"expected: %s\n", (int) res_len,
9213
test_input[i].expected);
9218
fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9221
fprintf(stderr, "FAILED\n\n");
9227
#endif /* UNIV_COMPILE_TEST_FUNCS */