|
|
|
@ -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; |
|
|
|
|