50
50
***********************************************************************/
52
52
/* TODO list for the InnoDB Cursor in 5.0:
53
- Remove the flag trx->active_trans and look at trx->conc_state
53
54
- fix savepoint functions to use savepoint storage area
54
55
- Find out what kind of problems the OS X case-insensitivity causes to
55
56
table and database names; should we 'normalize' the names like we do
60
#include "drizzled/server_includes.h"
64
61
#include "drizzled/error.h"
65
62
#include "drizzled/errmsg_print.h"
66
#include "drizzled/charset_info.h"
67
#include "drizzled/internal/m_string.h"
68
#include "drizzled/internal/my_sys.h"
69
#include "drizzled/my_hash.h"
63
#include "mystrings/m_ctype.h"
64
#include "mysys/my_sys.h"
65
#include "mysys/hash.h"
66
#include "mysys/mysys_err.h"
70
67
#include "drizzled/plugin.h"
71
68
#include "drizzled/show.h"
72
69
#include "drizzled/data_home.h"
73
70
#include "drizzled/error.h"
74
71
#include "drizzled/field.h"
75
#include "drizzled/charset.h"
76
72
#include "drizzled/session.h"
77
73
#include "drizzled/current_session.h"
78
74
#include "drizzled/table.h"
79
75
#include "drizzled/field/blob.h"
80
76
#include "drizzled/field/varstring.h"
81
77
#include "drizzled/field/timestamp.h"
82
#include "drizzled/plugin/xa_storage_engine.h"
83
#include "drizzled/plugin/daemon.h"
78
#include "drizzled/plugin/storage_engine.h"
79
#include "drizzled/plugin/info_schema_table.h"
84
80
#include "drizzled/memory/multi_malloc.h"
85
#include "drizzled/pthread_globals.h"
86
#include "drizzled/named_savepoint.h"
88
#include <drizzled/transaction_services.h>
90
82
/** @file ha_innodb.cc */
164
152
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
165
153
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
167
static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
168
static plugin::TableFunction* status_table_function_ptr= NULL;
169
static plugin::TableFunction* cmp_tool= NULL;
170
static plugin::TableFunction* cmp_reset_tool= NULL;
171
static plugin::TableFunction* cmp_mem_tool= NULL;
172
static plugin::TableFunction* cmp_mem_reset_tool= NULL;
173
static plugin::TableFunction* innodb_trx_tool= NULL;
174
static plugin::TableFunction* innodb_locks_tool= NULL;
175
static plugin::TableFunction* innodb_lock_waits_tool= NULL;
155
static drizzled::plugin::StorageEngine* innodb_engine_ptr= NULL;
177
157
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
178
158
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
258
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
260
239
static INNOBASE_SHARE *get_share(const char *table_name);
261
240
static void free_share(INNOBASE_SHARE *share);
263
class InnobaseEngine : public plugin::XaStorageEngine
242
class InnobaseEngine : public drizzled::plugin::StorageEngine
266
explicit InnobaseEngine(string name_arg) :
267
plugin::XaStorageEngine(name_arg,
269
HTON_CAN_INDEX_BLOBS |
270
HTON_PRIMARY_KEY_REQUIRED_FOR_POSITION |
271
HTON_PRIMARY_KEY_IN_READ_INDEX |
272
HTON_PARTIAL_COLUMN_READ |
273
HTON_TABLE_SCAN_ON_INDEX |
274
HTON_HAS_FOREIGN_KEYS |
275
HTON_HAS_DOES_TRANSACTIONS)
245
InnobaseEngine(string name_arg)
246
: drizzled::plugin::StorageEngine(name_arg,
248
HTON_CAN_INDEX_BLOBS |
249
HTON_PRIMARY_KEY_REQUIRED_FOR_POSITION |
250
HTON_PRIMARY_KEY_IN_READ_INDEX |
251
HTON_PARTIAL_COLUMN_READ |
252
HTON_TABLE_SCAN_ON_INDEX |
254
HTON_HAS_DOES_TRANSACTIONS, sizeof(trx_named_savept_t))
277
table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
256
table_definition_ext= drizzled::plugin::DEFAULT_DEFINITION_FILE_EXT;
278
257
addAlias("INNOBASE");
281
virtual ~InnobaseEngine()
286
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
288
hash_table_free(innobase_open_tables);
289
innobase_open_tables = NULL;
290
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
293
srv_free_paths_and_sizes();
294
if (internal_innobase_data_file_path)
295
free(internal_innobase_data_file_path);
296
pthread_mutex_destroy(&innobase_share_mutex);
297
pthread_mutex_destroy(&prepare_commit_mutex);
298
pthread_mutex_destroy(&commit_threads_m);
299
pthread_mutex_destroy(&commit_cond_m);
300
pthread_cond_destroy(&commit_cond);
305
virtual int doStartTransaction(Session *session, start_transaction_option_t options);
306
virtual void doStartStatement(Session *session);
307
virtual void doEndStatement(Session *session);
311
262
close_connection(
314
265
Session* session); /* in: handle to the MySQL thread of the user
315
266
whose resources should be free'd */
317
virtual int doSetSavepoint(Session* session,
318
drizzled::NamedSavepoint &savepoint);
319
virtual int doRollbackToSavepoint(Session* session,
320
drizzled::NamedSavepoint &savepoint);
321
virtual int doReleaseSavepoint(Session* session,
322
drizzled::NamedSavepoint &savepoint);
323
virtual int doXaCommit(Session* session, bool all)
325
return doCommit(session, all); /* XA commit just does a SQL COMMIT */
327
virtual int doXaRollback(Session *session, bool all)
329
return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
331
virtual int doCommit(Session* session, bool all);
332
virtual int doRollback(Session* session, bool all);
268
virtual int savepoint_set_hook(Session* session,
270
virtual int savepoint_rollback_hook(Session* session,
272
virtual int savepoint_release_hook(Session* session,
274
virtual int commit(Session* session, bool all);
275
virtual int rollback(Session* session, bool all);
334
277
/***********************************************************************
335
278
This function is used to prepare X/Open XA distributed transaction */
339
282
/*================*/
340
283
/* out: 0 or error number */
341
284
Session* session, /* in: handle to the MySQL thread of the user
346
289
This function is used to recover X/Open XA distributed transactions */
350
293
/*================*/
351
294
/* out: number of prepared transactions
352
295
stored in xid_list */
353
::drizzled::XID* xid_list, /* in/out: prepared transactions */
354
size_t len); /* in: number of slots in xid_list */
296
XID* xid_list, /* in/out: prepared transactions */
297
uint len); /* in: number of slots in xid_list */
355
298
/***********************************************************************
356
299
This function is used to commit one X/Open XA distributed transaction
357
300
which is in the prepared state */
361
304
/*===================*/
362
305
/* out: 0 or error number */
363
::drizzled::XID* xid); /* in: X/Open XA transaction identification */
306
XID* xid); /* in: X/Open XA transaction identification */
364
307
/***********************************************************************
365
308
This function is used to rollback one X/Open XA distributed transaction
366
309
which is in the prepared state */
370
313
/*=====================*/
371
314
/* out: 0 or error number */
372
::drizzled::XID *xid); /* in: X/Open XA transaction identification */
315
XID *xid); /* in: X/Open XA transaction identification */
374
317
virtual Cursor *create(TableShare &table,
375
memory::Root *mem_root)
377
320
return new (mem_root) ha_innobase(*this, table);
380
323
/*********************************************************************
381
324
Removes all tables in the named database inside InnoDB. */
384
328
/*===================*/
385
329
/* out: error number */
386
SchemaIdentifier &identifier); /* in: database path; inside InnoDB the name
330
char* path); /* in: database path; inside InnoDB the name
387
331
of the last directory in the path is used as
388
332
the database name: for example, in 'mysql/data/test'
389
333
the database name is 'test' */
335
/*********************************************************************
336
Creates an InnoDB transaction struct for the session if it does not yet have one.
337
Starts a new InnoDB transaction if a transaction is not yet started. And
338
assigns a new snapshot for a consistent read if the transaction does not yet
342
start_consistent_snapshot(
343
/*====================================*/
345
Session* session); /* in: MySQL thread handle of the user for whom
346
the transaction should be committed */
391
347
/********************************************************************
392
348
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
393
349
the logs, and the name of this function should be innobase_checkpoint. */
420
376
return(ha_innobase_exts);
423
UNIV_INTERN int doCreateTable(Session &session,
425
drizzled::TableIdentifier &identifier,
427
UNIV_INTERN int doRenameTable(Session&, TableIdentifier &from, TableIdentifier &to);
428
UNIV_INTERN int doDropTable(Session &session, TableIdentifier &identifier);
379
UNIV_INTERN int doCreateTable(Session *session,
380
const char *table_name,
382
drizzled::message::Table&);
383
UNIV_INTERN int doRenameTable(Session* session,
386
UNIV_INTERN int doDropTable(Session& session, const string table_path);
430
388
UNIV_INTERN virtual bool get_error_message(int error, String *buf);
443
401
HA_KEYREAD_ONLY);
446
int doGetTableDefinition(drizzled::Session& session,
447
drizzled::TableIdentifier &identifier,
448
drizzled::message::Table &table_proto);
450
void doGetTableNames(drizzled::CachedDirectory &directory,
451
drizzled::SchemaIdentifier &schema_identifier,
452
std::set<std::string> &set_of_names);
454
bool doDoesTableExist(drizzled::Session& session, drizzled::TableIdentifier &identifier);
456
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
457
drizzled::SchemaIdentifier &schema_identifier,
458
drizzled::TableIdentifiers &set_of_identifiers);
461
void InnobaseEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
462
drizzled::SchemaIdentifier &schema_identifier,
463
drizzled::TableIdentifiers &set_of_identifiers)
465
CachedDirectory::Entries entries= directory.getEntries();
467
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
468
entry_iter != entries.end(); ++entry_iter)
470
CachedDirectory::Entry *entry= *entry_iter;
471
const string *filename= &entry->filename;
473
assert(filename->size());
475
const char *ext= strchr(filename->c_str(), '.');
477
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
478
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
482
char uname[NAME_LEN + 1];
483
uint32_t file_name_len;
485
file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
486
// TODO: Remove need for memory copy here
487
uname[file_name_len - sizeof(DEFAULT_FILE_EXTENSION) + 1]= '\0'; // Subtract ending, place NULL
489
set_of_identifiers.push_back(TableIdentifier(schema_identifier, uname));
494
bool InnobaseEngine::doDoesTableExist(Session&, TableIdentifier &identifier)
496
string proto_path(identifier.getPath());
497
proto_path.append(DEFAULT_FILE_EXTENSION);
499
if (access(proto_path.c_str(), F_OK))
507
int InnobaseEngine::doGetTableDefinition(Session &,
508
drizzled::TableIdentifier &identifier,
509
message::Table &table_proto)
511
string proto_path(identifier.getPath());
512
proto_path.append(DEFAULT_FILE_EXTENSION);
514
if (access(proto_path.c_str(), F_OK))
519
if (StorageEngine::readTableFile(proto_path, table_proto))
525
void InnobaseEngine::doGetTableNames(CachedDirectory &directory, SchemaIdentifier&, set<string>& set_of_names)
527
CachedDirectory::Entries entries= directory.getEntries();
529
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
530
entry_iter != entries.end(); ++entry_iter)
532
CachedDirectory::Entry *entry= *entry_iter;
533
const string *filename= &entry->filename;
535
assert(filename->size());
537
const char *ext= strchr(filename->c_str(), '.');
539
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
540
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
544
char uname[NAME_LEN + 1];
545
uint32_t file_name_len;
547
file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
548
// TODO: Remove need for memory copy here
549
uname[file_name_len - sizeof(DEFAULT_FILE_EXTENSION) + 1]= '\0'; // Subtract ending, place NULL
550
set_of_names.insert(uname);
555
405
/** @brief Initialize the default value of innodb_commit_concurrency.
557
407
Once InnoDB is running, the innodb_commit_concurrency must not change
747
603
{NULL, NULL, SHOW_LONG}
750
InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
751
plugin::TableFunction::Generator(fields)
753
srv_export_innodb_status();
754
status_var_ptr= innodb_status_variables;
757
bool InnodbStatusTool::Generator::populate()
759
if (status_var_ptr->name)
761
std::ostringstream oss;
763
const char *value= status_var_ptr->value;
766
push(status_var_ptr->name);
768
switch (status_var_ptr->type)
771
oss << *(int64_t*) value;
772
return_value= oss.str();
775
oss << *(int64_t*) value;
776
return_value= oss.str();
779
return_value= *(bool*) value ? "ON" : "OFF";
786
if (return_value.length())
798
606
/* General functions */
800
608
/******************************************************************//**
1374
1165
/*========================*/
1377
int fd = mysql_tmpfile("ib");
1168
File fd = mysql_tmpfile("ib");
1379
1170
/* Copy the file descriptor, so that the additional resources
1380
1171
allocated by create_temp_file() can be freed by invoking
1381
internal::my_close().
1383
1174
Because the file descriptor returned by this function
1384
1175
will be passed to fdopen(), it will be closed by invoking
1385
1176
fclose(), which in turn will invoke close() instead of
1386
internal::my_close(). */
1390
1181
my_error(EE_OUT_OF_FILERESOURCES,
1391
1182
MYF(ME_BELL+ME_WAITTANG),
1394
internal::my_close(fd, MYF(MY_WME));
1185
my_close(fd, MYF(MY_WME));
1634
1425
update_session(session);
1428
/*********************************************************************//**
1429
Registers that InnoDB takes part in an SQL statement, so that MySQL knows to
1430
roll back the statement if the statement results in an error. This MUST be
1431
called for every SQL statement that may be rolled back by MySQL. Calling this
1432
several times to register the same statement is allowed, too. */
1435
innobase_register_stmt(
1436
/*===================*/
1437
drizzled::plugin::StorageEngine* engine, /*!< in: Innobase hton */
1438
Session* session) /*!< in: MySQL thd (connection) object */
1440
assert(engine == innodb_engine_ptr);
1441
/* Register the statement */
1442
trans_register_ha(session, FALSE, engine);
1445
/*********************************************************************//**
1446
Registers an InnoDB transaction in MySQL, so that the MySQL XA code knows
1447
to call the InnoDB prepare and commit, or rollback for the transaction. This
1448
MUST be called for every transaction for which the user may call commit or
1449
rollback. Calling this several times to register the same transaction is
1451
This function also registers the current SQL statement. */
1454
innobase_register_trx_and_stmt(
1455
/*===========================*/
1456
drizzled::plugin::StorageEngine *engine, /*!< in: Innobase StorageEngine */
1457
Session* session) /*!< in: MySQL thd (connection) object */
1459
/* NOTE that actually innobase_register_stmt() registers also
1460
the transaction in the AUTOCOMMIT=1 mode. */
1462
innobase_register_stmt(engine, session);
1464
if (session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
1466
/* No autocommit mode, register for a transaction */
1467
trans_register_ha(session, TRUE, engine);
1637
1471
/*****************************************************************//**
1638
1472
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1639
1473
and quote it if needed.
1801
1635
prebuilt->read_just_key = 0;
1638
/*****************************************************************//**
1639
Call this when you have opened a new table handle in HANDLER, before you
1640
call index_read_idx() etc. Actually, we can let the cursor stay open even
1641
over a transaction commit! Then you should call this before every operation,
1642
fetch next etc. This function inits the necessary things even after a
1643
transaction commit. */
1646
ha_innobase::init_table_handle_for_HANDLER(void)
1647
/*============================================*/
1649
/* If current session does not yet have a trx struct, create one.
1650
If the current handle does not yet have a prebuilt struct, create
1651
one. Update the trx pointers in the prebuilt struct. Normally
1652
this operation is done in external_lock. */
1654
update_session(ha_session());
1656
/* Initialize the prebuilt struct much like it would be inited in
1659
innobase_release_stat_resources(prebuilt->trx);
1661
/* If the transaction is not started yet, start it */
1663
trx_start_if_not_started(prebuilt->trx);
1665
/* Assign a read view if the transaction does not have it yet */
1667
trx_assign_read_view(prebuilt->trx);
1669
/* Set the MySQL flag to mark that there is an active transaction */
1671
if (prebuilt->trx->active_trans == 0) {
1673
innobase_register_trx_and_stmt(engine, user_session);
1675
prebuilt->trx->active_trans = 1;
1678
/* We did the necessary inits in this function, no need to repeat them
1679
in row_search_for_mysql */
1681
prebuilt->sql_stat_start = FALSE;
1683
/* We let HANDLER always to do the reads as consistent reads, even
1684
if the trx isolation level would have been specified as SERIALIZABLE */
1686
prebuilt->select_lock_type = LOCK_NONE;
1687
prebuilt->stored_select_lock_type = LOCK_NONE;
1689
/* Always fetch all columns in the index record */
1691
prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
1693
/* We want always to fetch all columns in the whole row? Or do
1696
prebuilt->used_in_HANDLER = TRUE;
1697
reset_template(prebuilt);
1804
1700
/*********************************************************************//**
1805
1701
Opens an InnoDB database.
1806
1702
@return 0 on success, error code on failure */
2086
1983
pthread_cond_init(&commit_cond, NULL);
2087
1984
innodb_inited= 1;
2089
status_table_function_ptr= new InnodbStatusTool;
2091
context.add(innodb_engine_ptr);
2093
context.add(status_table_function_ptr);
2095
cmp_tool= new(std::nothrow)CmpTool(false);
2096
context.add(cmp_tool);
2098
cmp_reset_tool= new(std::nothrow)CmpTool(true);
2099
context.add(cmp_reset_tool);
2101
cmp_mem_tool= new(std::nothrow)CmpmemTool(false);
2102
context.add(cmp_mem_tool);
2104
cmp_mem_reset_tool= new(std::nothrow)CmpmemTool(true);
2105
context.add(cmp_mem_reset_tool);
2107
innodb_trx_tool= new(std::nothrow)InnodbTrxTool("INNODB_TRX");
2108
context.add(innodb_trx_tool);
2110
innodb_locks_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCKS");
2111
context.add(innodb_locks_tool);
2113
innodb_lock_waits_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS");
2114
context.add(innodb_lock_waits_tool);
1986
if (innodb_locks_init() ||
1987
innodb_trx_init() ||
1988
innodb_lock_waits_init() ||
1990
i_s_cmp_reset_init() ||
1991
i_s_cmpmem_init() ||
1992
i_s_cmpmem_reset_init())
1995
registry.add(innodb_engine_ptr);
1997
registry.add(innodb_trx_schema_table);
1998
registry.add(innodb_locks_schema_table);
1999
registry.add(innodb_lock_waits_schema_table);
2000
registry.add(innodb_cmp_schema_table);
2001
registry.add(innodb_cmp_reset_schema_table);
2002
registry.add(innodb_cmpmem_schema_table);
2003
registry.add(innodb_cmpmem_reset_schema_table);
2116
2005
/* Get the current high water mark format. */
2117
2006
innobase_file_format_check = (char*) trx_sys_file_format_max_get();
2013
/*******************************************************************//**
2014
Closes an InnoDB database.
2015
@return TRUE if error */
2018
innobase_deinit(drizzled::plugin::Registry ®istry)
2021
i_s_common_deinit(registry);
2022
registry.remove(innodb_engine_ptr);
2023
delete innodb_engine_ptr;
2025
if (innodb_inited) {
2027
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
2029
hash_table_free(innobase_open_tables);
2030
innobase_open_tables = NULL;
2031
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
2034
srv_free_paths_and_sizes();
2035
if (internal_innobase_data_file_path)
2036
free(internal_innobase_data_file_path);
2037
pthread_mutex_destroy(&innobase_share_mutex);
2038
pthread_mutex_destroy(&prepare_commit_mutex);
2039
pthread_mutex_destroy(&commit_threads_m);
2040
pthread_mutex_destroy(&commit_cond_m);
2041
pthread_cond_destroy(&commit_cond);
2125
2047
/****************************************************************//**
2126
2048
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2165
InnobaseEngine::doStartTransaction(
2087
InnobaseEngine::start_consistent_snapshot(
2166
2088
/*====================================*/
2167
Session* session, /*!< in: MySQL thread handle of the user for whom
2168
the transaction should be committed */
2169
start_transaction_option_t options)
2089
Session* session) /*!< in: MySQL thread handle of the user for whom
2090
the transaction should be committed */
2171
2094
assert(this == innodb_engine_ptr);
2173
2096
/* Create a new trx struct for session, if it does not yet have one */
2174
trx_t *trx = check_trx_exists(session);
2098
trx = check_trx_exists(session);
2176
2100
/* This is just to play safe: release a possible FIFO ticket and
2177
2101
search latch. Since we will reserve the kernel mutex, we have to
2178
2102
release the search system latch first to obey the latching order. */
2179
2104
innobase_release_stat_resources(trx);
2181
2106
/* If the transaction is not started yet, start it */
2182
2108
trx_start_if_not_started(trx);
2184
2110
/* Assign a read view if the transaction does not have it yet */
2185
if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2186
trx_assign_read_view(trx);
2112
trx_assign_read_view(trx);
2114
/* Set the MySQL flag to mark that there is an active transaction */
2116
if (trx->active_trans == 0) {
2117
innobase_register_trx_and_stmt(this, current_session);
2118
trx->active_trans = 1;
2191
2124
/*****************************************************************//**
2213
2146
trx_search_latch_release_if_reserved(trx);
2149
/* The flag trx->active_trans is set to 1 in
2151
1. ::external_lock(),
2153
3. innobase_query_caching_of_table_permitted(),
2154
4. InnobaseEngine::savepoint_set(),
2155
5. ::init_table_handle_for_HANDLER(),
2156
6. InnobaseEngine::start_consistent_snapshot(),
2158
and it is only set to 0 in a commit or a rollback. If it is 0 we know
2159
there cannot be resources to be freed and we could return immediately.
2160
For the time being, we play safe and do the cleanup though there should
2161
be nothing to clean up. */
2163
if (trx->active_trans == 0
2164
&& trx->conc_state != TRX_NOT_STARTED) {
2166
errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
2167
" trx->conc_state != TRX_NOT_STARTED");
2217
2170
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
2393
2349
innobase_release_stat_resources(trx);
2395
error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2396
&mysql_binlog_cache_pos);
2351
/* TODO: use provided savepoint data area to store savepoint data */
2353
int64_t2str((ulint)savepoint, sp_name, 36);
2355
error = (int) trx_rollback_to_savepoint_for_mysql(trx, sp_name,
2356
&mysql_binlog_cache_pos);
2397
2357
return(convert_error_code_to_mysql(error, 0, NULL));
2402
2362
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2405
InnobaseEngine::doReleaseSavepoint(
2365
InnobaseEngine::savepoint_release_hook(
2406
2366
/*=======================*/
2407
2367
Session* session, /*!< in: handle to the MySQL thread of the user
2408
2368
whose transaction should be rolled back */
2409
drizzled::NamedSavepoint &named_savepoint) /*!< in: savepoint data */
2369
void* savepoint) /*!< in: savepoint data */
2414
2375
assert(this == innodb_engine_ptr);
2416
2377
trx = check_trx_exists(session);
2418
error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2379
/* TODO: use provided savepoint data area to store savepoint data */
2381
int64_t2str((ulint)savepoint, sp_name, 36);
2383
error = (int) trx_release_savepoint_for_mysql(trx, sp_name);
2420
2385
return(convert_error_code_to_mysql(error, 0, NULL));
2449
2414
innobase_release_stat_resources(trx);
2451
2416
/* cannot happen outside of transaction */
2452
assert(trx->conc_state != TRX_NOT_STARTED);
2454
error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2417
assert(trx->active_trans);
2419
/* TODO: use provided savepoint data area to store savepoint data */
2421
int64_t2str((ulint)savepoint,sp_name,36);
2423
error = (int) trx_savepoint_for_mysql(trx, sp_name, (ib_int64_t)0);
2456
2425
return(convert_error_code_to_mysql(error, 0, NULL));
2475
assert(session->killed != Session::NOT_KILLED ||
2476
trx->conc_state == TRX_NOT_STARTED);
2478
/* Warn if rolling back some things... */
2479
if (session->killed != Session::NOT_KILLED &&
2480
trx->conc_state != TRX_NOT_STARTED &&
2481
trx->undo_no.low > 0 &&
2482
global_system_variables.log_warnings)
2484
errmsg_printf(ERRMSG_LVL_WARN,
2485
"Drizzle is closing a connection during a KILL operation\n"
2486
"that has an active InnoDB transaction. %lu row modifications will "
2488
(ulong) trx->undo_no.low);
2444
if (trx->active_trans == 0
2445
&& trx->conc_state != TRX_NOT_STARTED) {
2447
errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
2448
" trx->conc_state != TRX_NOT_STARTED");
2452
if (trx->conc_state != TRX_NOT_STARTED &&
2453
global_system_variables.log_warnings) {
2454
errmsg_printf(ERRMSG_LVL_WARN,
2455
"MySQL is closing a connection that has an active "
2456
"InnoDB transaction. %lu row modifications will "
2458
(ulong) trx->undo_no.low);
2491
2461
innobase_rollback_trx(trx);
3908
3880
/* Commit the transaction. This will release the table
3909
3881
locks, so they have to be acquired again. */
3910
getTransactionalEngine()->commit(user_session, 1);
3882
engine->commit(user_session, 1);
3883
/* Note that this transaction is still active. */
3884
prebuilt->trx->active_trans = 1;
3911
3885
/* Re-acquire the table lock on the source table. */
3912
3886
row_lock_table_for_mysql(prebuilt, src_table, mode);
3913
3887
/* We will need an IX lock on the destination table. */
4511
4485
A) if the user has not explicitly set any MySQL table level locks:
4513
1) Drizzle calls StorageEngine::doStartStatement(), indicating to
4514
InnoDB that a new SQL statement has begun.
4516
2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
4517
to set an 'intention' table level lock on the table of the Cursor instance.
4518
There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should
4519
be set true if we are taking this table handle instance to use in a new SQL
4520
statement issued by the user.
4522
2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
4487
1) MySQL calls ::external_lock to set an 'intention' table level lock on
4488
the table of the handle instance. There we set
4489
prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set
4490
true if we are taking this table handle instance to use in a new SQL
4491
statement issued by the user. We also increment trx->n_mysql_tables_in_use.
4493
2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
4523
4494
instructions to prebuilt->template of the table handle instance in
4524
4495
::index_read. The template is used to save CPU time in large joins.
4531
4502
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
4532
4503
same table handle instance, if it is a join.
4534
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
4536
(a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter
4537
does NOT execute autocommit for pure read transactions, though it should.
4538
That is why we must execute the COMMIT in ::doEndStatement().
4505
5) When the SELECT ends, MySQL removes its intention table level locks
4506
in ::external_lock. When trx->n_mysql_tables_in_use drops to zero,
4507
(a) we execute a COMMIT there if the autocommit is on,
4539
4508
(b) we also release possible 'SQL statement level resources' InnoDB may
4540
have for this SQL statement.
4544
Remove need for InnoDB to call autocommit for read-only trx
4546
@todo Check the below is still valid (I don't think it is...)
4509
have for this SQL statement. The MySQL interpreter does NOT execute
4510
autocommit for pure read transactions, though it should. That is why the
4511
table Cursor in that case has to execute the COMMIT in ::external_lock.
4548
4513
B) If the user has explicitly set MySQL table level locks, then MySQL
4549
4514
does NOT call ::external_lock at the start of the statement. To determine
5552
5517
InnobaseEngine::doCreateTable(
5553
5518
/*================*/
5554
Session &session, /*!< in: Session */
5555
Table& form, /*!< in: information on table columns and indexes */
5556
drizzled::TableIdentifier &identifier,
5557
message::Table& create_proto)
5519
Session* session, /*!< in: Session */
5520
const char* table_name, /*!< in: table name */
5521
Table& form, /*!< in: information on table
5522
columns and indexes */
5523
drizzled::message::Table& create_proto)
5560
5526
dict_table_t* innobase_table;
5981
5945
InnobaseEngine::doDropTable(
5982
5946
/*======================*/
5984
TableIdentifier &identifier)
5948
const string table_path) /* in: table name */
5987
5951
trx_t* parent_trx;
5989
5953
char norm_name[1000];
5991
ut_a(identifier.getPath().length() < 1000);
5955
ut_a(table_path.length() < 1000);
5993
5957
/* Strangely, MySQL passes the table name without the '.frm'
5994
5958
extension, in contrast to ::create */
5995
normalize_table_name(norm_name, identifier.getPath().c_str());
5959
normalize_table_name(norm_name, table_path.c_str());
5997
5961
/* Get the transaction associated with the current session, or create one
5998
5962
if not yet created */
6032
5996
if(error!=ENOENT)
6033
5997
error = convert_error_code_to_mysql(error, 0, NULL);
6035
if (error == 0 || error == ENOENT)
6037
string path(identifier.getPath());
6039
path.append(DEFAULT_FILE_EXTENSION);
6041
(void)internal::my_delete(path.c_str(), MYF(0));
6047
6002
/*****************************************************************//**
6048
6003
Removes all tables in the named database inside InnoDB. */
6050
InnobaseEngine::doDropSchema(
6005
InnobaseEngine::drop_database(
6051
6006
/*===================*/
6052
SchemaIdentifier &identifier)
6053
/*!< in: database path; inside InnoDB the name
6007
char* path) /*!< in: database path; inside InnoDB the name
6054
6008
of the last directory in the path is used as
6055
6009
the database name: for example, in 'mysql/data/test'
6056
6010
the database name is 'test' */
6060
string schema_path(identifier.getPath());
6061
6017
Session* session = current_session;
6063
6019
/* Get the transaction associated with the current session, or create one
6076
6032
trx_search_latch_release_if_reserved(parent_trx);
6079
schema_path.append("/");
6035
ptr = strchr(path, '\0') - 2;
6037
while (ptr >= path && *ptr != '\\' && *ptr != '/') {
6043
namebuf = (char*) malloc((uint) len + 2);
6045
memcpy(namebuf, ptr, len);
6047
namebuf[len + 1] = '\0';
6049
innobase_casedn_str(namebuf);
6051
#if defined __WIN__ && !defined MYSQL_SERVER
6052
/* In the Windows plugin, thd = current_thd is always NULL */
6053
trx = trx_allocate_for_mysql();
6054
trx->mysql_thd = NULL;
6055
trx->mysql_query_str = NULL;
6080
6057
trx = innobase_trx_allocate(session);
6081
error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6059
error = row_drop_database_for_mysql(namebuf, trx);
6083
6062
/* Flush the log to reduce probability that the .frm files and
6084
6063
the InnoDB data dictionary get out-of-sync if the user runs
6160
6137
/*********************************************************************//**
6161
6138
Renames an InnoDB table.
6162
6139
@return 0 or error code */
6163
UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, TableIdentifier &from, TableIdentifier &to)
6142
InnobaseEngine::doRenameTable(
6143
/*======================*/
6145
const char* from, /*!< in: old name of the table */
6146
const char* to) /*!< in: new name of the table */
6165
// A temp table alter table/rename is a shallow rename and only the
6166
// definition needs to be updated.
6167
if (to.getType() == message::Table::TEMPORARY && from.getType() == message::Table::TEMPORARY)
6169
return plugin::StorageEngine::renameDefinitionFromPath(to, from);
6174
6150
trx_t* parent_trx;
6176
6152
/* Get the transaction associated with the current session, or create one
6177
6153
if not yet created */
6179
parent_trx = check_trx_exists(&session);
6155
parent_trx = check_trx_exists(session);
6181
6157
/* In case MySQL calls this in the middle of a SELECT query, release
6182
6158
possible adaptive hash latch to avoid deadlocks of threads */
6184
6160
trx_search_latch_release_if_reserved(parent_trx);
6186
trx = innobase_trx_allocate(&session);
6162
trx = innobase_trx_allocate(session);
6188
error = innobase_rename_table(trx, from.getPath().c_str(), to.getPath().c_str(), TRUE);
6164
error = innobase_rename_table(trx, from, to, TRUE);
6190
6166
/* Tell the InnoDB server that there might be work for
6191
6167
utility threads: */
6906
6877
ulen= filename_to_tablename(db_name, uname, sizeof(uname));
6907
f_key_info.referenced_db = session->make_lex_string(NULL, uname, ulen, true);
6878
f_key_info.referenced_db = session_make_lex_string(session, 0,
6909
6881
/* Table name */
6910
6882
tmp_buff+= i + 1;
6911
6883
ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
6912
f_key_info.referenced_table = session->make_lex_string(NULL, uname, ulen, true);
6884
f_key_info.referenced_table = session_make_lex_string(session, 0,
6915
6888
tmp_buff= foreign->foreign_col_names[i];
6916
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6889
name = session_make_lex_string(session, name,
6890
tmp_buff, (uint) strlen(tmp_buff), 1);
6917
6891
f_key_info.foreign_fields.push_back(name);
6918
6892
tmp_buff= foreign->referenced_col_names[i];
6919
name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6893
name = session_make_lex_string(session, name,
6894
tmp_buff, (uint) strlen(tmp_buff), 1);
6920
6895
f_key_info.referenced_fields.push_back(name);
6921
6896
if (++i >= foreign->n_fields)
6968
6943
tmp_buff= "RESTRICT";
6970
f_key_info.update_method = session->make_lex_string(
6971
f_key_info.update_method, tmp_buff, length, true);
6945
f_key_info.update_method = session_make_lex_string(
6946
session, f_key_info.update_method, tmp_buff, length, 1);
6972
6947
if (foreign->referenced_index &&
6973
6948
foreign->referenced_index->name)
6975
f_key_info.referenced_key_name = session->make_lex_string(
6976
f_key_info.referenced_key_name,
6950
f_key_info.referenced_key_name = session_make_lex_string(
6951
session, f_key_info.referenced_key_name,
6977
6952
foreign->referenced_index->name,
6978
strlen(foreign->referenced_index->name), true);
6953
(uint) strlen(foreign->referenced_index->name), 1);
6981
6956
f_key_info.referenced_key_name= 0;
7132
7107
/******************************************************************//**
7108
MySQL calls this function at the start of each SQL statement inside LOCK
7109
TABLES. Inside LOCK TABLES the ::external_lock method does not work to
7110
mark SQL statement borders. Note also a special case: if a temporary table
7111
is created inside LOCK TABLES, MySQL has not called external_lock() at all
7113
MySQL-5.0 also calls this before each statement in an execution of a stored
7114
procedure. To make the execution more deterministic for binlogging, MySQL-5.0
7115
locks all tables involved in a stored procedure with full explicit table
7116
locks (session_in_lock_tables(session) holds in store_lock()) before executing
7118
@return 0 or error code */
7121
ha_innobase::start_stmt(
7122
/*====================*/
7123
Session* session, /*!< in: handle to the user thread */
7124
thr_lock_type lock_type)
7128
update_session(session);
7130
trx = prebuilt->trx;
7132
/* Here we release the search latch and the InnoDB thread FIFO ticket
7133
if they were reserved. They should have been released already at the
7134
end of the previous statement, but because inside LOCK TABLES the
7135
lock count method does not work to mark the end of a SELECT statement,
7136
that may not be the case. We MUST release the search latch before an
7137
INSERT, for example. */
7139
innobase_release_stat_resources(trx);
7141
/* Reset the AUTOINC statement level counter for multi-row INSERTs. */
7142
trx->n_autoinc_rows = 0;
7144
prebuilt->sql_stat_start = TRUE;
7145
prebuilt->hint_need_to_fetch_extra_cols = 0;
7146
reset_template(prebuilt);
7148
if (!prebuilt->mysql_has_locked) {
7149
/* This handle is for a temporary table created inside
7150
this same LOCK TABLES; since MySQL does NOT call external_lock
7151
in this case, we must use x-row locks inside InnoDB to be
7152
prepared for an update of a row */
7154
prebuilt->select_lock_type = LOCK_X;
7156
if (trx->isolation_level != TRX_ISO_SERIALIZABLE
7157
&& session_sql_command(session) == SQLCOM_SELECT
7158
&& lock_type == TL_READ) {
7160
/* For other than temporary tables, we obtain
7161
no lock for consistent read (plain SELECT). */
7163
prebuilt->select_lock_type = LOCK_NONE;
7165
/* Not a consistent read: restore the
7166
select_lock_type value. The value of
7167
stored_select_lock_type was decided in:
7169
2) ::external_lock(),
7170
3) ::init_table_handle_for_HANDLER(), and
7173
prebuilt->select_lock_type =
7174
prebuilt->stored_select_lock_type;
7178
trx->detailed_error[0] = '\0';
7180
/* Set the MySQL flag to mark that there is an active transaction */
7181
if (trx->active_trans == 0) {
7183
innobase_register_trx_and_stmt(engine, session);
7184
trx->active_trans = 1;
7186
innobase_register_stmt(engine, session);
7192
/******************************************************************//**
7133
7193
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7134
7194
@return InnoDB isolation level */
7150
7210
/******************************************************************//**
7151
7211
As MySQL will execute an external lock for every new table it uses when it
7152
starts to process an SQL statement. We can use this function to store the pointer to
7153
the Session in the handle.
7212
starts to process an SQL statement (an exception is when MySQL calls
7213
start_stmt for the handle) we can use this function to store the pointer to
7214
the Session in the handle. We will also use this function to communicate
7215
to InnoDB that a new SQL statement has started and that we must store a
7216
savepoint to our transaction handle, so that we are able to roll back
7217
the SQL statement in case of an error.
7179
7246
if (lock_type != F_UNLCK) {
7180
7247
/* MySQL is setting a new table lock */
7249
trx->detailed_error[0] = '\0';
7251
/* Set the MySQL flag to mark that there is an active
7253
if (trx->active_trans == 0) {
7255
innobase_register_trx_and_stmt(engine, session);
7256
trx->active_trans = 1;
7257
} else if (trx->n_mysql_tables_in_use == 0) {
7258
innobase_register_stmt(engine, session);
7182
7261
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
7183
7262
&& prebuilt->select_lock_type == LOCK_NONE
7184
7263
&& session_test_options(session,
7211
7290
trx->mysql_n_tables_locked++;
7293
trx->n_mysql_tables_in_use++;
7214
7294
prebuilt->mysql_has_locked = TRUE;
7219
7299
/* MySQL is releasing a table lock */
7301
trx->n_mysql_tables_in_use--;
7220
7302
prebuilt->mysql_has_locked = FALSE;
7221
trx->mysql_n_tables_locked= 0;
7304
/* Release a possible FIFO ticket and search latch. Since we
7305
may reserve the kernel mutex, we have to release the search
7306
system latch first to obey the latching order. */
7308
innobase_release_stat_resources(trx);
7310
/* If the MySQL lock count drops to zero we know that the current SQL
7311
statement has ended */
7313
if (trx->n_mysql_tables_in_use == 0) {
7315
trx->mysql_n_tables_locked = 0;
7316
prebuilt->used_in_HANDLER = FALSE;
7318
if (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7319
if (trx->active_trans != 0) {
7320
engine->commit(session, TRUE);
7323
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
7324
&& trx->global_read_view) {
7326
/* At low transaction isolation levels we let
7327
each consistent read set its own snapshot */
7329
read_view_close_for_mysql(trx);
7226
7337
/************************************************************************//**
7338
Here we export InnoDB status variables to MySQL. */
7341
innodb_export_status(void)
7342
/*======================*/
7344
if (innodb_inited) {
7345
srv_export_innodb_status();
7349
/************************************************************************//**
7227
7350
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
7228
7351
Monitor to the client. */
7231
7354
innodb_show_status(
7232
7355
/*===============*/
7233
plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7356
drizzled::plugin::StorageEngine* engine, /*!< in: the innodb StorageEngine */
7234
7357
Session* session,/*!< in: the MySQL query thread of the caller */
7235
7358
stat_print_fn *stat_print)
7562
7685
trx = check_trx_exists(session);
7687
/* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
7688
Be careful to ignore TL_IGNORE if we are going to do something with
7689
only 'real' locks! */
7691
/* If no MySQL table is in use, we need to set the isolation level
7692
of the transaction. */
7694
if (lock_type != TL_IGNORE
7695
&& trx->n_mysql_tables_in_use == 0) {
7696
trx->isolation_level = innobase_map_isolation_level(
7697
(enum_tx_isolation) session_tx_isolation(session));
7699
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
7700
&& trx->global_read_view) {
7702
/* At low transaction isolation levels we let
7703
each consistent read set its own snapshot */
7705
read_view_close_for_mysql(trx);
7564
7709
assert(EQ_CURRENT_SESSION(session));
7565
7710
const uint32_t sql_command = session_sql_command(session);
8033
8185
return(char_length);
8036
* We will also use this function to communicate
8037
* to InnoDB that a new SQL statement has started and that we must store a
8038
* savepoint to our transaction handle, so that we are able to roll back
8039
* the SQL statement in case of an error.
8042
InnobaseEngine::doStartStatement(
8043
Session *session) /*!< in: handle to the Drizzle session */
8046
* Create the InnoDB transaction structure
8049
trx_t *trx= check_trx_exists(session);
8051
/* "reset" the error message for the transaction */
8052
trx->detailed_error[0]= '\0';
8054
/* Set the isolation level of the transaction. */
8055
trx->isolation_level= innobase_map_isolation_level((enum_tx_isolation) session_tx_isolation(session));
8059
InnobaseEngine::doEndStatement(
8062
trx_t *trx= check_trx_exists(session);
8064
/* Release a possible FIFO ticket and search latch. Since we
8065
may reserve the kernel mutex, we have to release the search
8066
system latch first to obey the latching order. */
8068
innobase_release_stat_resources(trx);
8070
if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
8072
if (trx->conc_state != TRX_NOT_STARTED)
8074
commit(session, TRUE);
8079
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
8080
trx->global_read_view)
8082
/* At low transaction isolation levels we let
8083
each consistent read set its own snapshot */
8084
read_view_close_for_mysql(trx);
8089
8188
/*******************************************************************//**
8090
8189
This function is used to prepare an X/Open XA distributed transaction.
8091
8190
@return 0 or error number */
8093
InnobaseEngine::doXaPrepare(
8192
InnobaseEngine::prepare(
8094
8193
/*================*/
8095
8194
Session* session,/*!< in: handle to the MySQL thread of
8096
8195
the user whose XA transaction should
8121
8220
innobase_release_stat_resources(trx);
8222
if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) {
8224
errmsg_printf(ERRMSG_LVL_ERROR,
8225
"trx->active_trans == 0, but trx->conc_state != "
8124
8230
|| (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
8126
8232
/* We were instructed to prepare the whole transaction, or
8127
8233
this is an SQL statement end and autocommit is on */
8129
ut_ad(trx->conc_state != TRX_NOT_STARTED);
8235
ut_ad(trx->active_trans);
8131
8237
error = (int) trx_prepare_for_mysql(trx);
8610
8716
*(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
8719
static int show_innodb_vars(SHOW_VAR *var, char *)
8721
innodb_export_status();
8722
var->type= SHOW_ARRAY;
8723
var->value= (char *) &innodb_status_variables;
8727
static st_show_var_func_container
8728
show_innodb_vars_cont = { &show_innodb_vars };
8730
static SHOW_VAR innodb_status_variables_export[]= {
8731
{"Innodb", (char*) &show_innodb_vars_cont, SHOW_FUNC},
8732
{NULL, NULL, SHOW_LONG}
8613
8736
/* plugin options */
8614
8737
static DRIZZLE_SYSVAR_BOOL(checksums, innobase_use_checksums,
8615
8738
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8670
8793
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
8671
8794
"With which method to flush data.", NULL, NULL, NULL);
8796
static DRIZZLE_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binlog,
8797
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
8798
"Force InnoDB to not use next-key locking, to use only row-level locking.",
8673
8801
#ifdef UNIV_LOG_ARCHIVE
8674
8802
static DRIZZLE_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
8675
8803
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,