344
348
the database name: for example, in 'mysql/data/test'
345
349
the database name is 'test' */
347
/*********************************************************************
348
Creates an InnoDB transaction struct for the session if it does not yet have one.
349
Starts a new InnoDB transaction if a transaction is not yet started. And
350
assigns a new snapshot for a consistent read if the transaction does not yet
354
doStartConsistentSnapshot(
355
/*====================================*/
357
Session* session); /* in: MySQL thread handle of the user for whom
358
the transaction should be committed */
359
351
/********************************************************************
360
352
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
361
353
the logs, and the name of this function should be innobase_checkpoint. */
1502
1494
update_session(session);
1505
/*********************************************************************//**
1506
Registers that InnoDB takes part in an SQL statement, so that MySQL knows to
1507
roll back the statement if the statement results in an error. This MUST be
1508
called for every SQL statement that may be rolled back by MySQL. Calling this
1509
several times to register the same statement is allowed, too. */
1512
innobase_register_stmt(
1513
/*===================*/
1514
plugin::TransactionalStorageEngine* engine, /*!< in: Innobase hton */
1515
Session* session) /*!< in: MySQL thd (connection) object */
1517
assert(engine == innodb_engine_ptr);
1518
/* Register the statement */
1519
TransactionServices &transaction_services= TransactionServices::singleton();
1520
transaction_services.trans_register_ha(session, FALSE, engine);
1523
/*********************************************************************//**
1524
Registers an InnoDB transaction in MySQL, so that the MySQL XA code knows
1525
to call the InnoDB prepare and commit, or rollback for the transaction. This
1526
MUST be called for every transaction for which the user may call commit or
1527
rollback. Calling this several times to register the same transaction is
1529
This function also registers the current SQL statement. */
1532
innobase_register_trx_and_stmt(
1533
/*===========================*/
1534
plugin::TransactionalStorageEngine *engine, /*!< in: Innobase StorageEngine */
1535
Session* session) /*!< in: MySQL thd (connection) object */
1537
/* NOTE that actually innobase_register_stmt() registers also
1538
the transaction in the AUTOCOMMIT=1 mode. */
1540
innobase_register_stmt(engine, session);
1542
if (session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
1544
/* No autocommit mode, register for a transaction */
1545
TransactionServices &transaction_services= TransactionServices::singleton();
1546
transaction_services.trans_register_ha(session, TRUE, engine);
1550
1497
/*****************************************************************//**
1551
1498
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1552
1499
and quote it if needed.
1714
1661
prebuilt->read_just_key = 0;
1717
/*****************************************************************//**
1718
Call this when you have opened a new table handle in HANDLER, before you
1719
call index_read_idx() etc. Actually, we can let the cursor stay open even
1720
over a transaction commit! Then you should call this before every operation,
1721
fetch next etc. This function inits the necessary things even after a
1722
transaction commit. */
1725
ha_innobase::init_table_handle_for_HANDLER(void)
1726
/*============================================*/
1728
/* If current session does not yet have a trx struct, create one.
1729
If the current handle does not yet have a prebuilt struct, create
1730
one. Update the trx pointers in the prebuilt struct. Normally
1731
this operation is done in external_lock. */
1733
update_session(ha_session());
1735
/* Initialize the prebuilt struct much like it would be inited in
1738
innobase_release_stat_resources(prebuilt->trx);
1740
/* If the transaction is not started yet, start it */
1742
trx_start_if_not_started(prebuilt->trx);
1744
/* Assign a read view if the transaction does not have it yet */
1746
trx_assign_read_view(prebuilt->trx);
1748
/* Set the MySQL flag to mark that there is an active transaction */
1750
if (prebuilt->trx->active_trans == 0) {
1752
innobase_register_trx_and_stmt(innodb_engine_ptr, user_session);
1754
prebuilt->trx->active_trans = 1;
1757
/* We did the necessary inits in this function, no need to repeat them
1758
in row_search_for_mysql */
1760
prebuilt->sql_stat_start = FALSE;
1762
/* We let HANDLER always to do the reads as consistent reads, even
1763
if the trx isolation level would have been specified as SERIALIZABLE */
1765
prebuilt->select_lock_type = LOCK_NONE;
1766
prebuilt->stored_select_lock_type = LOCK_NONE;
1768
/* Always fetch all columns in the index record */
1770
prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
1772
/* We want always to fetch all columns in the whole row? Or do
1775
prebuilt->used_in_HANDLER = TRUE;
1776
reset_template(prebuilt);
1779
1664
/*********************************************************************//**
1780
1665
Opens an InnoDB database.
1781
1666
@return 0 on success, error code on failure */
2180
InnobaseEngine::doStartConsistentSnapshot(
2065
InnobaseEngine::doStartTransaction(
2181
2066
/*====================================*/
2182
Session* session) /*!< in: MySQL thread handle of the user for whom
2183
the transaction should be committed */
2067
Session* session, /*!< in: MySQL thread handle of the user for whom
2068
the transaction should be committed */
2069
start_transaction_option_t options)
2187
2071
assert(this == innodb_engine_ptr);
2189
2073
/* Create a new trx struct for session, if it does not yet have one */
2191
trx = check_trx_exists(session);
2074
trx_t *trx = check_trx_exists(session);
2193
2076
/* This is just to play safe: release a possible FIFO ticket and
2194
2077
search latch. Since we will reserve the kernel mutex, we have to
2195
2078
release the search system latch first to obey the latching order. */
2197
2079
innobase_release_stat_resources(trx);
2199
2081
/* If the transaction is not started yet, start it */
2201
2082
trx_start_if_not_started(trx);
2203
2084
/* Assign a read view if the transaction does not have it yet */
2205
trx_assign_read_view(trx);
2207
/* Set the MySQL flag to mark that there is an active transaction */
2085
if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2086
trx_assign_read_view(trx);
2088
/* Set the Drizzle flag to mark that there is an active transaction */
2209
2089
if (trx->active_trans == 0) {
2210
innobase_register_trx_and_stmt(this, current_session);
2211
trx->active_trans = 1;
2090
trx->active_trans= 1;
2217
2096
/*****************************************************************//**
2242
2121
/* The flag trx->active_trans is set to 1 in
2244
1. ::external_lock(),
2246
3. innobase_query_caching_of_table_permitted(),
2247
4. InnobaseEngine::setSavepoint(),
2248
5. ::init_table_handle_for_HANDLER(),
2249
6. InnobaseEngine::start_consistent_snapshot(),
2123
1. ::external_lock()
2124
2 InnobaseEngine::doStartStatement()
2125
3. InnobaseEngine::setSavepoint()
2126
4. InnobaseEngine::doStartTransaction()
2251
2128
and it is only set to 0 in a commit or a rollback. If it is 0 we know
2252
2129
there cannot be resources to be freed and we could return immediately.
4567
4444
A) if the user has not explicitly set any MySQL table level locks:
4569
1) MySQL calls ::external_lock to set an 'intention' table level lock on
4570
the table of the handle instance. There we set
4571
prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set
4572
true if we are taking this table handle instance to use in a new SQL
4573
statement issued by the user. We also increment trx->n_mysql_tables_in_use.
4575
2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
4446
1) Drizzle calls StorageEngine::doStartStatement(), indicating to
4447
InnoDB that a new SQL statement has begun.
4449
2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
4450
to set an 'intention' table level lock on the table of the Cursor instance.
4451
There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should
4452
be set true if we are taking this table handle instance to use in a new SQL
4453
statement issued by the user.
4455
2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
4576
4456
instructions to prebuilt->template of the table handle instance in
4577
4457
::index_read. The template is used to save CPU time in large joins.
4584
4464
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
4585
4465
same table handle instance, if it is a join.
4587
5) When the SELECT ends, MySQL removes its intention table level locks
4588
in ::external_lock. When trx->n_mysql_tables_in_use drops to zero,
4589
(a) we execute a COMMIT there if the autocommit is on,
4467
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
4469
(a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter
4470
does NOT execute autocommit for pure read transactions, though it should.
4471
That is why we must execute the COMMIT in ::doEndStatement().
4590
4472
(b) we also release possible 'SQL statement level resources' InnoDB may
4591
have for this SQL statement. The MySQL interpreter does NOT execute
4592
autocommit for pure read transactions, though it should. That is why the
4593
table Cursor in that case has to execute the COMMIT in ::external_lock.
4473
have for this SQL statement.
4477
Remove need for InnoDB to call autocommit for read-only trx
4479
@todo Check the below is still valid (I don't think it is...)
4595
4481
B) If the user has explicitly set MySQL table level locks, then MySQL
4596
4482
does NOT call ::external_lock at the start of the statement. To determine
7184
7070
/******************************************************************//**
7185
MySQL calls this function at the start of each SQL statement inside LOCK
7186
TABLES. Inside LOCK TABLES the ::external_lock method does not work to
7187
mark SQL statement borders. Note also a special case: if a temporary table
7188
is created inside LOCK TABLES, MySQL has not called external_lock() at all
7190
MySQL-5.0 also calls this before each statement in an execution of a stored
7191
procedure. To make the execution more deterministic for binlogging, MySQL-5.0
7192
locks all tables involved in a stored procedure with full explicit table
7193
locks (session_in_lock_tables(session) holds in store_lock()) before executing
7195
@return 0 or error code */
7198
ha_innobase::start_stmt(
7199
/*====================*/
7200
Session* session, /*!< in: handle to the user thread */
7201
thr_lock_type lock_type)
7205
update_session(session);
7207
trx = prebuilt->trx;
7209
/* Here we release the search latch and the InnoDB thread FIFO ticket
7210
if they were reserved. They should have been released already at the
7211
end of the previous statement, but because inside LOCK TABLES the
7212
lock count method does not work to mark the end of a SELECT statement,
7213
that may not be the case. We MUST release the search latch before an
7214
INSERT, for example. */
7216
innobase_release_stat_resources(trx);
7218
/* Reset the AUTOINC statement level counter for multi-row INSERTs. */
7219
trx->n_autoinc_rows = 0;
7221
prebuilt->sql_stat_start = TRUE;
7222
prebuilt->hint_need_to_fetch_extra_cols = 0;
7223
reset_template(prebuilt);
7225
if (!prebuilt->mysql_has_locked) {
7226
/* This handle is for a temporary table created inside
7227
this same LOCK TABLES; since MySQL does NOT call external_lock
7228
in this case, we must use x-row locks inside InnoDB to be
7229
prepared for an update of a row */
7231
prebuilt->select_lock_type = LOCK_X;
7233
if (trx->isolation_level != TRX_ISO_SERIALIZABLE
7234
&& session_sql_command(session) == SQLCOM_SELECT
7235
&& lock_type == TL_READ) {
7237
/* For other than temporary tables, we obtain
7238
no lock for consistent read (plain SELECT). */
7240
prebuilt->select_lock_type = LOCK_NONE;
7242
/* Not a consistent read: restore the
7243
select_lock_type value. The value of
7244
stored_select_lock_type was decided in:
7246
2) ::external_lock(),
7247
3) ::init_table_handle_for_HANDLER(), and
7250
prebuilt->select_lock_type =
7251
prebuilt->stored_select_lock_type;
7255
trx->detailed_error[0] = '\0';
7257
/* Set the MySQL flag to mark that there is an active transaction */
7258
if (trx->active_trans == 0) {
7260
innobase_register_trx_and_stmt(innodb_engine_ptr, session);
7261
trx->active_trans = 1;
7263
innobase_register_stmt(innodb_engine_ptr, session);
7269
/******************************************************************//**
7270
7071
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7271
7072
@return InnoDB isolation level */
7287
7088
/******************************************************************//**
7288
7089
As MySQL will execute an external lock for every new table it uses when it
7289
starts to process an SQL statement (an exception is when MySQL calls
7290
start_stmt for the handle) we can use this function to store the pointer to
7291
the Session in the handle. We will also use this function to communicate
7292
to InnoDB that a new SQL statement has started and that we must store a
7293
savepoint to our transaction handle, so that we are able to roll back
7294
the SQL statement in case of an error.
7090
starts to process an SQL statement. We can use this function to store the pointer to
7091
the Session in the handle.
7323
7117
if (lock_type != F_UNLCK) {
7324
7118
/* MySQL is setting a new table lock */
7326
trx->detailed_error[0] = '\0';
7328
/* Set the MySQL flag to mark that there is an active
7330
if (trx->active_trans == 0) {
7332
innobase_register_trx_and_stmt(innodb_engine_ptr, session);
7333
trx->active_trans = 1;
7334
} else if (trx->n_mysql_tables_in_use == 0) {
7335
innobase_register_stmt(innodb_engine_ptr, session);
7338
7120
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
7339
7121
&& prebuilt->select_lock_type == LOCK_NONE
7340
7122
&& session_test_options(session,
7367
7149
trx->mysql_n_tables_locked++;
7370
trx->n_mysql_tables_in_use++;
7371
7152
prebuilt->mysql_has_locked = TRUE;
7376
7157
/* MySQL is releasing a table lock */
7378
trx->n_mysql_tables_in_use--;
7379
7158
prebuilt->mysql_has_locked = FALSE;
7381
/* Release a possible FIFO ticket and search latch. Since we
7382
may reserve the kernel mutex, we have to release the search
7383
system latch first to obey the latching order. */
7385
innobase_release_stat_resources(trx);
7387
/* If the MySQL lock count drops to zero we know that the current SQL
7388
statement has ended */
7390
if (trx->n_mysql_tables_in_use == 0) {
7392
trx->mysql_n_tables_locked = 0;
7393
prebuilt->used_in_HANDLER = FALSE;
7395
if (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7396
if (trx->active_trans != 0) {
7397
getTransactionalEngine()->commit(session, TRUE);
7400
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
7401
&& trx->global_read_view) {
7403
/* At low transaction isolation levels we let
7404
each consistent read set its own snapshot */
7406
read_view_close_for_mysql(trx);
7159
trx->mysql_n_tables_locked= 0;
7750
7500
trx = check_trx_exists(session);
7752
/* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
7753
Be careful to ignore TL_IGNORE if we are going to do something with
7754
only 'real' locks! */
7756
/* If no MySQL table is in use, we need to set the isolation level
7757
of the transaction. */
7759
if (lock_type != TL_IGNORE
7760
&& trx->n_mysql_tables_in_use == 0) {
7761
trx->isolation_level = innobase_map_isolation_level(
7762
(enum_tx_isolation) session_tx_isolation(session));
7764
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
7765
&& trx->global_read_view) {
7767
/* At low transaction isolation levels we let
7768
each consistent read set its own snapshot */
7770
read_view_close_for_mysql(trx);
7774
7502
assert(EQ_CURRENT_SESSION(session));
7775
7503
const uint32_t sql_command = session_sql_command(session);
7851
7579
TABLESPACE or TRUNCATE TABLE then allow multiple
7852
7580
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
7853
7581
< TL_WRITE_CONCURRENT_INSERT.
7855
We especially allow multiple writers if MySQL is at the
7856
start of a stored procedure call (SQLCOM_CALL) or a
7857
stored function call (MySQL does have in_lock_tables
7860
7584
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
7861
7585
&& lock_type <= TL_WRITE)
7871
7595
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
7872
7596
to t2. Convert the lock to a normal read lock to allow
7873
7597
concurrent inserts to t2.
7875
We especially allow concurrent inserts if MySQL is at the
7876
start of a stored procedure call (SQLCOM_CALL)
7877
(MySQL does have session_in_lock_tables() TRUE there). */
7879
7600
if (lock_type == TL_READ_NO_INSERT) {
8250
7971
return(char_length);
7974
* We will also use this function to communicate
7975
* to InnoDB that a new SQL statement has started and that we must store a
7976
* savepoint to our transaction handle, so that we are able to roll back
7977
* the SQL statement in case of an error.
7980
InnobaseEngine::doStartStatement(
7981
Session *session) /*!< in: handle to the Drizzle session */
7984
* Create the InnoDB transaction structure
7987
trx_t *trx= check_trx_exists(session);
7989
/* "reset" the error message for the transaction */
7990
trx->detailed_error[0]= '\0';
7992
/* Set the isolation level of the transaction. */
7993
trx->isolation_level= innobase_map_isolation_level((enum_tx_isolation) session_tx_isolation(session));
7996
* Set the Drizzle flag to mark that there is an active
7999
* @todo this should go away
8001
if (trx->active_trans == 0) {
8002
trx->active_trans= 1;
8007
InnobaseEngine::doEndStatement(
8010
trx_t *trx= check_trx_exists(session);
8012
/* Release a possible FIFO ticket and search latch. Since we
8013
may reserve the kernel mutex, we have to release the search
8014
system latch first to obey the latching order. */
8016
innobase_release_stat_resources(trx);
8018
if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
8020
if (trx->active_trans != 0)
8022
commit(session, TRUE);
8023
trx->active_trans= 0;
8028
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
8029
trx->global_read_view)
8031
/* At low transaction isolation levels we let
8032
each consistent read set its own snapshot */
8033
read_view_close_for_mysql(trx);
8253
8038
/*******************************************************************//**
8254
8039
This function is used to prepare an X/Open XA distributed transaction.