Added support of thd->tx_read_only

Moved timestamp handling from all handler::write() methods in the storage engines to handler::ha_write

sql/handler.cc:
  Added PSI_CALL's
This commit is contained in:
Michael Widenius 2012-08-07 07:25:15 +03:00
parent 0a70eb33d1
commit b39e6e3d09
30 changed files with 559 additions and 168 deletions

29
TODO Normal file
View File

@ -0,0 +1,29 @@
State of MERGE between MariaDB 5.5 and MySQL 5.6.5
Featured copied/merged
- storage/innodb/*
- storage/perfschema
- sql/share/errmsg-utf8.txt
- All CF_XXX states in sql_class.h.
- handler error messages.
- Removed timestamp handling from all handler::write and handler::update
methods.
Features recoded
- Better error messages
- Added support of timestamps to ha_write and ha_update.
Fetures half done:
- Support for TRANSACTION READ ONLY | READ WRITE
- CF_XXX states added to init_update_queries() but not otherwise used.
Short time TODO:
- Add support for TRANSACTION READ ONLY | READ WRITE in sql_yacc.yy
(support for variable tx_read_only)
- merge hostname.cc / hostname.h
- add support for host_error()
- Enable performance_schema.host_cache in scripts/mysql_system_tables.sql
- Add full support for timestamp. (remove timestamp handling from ha_write())

View File

@ -276,6 +276,15 @@ enum enum_server_command
*/
#define SERVER_PS_OUT_PARAMS 4096
/**
Set at the same time as SERVER_STATUS_IN_TRANS if the started
multi-statement transaction is a read-only transaction. Cleared
when the transaction commits or aborts. Since this flag is sent
to clients in OK and EOF packets, the flag indicates the
transaction status at the end of command execution.
*/
#define SERVER_STATUS_IN_TRANS_READONLY 8192
/**
Server status flags that must be cleared when starting
execution of a new SQL statement.

View File

@ -12,7 +12,7 @@ INSERT INTO t1 VALUES (1),(2);
COMMIT;
START TRANSACTION;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ERROR 25001: Transaction isolation level can't be changed while a transaction is in progress
ERROR 25001: Transaction characteristics can't be changed while a transaction is in progress
COMMIT;
SET @@autocommit=0;
COMMIT;

View File

@ -28,7 +28,7 @@ COMMIT;
# inside a transaction
#
START TRANSACTION;
--error ER_CANT_CHANGE_TX_ISOLATION
--error ER_CANT_CHANGE_TX_CHARACTERISTICS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
COMMIT;

View File

@ -1455,6 +1455,7 @@ end:
else
{
ulong saved_master_access;
bool save_tx_read_only;
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
@ -1466,9 +1467,12 @@ end:
saved_master_access= thd->security_ctx->master_access;
thd->security_ctx->master_access |= SUPER_ACL;
save_tx_read_only= thd->tx_read_only;
thd->tx_read_only= false;
ret= Events::drop_event(thd, dbname, name, FALSE);
thd->tx_read_only= save_tx_read_only;
thd->security_ctx->master_access= saved_master_access;
}
}

View File

@ -413,6 +413,8 @@ Event_scheduler::start()
for writing when the server is running in the read-only mode.
*/
new_thd->security_ctx->master_access |= SUPER_ACL;
new_thd->variables.tx_read_only= false;
new_thd->tx_read_only= false;
scheduler_param_value=
(struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0));

View File

@ -1055,6 +1055,7 @@ Events::load_events_from_db(THD *thd)
bool ret= TRUE;
uint count= 0;
ulong saved_master_access;
bool save_tx_read_only;
DBUG_ENTER("Events::load_events_from_db");
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
@ -1067,9 +1068,12 @@ Events::load_events_from_db(THD *thd)
saved_master_access= thd->security_ctx->master_access;
thd->security_ctx->master_access |= SUPER_ACL;
save_tx_read_only= thd->tx_read_only;
thd->tx_read_only= false;
ret= db_repository->open_event_table(thd, TL_WRITE, &table);
thd->tx_read_only= save_tx_read_only;
thd->security_ctx->master_access= saved_master_access;
if (ret)

View File

@ -11,8 +11,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/** @file handler.cc
@ -230,7 +230,7 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
return NULL;
}
RUN_HOOK(transaction, after_rollback, (thd, FALSE));
(void) RUN_HOOK(transaction, after_rollback, (thd, FALSE));
switch (database_type) {
case DB_TYPE_MRG_ISAM:
@ -365,6 +365,7 @@ int ha_init_errors(void)
SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT));
SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL));
SETMSG(HA_FTS_INVALID_DOCID, "Invalid InnoDB FTS Doc ID");
/* Register the error messages for use with my_error(). */
return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
@ -994,11 +995,14 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
{
trans= &thd->transaction.all;
thd->server_status|= SERVER_STATUS_IN_TRANS;
if (thd->tx_read_only)
thd->server_status|= SERVER_STATUS_IN_TRANS_READONLY;
DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS"));
}
else
trans= &thd->transaction.stmt;
ha_info= thd->ha_data[ht_arg->slot].ha_info + static_cast<unsigned>(all);
ha_info= thd->ha_data[ht_arg->slot].ha_info + (all ? 1 : 0);
if (ha_info->is_started())
DBUG_VOID_RETURN; /* already registered, return */
@ -1155,6 +1159,9 @@ int ha_commit_trans(THD *thd, bool all)
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)););
DBUG_PRINT("info",
("all: %d thd->in_sub_stmt: %d ha_info: %p is_real_trans: %d",
all, thd->in_sub_stmt, ha_info, is_real_trans));
/*
We must not commit the normal transaction if a statement
transaction is pending. Otherwise statement transaction
@ -1191,7 +1198,9 @@ int ha_commit_trans(THD *thd, bool all)
if (!ha_info)
{
/* Free resources and perform other cleanup even for 'empty' transactions. */
/*
Free resources and perform other cleanup even for 'empty' transactions.
*/
if (is_real_trans)
thd->transaction.cleanup();
DBUG_RETURN(0);
@ -1490,7 +1499,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));
RUN_HOOK(transaction, after_rollback, (thd, FALSE));
(void) RUN_HOOK(transaction, after_rollback, (thd, FALSE));
DBUG_RETURN(error);
}
@ -2147,6 +2156,16 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
ha_delete_table_error_handler.buff);
}
delete file;
#ifdef HAVE_PSI_TABLE_INTERFACE
if (likely(error == 0))
{
my_bool temp_table= (my_bool)is_prefix(alias, tmp_file_prefix);
PSI_CALL(drop_table_share)(temp_table, db, strlen(db),
alias, strlen(alias));
}
#endif
DBUG_RETURN(error);
}
@ -2214,6 +2233,30 @@ THD *handler::ha_thd(void) const
return (table && table->in_use) ? table->in_use : current_thd;
}
void handler::unbind_psi()
{
#ifdef HAVE_PSI_TABLE_INTERFACE
/*
Notify the instrumentation that this table is not owned
by this thread any more.
*/
PSI_CALL(unbind_table)(m_psi);
#endif
}
void handler::rebind_psi()
{
#ifdef HAVE_PSI_TABLE_INTERFACE
/*
Notify the instrumentation that this table is now owned
by this thread.
*/
PSI_table_share *share_psi= ha_table_share_psi(table_share);
m_psi= PSI_CALL(rebind_table)(share_psi, this, m_psi);
#endif
}
PSI_table_share *handler::ha_table_share_psi(const TABLE_SHARE *share) const
{
return share->m_psi;
@ -2256,6 +2299,13 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
}
else
{
DBUG_ASSERT(m_psi == NULL);
DBUG_ASSERT(table_share != NULL);
#ifdef HAVE_PSI_TABLE_INTERFACE
PSI_table_share *share_psi= ha_table_share_psi(table_share);
m_psi= PSI_CALL(open_table)(share_psi, this);
#endif
if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
table->db_stat|=HA_READ_ONLY;
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
@ -2264,7 +2314,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
if (!ref && !(ref= (uchar*) alloc_root(&table->mem_root,
ALIGN_SIZE(ref_length)*2)))
{
close();
ha_close();
error=HA_ERR_OUT_OF_MEM;
}
else
@ -2276,7 +2326,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
DBUG_RETURN(error);
}
int handler::ha_close()
int handler::ha_close(void)
{
DBUG_ENTER("ha_close");
/*
@ -2285,6 +2335,11 @@ int handler::ha_close()
*/
if (table->in_use)
status_var_add(table->in_use->status_var.rows_tmp_read, rows_tmp_read);
#ifdef HAVE_PSI_TABLE_INTERFACE
PSI_CALL(close_table)(m_psi);
m_psi= NULL; /* instrumentation handle, invalid after close_table() */
#endif
DBUG_RETURN(close());
}
@ -2718,7 +2773,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
ha_index_init(table->s->next_number_index, 1);
if (table->s->next_number_keypart == 0)
{ // Autoincrement at key-start
error=ha_index_last(table->record[1]);
error= ha_index_last(table->record[1]);
/*
MySQL implicitely assumes such method does locking (as MySQL decides to
use nr+increment without checking again with the handler, in
@ -3978,10 +4033,19 @@ int ha_create_table(THD *thd, const char *path,
const char *name;
TABLE_SHARE share;
DBUG_ENTER("ha_create_table");
#ifdef HAVE_PSI_TABLE_INTERFACE
my_bool temp_table= (my_bool)is_prefix(table_name, tmp_file_prefix) ||
(create_info->options & HA_LEX_CREATE_TMP_TABLE ? TRUE : FALSE);
#endif
init_tmp_table_share(thd, &share, db, 0, table_name, path);
if (open_table_def(thd, &share, 0) ||
open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table,
if (open_table_def(thd, &share, 0))
goto err;
#ifdef HAVE_PSI_TABLE_INTERFACE
share.m_psi= PSI_CALL(get_table_share)(temp_table, &share);
#endif
if (open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table,
TRUE))
goto err;
@ -3996,6 +4060,10 @@ int ha_create_table(THD *thd, const char *path,
{
strxmov(name_buff, db, ".", table_name, NullS);
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
#ifdef HAVE_PSI_TABLE_INTERFACE
PSI_CALL(drop_table_share)(temp_table, db, strlen(db), table_name,
strlen(table_name));
#endif
}
err:
free_table_share(&share);
@ -4051,6 +4119,15 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
{
DBUG_RETURN(3);
}
#ifdef HAVE_PSI_TABLE_INTERFACE
/*
Table discovery is not instrumented.
Once discovered, the table will be opened normally,
and instrumented normally.
*/
#endif
if (open_table_from_share(thd, &share, "" ,0, 0, 0, &table, FALSE))
{
free_table_share(&share);
@ -4973,6 +5050,7 @@ static int binlog_log_row(TABLE* table,
int handler::ha_external_lock(THD *thd, int lock_type)
{
int error;
DBUG_ENTER("handler::ha_external_lock");
/*
Whether this is lock or unlock, this should be true, and is to verify that
@ -5002,11 +5080,14 @@ int handler::ha_external_lock(THD *thd, int lock_type)
}
}
ha_statistic_increment(&SSV::ha_external_lock_count);
/*
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);
MYSQL_TABLE_LOCK_WAIT(m_psi, PSI_TABLE_EXTERNAL_LOCK, lock_type,
{ error= external_lock(thd, lock_type); })
if (error == 0)
cached_table_flags= table_flags();
@ -5064,11 +5145,17 @@ 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");
/* If we have a timestamp column, update it to the current time */
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_write_count);
error= write_row(buf);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
{ error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
if (unlikely(error))
DBUG_RETURN(error);
@ -5090,11 +5177,16 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
*/
DBUG_ASSERT(new_data == table->record[0]);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_update_count);
error= update_row(old_data, new_data);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
{ error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error);
if (unlikely(error))
return error;
@ -5113,7 +5205,8 @@ int handler::ha_delete_row(const uchar *buf)
mark_trx_read_write();
increment_statistics(&SSV::ha_delete_count);
error= delete_row(buf);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_DELETE_ROW, active_index, 0,
{ error= delete_row(buf);})
MYSQL_DELETE_ROW_DONE(error);
if (unlikely(error))
return error;

View File

@ -326,8 +326,24 @@
#define HA_CACHE_TBL_ASKTRANSACT 2
#define HA_CACHE_TBL_TRANSACT 4
/* Options of START TRANSACTION statement (and later of SET TRANSACTION stmt) */
#define MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT 1
/**
Options for the START TRANSACTION statement.
Note that READ ONLY and READ WRITE are logically mutually exclusive.
This is enforced by the parser and depended upon by trans_begin().
We need two flags instead of one in order to differentiate between
situation when no READ WRITE/ONLY clause were given and thus transaction
is implicitly READ WRITE and the case when READ WRITE clause was used
explicitly.
*/
// WITH CONSISTENT SNAPSHOT option
static const uint MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT = 1;
// READ ONLY option
static const uint MYSQL_START_TRANS_OPT_READ_ONLY = 2;
// READ WRITE option
static const uint MYSQL_START_TRANS_OPT_READ_WRITE = 4;
/* Flags for method is_fatal_error */
#define HA_CHECK_DUP_KEY 1
@ -1840,6 +1856,9 @@ public:
*/
PSI_table *m_psi;
virtual void unbind_psi();
virtual void rebind_psi();
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
:table_share(share_arg), table(0),
estimation_rows_to_insert(0), ht(ht_arg),

View File

@ -6453,6 +6453,12 @@ struct my_option my_long_options[]=
&global_system_variables.tx_isolation,
&global_system_variables.tx_isolation, &tx_isolation_typelib,
GET_ENUM, REQUIRED_ARG, ISO_REPEATABLE_READ, 0, 0, 0, 0, 0},
{"transaction-read-only", 0,
"Default transaction access mode. "
"True if transactions are read-only.",
&global_system_variables.tx_read_only,
&global_system_variables.tx_read_only, 0,
GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Used with --help option for detailed help.",
@ -6946,7 +6952,7 @@ SHOW_VAR status_vars[]= {
{"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS},
{"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS},
{"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS},
{"Handler_external_lock", (char*) offsetof(STATUS_VAR, ha_external_lock_count), SHOW_LONGLONG_STATUS},
{"Handler_icp_attempts", (char*) offsetof(STATUS_VAR, ha_icp_attempts), SHOW_LONG_STATUS},
{"Handler_icp_match", (char*) offsetof(STATUS_VAR, ha_icp_match), SHOW_LONG_STATUS},

View File

@ -5981,9 +5981,8 @@ ER_WRONG_PARTITION_NAME
eng "Incorrect partition name"
ger "Falscher Partitionsname"
swe "Felaktigt partitionsnamn"
ER_CANT_CHANGE_TX_ISOLATION 25001
eng "Transaction isolation level can't be changed while a transaction is in progress"
ger "Transaktionsisolationsebene kann während einer laufenden Transaktion nicht geändert werden"
ER_CANT_CHANGE_TX_CHARACTERISTICS 25001
eng "Transaction characteristics can't be changed while a transaction is in progress"
ER_DUP_ENTRY_AUTOINCREMENT_CASE
eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.192s' for key '%-.192s'"
ger "ALTER TABLE führt zur Neusequenzierung von auto_increment, wodurch der doppelte Eintrag '%-.192s' für Schlüssel '%-.192s' auftritt"

View File

@ -2907,6 +2907,16 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
{
/*
Check if we're trying to take a write lock in a read only transaction.
*/
if (table_list->mdl_request.type >= MDL_SHARED_WRITE &&
thd->tx_read_only)
{
my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0));
DBUG_RETURN(true);
}
/*
We are not under LOCK TABLES and going to acquire write-lock/
modify the base table. We need to acquire protection against
@ -4706,6 +4716,15 @@ lock_table_names(THD *thd,
! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
find_temporary_table(thd, table))))
{
/*
Write lock on normal tables is not allowed in a read only transaction.
*/
if (thd->tx_read_only)
{
my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0));
return true;
}
if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
schema_set.insert(table))
DBUG_RETURN(TRUE);

View File

@ -592,6 +592,12 @@ int thd_tx_isolation(const THD *thd)
return (int) thd->tx_isolation;
}
extern "C"
int thd_tx_is_read_only(const THD *thd)
{
return (int) thd->tx_read_only;
}
extern "C"
void thd_inc_row_count(THD *thd)
{
@ -1178,6 +1184,7 @@ void THD::init(void)
TL_WRITE_LOW_PRIORITY :
TL_WRITE);
tx_isolation= (enum_tx_isolation) variables.tx_isolation;
tx_read_only= variables.tx_read_only;
update_charset();
reset_current_stmt_binlog_format_row();
bzero((char *) &status_var, sizeof(status_var));

View File

@ -43,7 +43,7 @@
#include "violite.h" /* vio_is_connected */
#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA,
THR_LOCK_INFO */
#include <mysql/psi/mysql_table.h>
class Reprepare_observer;
class Relay_log_info;
@ -537,6 +537,10 @@ typedef struct system_variables
*/
my_thread_id pseudo_thread_id;
/**
Default transaction access mode. READ ONLY (true) or READ WRITE (false).
*/
my_bool tx_read_only;
my_bool low_priority_updates;
my_bool query_cache_wlock_invalidate;
my_bool engine_condition_pushdown;
@ -619,6 +623,7 @@ typedef struct system_status_var
ulong ha_discover_count;
ulong ha_savepoint_count;
ulong ha_savepoint_rollback_count;
ulong ha_external_lock_count;
#if 0
/* KEY_CACHE parts. These are copies of the original */
@ -2175,6 +2180,11 @@ public:
above.
*/
enum_tx_isolation tx_isolation;
/*
Current or next transaction access mode.
See comment above regarding tx_isolation.
*/
bool tx_read_only;
enum_check_fields count_cuted_fields;
DYNAMIC_ARRAY user_var_events; /* For user variables replication */
@ -4083,6 +4093,32 @@ public:
*/
#define CF_CAN_GENERATE_ROW_EVENTS (1U << 9)
/**
Identifies statements which may deal with temporary tables and for which
temporary tables should be pre-opened to simplify privilege checks.
*/
#define CF_PREOPEN_TMP_TABLES (1U << 10)
/**
Identifies statements for which open handlers should be closed in the
beginning of the statement.
*/
#define CF_HA_CLOSE (1U << 11)
/**
Identifies statements that can be explained with EXPLAIN.
*/
#define CF_CAN_BE_EXPLAINED (1U << 12)
/** Identifies statements which may generate an optimizer trace */
#define CF_OPTIMIZER_TRACE (1U << 14)
/**
Identifies statements that should always be disallowed in
read only transactions.
*/
#define CF_DISALLOW_IN_RO_TRANS (1U << 15)
/* Bits in server_command_flags */
/**
@ -4144,14 +4180,15 @@ inline int handler::ha_index_read_map(uchar * buf, const uchar * key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
int error;
DBUG_ASSERT(inited==INDEX);
MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_read_key_count);
int error= index_read_map(buf, key, keypart_map, find_flag);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ error= index_read_map(buf, key, keypart_map,
find_flag); })
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_INDEX_READ_ROW_DONE(error);
return error;
}
@ -4167,83 +4204,84 @@ inline int handler::ha_index_read_idx_map(uchar * buf, uint index,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
int error;
DBUG_ASSERT(inited==NONE);
MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_read_key_count);
int error= index_read_idx_map(buf, index, key, keypart_map, find_flag);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, index, 0,
{ error= index_read_idx_map(buf, index, key, keypart_map,
find_flag); })
if (!error)
{
update_rows_read();
index_rows_read[index]++;
}
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_INDEX_READ_ROW_DONE(error);
return error;
}
inline int handler::ha_index_next(uchar * buf)
{
int error;
DBUG_ASSERT(inited==INDEX);
MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_read_next_count);
int error= index_next(buf);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ error= index_next(buf); })
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_INDEX_READ_ROW_DONE(error);
return error;
}
inline int handler::ha_index_prev(uchar * buf)
{
int error;
DBUG_ASSERT(inited==INDEX);
MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_read_prev_count);
int error= index_prev(buf);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ error= index_prev(buf); })
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_INDEX_READ_ROW_DONE(error);
return error;
}
inline int handler::ha_index_first(uchar * buf)
{
int error;
DBUG_ASSERT(inited==INDEX);
MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_read_first_count);
int error= index_first(buf);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ error= index_first(buf); })
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_INDEX_READ_ROW_DONE(error);
return error;
}
inline int handler::ha_index_last(uchar * buf)
{
int error;
DBUG_ASSERT(inited==INDEX);
MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_read_last_count);
int error= index_last(buf);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ error= index_last(buf); })
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_INDEX_READ_ROW_DONE(error);
return error;
}
inline int handler::ha_index_next_same(uchar *buf, const uchar *key,
uint keylen)
{
int error;
DBUG_ASSERT(inited==INDEX);
MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_read_next_count);
int error= index_next_same(buf, key, keylen);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ error= index_next_same(buf, key, keylen); })
if (!error)
update_index_statistics();
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_INDEX_READ_ROW_DONE(error);
return error;
}
@ -4259,8 +4297,9 @@ inline int handler::ha_ft_read(uchar *buf)
inline int handler::ha_rnd_next(uchar *buf)
{
MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, TRUE);
int error= rnd_next(buf);
int error;
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
{ error= rnd_next(buf); })
if (!error)
{
update_rows_read();
@ -4272,19 +4311,18 @@ inline int handler::ha_rnd_next(uchar *buf)
increment_statistics(&SSV::ha_read_rnd_next_count);
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_READ_ROW_DONE(error);
return error;
}
inline int handler::ha_rnd_pos(uchar *buf, uchar *pos)
{
MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, FALSE);
int error;
increment_statistics(&SSV::ha_read_rnd_count);
int error= rnd_pos(buf, pos);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
{ error= rnd_pos(buf, pos); })
if (!error)
update_rows_read();
table->status=error ? STATUS_NOT_FOUND: 0;
MYSQL_READ_ROW_DONE(error);
return error;
}
@ -4308,18 +4346,22 @@ inline int handler::ha_read_first_row(uchar *buf, uint primary_key)
inline int handler::ha_write_tmp_row(uchar *buf)
{
int error;
MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_tmp_write_count);
int error= write_row(buf);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
{ error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
return error;
}
inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data)
{
int error;
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_tmp_update_count);
int error= update_row(old_data, new_data);
MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
{ error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error);
return error;
}

View File

@ -553,6 +553,13 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
DBUG_ENTER("open_and_lock_for_insert_delayed");
#ifndef EMBEDDED_LIBRARY
/* INSERT DELAYED is not allowed in a read only transaction. */
if (thd->tx_read_only)
{
my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0));
DBUG_RETURN(true);
}
/*
In order for the deadlock detector to be able to find any deadlocks
caused by the handler thread waiting for GRL or this table, we acquire

View File

@ -291,26 +291,54 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;;
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;;
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED;
// (1) so that subquery is traced when doing "SET @var = (subquery)"
/*
@todo SQLCOM_SET_OPTION should have CF_CAN_GENERATE_ROW_EVENTS
set, because it may invoke a stored function that generates row
events. /Sven
*/
sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE |
CF_AUTO_COMMIT_TRANS |
CF_OPTIMIZER_TRACE; // (1)
// (1) so that subquery is traced when doing "DO @var := (subquery)"
sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE; // (1)
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
@ -351,6 +379,11 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
/*
@todo SQLCOM_BINLOG_BASE64_EVENT should have
CF_CAN_GENERATE_ROW_EVENTS set, because this surely generates row
events. /Sven
*/
sql_command_flags[SQLCOM_BINLOG_BASE64_EVENT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CLIENT_STATS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_USER_STATS]= CF_STATUS_COMMAND;
@ -366,6 +399,12 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_REVOKE]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_OPTIMIZE]= CF_CHANGES_DATA;
/*
@todo SQLCOM_CREATE_FUNCTION should have CF_AUTO_COMMIT_TRANS
set. this currently is binlogged *before* the transaction if
executed inside a transaction because it does not have an implicit
pre-commit and is written to the statement cache. /Sven
*/
sql_command_flags[SQLCOM_CREATE_FUNCTION]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CREATE_SPFUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
@ -382,8 +421,13 @@ void init_update_queries(void)
last called (or executed) statement is preserved.
See mysql_execute_command() for how CF_ROW_COUNT is used.
*/
/*
(1): without it, in "CALL some_proc((subq))", subquery would not be
traced.
*/
sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE; // (1)
sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS;
/*
@ -411,6 +455,104 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS;
/*
The following statements can deal with temporary tables,
so temporary tables should be pre-opened for those statements to
simplify privilege checking.
There are other statements that deal with temporary tables and open
them, but which are not listed here. The thing is that the order of
pre-opening temporary tables for those statements is somewhat custom.
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_LOAD]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DROP_INDEX]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_UPDATE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_UPDATE_MULTI]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CHECK]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_OPTIMIZE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_REPAIR]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_PREOPEN_TMP_TABLES;
/*
DDL statements that should start with closing opened handlers.
We use this flag only for statements for which open HANDLERs
have to be closed before emporary tables are pre-opened.
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_OPTIMIZE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_ANALYZE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_CHECK]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_DROP_INDEX]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_HA_CLOSE;
/*
Mark statements that always are disallowed in read-only
transactions. Note that according to the SQL standard,
even temporary table DDL should be disallowed.
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_DB]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_DB]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_DB]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_VIEW]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_TRIGGER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_TRIGGER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_EVENT]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_EVENT]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_EVENT]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_USER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_RENAME_USER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_USER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_SERVER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_SERVER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_SERVER]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_SPFUNCTION]|=CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_TRUNCATE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_TABLESPACE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_REPAIR]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_OPTIMIZE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_GRANT]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_REVOKE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_REVOKE_ALL]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_INSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS;
}
bool sqlcom_can_generate_row_events(const THD *thd)
@ -2115,6 +2257,19 @@ mysql_execute_command(THD *thd)
DEBUG_SYNC(thd,"before_execute_sql_command");
#endif
/*
Check if we are in a read-only transaction and we're trying to
execute a statement which should always be disallowed in such cases.
Note that this check is done after any implicit commits.
*/
if (thd->tx_read_only &&
(sql_command_flags[lex->sql_command] & CF_DISALLOW_IN_RO_TRANS))
{
my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0));
goto error;
}
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@ -3766,12 +3921,13 @@ end_with_restore_list:
if (tx_chain)
{
if (trans_begin(thd))
goto error;
goto error;
}
else
{
/* Reset the isolation level if no chaining transaction. */
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
thd->tx_read_only= thd->variables.tx_read_only;
}
/* Disconnect the current client connection. */
if (tx_release)
@ -4325,6 +4481,7 @@ create_sp_error:
isolation level to the session default.
*/
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
thd->tx_read_only= thd->variables.tx_read_only;
my_ok(thd);
break;
case SQLCOM_XA_ROLLBACK:
@ -4336,6 +4493,7 @@ create_sp_error:
isolation level to the session default.
*/
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
thd->tx_read_only= thd->variables.tx_read_only;
my_ok(thd);
break;
case SQLCOM_XA_RECOVER:

View File

@ -2366,7 +2366,7 @@ static bool check_tx_isolation(sys_var *self, THD *thd, set_var *var)
if (var->type == OPT_DEFAULT && thd->in_active_multi_stmt_transaction())
{
DBUG_ASSERT(thd->in_multi_stmt_transaction_mode());
my_error(ER_CANT_CHANGE_TX_ISOLATION, MYF(0));
my_error(ER_CANT_CHANGE_TX_CHARACTERISTICS, MYF(0));
return TRUE;
}
return FALSE;
@ -2379,6 +2379,42 @@ static Sys_var_tx_isolation Sys_tx_isolation(
tx_isolation_names, DEFAULT(ISO_REPEATABLE_READ),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_tx_isolation));
/**
Can't change the tx_read_only state if we are already in a
transaction.
*/
static bool check_tx_read_only(sys_var *self, THD *thd, set_var *var)
{
if (var->type == OPT_DEFAULT && thd->in_active_multi_stmt_transaction())
{
DBUG_ASSERT(thd->in_multi_stmt_transaction_mode());
my_error(ER_CANT_CHANGE_TX_CHARACTERISTICS, MYF(0));
return true;
}
return false;
}
bool Sys_var_tx_read_only::session_update(THD *thd, set_var *var)
{
if (var->type == OPT_SESSION && Sys_var_mybool::session_update(thd, var))
return true;
if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction())
{
// @see Sys_var_tx_isolation::session_update() above for the rules.
thd->tx_read_only= var->save_result.ulonglong_value;
}
return false;
}
static Sys_var_tx_read_only Sys_tx_read_only(
"tx_read_only", "Set default transaction access mode to read only.",
SESSION_VAR(tx_read_only), NO_CMD_LINE, DEFAULT(0),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_tx_read_only));
static Sys_var_ulonglong Sys_tmp_table_size(
"tmp_table_size",
"If an internal in-memory temporary table exceeds this size, MySQL "

View File

@ -1840,6 +1840,30 @@ public:
}
};
/**
Class representing the tx_read_only system variable for setting
default transaction access mode.
Note that there is a special syntax - SET TRANSACTION READ ONLY
(or READ WRITE) that sets the access mode for the next transaction
only.
*/
class Sys_var_tx_read_only: public Sys_var_mybool
{
public:
Sys_var_tx_read_only(const char *name_arg, const char *comment, int flag_args,
ptrdiff_t off, size_t size, CMD_LINE getopt,
my_bool def_val, PolyLock *lock,
enum binlog_status_enum binlog_status_arg,
on_check_function on_check_func)
:Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt,
def_val, lock, binlog_status_arg, on_check_func)
{}
virtual bool session_update(THD *thd, set_var *var);
};
/*
Class for replicate_events_marked_for_skip.
We need a custom update function that ensures the slave is stopped when

View File

@ -22,6 +22,7 @@
#include "transaction.h"
#include "rpl_handler.h"
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_acl.h"
/* Conditions under which the transaction state must not change. */
static bool trans_check(THD *thd)
@ -150,9 +151,35 @@ bool trans_begin(THD *thd, uint flags)
*/
thd->mdl_context.release_transactional_locks();
// The RO/RW options are mutually exclusive.
DBUG_ASSERT(!((flags & MYSQL_START_TRANS_OPT_READ_ONLY) &&
(flags & MYSQL_START_TRANS_OPT_READ_WRITE)));
if (flags & MYSQL_START_TRANS_OPT_READ_ONLY)
thd->tx_read_only= true;
else if (flags & MYSQL_START_TRANS_OPT_READ_WRITE)
{
/*
Explicitly starting a RW transaction when the server is in
read-only mode, is not allowed unless the user has SUPER priv.
Implicitly starting a RW transaction is allowed for backward
compatibility.
*/
const bool user_is_super=
test(thd->security_ctx->master_access & SUPER_ACL);
if (opt_readonly && !user_is_super)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
DBUG_RETURN(true);
}
thd->tx_read_only= false;
}
thd->variables.option_bits|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
if (thd->tx_read_only)
thd->server_status|= SERVER_STATUS_IN_TRANS_READONLY;
/* ha_start_consistent_snapshot() relies on OPTION_BEGIN flag set. */
if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
res= ha_start_consistent_snapshot(thd);
@ -234,6 +261,7 @@ bool trans_commit_implicit(THD *thd)
to not have any effect on implicit commit.
*/
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
thd->tx_read_only= thd->variables.tx_read_only;
DBUG_RETURN(res);
}
@ -298,7 +326,10 @@ bool trans_commit_stmt(THD *thd)
{
res= ha_commit_trans(thd, FALSE);
if (! thd->in_active_multi_stmt_transaction())
{
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
thd->tx_read_only= thd->variables.tx_read_only;
}
}
if (res)
@ -342,7 +373,10 @@ bool trans_rollback_stmt(THD *thd)
if (thd->transaction_rollback_request && !thd->in_sub_stmt)
ha_rollback_trans(thd, TRUE);
if (! thd->in_active_multi_stmt_transaction())
{
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
thd->tx_read_only= thd->variables.tx_read_only;
}
}
RUN_HOOK(transaction, after_rollback, (thd, FALSE));

View File

@ -889,9 +889,6 @@ int ha_archive::write_row(uchar *buf)
if (share->crashed)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
ha_statistic_increment(&SSV::ha_write_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
mysql_mutex_lock(&share->mutex);
if (!share->archive_write_open)
@ -1315,7 +1312,6 @@ int ha_archive::rnd_next(uchar *buf)
}
scan_rows--;
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
current_position= aztell(&archive);
rc= get_row(&archive, buf);
@ -1351,7 +1347,6 @@ int ha_archive::rnd_pos(uchar * buf, uchar *pos)
{
int rc;
DBUG_ENTER("ha_archive::rnd_pos");
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
current_position= (my_off_t)my_get_ptr(pos, ref_length);
if (azseek(&archive, current_position, SEEK_SET) == (my_off_t)(-1L))
{

View File

@ -997,11 +997,6 @@ int ha_tina::write_row(uchar * buf)
if (share->crashed)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
ha_statistic_increment(&SSV::ha_write_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
size= encode_quote(buf);
if (!share->tina_write_opened)
@ -1062,11 +1057,6 @@ int ha_tina::update_row(const uchar * old_data, uchar * new_data)
int rc= -1;
DBUG_ENTER("ha_tina::update_row");
ha_statistic_increment(&SSV::ha_update_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
size= encode_quote(new_data);
/*
@ -1109,7 +1099,6 @@ err:
int ha_tina::delete_row(const uchar * buf)
{
DBUG_ENTER("ha_tina::delete_row");
ha_statistic_increment(&SSV::ha_delete_count);
if (chain_append())
DBUG_RETURN(-1);
@ -1231,8 +1220,6 @@ int ha_tina::rnd_next(uchar *buf)
goto end;
}
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
current_position= next_position;
/* don't scan an empty file */
@ -1281,7 +1268,6 @@ int ha_tina::rnd_pos(uchar * buf, uchar *pos)
DBUG_ENTER("ha_tina::rnd_pos");
MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
FALSE);
ha_statistic_increment(&SSV::ha_read_rnd_count);
current_position= my_get_ptr(pos,ref_length);
rc= find_current_row(buf);
MYSQL_READ_ROW_DONE(rc);

View File

@ -495,8 +495,6 @@ int ha_example::write_row(uchar *buf)
Currently new_data will not have an updated auto_increament record, or
and updated timestamp field. You can do these for example by doing:
@code
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
if (table->next_number_field && record == table->record[0])
update_auto_increment();
@endcode

View File

@ -1848,9 +1848,6 @@ int ha_federated::write_row(uchar *buf)
values_string.length(0);
insert_field_value_string.length(0);
ha_statistic_increment(&SSV::ha_write_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
/*
start both our field and field values strings
@ -2434,7 +2431,6 @@ int ha_federated::index_read_idx_with_result_set(uchar *buf, uint index,
*result= 0; // In case of errors
index_string.length(0);
sql_query.length(0);
ha_statistic_increment(&SSV::ha_read_key_count);
sql_query.append(share->select_query);
@ -2562,7 +2558,6 @@ int ha_federated::index_next(uchar *buf)
{
int retval;
DBUG_ENTER("ha_federated::index_next");
ha_statistic_increment(&SSV::ha_read_next_count);
retval= read_next(buf, stored_result);
DBUG_RETURN(retval);
}
@ -2772,8 +2767,6 @@ int ha_federated::rnd_pos(uchar *buf, uchar *pos)
int ret_val;
DBUG_ENTER("ha_federated::rnd_pos");
ha_statistic_increment(&SSV::ha_read_rnd_count);
/* Get stored result set. */
memcpy(&result, pos, sizeof(MYSQL_RES *));
DBUG_ASSERT(result);

View File

@ -1993,8 +1993,6 @@ int ha_federatedx::write_row(uchar *buf)
values_string.length(0);
insert_field_value_string.length(0);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
/*
start both our field and field values strings

View File

@ -241,8 +241,6 @@ void ha_heap::update_key_stats()
int ha_heap::write_row(uchar * buf)
{
int res;
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0])
{
if ((res= update_auto_increment()))
@ -264,8 +262,6 @@ int ha_heap::write_row(uchar * buf)
int ha_heap::update_row(const uchar * old_data, uchar * new_data)
{
int res;
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
res= heap_update(file,old_data,new_data);
if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
file->s->records)

View File

@ -6107,8 +6107,6 @@ ha_innobase::write_row(
++trx->will_lock;
}
ha_statistic_increment(&SSV::ha_write_count);
sql_command = thd_sql_command(user_thd);
if ((sql_command == SQLCOM_ALTER_TABLE
@ -6648,8 +6646,6 @@ ha_innobase::update_row(
}
}
ha_statistic_increment(&SSV::ha_update_count);
if (prebuilt->upd_node) {
uvect = prebuilt->upd_node->update;
} else {
@ -6760,8 +6756,6 @@ ha_innobase::delete_row(
++trx->will_lock;
}
ha_statistic_increment(&SSV::ha_delete_count);
if (!prebuilt->upd_node) {
row_get_prebuilt_update_vector(prebuilt);
}
@ -7023,8 +7017,6 @@ ha_innobase::index_read(
ut_a(prebuilt->trx == thd_to_trx(user_thd));
ha_statistic_increment(&SSV::ha_read_key_count);
index = prebuilt->index;
if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) {
@ -7367,8 +7359,6 @@ ha_innobase::index_next(
uchar* buf) /*!< in/out: buffer for next row in MySQL
format */
{
ha_statistic_increment(&SSV::ha_read_next_count);
return(general_fetch(buf, ROW_SEL_NEXT, 0));
}
@ -7383,8 +7373,6 @@ ha_innobase::index_next_same(
const uchar* key, /*!< in: key value */
uint keylen) /*!< in: key value length */
{
ha_statistic_increment(&SSV::ha_read_next_count);
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
}
@ -7398,8 +7386,6 @@ ha_innobase::index_prev(
/*====================*/
uchar* buf) /*!< in/out: buffer for previous row in MySQL format */
{
ha_statistic_increment(&SSV::ha_read_prev_count);
return(general_fetch(buf, ROW_SEL_PREV, 0));
}
@ -7416,7 +7402,6 @@ ha_innobase::index_first(
int error;
DBUG_ENTER("index_first");
ha_statistic_increment(&SSV::ha_read_first_count);
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
@ -7442,7 +7427,6 @@ ha_innobase::index_last(
int error;
DBUG_ENTER("index_last");
ha_statistic_increment(&SSV::ha_read_last_count);
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
@ -7512,7 +7496,6 @@ ha_innobase::rnd_next(
int error;
DBUG_ENTER("rnd_next");
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
if (start_of_scan) {
error = index_first(buf);
@ -7546,8 +7529,6 @@ ha_innobase::rnd_pos(
DBUG_ENTER("rnd_pos");
DBUG_DUMP("key", pos, ref_length);
ha_statistic_increment(&SSV::ha_read_rnd_count);
ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
/* Note that we assume the length of the row reference is fixed

View File

@ -1226,10 +1226,6 @@ int ha_maria::close(void)
int ha_maria::write_row(uchar * buf)
{
/* If we have a timestamp column, update it to the current time */
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
/*
If we have an auto_increment column and we are writing a changed row
or a new row, then update the auto_increment value in the record.
@ -2223,8 +2219,6 @@ bool ha_maria::is_crashed() const
int ha_maria::update_row(const uchar * old_data, uchar * new_data)
{
CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("UPDATE in WRITE CONCURRENT");
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return maria_update(file, old_data, new_data);
}

View File

@ -810,10 +810,6 @@ int ha_myisam::close(void)
int ha_myisam::write_row(uchar *buf)
{
/* If we have a timestamp column, update it to the current time */
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
/*
If we have an auto_increment column and we are writing a changed row
or a new row, then update the auto_increment value in the record.
@ -1634,8 +1630,6 @@ bool ha_myisam::is_crashed() const
int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
{
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return mi_update(file,old_data,new_data);
}

View File

@ -1073,13 +1073,10 @@ int ha_myisammrg::write_row(uchar * buf)
{
DBUG_ENTER("ha_myisammrg::write_row");
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_write_count);
if (file->merge_insert_method == MERGE_INSERT_DISABLED || !file->tables)
DBUG_RETURN(HA_ERR_TABLE_READONLY);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0])
{
int error;
@ -1092,16 +1089,12 @@ int ha_myisammrg::write_row(uchar * buf)
int ha_myisammrg::update_row(const uchar * old_data, uchar * new_data)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_update_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return myrg_update(file,old_data,new_data);
}
int ha_myisammrg::delete_row(const uchar * buf)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_delete_count);
return myrg_delete(file,buf);
}
@ -1110,7 +1103,6 @@ int ha_myisammrg::index_read_map(uchar * buf, const uchar * key,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_key_count);
int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@ -1121,7 +1113,6 @@ int ha_myisammrg::index_read_idx_map(uchar * buf, uint index, const uchar * key,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_key_count);
int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@ -1131,7 +1122,6 @@ int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key,
key_part_map keypart_map)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_key_count);
int error=myrg_rkey(file,buf,active_index, key, keypart_map,
HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
@ -1141,7 +1131,6 @@ int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key,
int ha_myisammrg::index_next(uchar * buf)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_next_count);
int error=myrg_rnext(file,buf,active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@ -1150,7 +1139,6 @@ int ha_myisammrg::index_next(uchar * buf)
int ha_myisammrg::index_prev(uchar * buf)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_prev_count);
int error=myrg_rprev(file,buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@ -1159,7 +1147,6 @@ int ha_myisammrg::index_prev(uchar * buf)
int ha_myisammrg::index_first(uchar * buf)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_first_count);
int error=myrg_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@ -1168,7 +1155,6 @@ int ha_myisammrg::index_first(uchar * buf)
int ha_myisammrg::index_last(uchar * buf)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_last_count);
int error=myrg_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@ -1180,7 +1166,6 @@ int ha_myisammrg::index_next_same(uchar * buf,
{
int error;
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_next_count);
do
{
error= myrg_rnext_same(file,buf);
@ -1200,7 +1185,6 @@ int ha_myisammrg::rnd_init(bool scan)
int ha_myisammrg::rnd_next(uchar *buf)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@ -1210,7 +1194,6 @@ int ha_myisammrg::rnd_next(uchar *buf)
int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos)
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_read_rnd_count);
int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return error;

View File

@ -5856,8 +5856,6 @@ ha_innobase::write_row(
ut_error;
}
ha_statistic_increment(&SSV::ha_write_count);
if (share->ib_table->is_corrupt) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -6279,8 +6277,6 @@ ha_innobase::update_row(
}
}
ha_statistic_increment(&SSV::ha_update_count);
if (share->ib_table->is_corrupt) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -6395,8 +6391,6 @@ ha_innobase::delete_row(
ut_a(prebuilt->trx == trx);
ha_statistic_increment(&SSV::ha_delete_count);
if (share->ib_table->is_corrupt) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -6671,8 +6665,6 @@ ha_innobase::index_read(
ut_a(prebuilt->trx == thd_to_trx(user_thd));
ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT);
ha_statistic_increment(&SSV::ha_read_key_count);
if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -7036,8 +7028,6 @@ ha_innobase::index_next(
uchar* buf) /*!< in/out: buffer for next row in MySQL
format */
{
ha_statistic_increment(&SSV::ha_read_next_count);
return(general_fetch(buf, ROW_SEL_NEXT, 0));
}
@ -7052,8 +7042,6 @@ ha_innobase::index_next_same(
const uchar* key, /*!< in: key value */
uint keylen) /*!< in: key value length */
{
ha_statistic_increment(&SSV::ha_read_next_count);
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
}
@ -7067,8 +7055,6 @@ ha_innobase::index_prev(
/*====================*/
uchar* buf) /*!< in/out: buffer for previous row in MySQL format */
{
ha_statistic_increment(&SSV::ha_read_prev_count);
return(general_fetch(buf, ROW_SEL_PREV, 0));
}
@ -7085,7 +7071,6 @@ ha_innobase::index_first(
int error;
DBUG_ENTER("index_first");
ha_statistic_increment(&SSV::ha_read_first_count);
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
@ -7111,7 +7096,6 @@ ha_innobase::index_last(
int error;
DBUG_ENTER("index_last");
ha_statistic_increment(&SSV::ha_read_last_count);
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
@ -7181,7 +7165,6 @@ ha_innobase::rnd_next(
int error;
DBUG_ENTER("rnd_next");
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
if (start_of_scan) {
error = index_first(buf);
@ -7216,8 +7199,6 @@ ha_innobase::rnd_pos(
DBUG_ENTER("rnd_pos");
DBUG_DUMP("key", pos, ref_length);
ha_statistic_increment(&SSV::ha_read_rnd_count);
ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
if (prebuilt->clust_index_was_generated) {