summaryrefslogtreecommitdiff
path: root/sql/handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/handler.cc')
-rw-r--r--sql/handler.cc645
1 files changed, 388 insertions, 257 deletions
diff --git a/sql/handler.cc b/sql/handler.cc
index 04f10586484..50db743a8ff 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -24,16 +24,34 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "rpl_handler.h"
+#include "sql_cache.h" // query_cache, query_cache_*
+#include "sql_connect.h" // global_table_stats
+#include "key.h" // key_copy, key_unpack, key_cmp_if_same, key_cmp
+#include "sql_table.h" // build_table_filename
+#include "sql_parse.h" // check_stack_overrun
+#include "sql_acl.h" // SUPER_ACL
+#include "sql_base.h" // free_io_cache
+#include "discover.h" // writefrm
+#include "log_event.h" // *_rows_log_event
#include "create_options.h"
#include "rpl_filter.h"
#include <myisampack.h>
+#include "transaction.h"
#include "myisam.h"
+#include "probes_mysql.h"
+#include "debug_sync.h" // DEBUG_SYNC
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
+#ifdef WITH_ARIA_STORAGE_ENGINE
+#include "../storage/maria/ha_maria.h"
+#endif
+
/*
While we have legacy_db_type, we have this array to
check for dups and to find handlerton from legacy_db_type.
@@ -45,7 +63,8 @@ static handlerton *installed_htons[128];
#define BITMAP_STACKBUF_SIZE (128/8)
-KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} };
+KEY_CREATE_INFO default_key_create_info=
+ { HA_KEY_ALG_UNDEF, 0, {NullS, 0}, {NullS, 0} };
/* number of entries in handlertons[] */
ulong total_ha= 0;
@@ -82,7 +101,6 @@ uint known_extensions_id= 0;
static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans,
bool is_real_trans);
-
static plugin_ref ha_default_plugin(THD *thd)
{
if (thd->variables.table_plugin)
@@ -175,15 +193,6 @@ plugin_ref ha_lock_engine(THD *thd, const handlerton *hton)
}
-#ifdef NOT_USED
-static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root)
-{
- handlerton *hton= ha_default_handlerton(current_thd);
- return (hton && hton->create) ? hton->create(hton, table, mem_root) : NULL;
-}
-#endif
-
-
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
{
plugin_ref plugin;
@@ -221,11 +230,9 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
return NULL;
}
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+
switch (database_type) {
-#ifndef NO_HASH
- case DB_TYPE_HASH:
- return ha_resolve_by_legacy_type(thd, DB_TYPE_HASH);
-#endif
case DB_TYPE_MRG_ISAM:
return ha_resolve_by_legacy_type(thd, DB_TYPE_MRG_MYISAM);
default:
@@ -282,6 +289,16 @@ handler *get_ha_partition(partition_info *part_info)
#endif
+static const char **handler_errmsgs;
+
+C_MODE_START
+static const char **get_handler_errmsgs()
+{
+ return handler_errmsgs;
+}
+C_MODE_END
+
+
/**
Register handler error messages for use with my_error().
@@ -293,62 +310,63 @@ handler *get_ha_partition(partition_info *part_info)
int ha_init_errors(void)
{
-#define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg)
- const char **errmsgs;
+#define SETMSG(nr, msg) handler_errmsgs[(nr) - HA_ERR_FIRST]= (msg)
/* Allocate a pointer array for the error message strings. */
/* Zerofill it to avoid uninitialized gaps. */
- if (! (errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*),
- MYF(MY_WME | MY_ZEROFILL))))
+ if (! (handler_errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*),
+ MYF(MY_WME | MY_ZEROFILL))))
return 1;
/* Set the dedicated error messages. */
- SETMSG(HA_ERR_KEY_NOT_FOUND, ER(ER_KEY_NOT_FOUND));
- SETMSG(HA_ERR_FOUND_DUPP_KEY, ER(ER_DUP_KEY));
+ SETMSG(HA_ERR_KEY_NOT_FOUND, ER_DEFAULT(ER_KEY_NOT_FOUND));
+ SETMSG(HA_ERR_FOUND_DUPP_KEY, ER_DEFAULT(ER_DUP_KEY));
SETMSG(HA_ERR_RECORD_CHANGED, "Update wich is recoverable");
SETMSG(HA_ERR_WRONG_INDEX, "Wrong index given to function");
- SETMSG(HA_ERR_CRASHED, ER(ER_NOT_KEYFILE));
- SETMSG(HA_ERR_WRONG_IN_RECORD, ER(ER_CRASHED_ON_USAGE));
+ SETMSG(HA_ERR_CRASHED, ER_DEFAULT(ER_NOT_KEYFILE));
+ SETMSG(HA_ERR_WRONG_IN_RECORD, ER_DEFAULT(ER_CRASHED_ON_USAGE));
SETMSG(HA_ERR_OUT_OF_MEM, "Table handler out of memory");
SETMSG(HA_ERR_NOT_A_TABLE, "Incorrect file format '%.64s'");
SETMSG(HA_ERR_WRONG_COMMAND, "Command not supported");
- SETMSG(HA_ERR_OLD_FILE, ER(ER_OLD_KEYFILE));
+ SETMSG(HA_ERR_OLD_FILE, ER_DEFAULT(ER_OLD_KEYFILE));
SETMSG(HA_ERR_NO_ACTIVE_RECORD, "No record read in update");
SETMSG(HA_ERR_RECORD_DELETED, "Intern record deleted");
- SETMSG(HA_ERR_RECORD_FILE_FULL, ER(ER_RECORD_FILE_FULL));
+ SETMSG(HA_ERR_RECORD_FILE_FULL, ER_DEFAULT(ER_RECORD_FILE_FULL));
SETMSG(HA_ERR_INDEX_FILE_FULL, "No more room in index file '%.64s'");
SETMSG(HA_ERR_END_OF_FILE, "End in next/prev/first/last");
- SETMSG(HA_ERR_UNSUPPORTED, ER(ER_ILLEGAL_HA));
+ SETMSG(HA_ERR_UNSUPPORTED, ER_DEFAULT(ER_ILLEGAL_HA));
SETMSG(HA_ERR_TO_BIG_ROW, "Too big row");
SETMSG(HA_WRONG_CREATE_OPTION, "Wrong create option");
- SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER(ER_DUP_UNIQUE));
+ SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER_DEFAULT(ER_DUP_UNIQUE));
SETMSG(HA_ERR_UNKNOWN_CHARSET, "Can't open charset");
- SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER(ER_WRONG_MRG_TABLE));
- SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER(ER_CRASHED_ON_REPAIR));
- SETMSG(HA_ERR_CRASHED_ON_USAGE, ER(ER_CRASHED_ON_USAGE));
- SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER(ER_LOCK_WAIT_TIMEOUT));
- SETMSG(HA_ERR_LOCK_TABLE_FULL, ER(ER_LOCK_TABLE_FULL));
- SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION));
- SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK));
- SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN));
- SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW_2));
- SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED_2));
+ SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER_DEFAULT(ER_WRONG_MRG_TABLE));
+ SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER_DEFAULT(ER_CRASHED_ON_REPAIR));
+ SETMSG(HA_ERR_CRASHED_ON_USAGE, ER_DEFAULT(ER_CRASHED_ON_USAGE));
+ SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER_DEFAULT(ER_LOCK_WAIT_TIMEOUT));
+ SETMSG(HA_ERR_LOCK_TABLE_FULL, ER_DEFAULT(ER_LOCK_TABLE_FULL));
+ SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER_DEFAULT(ER_READ_ONLY_TRANSACTION));
+ SETMSG(HA_ERR_LOCK_DEADLOCK, ER_DEFAULT(ER_LOCK_DEADLOCK));
+ SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER_DEFAULT(ER_CANNOT_ADD_FOREIGN));
+ SETMSG(HA_ERR_NO_REFERENCED_ROW, ER_DEFAULT(ER_NO_REFERENCED_ROW_2));
+ SETMSG(HA_ERR_ROW_IS_REFERENCED, ER_DEFAULT(ER_ROW_IS_REFERENCED_2));
SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name");
SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size");
SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'");
- SETMSG(HA_ERR_TABLE_EXIST, ER(ER_TABLE_EXISTS_ERROR));
+ SETMSG(HA_ERR_TABLE_EXIST, ER_DEFAULT(ER_TABLE_EXISTS_ERROR));
SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine");
- SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER(ER_TABLE_DEF_CHANGED));
+ SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER_DEFAULT(ER_TABLE_DEF_CHANGED));
SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY, "FK constraint would lead to duplicate key");
- SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER(ER_TABLE_NEEDS_UPGRADE));
- SETMSG(HA_ERR_TABLE_READONLY, ER(ER_OPEN_AS_READONLY));
- SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER(ER_AUTOINC_READ_FAILED));
- SETMSG(HA_ERR_AUTOINC_ERANGE, ER(ER_WARN_DATA_OUT_OF_RANGE));
- SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER(ER_TOO_MANY_CONCURRENT_TRXS));
- SETMSG(HA_ERR_DISK_FULL, ER(ER_DISK_FULL));
+ SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER_DEFAULT(ER_TABLE_NEEDS_UPGRADE));
+ SETMSG(HA_ERR_TABLE_READONLY, ER_DEFAULT(ER_OPEN_AS_READONLY));
+ SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER_DEFAULT(ER_AUTOINC_READ_FAILED));
+ SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE));
+ SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS));
+ SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG));
+ SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT));
+ SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL));
/* Register the error messages for use with my_error(). */
- return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
+ return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
}
@@ -367,7 +385,7 @@ static int ha_finish_errors(void)
/* Allocate a pointer array for the error message strings. */
if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST)))
return 1;
- my_free((uchar*) errmsgs, MYF(0));
+ my_free(errmsgs);
return 0;
}
@@ -413,9 +431,15 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
reuse an array slot. Otherwise the number of uninstall/install
cycles would be limited.
*/
- hton2plugin[hton->slot]= NULL;
+ if (hton->slot != HA_SLOT_UNDEF)
+ {
+ /* Make sure we are not unpluging another plugin */
+ DBUG_ASSERT(hton2plugin[hton->slot] == plugin);
+ DBUG_ASSERT(hton->slot < MAX_HA);
+ hton2plugin[hton->slot]= NULL;
+ }
- my_free((uchar*)hton, MYF(0));
+ my_free(hton);
end:
DBUG_RETURN(0);
@@ -430,6 +454,15 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
hton= (handlerton *)my_malloc(sizeof(handlerton),
MYF(MY_WME | MY_ZEROFILL));
+
+ if (hton == NULL)
+ {
+ sql_print_error("Unable to allocate memory for plugin '%s' handlerton.",
+ plugin->name.str);
+ goto err_no_hton_memory;
+ }
+
+ hton->slot= HA_SLOT_UNDEF;
/* Historical Requirement */
plugin->data= hton; // shortcut for the future
if (plugin->plugin->init && plugin->plugin->init(hton))
@@ -463,8 +496,6 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
if (idx == (int) DB_TYPE_DEFAULT)
{
sql_print_warning("Too many storage engines!");
- my_free(hton, MYF(0));
- plugin->data= 0;
goto err_deinit;
}
if (hton->db_type != DB_TYPE_UNKNOWN)
@@ -545,7 +576,8 @@ err_deinit:
(void) plugin->plugin->deinit(NULL);
err:
- my_free((uchar*) hton, MYF(0));
+ my_free(hton);
+err_no_hton_memory:
plugin->data= NULL;
DBUG_RETURN(1);
}
@@ -886,16 +918,16 @@ void ha_close_connection(THD* thd)
a transaction in a given engine is read-write and will not
involve the two-phase commit protocol!
- At the end of a statement, server call
- ha_autocommit_or_rollback() is invoked. This call in turn
- invokes handlerton::prepare() for every involved engine.
- Prepare is followed by a call to handlerton::commit_one_phase()
- If a one-phase commit will suffice, handlerton::prepare() is not
- invoked and the server only calls handlerton::commit_one_phase().
- At statement commit, the statement-related read-write engine
- flag is propagated to the corresponding flag in the normal
- transaction. When the commit is complete, the list of registered
- engines is cleared.
+ At the end of a statement, server call trans_commit_stmt is
+ invoked. This call in turn invokes handlerton::prepare()
+ for every involved engine. Prepare is followed by a call
+ to handlerton::commit_one_phase() If a one-phase commit
+ will suffice, handlerton::prepare() is not invoked and
+ the server only calls handlerton::commit_one_phase().
+ At statement commit, the statement-related read-write
+ engine flag is propagated to the corresponding flag in the
+ normal transaction. When the commit is complete, the list
+ of registered engines is cleared.
Rollback is handled in a similar fashion.
@@ -906,7 +938,7 @@ void ha_close_connection(THD* thd)
do not "register" in thd->transaction lists, and thus do not
modify the transaction state. Besides, each DDL in
MySQL is prefixed with an implicit normal transaction commit
- (a call to end_active_trans()), and thus leaves nothing
+ (a call to trans_commit_implicit()), and thus leaves nothing
to modify.
However, as it has been pointed out with CREATE TABLE .. SELECT,
some DDL statements can start a *new* transaction.
@@ -990,7 +1022,7 @@ int ha_prepare(THD *thd)
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
Ha_trx_info *ha_info= trans->ha_list;
DBUG_ENTER("ha_prepare");
-#ifdef USING_TRANSACTIONS
+
if (ha_info)
{
for (; ha_info; ha_info= ha_info->next())
@@ -1016,7 +1048,7 @@ int ha_prepare(THD *thd)
}
}
}
-#endif /* USING_TRANSACTIONS */
+
DBUG_RETURN(error);
}
@@ -1133,6 +1165,7 @@ int ha_commit_trans(THD *thd, bool all)
if (thd->in_sub_stmt)
{
+ DBUG_ASSERT(0);
/*
Since we don't support nested statement transactions in 5.0,
we can't commit or rollback stmt transactions while we are inside
@@ -1147,11 +1180,14 @@ int ha_commit_trans(THD *thd, bool all)
bail out with error even before ha_commit_trans() call. To be 100% safe
let us throw error in non-debug builds.
*/
- DBUG_ASSERT(0);
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
DBUG_RETURN(2);
}
-#ifdef USING_TRANSACTIONS
+
+#ifdef WITH_ARIA_STORAGE_ENGINE
+ ha_maria::implicit_commit(thd, FALSE);
+#endif
+
if (!ha_info)
{
/* Free resources and perform other cleanup even for 'empty' transactions. */
@@ -1169,12 +1205,29 @@ int ha_commit_trans(THD *thd, bool all)
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
/* rw_trans is TRUE when we in a transaction changing data */
bool rw_trans= is_real_trans && (rw_ha_count > 0);
+ MDL_request mdl_request;
- if (rw_trans &&
- wait_if_global_read_lock(thd, 0, 0))
+ if (rw_trans)
{
- ha_rollback_trans(thd, all);
- DBUG_RETURN(1);
+ /*
+ Acquire a metadata lock which will ensure that COMMIT is blocked
+ by an active FLUSH TABLES WITH READ LOCK (and vice versa:
+ COMMIT in progress blocks FTWRL).
+
+ We allow the owner of FTWRL to COMMIT; we assume that it knows
+ what it does.
+ */
+ mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_EXPLICIT);
+
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ {
+ ha_rollback_trans(thd, all);
+ DBUG_RETURN(1);
+ }
+
+ DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock");
}
if (rw_trans &&
@@ -1189,8 +1242,7 @@ int ha_commit_trans(THD *thd, bool all)
if (trans->no_2pc || (rw_ha_count <= 1))
{
error= ha_commit_one_phase(thd, all);
- DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
- goto end;
+ goto done;
}
need_prepare_ordered= FALSE;
@@ -1228,8 +1280,7 @@ int ha_commit_trans(THD *thd, bool all)
if (!is_real_trans)
{
error= commit_one_phase_2(thd, all, trans, is_real_trans);
- DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
- goto end;
+ goto done;
}
cookie= tc_log->log_and_order(thd, xid, all, need_prepare_ordered,
@@ -1240,7 +1291,6 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
- DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (tc_log->unlog(cookie, xid))
@@ -1249,7 +1299,9 @@ int ha_commit_trans(THD *thd, bool all)
goto end;
}
+done:
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
+ RUN_HOOK(transaction, after_commit, (thd, FALSE));
goto end;
/* Come here if error and we need to rollback. */
@@ -1258,38 +1310,59 @@ err:
ha_rollback_trans(thd, all);
end:
- if (rw_trans)
- start_waiting_global_read_lock(thd);
-#endif /* USING_TRANSACTIONS */
+ if (rw_trans && mdl_request.ticket)
+ {
+ /*
+ We do not always immediately release transactional locks
+ after ha_commit_trans() (see uses of ha_enable_transaction()),
+ thus we release the commit blocker lock as soon as it's
+ not needed.
+ */
+ thd->mdl_context.release_lock(mdl_request.ticket);
+ }
DBUG_RETURN(error);
}
/**
@note
This function does not care about global read lock. A caller should.
+
+ @param[in] all Is set in case of explicit commit
+ (COMMIT statement), or implicit commit
+ issued by DDL. Is not set when called
+ at the end of statement, even if
+ autocommit=1.
*/
+
int ha_commit_one_phase(THD *thd, bool all)
{
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
/*
"real" is a nick name for a transaction for which a commit will
make persistent changes. E.g. a 'stmt' transaction inside a 'all'
- transation is not 'real': even though it's possible to commit it,
+ transaction is not 'real': even though it's possible to commit it,
the changes are not durable as they might be rolled back if the
enclosing 'all' transaction is rolled back.
+ We establish the value of 'is_real_trans' by checking
+ if it's an explicit COMMIT/BEGIN statement, or implicit
+ commit issued by DDL (all == TRUE), or if we're running
+ in autocommit mode (it's only in the autocommit mode
+ ha_commit_one_phase() can be called with an empty
+ transaction.all.ha_list, see why in trans_register_ha()).
*/
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
DBUG_ENTER("ha_commit_one_phase");
- DBUG_RETURN(commit_one_phase_2(thd, all, trans, is_real_trans));
+ int res= commit_one_phase_2(thd, all, trans, is_real_trans);
+ DBUG_RETURN(res);
}
+
static int
commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
{
int error= 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("commit_one_phase_2");
-#ifdef USING_TRANSACTIONS
if (ha_info)
{
for (; ha_info; ha_info= ha_info_next)
@@ -1314,13 +1387,12 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
if (thd->transaction.changed_tables)
query_cache.invalidate(thd, thd->transaction.changed_tables);
#endif
- thd->variables.tx_isolation=thd->session_tx_isolation;
}
}
/* Free resources and perform other cleanup even for 'empty' transactions. */
if (is_real_trans)
thd->transaction.cleanup();
-#endif /* USING_TRANSACTIONS */
+
DBUG_RETURN(error);
}
@@ -1333,9 +1405,15 @@ int ha_rollback_trans(THD *thd, bool all)
/*
"real" is a nick name for a transaction for which a commit will
make persistent changes. E.g. a 'stmt' transaction inside a 'all'
- transation is not 'real': even though it's possible to commit it,
+ transaction is not 'real': even though it's possible to commit it,
the changes are not durable as they might be rolled back if the
enclosing 'all' transaction is rolled back.
+ We establish the value of 'is_real_trans' by checking
+ if it's an explicit COMMIT or BEGIN statement, or implicit
+ commit issued by DDL (in these cases all == TRUE),
+ or if we're running in autocommit mode (it's only in the autocommit mode
+ ha_commit_one_phase() is called with an empty
+ transaction.all.ha_list, see why in trans_register_ha()).
*/
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
DBUG_ENTER("ha_rollback_trans");
@@ -1349,6 +1427,7 @@ int ha_rollback_trans(THD *thd, bool all)
if (thd->in_sub_stmt)
{
+ DBUG_ASSERT(0);
/*
If we are inside stored function or trigger we should not commit or
rollback current statement transaction. See comment in ha_commit_trans()
@@ -1356,11 +1435,10 @@ int ha_rollback_trans(THD *thd, bool all)
*/
if (!all)
DBUG_RETURN(0);
- DBUG_ASSERT(0);
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
DBUG_RETURN(1);
}
-#ifdef USING_TRANSACTIONS
+
if (ha_info)
{
/* Close all cursors that can not survive ROLLBACK */
@@ -1384,14 +1462,11 @@ int ha_rollback_trans(THD *thd, bool all)
trans->no_2pc=0;
if (is_real_trans && thd->transaction_rollback_request &&
thd->transaction.xid_state.xa_state != XA_NOTR)
- thd->transaction.xid_state.rm_error= thd->main_da.sql_errno();
- if (all)
- thd->variables.tx_isolation=thd->session_tx_isolation;
+ thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno();
}
- /* Always cleanup. Even if there nht==0. There may be savepoints. */
+ /* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
thd->transaction.cleanup();
-#endif /* USING_TRANSACTIONS */
if (all)
thd->transaction_rollback_request= FALSE;
@@ -1413,41 +1488,7 @@ int ha_rollback_trans(THD *thd, bool all)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
- DBUG_RETURN(error);
-}
-
-/**
- This is used to commit or rollback a single statement depending on
- the value of error.
-
- @note
- Note that if the autocommit is on, then the following call inside
- InnoDB will commit or rollback the whole transaction (= the statement). The
- autocommit mechanism built into InnoDB is based on counting locks, but if
- the user has used LOCK TABLES then that mechanism does not know to do the
- commit.
-*/
-int ha_autocommit_or_rollback(THD *thd, int error)
-{
- DBUG_ENTER("ha_autocommit_or_rollback");
-#ifdef USING_TRANSACTIONS
- if (thd->transaction.stmt.ha_list)
- {
- if (!error)
- {
- if (ha_commit_trans(thd, 0))
- error=1;
- }
- else
- {
- (void) ha_rollback_trans(thd, 0);
- if (thd->transaction_rollback_request && !thd->in_sub_stmt)
- (void) ha_rollback(thd);
- }
-
- thd->variables.tx_isolation=thd->session_tx_isolation;
- }
-#endif
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
DBUG_RETURN(error);
}
@@ -1608,7 +1649,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
}
// recovery mode
if (info->commit_list ?
- hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
+ my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
{
#ifndef DBUG_OFF
@@ -1669,7 +1710,7 @@ int ha_recover(HASH *commit_list)
plugin_foreach(NULL, xarecover_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &info);
- my_free((uchar*)info.list, MYF(0));
+ my_free(info.list);
if (info.found_foreign_xids)
sql_print_warning("Found %d prepared XA transactions",
info.found_foreign_xids);
@@ -1710,12 +1751,12 @@ bool mysql_xa_recover(THD *thd)
field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(1);
- pthread_mutex_lock(&LOCK_xid_cache);
- while ((xs= (XID_STATE*)hash_element(&xid_cache, i++)))
+ mysql_mutex_lock(&LOCK_xid_cache);
+ while ((xs= (XID_STATE*) my_hash_element(&xid_cache, i++)))
{
if (xs->xa_state==XA_PREPARED)
{
@@ -1727,13 +1768,13 @@ bool mysql_xa_recover(THD *thd)
&my_charset_bin);
if (protocol->write())
{
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_unlock(&LOCK_xid_cache);
DBUG_RETURN(1);
}
}
}
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_unlock(&LOCK_xid_cache);
my_eof(thd);
DBUG_RETURN(0);
}
@@ -1840,7 +1881,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
&thd->transaction.all);
Ha_trx_info *ha_info= trans->ha_list;
DBUG_ENTER("ha_savepoint");
-#ifdef USING_TRANSACTIONS
+
for (; ha_info; ha_info= ha_info->next())
{
int err;
@@ -1864,7 +1905,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
engines are prepended to the beginning of the list.
*/
sv->ha_list= trans->ha_list;
-#endif /* USING_TRANSACTIONS */
+
DBUG_RETURN(error);
}
@@ -1917,9 +1958,9 @@ int ha_start_consistent_snapshot(THD *thd)
START TRANSACTION WITH CONSISTENT SNAPSHOT and
have a consistent binlog position.
*/
- pthread_mutex_lock(&LOCK_commit_ordered);
+ mysql_mutex_lock(&LOCK_commit_ordered);
plugin_foreach(thd, snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &warn);
- pthread_mutex_unlock(&LOCK_commit_ordered);
+ mysql_mutex_unlock(&LOCK_commit_ordered);
/*
Same idea as when one wants to CREATE TABLE in one engine which does not
@@ -2019,23 +2060,28 @@ const char *get_canonical_filename(handler *file, const char *path,
struct Ha_delete_table_error_handler: public Internal_error_handler
{
public:
- virtual bool handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
char buff[MYSQL_ERRMSG_SIZE];
};
bool
Ha_delete_table_error_handler::
-handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd)
-{
+handle_condition(THD *,
+ uint,
+ const char*,
+ MYSQL_ERROR::enum_warning_level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+{
+ *cond_hdl= NULL;
/* Grab the error message */
- strmake(buff, message, sizeof(buff)-1);
+ strmake(buff, msg, sizeof(buff)-1);
return TRUE;
}
@@ -2095,7 +2141,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
XXX: should we convert *all* errors to warnings here?
What if the error is fatal?
*/
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error,
ha_delete_table_error_handler.buff);
}
delete file;
@@ -2132,7 +2178,6 @@ handler *handler::clone(const char *name, MEM_ROOT *mem_root)
HA_OPEN_IGNORE_IF_LOCKED))
return NULL;
- new_handler->cloned= 1; // Marker for debugging
return new_handler;
}
@@ -2164,6 +2209,10 @@ THD *handler::ha_thd(void) const
return (table && table->in_use) ? table->in_use : current_thd;
}
+PSI_table_share *handler::ha_table_share_psi(const TABLE_SHARE *share) const
+{
+ return share->m_psi;
+}
/** @brief
Open database-handler.
@@ -2585,7 +2634,7 @@ int handler::update_auto_increment()
variables->auto_increment_increment);
auto_inc_intervals_count++;
/* Row-based replication does not need to store intervals in binlog */
- if (mysql_bin_log.is_open() && !thd->current_stmt_binlog_row_based)
+ if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row())
thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(),
auto_inc_interval_for_cur_row.values(),
variables->auto_increment_increment);
@@ -2786,6 +2835,7 @@ void handler::print_error(int error, myf errflag)
break;
case HA_ERR_KEY_NOT_FOUND:
case HA_ERR_NO_ACTIVE_RECORD:
+ case HA_ERR_RECORD_DELETED:
case HA_ERR_END_OF_FILE:
/*
This errors is not not normally fatal (for example for reads). However
@@ -2963,6 +3013,9 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_TABLE_NEEDS_UPGRADE:
textno=ER_TABLE_NEEDS_UPGRADE;
break;
+ case HA_ERR_NO_PARTITION_FOUND:
+ textno=ER_WRONG_PARTITION_NAME;
+ break;
case HA_ERR_TABLE_READONLY:
textno= ER_OPEN_AS_READONLY;
break;
@@ -2975,6 +3028,15 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_TOO_MANY_CONCURRENT_TRXS:
textno= ER_TOO_MANY_CONCURRENT_TRXS;
break;
+ case HA_ERR_INDEX_COL_TOO_LONG:
+ textno= ER_INDEX_COLUMN_TOO_LONG;
+ break;
+ case HA_ERR_INDEX_CORRUPT:
+ textno= ER_INDEX_CORRUPT;
+ break;
+ case HA_ERR_UNDO_REC_TOO_BIG:
+ textno= ER_UNDO_RECORD_TOO_BIG;
+ break;
default:
{
/* The error was "unknown" to this function.
@@ -3013,7 +3075,6 @@ void handler::print_error(int error, myf errflag)
}
}
my_error(textno, errflag, table_share->table_name.str, error);
- DBUG_ASSERT(!fatal_error || !debug_assert_if_crashed_table);
DBUG_VOID_RETURN;
}
@@ -3160,27 +3221,21 @@ static bool update_frm_version(TABLE *table)
strxmov(path, table->s->normalized_path.str, reg_ext, NullS);
- if ((file= my_open(path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
+ if ((file= mysql_file_open(key_file_frm,
+ path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
{
uchar version[4];
- char *key= table->s->table_cache_key.str;
- uint key_length= table->s->table_cache_key.length;
- TABLE *entry;
- HASH_SEARCH_STATE state;
int4store(version, MYSQL_VERSION_ID);
- if ((result= my_pwrite(file,(uchar*) version,4,51L,MYF_RW)))
+ if ((result= mysql_file_pwrite(file, (uchar*) version, 4, 51L, MYF_RW)))
goto err;
- for (entry=(TABLE*) hash_first(&open_cache,(uchar*) key,key_length, &state);
- entry;
- entry= (TABLE*) hash_next(&open_cache,(uchar*) key,key_length, &state))
- entry->s->mysql_version= MYSQL_VERSION_ID;
+ table->s->mysql_version= MYSQL_VERSION_ID;
}
err:
if (file >= 0)
- VOID(my_close(file,MYF(MY_WME)));
+ (void) mysql_file_close(file, MYF(MY_WME));
DBUG_RETURN(result);
}
@@ -3227,7 +3282,7 @@ int handler::delete_table(const char *name)
for (const char **ext=bas_ext(); *ext ; ext++)
{
fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT);
- if (my_delete_with_symlink(buff, MYF(0)))
+ if (mysql_file_delete_with_symlink(key_file_misc, buff, MYF(0)))
{
if (my_errno != ENOENT)
{
@@ -3363,9 +3418,13 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt)
mark_trx_read_write();
- if ((result= repair(thd, check_opt)))
- return result;
- return update_frm_version(table);
+ result= repair(thd, check_opt);
+ DBUG_ASSERT(result == HA_ADMIN_NOT_IMPLEMENTED ||
+ ha_table_flags() & HA_CAN_REPAIR);
+
+ if (result == HA_ADMIN_OK)
+ result= update_frm_version(table);
+ return result;
}
@@ -3401,47 +3460,32 @@ handler::ha_delete_all_rows()
/**
- Reset auto increment: public interface.
-
- @sa handler::reset_auto_increment()
-*/
-
-int
-handler::ha_reset_auto_increment(ulonglong value)
-{
- mark_trx_read_write();
-
- return reset_auto_increment(value);
-}
-
-
-/**
- Backup table: public interface.
+ Truncate table: public interface.
- @sa handler::backup()
+ @sa handler::truncate()
*/
int
-handler::ha_backup(THD* thd, HA_CHECK_OPT* check_opt)
+handler::ha_truncate()
{
mark_trx_read_write();
- return backup(thd, check_opt);
+ return truncate();
}
/**
- Restore table: public interface.
+ Reset auto increment: public interface.
- @sa handler::restore()
+ @sa handler::reset_auto_increment()
*/
int
-handler::ha_restore(THD* thd, HA_CHECK_OPT* check_opt)
+handler::ha_reset_auto_increment(ulonglong value)
{
mark_trx_read_write();
- return restore(thd, check_opt);
+ return reset_auto_increment(value);
}
@@ -3705,7 +3749,7 @@ int ha_enable_transaction(THD *thd, bool on)
So, let's commit an open transaction (if any) now.
*/
if (!(error= ha_commit_trans(thd, 0)))
- error= end_trans(thd, COMMIT);
+ error= trans_commit_implicit(thd);
}
DBUG_RETURN(error);
}
@@ -3763,7 +3807,7 @@ int handler::index_next_same(uchar *buf, const uchar *key, uint keylen)
}
-void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
+void handler::get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id)
{
info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
@@ -3806,10 +3850,10 @@ void handler::update_global_table_stats()
DBUG_ASSERT(table->s && table->s->table_cache_key.str);
- pthread_mutex_lock(&LOCK_global_table_stats);
+ mysql_mutex_lock(&LOCK_global_table_stats);
/* Gets the global table stats, creating one if necessary. */
if (!(table_stats= (TABLE_STATS*)
- hash_search(&global_table_stats,
+ my_hash_search(&global_table_stats,
(uchar*) table->s->table_cache_key.str,
table->s->table_cache_key.length)))
{
@@ -3829,7 +3873,7 @@ void handler::update_global_table_stats()
if (my_hash_insert(&global_table_stats, (uchar*) table_stats))
{
/* Out of memory error is already given */
- my_free(table_stats, 0);
+ my_free(table_stats);
goto end;
}
}
@@ -3841,7 +3885,7 @@ void handler::update_global_table_stats()
1));
rows_read= rows_changed= 0;
end:
- pthread_mutex_unlock(&LOCK_global_table_stats);
+ mysql_mutex_unlock(&LOCK_global_table_stats);
}
@@ -3872,9 +3916,9 @@ void handler::update_global_index_stats()
if (!key_info->cache_name)
continue;
key_length= table->s->table_cache_key.length + key_info->name_length + 1;
- pthread_mutex_lock(&LOCK_global_index_stats);
+ mysql_mutex_lock(&LOCK_global_index_stats);
// Gets the global index stats, creating one if necessary.
- if (!(index_stats= (INDEX_STATS*) hash_search(&global_index_stats,
+ if (!(index_stats= (INDEX_STATS*) my_hash_search(&global_index_stats,
key_info->cache_name,
key_length)))
{
@@ -3887,7 +3931,7 @@ void handler::update_global_index_stats()
index_stats->index_name_length= key_length;
if (my_hash_insert(&global_index_stats, (uchar*) index_stats))
{
- my_free(index_stats, 0);
+ my_free(index_stats);
goto end;
}
}
@@ -3895,7 +3939,7 @@ void handler::update_global_index_stats()
index_stats->rows_read+= index_rows_read[index];
index_rows_read[index]= 0;
end:
- pthread_mutex_unlock(&LOCK_global_index_stats);
+ mysql_mutex_unlock(&LOCK_global_index_stats);
}
}
}
@@ -3937,8 +3981,7 @@ int ha_create_table(THD *thd, const char *path,
name= get_canonical_filename(table.file, share.path.str, name_buff);
error= table.file->ha_create(name, &table, create_info);
-
- VOID(closefrm(&table, 0));
+ (void) closefrm(&table, 0);
if (error)
{
strxmov(name_buff, db, ".", table_name, NullS);
@@ -3989,7 +4032,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
build_table_filename(path, sizeof(path) - 1, db, name, "", 0);
// Save the frm file
error= writefrm(path, frmblob, frmlen);
- my_free(frmblob, MYF(0));
+ my_free(frmblob);
if (error)
DBUG_RETURN(2);
@@ -4009,11 +4052,39 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
get_canonical_filename(table.file, path, path);
error=table.file->ha_create(path, &table, &create_info);
- VOID(closefrm(&table, 1));
+ (void) closefrm(&table, 1);
DBUG_RETURN(error != 0);
}
+
+/**
+ Try to find a table in a storage engine.
+
+ @param db Normalized table schema name
+ @param name Normalized table name.
+ @param[out] exists Only valid if the function succeeded.
+
+ @retval TRUE An error is found
+ @retval FALSE Success, check *exists
+*/
+
+bool
+ha_check_if_table_exists(THD* thd, const char *db, const char *name,
+ bool *exists)
+{
+ uchar *frmblob= NULL;
+ size_t frmlen;
+ DBUG_ENTER("ha_check_if_table_exists");
+
+ *exists= ! ha_discover(thd, db, name, &frmblob, &frmlen);
+ if (*exists)
+ my_free(frmblob);
+
+ DBUG_RETURN(FALSE);
+}
+
+
void st_ha_check_opt::init()
{
flags= sql_flags= 0;
@@ -4034,19 +4105,20 @@ void st_ha_check_opt::init()
/**
Init a key cache if it has not been initied before.
*/
-int ha_init_key_cache(const char *name, KEY_CACHE *key_cache)
+int ha_init_key_cache(const char *name, KEY_CACHE *key_cache, void *unused
+ __attribute__((unused)))
{
DBUG_ENTER("ha_init_key_cache");
if (!key_cache->key_cache_inited)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
size_t tmp_buff_size= (size_t) key_cache->param_buff_size;
uint tmp_block_size= (uint) key_cache->param_block_size;
- uint division_limit= key_cache->param_division_limit;
- uint age_threshold= key_cache->param_age_threshold;
- uint partitions= key_cache->param_partitions;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ uint division_limit= (uint)key_cache->param_division_limit;
+ uint age_threshold= (uint)key_cache->param_age_threshold;
+ uint partitions= (uint)key_cache->param_partitions;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
DBUG_RETURN(!init_key_cache(key_cache,
tmp_block_size,
tmp_buff_size,
@@ -4066,12 +4138,12 @@ int ha_resize_key_cache(KEY_CACHE *key_cache)
if (key_cache->key_cache_inited)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
size_t tmp_buff_size= (size_t) key_cache->param_buff_size;
long tmp_block_size= (long) key_cache->param_block_size;
- uint division_limit= key_cache->param_division_limit;
- uint age_threshold= key_cache->param_age_threshold;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ uint division_limit= (uint)key_cache->param_division_limit;
+ uint age_threshold= (uint)key_cache->param_age_threshold;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
DBUG_RETURN(!resize_key_cache(key_cache, tmp_block_size,
tmp_buff_size,
division_limit, age_threshold));
@@ -4089,10 +4161,10 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache)
if (key_cache->key_cache_inited)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
- uint division_limit= key_cache->param_division_limit;
- uint age_threshold= key_cache->param_age_threshold;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ uint division_limit= (uint)key_cache->param_division_limit;
+ uint age_threshold= (uint)key_cache->param_age_threshold;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
change_key_cache_param(key_cache, division_limit, age_threshold);
}
DBUG_RETURN(0);
@@ -4108,13 +4180,13 @@ int ha_repartition_key_cache(KEY_CACHE *key_cache)
if (key_cache->key_cache_inited)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
size_t tmp_buff_size= (size_t) key_cache->param_buff_size;
long tmp_block_size= (long) key_cache->param_block_size;
- uint division_limit= key_cache->param_division_limit;
- uint age_threshold= key_cache->param_age_threshold;
- uint partitions= key_cache->param_partitions;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ uint division_limit= (uint)key_cache->param_division_limit;
+ uint age_threshold= (uint)key_cache->param_age_threshold;
+ uint partitions= (uint)key_cache->param_partitions;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
DBUG_RETURN(!repartition_key_cache(key_cache, tmp_block_size,
tmp_buff_size,
division_limit, age_threshold,
@@ -4125,15 +4197,6 @@ int ha_repartition_key_cache(KEY_CACHE *key_cache)
/**
- Free memory allocated by a key cache.
-*/
-int ha_end_key_cache(KEY_CACHE *key_cache)
-{
- end_key_cache(key_cache, 1); // Can never fail
- return 0;
-}
-
-/**
Move all tables from one key cache to another one.
*/
int ha_change_key_cache(KEY_CACHE *old_key_cache,
@@ -4233,8 +4296,7 @@ ha_find_files(THD *thd,const char *db,const char *path,
int error= 0;
DBUG_ENTER("ha_find_files");
DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d",
- val_or_null(db), val_or_null(path),
- val_or_null(wild), dir));
+ db, path, wild, dir));
st_find_files_args args= {db, path, wild, dir, files};
plugin_foreach(thd, find_files_handlerton,
@@ -4699,7 +4761,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
field_list.push_back(new Item_empty_string("Name",FN_REFLEN));
field_list.push_back(new Item_empty_string("Status",10));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
return TRUE;
@@ -4753,9 +4815,9 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
table->s->cached_row_logging_check == 1);
- return (thd->current_stmt_binlog_row_based &&
+ return (thd->is_current_stmt_binlog_format_row() &&
table->s->cached_row_logging_check &&
- (thd->options & OPTION_BIN_LOG) &&
+ (thd->variables.option_bits & OPTION_BIN_LOG) &&
mysql_bin_log.is_open());
}
@@ -4771,9 +4833,7 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
DESCRIPTION
This function will generate and write table maps for all tables
- that are locked by the thread 'thd'. Either manually locked
- (stored in THD::locked_tables) and automatically locked (stored
- in THD::lock) are considered.
+ that are locked by the thread 'thd'.
RETURN VALUE
0 All OK
@@ -4781,25 +4841,22 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
SEE ALSO
THD::lock
- THD::locked_tables
*/
static int write_locked_table_maps(THD *thd)
{
DBUG_ENTER("write_locked_table_maps");
- DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx thd->locked_tables: 0x%lx "
+ DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx "
"thd->extra_lock: 0x%lx",
- (long) thd, (long) thd->lock,
- (long) thd->locked_tables, (long) thd->extra_lock));
+ (long) thd, (long) thd->lock, (long) thd->extra_lock));
DBUG_PRINT("debug", ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps()));
if (thd->get_binlog_table_maps() == 0)
{
- MYSQL_LOCK *locks[3];
+ MYSQL_LOCK *locks[2];
locks[0]= thd->extra_lock;
locks[1]= thd->lock;
- locks[2]= thd->locked_tables;
my_bool with_annotate= thd->variables.binlog_annotate_row_events &&
thd->query() && thd->query_length();
@@ -4819,7 +4876,21 @@ static int write_locked_table_maps(THD *thd)
if (table->current_lock == F_WRLCK &&
check_table_binlog_row_based(thd, table))
{
- int const has_trans= table->file->has_transactions();
+ /*
+ We need to have a transactional behavior for SQLCOM_CREATE_TABLE
+ (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
+ compatible behavior with the STMT based replication even when
+ the table is not transactional. In other words, if the operation
+ fails while executing the insert phase nothing is written to the
+ binlog.
+
+ Note that at this point, we check the type of a set of tables to
+ create the table map events. In the function binlog_log_row(),
+ which calls the current function, we check the type of the table
+ of the current row.
+ */
+ bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
+ table->file->has_transactions();
int const error= thd->binlog_write_table_map(table, has_trans,
&with_annotate);
/*
@@ -4869,10 +4940,20 @@ static int binlog_log_row(TABLE* table,
{
bitmap_set_all(&cols);
if (likely(!(error= write_locked_table_maps(thd))))
- error= (*log_func)(thd, table, table->file->has_transactions(),
- &cols, table->s->fields,
+ {
+ /*
+ We need to have a transactional behavior for SQLCOM_CREATE_TABLE
+ (i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
+ compatible behavior with the STMT based replication even when
+ the table is not transactional. In other words, if the operation
+ fails while executing the insert phase nothing is written to the
+ binlog.
+ */
+ bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
+ table->file->has_transactions();
+ error= (*log_func)(thd, table, has_trans, &cols, table->s->fields,
before_record, after_record);
-
+ }
if (!use_bitbuf)
bitmap_free(&cols);
}
@@ -4890,13 +4971,53 @@ int handler::ha_external_lock(THD *thd, int lock_type)
*/
DBUG_ASSERT(next_insert_id == 0);
+ if (MYSQL_HANDLER_RDLOCK_START_ENABLED() ||
+ MYSQL_HANDLER_WRLOCK_START_ENABLED() ||
+ MYSQL_HANDLER_UNLOCK_START_ENABLED())
+ {
+ if (lock_type == F_RDLCK)
+ {
+ MYSQL_HANDLER_RDLOCK_START(table_share->db.str,
+ table_share->table_name.str);
+ }
+ else if (lock_type == F_WRLCK)
+ {
+ MYSQL_HANDLER_WRLOCK_START(table_share->db.str,
+ table_share->table_name.str);
+ }
+ else if (lock_type == F_UNLCK)
+ {
+ MYSQL_HANDLER_UNLOCK_START(table_share->db.str,
+ table_share->table_name.str);
+ }
+ }
+
/*
We cache the table flags if the locking succeeded. Otherwise, we
keep them as they were when they were fetched in ha_open().
*/
int error= external_lock(thd, lock_type);
+
if (error == 0)
cached_table_flags= table_flags();
+
+ if (MYSQL_HANDLER_RDLOCK_DONE_ENABLED() ||
+ MYSQL_HANDLER_WRLOCK_DONE_ENABLED() ||
+ MYSQL_HANDLER_UNLOCK_DONE_ENABLED())
+ {
+ if (lock_type == F_RDLCK)
+ {
+ MYSQL_HANDLER_RDLOCK_DONE(error);
+ }
+ else if (lock_type == F_WRLCK)
+ {
+ MYSQL_HANDLER_WRLOCK_DONE(error);
+ }
+ else if (lock_type == F_UNLCK)
+ {
+ MYSQL_HANDLER_UNLOCK_DONE(error);
+ }
+ }
DBUG_RETURN(error);
}
@@ -4933,10 +5054,13 @@ int handler::ha_write_row(uchar *buf)
Log_func *log_func= Write_rows_log_event::binlog_row_logging_function;
DBUG_ENTER("handler::ha_write_row");
+ MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_write_count);
- if (unlikely(error= write_row(buf)))
+ error= write_row(buf);
+ MYSQL_INSERT_ROW_DONE(error);
+ if (unlikely(error))
DBUG_RETURN(error);
rows_changed++;
if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
@@ -4956,10 +5080,13 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
*/
DBUG_ASSERT(new_data == table->record[0]);
+ MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_update_count);
- if (unlikely(error= update_row(old_data, new_data)))
+ error= update_row(old_data, new_data);
+ MYSQL_UPDATE_ROW_DONE(error);
+ if (unlikely(error))
return error;
rows_changed++;
if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
@@ -4972,10 +5099,13 @@ int handler::ha_delete_row(const uchar *buf)
int error;
Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function;
+ MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_delete_count);
- if (unlikely(error= delete_row(buf)))
+ error= delete_row(buf);
+ MYSQL_DELETE_ROW_DONE(error);
+ if (unlikely(error))
return error;
rows_changed++;
if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
@@ -5036,7 +5166,8 @@ int example_of_iterator_using_for_logs_cleanup(handlerton *hton)
{
printf("%s\n", data.filename.str);
if (data.status == HA_LOG_STATUS_FREE &&
- my_delete(data.filename.str, MYF(MY_WME)))
+ mysql_file_delete(INSTRUMENT_ME,
+ data.filename.str, MYF(MY_WME)))
goto err;
}
res= 0;
@@ -5064,7 +5195,7 @@ err:
enum log_status fl_get_log_status(char *log)
{
MY_STAT stat_buff;
- if (my_stat(log, &stat_buff, MYF(0)))
+ if (mysql_file_stat(INSTRUMENT_ME, log, &stat_buff, MYF(0)))
return HA_LOG_STATUS_INUSE;
return HA_LOG_STATUS_NOSUCHLOG;
}
@@ -5096,7 +5227,7 @@ int fl_log_iterator_next(struct handler_iterator *iterator,
void fl_log_iterator_destroy(struct handler_iterator *iterator)
{
- my_free((uchar*)iterator->buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(iterator->buffer);
}