summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2019-11-05 16:15:20 +0100
committerMarko Mäkelä <marko.makela@mariadb.com>2019-11-07 08:52:30 +0100
commit3ad37ed0eb343cd173b103974aded5783958a88e (patch)
treef4ff854553d26a9e7d57791e7d671d4349a58d2d /sql
parent46f2f24ec43e9c1fa2d994afd615f58736c00d65 (diff)
parent0339cbe2f628f8a122ba7ea3a75fc99fa1dc4c96 (diff)
downloadmariadb-git-3ad37ed0eb343cd173b103974aded5783958a88e.tar.gz
Merge 10.4 into 10.5
Diffstat (limited to 'sql')
-rw-r--r--sql/backup.cc8
-rw-r--r--sql/ha_partition.cc24
-rw-r--r--sql/ha_partition.h13
-rw-r--r--sql/item_strfunc.cc13
-rw-r--r--sql/keycaches.cc15
-rw-r--r--sql/keycaches.h7
-rw-r--r--sql/log.cc9
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/opt_subselect.cc12
-rw-r--r--sql/rpl_rli.cc2
-rw-r--r--sql/semisync_master.cc2
-rw-r--r--sql/service_wsrep.cc21
-rw-r--r--sql/sp.cc2
-rw-r--r--sql/sp_head.cc6
-rw-r--r--sql/sql_acl.cc4
-rw-r--r--sql/sql_admin.cc6
-rw-r--r--sql/sql_base.cc28
-rw-r--r--sql/sql_class.cc104
-rw-r--r--sql/sql_class.h25
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_insert.cc56
-rw-r--r--sql/sql_lex.cc2
-rw-r--r--sql/sql_lex.h12
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc51
-rw-r--r--sql/sql_prepare.cc4
-rw-r--r--sql/sql_show.cc12
-rw-r--r--sql/sql_statistics.cc10
-rw-r--r--sql/sql_table.cc54
-rw-r--r--sql/sql_type.cc45
-rw-r--r--sql/sql_type.h16
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_view.cc15
-rw-r--r--sql/sql_yacc.yy16
-rw-r--r--sql/sql_yacc_ora.yy16
-rw-r--r--sql/table.cc11
-rw-r--r--sql/table.h11
-rw-r--r--sql/wsrep_binlog.cc4
-rw-r--r--sql/wsrep_client_service.cc6
-rw-r--r--sql/wsrep_client_service.h2
-rw-r--r--sql/wsrep_dummy.cc2
-rw-r--r--sql/wsrep_high_priority_service.cc9
-rw-r--r--sql/wsrep_high_priority_service.h4
-rw-r--r--sql/wsrep_mysqld.cc26
-rw-r--r--sql/wsrep_storage_service.cc3
-rw-r--r--sql/wsrep_storage_service.h3
46 files changed, 486 insertions, 220 deletions
diff --git a/sql/backup.cc b/sql/backup.cc
index 73cd13ffe2a..5976506cf92 100644
--- a/sql/backup.cc
+++ b/sql/backup.cc
@@ -290,6 +290,14 @@ static bool backup_block_commit(THD *thd)
/* We can ignore errors from flush_tables () */
(void) flush_tables(thd, FLUSH_SYS_TABLES);
+
+ if (mysql_bin_log.is_open())
+ {
+ mysql_mutex_lock(mysql_bin_log.get_log_lock());
+ mysql_file_sync(mysql_bin_log.get_log_file()->file,
+ MYF(MY_WME|MY_SYNC_FILESIZE));
+ mysql_mutex_unlock(mysql_bin_log.get_log_lock());
+ }
thd->clear_error();
DBUG_RETURN(0);
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 45ea9eb1552..10d97328c70 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -3461,8 +3461,7 @@ bool ha_partition::init_partition_bitmaps()
/*
Open handler object
-
- SYNOPSIS
+SYNOPSIS
open()
name Full path of table name
mode Open mode flags
@@ -3588,6 +3587,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
}
else
{
+ check_insert_autoincrement();
if (unlikely((error= open_read_partitions(name_buff, sizeof(name_buff)))))
goto err_handler;
m_num_locks= m_file_sample->lock_count();
@@ -4473,11 +4473,8 @@ exit:
table->found_next_number_field->field_index))
{
update_next_auto_inc_val();
- /*
- The following call is safe as part_share->auto_inc_initialized
- (tested in the call) is guaranteed to be set for update statements.
- */
- set_auto_increment_if_higher(table->found_next_number_field);
+ if (part_share->auto_inc_initialized)
+ set_auto_increment_if_higher(table->found_next_number_field);
}
DBUG_RETURN(error);
}
@@ -8138,6 +8135,7 @@ int ha_partition::info(uint flag)
if (flag & HA_STATUS_AUTO)
{
bool auto_inc_is_first_in_idx= (table_share->next_number_keypart == 0);
+ bool all_parts_opened= true;
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
if (!table->found_next_number_field)
stats.auto_increment_value= 0;
@@ -8168,6 +8166,15 @@ int ha_partition::info(uint flag)
("checking all partitions for auto_increment_value"));
do
{
+ if (!bitmap_is_set(&m_opened_partitions, (uint)(file_array - m_file)))
+ {
+ /*
+ Some partitions aren't opened.
+ So we can't calculate the autoincrement.
+ */
+ all_parts_opened= false;
+ break;
+ }
file= *file_array;
file->info(HA_STATUS_AUTO | no_lock_flag);
set_if_bigger(auto_increment_value,
@@ -8176,7 +8183,7 @@ int ha_partition::info(uint flag)
DBUG_ASSERT(auto_increment_value);
stats.auto_increment_value= auto_increment_value;
- if (auto_inc_is_first_in_idx)
+ if (all_parts_opened && auto_inc_is_first_in_idx)
{
set_if_bigger(part_share->next_auto_inc_val,
auto_increment_value);
@@ -8485,6 +8492,7 @@ int ha_partition::change_partitions_to_open(List<String> *partition_names)
return 0;
}
+ check_insert_autoincrement();
if (bitmap_cmp(&m_opened_partitions, &m_part_info->read_partitions) != 0)
return 0;
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 0fe98dc4608..ff02ea5aa1c 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1329,6 +1329,19 @@ private:
unlock_auto_increment();
}
+ void check_insert_autoincrement()
+ {
+ /*
+ If we INSERT into the table having the AUTO_INCREMENT column,
+ we have to read all partitions for the next autoincrement value
+ unless we already did it.
+ */
+ if (!part_share->auto_inc_initialized &&
+ ha_thd()->lex->sql_command == SQLCOM_INSERT &&
+ table->found_next_number_field)
+ bitmap_set_all(&m_part_info->read_partitions);
+ }
+
public:
/*
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index bf571473211..78c29ac8e33 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -2666,10 +2666,17 @@ const int FORMAT_MAX_DECIMALS= 30;
bool Item_func_format::fix_length_and_dec()
{
- uint32 char_length= args[0]->max_char_length();
- uint32 max_sep_count= (char_length / 3) + (decimals ? 1 : 0) + /*sign*/1;
+ uint32 char_length= args[0]->type_handler()->Item_decimal_notation_int_digits(args[0]);
+ uint dec= FORMAT_MAX_DECIMALS;
+ if (args[1]->const_item() && !args[1]->is_expensive())
+ {
+ Longlong_hybrid tmp= args[1]->to_longlong_hybrid();
+ if (!args[1]->null_value)
+ dec= tmp.to_uint(FORMAT_MAX_DECIMALS);
+ }
+ uint32 max_sep_count= (char_length / 3) + (dec ? 1 : 0) + /*sign*/1;
collation.set(default_charset());
- fix_char_length(char_length + max_sep_count + decimals);
+ fix_char_length(char_length + max_sep_count + dec);
if (arg_count == 3)
locale= args[2]->basic_const_item() ? args[2]->locale_from_val_str() : NULL;
else
diff --git a/sql/keycaches.cc b/sql/keycaches.cc
index f38a43f83cf..60049cdd67d 100644
--- a/sql/keycaches.cc
+++ b/sql/keycaches.cc
@@ -68,7 +68,7 @@ uchar* find_named(I_List<NAMED_ILINK> *list, const char *name, size_t length,
}
-bool NAMED_ILIST::delete_element(const char *name, size_t length, void (*free_element)(const char *name, uchar*))
+bool NAMED_ILIST::delete_element(const char *name, size_t length, void (*free_element)(const char *name, void*))
{
I_List_iterator<NAMED_ILINK> it(*this);
NAMED_ILINK *element;
@@ -85,7 +85,7 @@ bool NAMED_ILIST::delete_element(const char *name, size_t length, void (*free_el
DBUG_RETURN(1);
}
-void NAMED_ILIST::delete_elements(void (*free_element)(const char *name, uchar*))
+void NAMED_ILIST::delete_elements(void (*free_element)(const char *name, void*))
{
NAMED_ILINK *element;
DBUG_ENTER("NAMED_ILIST::delete_elements");
@@ -157,9 +157,9 @@ KEY_CACHE *get_or_create_key_cache(const char *name, size_t length)
}
-void free_key_cache(const char *name, KEY_CACHE *key_cache)
+void free_key_cache(const char *name, void *key_cache)
{
- end_key_cache(key_cache, 1); // Can never fail
+ end_key_cache(static_cast<KEY_CACHE *>(key_cache), 1); // Can never fail
my_free(key_cache);
}
@@ -221,13 +221,12 @@ Rpl_filter *get_or_create_rpl_filter(const char *name, size_t length)
return filter;
}
-void free_rpl_filter(const char *name, Rpl_filter *filter)
+void free_rpl_filter(const char *name, void *filter)
{
- delete filter;
- filter= 0;
+ delete static_cast<Rpl_filter*>(filter);
}
void free_all_rpl_filters()
{
- rpl_filters.delete_elements((void (*)(const char*, uchar*)) free_rpl_filter);
+ rpl_filters.delete_elements(free_rpl_filter);
}
diff --git a/sql/keycaches.h b/sql/keycaches.h
index 9da93e5f7ba..68c3dd3a2b0 100644
--- a/sql/keycaches.h
+++ b/sql/keycaches.h
@@ -30,8 +30,8 @@ class NAMED_ILINK;
class NAMED_ILIST: public I_List<NAMED_ILINK>
{
public:
- void delete_elements(void (*free_element)(const char*, uchar*));
- bool delete_element(const char *name, size_t length, void (*free_element)(const char*, uchar*));
+ void delete_elements(void (*free_element)(const char*, void*));
+ bool delete_element(const char *name, size_t length, void (*free_element)(const char*, void*));
};
/* For key cache */
@@ -42,7 +42,7 @@ extern NAMED_ILIST key_caches;
KEY_CACHE *create_key_cache(const char *name, size_t length);
KEY_CACHE *get_key_cache(const LEX_CSTRING *cache_name);
KEY_CACHE *get_or_create_key_cache(const char *name, size_t length);
-void free_key_cache(const char *name, KEY_CACHE *key_cache);
+void free_key_cache(const char *name, void *key_cache);
bool process_key_caches(process_key_cache_t func, void *param);
/* For Rpl_filter */
@@ -52,7 +52,6 @@ extern NAMED_ILIST rpl_filters;
Rpl_filter *create_rpl_filter(const char *name, size_t length);
Rpl_filter *get_rpl_filter(LEX_CSTRING *filter_name);
Rpl_filter *get_or_create_rpl_filter(const char *name, size_t length);
-void free_rpl_filter(const char *name, Rpl_filter *filter);
void free_all_rpl_filters(void);
#endif /* KEYCACHES_INCLUDED */
diff --git a/sql/log.cc b/sql/log.cc
index 4f51a9a9c17..98fb4a6d5a6 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5968,7 +5968,6 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
DBUG_ASSERT(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open());
DBUG_PRINT("enter", ("event: %p", event));
- int error= 0;
binlog_cache_mngr *const cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
@@ -6006,7 +6005,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
thd->binlog_set_pending_rows_event(event, is_transactional);
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
}
@@ -7718,7 +7717,7 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
mysql_mutex_unlock(&LOCK_prepare_ordered);
DEBUG_SYNC(orig_entry->thd, "commit_after_release_LOCK_prepare_ordered");
- DBUG_PRINT("info", ("Queued for group commit as %s\n",
+ DBUG_PRINT("info", ("Queued for group commit as %s",
(orig_queue == NULL) ? "leader" : "participant"));
DBUG_RETURN(orig_queue == NULL);
}
@@ -10734,13 +10733,13 @@ bool wsrep_stmt_rollback_is_safe(THD* thd)
binlog_cache_data * trx_cache = &cache_mngr->trx_cache;
if (thd->wsrep_sr().fragments_certified() > 0 &&
(trx_cache->get_prev_position() == MY_OFF_T_UNDEF ||
- trx_cache->get_prev_position() < thd->wsrep_sr().bytes_certified()))
+ trx_cache->get_prev_position() < thd->wsrep_sr().log_position()))
{
WSREP_DEBUG("statement rollback is not safe for streaming replication"
" pre-stmt_pos: %llu, frag repl pos: %zu\n"
"Thread: %llu, SQL: %s",
trx_cache->get_prev_position(),
- thd->wsrep_sr().bytes_certified(),
+ thd->wsrep_sr().log_position(),
thd->thread_id, thd->query());
ret = false;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 1df08eb739e..18b8148ed57 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -668,7 +668,9 @@ SHOW_COMP_OPTION have_crypt, have_compress;
SHOW_COMP_OPTION have_profiling;
SHOW_COMP_OPTION have_openssl;
+#ifndef EMBEDDED_LIBRARY
static std::atomic<char*> shutdown_user;
+#endif //EMBEDDED_LIBRARY
/* Thread specific variables */
@@ -1987,7 +1989,7 @@ static void clean_up(bool print_message)
tdc_deinit();
mdl_destroy();
dflt_key_cache= 0;
- key_caches.delete_elements((void (*)(const char*, uchar*)) free_key_cache);
+ key_caches.delete_elements(free_key_cache);
wt_end();
multi_keycache_free();
sp_cache_end();
@@ -4303,7 +4305,6 @@ static int init_common_variables()
return 1;
}
- global_system_variables.in_subquery_conversion_threshold= IN_SUBQUERY_CONVERSION_THRESHOLD;
#ifdef WITH_WSREP
/*
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index eeefe4200da..484836af23e 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -2681,9 +2681,17 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables)
{
do /* For all equalities on all key parts */
{
- /* Check if this is "t.keypart = expr(outer_tables) */
+ /*
+ Check if this is "t.keypart = expr(outer_tables)
+
+ Don't allow variants that can produce duplicates:
+ - Dont allow "ref or null"
+ - the keyuse (that is, the operation) must be null-rejecting,
+ unless the other expression is non-NULLable.
+ */
if (!(keyuse->used_tables & sj_inner_tables) &&
- !(keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL))
+ !(keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) &&
+ (keyuse->null_rejecting || !keyuse->val->maybe_null))
{
bound_parts |= 1 << keyuse->keypart;
}
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 48bc2bb0210..6d55b06b497 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1561,7 +1561,7 @@ scan_one_gtid_slave_pos_table(THD *thd, HASH *hash, DYNAMIC_ARRAY *array,
sub_id= (ulonglong)table->field[1]->val_int();
server_id= (uint32)table->field[2]->val_int();
seq_no= (ulonglong)table->field[3]->val_int();
- DBUG_PRINT("info", ("Read slave state row: %u-%u-%lu sub_id=%lu\n",
+ DBUG_PRINT("info", ("Read slave state row: %u-%u-%lu sub_id=%lu",
(unsigned)domain_id, (unsigned)server_id,
(ulong)seq_no, (ulong)sub_id));
diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc
index f9fb4d9147d..b239a9776a7 100644
--- a/sql/semisync_master.cc
+++ b/sql/semisync_master.cc
@@ -806,7 +806,7 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
if (!get_master_enabled() || !is_on())
goto l_end;
- DBUG_PRINT("semisync", ("%s: wait pos (%s, %lu), repl(%d)\n",
+ DBUG_PRINT("semisync", ("%s: wait pos (%s, %lu), repl(%d)",
"Repl_semi_sync_master::commit_trx",
trx_wait_binlog_name, (ulong)trx_wait_binlog_pos,
(int)is_on()));
diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc
index b365b393e0b..204d671d53b 100644
--- a/sql/service_wsrep.cc
+++ b/sql/service_wsrep.cc
@@ -55,7 +55,26 @@ extern "C" const char* wsrep_thd_transaction_state_str(const THD *thd)
extern "C" const char *wsrep_thd_query(const THD *thd)
{
- return thd ? thd->query() : NULL;
+ if (thd)
+ {
+ switch(thd->lex->sql_command)
+ {
+ case SQLCOM_CREATE_USER:
+ return "CREATE USER";
+ case SQLCOM_GRANT:
+ return "GRANT";
+ case SQLCOM_REVOKE:
+ return "REVOKE";
+ case SQLCOM_SET_OPTION:
+ if (thd->lex->definer)
+ return "SET PASSWORD";
+ /* fallthrough */
+ default:
+ if (thd->query())
+ return thd->query();
+ }
+ }
+ return "NULL";
}
extern "C" query_id_t wsrep_thd_transaction_id(const THD *thd)
diff --git a/sql/sp.cc b/sql/sp.cc
index c9d1e2e3c4a..058a29e65f7 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1466,7 +1466,7 @@ log:
/* Such a statement can always go directly to binlog, no trans cache */
if (thd->binlog_query(THD::STMT_QUERY_TYPE,
log_query.ptr(), log_query.length(),
- FALSE, FALSE, FALSE, 0))
+ FALSE, FALSE, FALSE, 0) > 0)
{
my_error(ER_ERROR_ON_WRITE, MYF(0), "binary log", -1);
goto done;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 8c07a060f30..945b3ac8854 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -4722,6 +4722,7 @@ typedef struct st_sp_table
uint lock_count;
uint query_lock_count;
uint8 trg_event_map;
+ my_bool for_insert_data;
} SP_TABLE;
@@ -4817,6 +4818,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
if (tab->query_lock_count > tab->lock_count)
tab->lock_count++;
tab->trg_event_map|= table->trg_event_map;
+ tab->for_insert_data|= table->for_insert_data;
}
else
{
@@ -4840,6 +4842,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
tab->lock_type= table->lock_type;
tab->lock_count= tab->query_lock_count= 1;
tab->trg_event_map= table->trg_event_map;
+ tab->for_insert_data= table->for_insert_data;
if (my_hash_insert(&m_sptabs, (uchar *)tab))
return FALSE;
}
@@ -4923,7 +4926,8 @@ sp_head::add_used_tables_to_table_list(THD *thd,
TABLE_LIST::PRELOCK_ROUTINE,
belong_to_view,
stab->trg_event_map,
- query_tables_last_ptr);
+ query_tables_last_ptr,
+ stab->for_insert_data);
tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST));
result= TRUE;
}
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index ff8a2bebb8d..4c8eaee3145 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3788,7 +3788,7 @@ bool change_password(THD *thd, LEX_USER *user)
DBUG_ASSERT(query_length);
thd->clear_error();
result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
- FALSE, FALSE, FALSE, 0);
+ FALSE, FALSE, FALSE, 0) > 0;
}
end:
if (result)
@@ -3940,7 +3940,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
DBUG_ASSERT(query_length);
thd->clear_error();
result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
- FALSE, FALSE, FALSE, 0);
+ FALSE, FALSE, FALSE, 0) > 0;
}
end:
close_mysql_tables(thd);
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 5dcb7ffac72..3b15c5a505e 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -1317,7 +1317,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
"analyze", lock_type, 1, 0, 0, 0,
&handler::ha_analyze, 0);
/* ! we write after unlocking the table */
- if (!res && !m_lex->no_write_to_binlog)
+ if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
{
/*
Presumably, ANALYZE and binlog writing doesn't require synchronization
@@ -1377,7 +1377,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
"optimize", TL_WRITE, 1, 0, 0, 0,
&handler::ha_optimize, 0);
/* ! we write after unlocking the table */
- if (!res && !m_lex->no_write_to_binlog)
+ if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
{
/*
Presumably, OPTIMIZE and binlog writing doesn't require synchronization
@@ -1413,7 +1413,7 @@ bool Sql_cmd_repair_table::execute(THD *thd)
&handler::ha_repair, &view_repair);
/* ! we write after unlocking the table */
- if (!res && !m_lex->no_write_to_binlog)
+ if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
{
/*
Presumably, REPAIR and binlog writing doesn't require synchronization
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 15c0e976c26..da061adfc1f 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2668,6 +2668,7 @@ Locked_tables_list::reopen_tables(THD *thd, bool need_reopen)
{
thd->locked_tables_list.unlink_from_list(thd, table_list, false);
mysql_lock_remove(thd, thd->lock, *prev);
+ (*prev)->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE);
close_thread_table(thd, prev);
break;
}
@@ -4604,9 +4605,11 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *tables)
{
TABLE_LIST *global_table_list= prelocking_ctx->query_tables;
+ DBUG_ENTER("add_internal_tables");
do
{
+ DBUG_PRINT("info", ("table name: %s", tables->table_name.str));
/*
Skip table if already in the list. Can happen with prepared statements
*/
@@ -4616,20 +4619,22 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
if (!tl)
- return TRUE;
+ DBUG_RETURN(TRUE);
tl->init_one_table_for_prelocking(&tables->db,
&tables->table_name,
NULL, tables->lock_type,
TABLE_LIST::PRELOCK_NONE,
0, 0,
- &prelocking_ctx->query_tables_last);
+ &prelocking_ctx->query_tables_last,
+ tables->for_insert_data);
/*
Store link to the new table_list that will be used by open so that
Item_func_nextval() can find it
*/
tables->next_local= tl;
+ DBUG_PRINT("info", ("table name: %s added", tables->table_name.str));
} while ((tables= tables->next_global));
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -4660,6 +4665,7 @@ bool DML_prelocking_strategy::
handle_table(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking)
{
+ DBUG_ENTER("handle_table");
TABLE *table= table_list->table;
/* We rely on a caller to check that table is going to be changed. */
DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE ||
@@ -4690,7 +4696,7 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
{
if (arena)
thd->restore_active_arena(arena, &backup);
- return TRUE;
+ DBUG_RETURN(TRUE);
}
*need_prelocking= TRUE;
@@ -4718,7 +4724,8 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
NULL, lock_type,
TABLE_LIST::PRELOCK_FK,
table_list->belong_to_view, op,
- &prelocking_ctx->query_tables_last);
+ &prelocking_ctx->query_tables_last,
+ table_list->for_insert_data);
}
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -4726,8 +4733,11 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
}
/* Open any tables used by DEFAULT (like sequence tables) */
+ DBUG_PRINT("info", ("table: %p name: %s db: %s flags: %u",
+ table_list, table_list->table_name.str,
+ table_list->db.str, table_list->for_insert_data));
if (table->internal_tables &&
- ((sql_command_flags[thd->lex->sql_command] & CF_INSERTS_DATA) ||
+ (table_list->for_insert_data ||
thd->lex->default_used))
{
Query_arena *arena, backup;
@@ -4740,10 +4750,10 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
if (unlikely(error))
{
*need_prelocking= TRUE;
- return TRUE;
+ DBUG_RETURN(TRUE);
}
}
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -4760,7 +4770,7 @@ bool open_and_lock_internal_tables(TABLE *table, bool lock_table)
THD *thd= table->in_use;
TABLE_LIST *tl;
MYSQL_LOCK *save_lock,*new_lock;
- DBUG_ENTER("open_internal_tables");
+ DBUG_ENTER("open_and_lock_internal_tables");
/* remove pointer to old select_lex which is already destroyed */
for (tl= table->internal_tables ; tl ; tl= tl->next_global)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a4861620bf0..cc572065e92 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -49,7 +49,7 @@
#include <m_ctype.h>
#include <sys/stat.h>
#include <thr_alarm.h>
-#ifdef __WIN__
+#ifdef __WIN__0
#include <io.h>
#endif
#include <mysys_err.h>
@@ -5848,17 +5848,33 @@ int THD::decide_logging_format(TABLE_LIST *tables)
Get the capabilities vector for all involved storage engines and
mask out the flags for the binary log.
*/
- for (TABLE_LIST *table= tables; table; table= table->next_global)
+ for (TABLE_LIST *tbl= tables; tbl; tbl= tbl->next_global)
{
- if (table->placeholder())
+ TABLE *table;
+ TABLE_SHARE *share;
+ handler::Table_flags flags;
+ if (tbl->placeholder())
continue;
- handler::Table_flags const flags= table->table->file->ha_table_flags();
+ table= tbl->table;
+ share= table->s;
+ flags= table->file->ha_table_flags();
+ if (!share->table_creation_was_logged)
+ {
+ /*
+ This is a temporary table which was not logged in the binary log.
+ Disable statement logging to enforce row level logging.
+ */
+ DBUG_ASSERT(share->tmp_table);
+ flags&= ~HA_BINLOG_STMT_CAPABLE;
+ /* We can only use row logging */
+ set_current_stmt_binlog_format_row();
+ }
DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
- table->table_name.str, flags));
+ tbl->table_name.str, flags));
- if (table->table->s->no_replicate)
+ if (share->no_replicate)
{
/*
The statement uses a table that is not replicated.
@@ -5876,44 +5892,44 @@ int THD::decide_logging_format(TABLE_LIST *tables)
*/
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
- if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ if (tbl->lock_type >= TL_WRITE_ALLOW_WRITE)
{
non_replicated_tables_count++;
continue;
}
}
- if (table == lex->first_not_own_table())
+ if (tbl == lex->first_not_own_table())
found_first_not_own_table= true;
replicated_tables_count++;
- if (table->prelocking_placeholder != TABLE_LIST::PRELOCK_FK)
+ if (tbl->prelocking_placeholder != TABLE_LIST::PRELOCK_FK)
{
- if (table->lock_type <= TL_READ_NO_INSERT)
+ if (tbl->lock_type <= TL_READ_NO_INSERT)
has_read_tables= true;
- else if (table->table->found_next_number_field &&
- (table->lock_type >= TL_WRITE_ALLOW_WRITE))
+ else if (table->found_next_number_field &&
+ (tbl->lock_type >= TL_WRITE_ALLOW_WRITE))
{
has_auto_increment_write_tables= true;
has_auto_increment_write_tables_not_first= found_first_not_own_table;
- if (table->table->s->next_number_keypart != 0)
+ if (share->next_number_keypart != 0)
has_write_table_auto_increment_not_first_in_pk= true;
}
}
- if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ if (tbl->lock_type >= TL_WRITE_ALLOW_WRITE)
{
bool trans;
if (prev_write_table && prev_write_table->file->ht !=
- table->table->file->ht)
+ table->file->ht)
multi_write_engine= TRUE;
- if (table->table->s->non_determinstic_insert &&
+ if (share->non_determinstic_insert &&
!(sql_command_flags[lex->sql_command] & CF_SCHEMA_CHANGE))
has_write_tables_with_unsafe_statements= true;
- trans= table->table->file->has_transactions();
+ trans= table->file->has_transactions();
- if (table->table->s->tmp_table)
+ if (share->tmp_table)
lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE :
LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE);
else
@@ -5924,17 +5940,16 @@ int THD::decide_logging_format(TABLE_LIST *tables)
flags_write_some_set |= flags;
is_write= TRUE;
- prev_write_table= table->table;
+ prev_write_table= table;
}
flags_access_some_set |= flags;
- if (lex->sql_command != SQLCOM_CREATE_TABLE ||
- (lex->sql_command == SQLCOM_CREATE_TABLE && lex->tmp_table()))
+ if (lex->sql_command != SQLCOM_CREATE_TABLE || lex->tmp_table())
{
- my_bool trans= table->table->file->has_transactions();
+ my_bool trans= table->file->has_transactions();
- if (table->table->s->tmp_table)
+ if (share->tmp_table)
lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TEMP_TRANS_TABLE :
LEX::STMT_READS_TEMP_NON_TRANS_TABLE);
else
@@ -5943,10 +5958,10 @@ int THD::decide_logging_format(TABLE_LIST *tables)
}
if (prev_access_table && prev_access_table->file->ht !=
- table->table->file->ht)
+ table->file->ht)
multi_access_engine= TRUE;
- prev_access_table= table->table;
+ prev_access_table= table;
}
if (wsrep_binlog_format() != BINLOG_FORMAT_ROW)
@@ -6075,10 +6090,17 @@ int THD::decide_logging_format(TABLE_LIST *tables)
{
/*
5. Error: Cannot modify table that uses a storage engine
- limited to row-logging when binlog_format = STATEMENT
+ limited to row-logging when binlog_format = STATEMENT, except
+ if all tables that are updated are temporary tables
*/
- if (IF_WSREP((!WSREP_NNULL(this) ||
- wsrep_cs().mode() == wsrep::client_state::m_local),1))
+ if (!lex->stmt_writes_to_non_temp_table())
+ {
+ /* As all updated tables are temporary, nothing will be logged */
+ set_current_stmt_binlog_format_row();
+ }
+ else if (IF_WSREP((!WSREP(this) ||
+ wsrep_cs().mode() ==
+ wsrep::client_state::m_local),1))
{
my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
}
@@ -6147,10 +6169,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
"ROW" : "STATEMENT"));
if (variables.binlog_format == BINLOG_FORMAT_ROW &&
- (lex->sql_command == SQLCOM_UPDATE ||
- lex->sql_command == SQLCOM_UPDATE_MULTI ||
- lex->sql_command == SQLCOM_DELETE ||
- lex->sql_command == SQLCOM_DELETE_MULTI))
+ (sql_command_flags[lex->sql_command] &
+ (CF_UPDATES_DATA | CF_DELETES_DATA)))
{
String table_names;
/*
@@ -6170,8 +6190,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
}
if (!table_names.is_empty())
{
- bool is_update= (lex->sql_command == SQLCOM_UPDATE ||
- lex->sql_command == SQLCOM_UPDATE_MULTI);
+ bool is_update= MY_TEST(sql_command_flags[lex->sql_command] &
+ CF_UPDATES_DATA);
/*
Replace the last ',' with '.' for table_names
*/
@@ -7008,11 +7028,12 @@ void THD::issue_unsafe_warnings()
@see decide_logging_format
+ @retval < 0 No logging of query (ok)
@retval 0 Success
-
- @retval nonzero If there is a failure when writing the query (e.g.,
- write failure), then the error code is returned.
+ @retval > 0 If there is a failure when writing the query (e.g.,
+ write failure), then the error code is returned.
*/
+
int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
ulong query_len, bool is_trans, bool direct,
bool suppress_use, int errcode)
@@ -7038,7 +7059,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
The current statement is to be ignored, and not written to
the binlog. Do not call issue_unsafe_warnings().
*/
- DBUG_RETURN(0);
+ DBUG_RETURN(-1);
}
/*
@@ -7054,7 +7075,10 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
{
int error;
if (unlikely(error= binlog_flush_pending_rows_event(TRUE, is_trans)))
+ {
+ DBUG_ASSERT(error > 0);
DBUG_RETURN(error);
+ }
}
/*
@@ -7097,7 +7121,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
("is_current_stmt_binlog_format_row: %d",
is_current_stmt_binlog_format_row()));
if (is_current_stmt_binlog_format_row())
- DBUG_RETURN(0);
+ DBUG_RETURN(-1);
/* Fall through */
/*
@@ -7138,7 +7162,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
}
binlog_table_maps= 0;
- DBUG_RETURN(error);
+ DBUG_RETURN(error >= 0 ? error : 1);
}
case THD::QUERY_TYPE_COUNT:
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a208b627b7e..2fb5797b325 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1630,12 +1630,16 @@ public:
/**
@class Sub_statement_state
@brief Used to save context when executing a function or trigger
+
+ operations on stat tables aren't technically a sub-statement, but they are
+ similar in a sense that they cannot change the transaction status.
*/
/* Defines used for Sub_statement_state::in_sub_stmt */
#define SUB_STMT_TRIGGER 1
#define SUB_STMT_FUNCTION 2
+#define SUB_STMT_STAT_TABLES 4
class Sub_statement_state
@@ -6654,6 +6658,11 @@ public:
/* Bits in server_command_flags */
/**
+ Statement that deletes existing rows (DELETE, DELETE_MULTI)
+*/
+#define CF_DELETES_DATA (1U << 24)
+
+/**
Skip the increase of the global query id counter. Commonly set for
commands that are stateless (won't cause any change on the server
internal states).
@@ -6858,6 +6867,22 @@ class Sql_mode_save
sql_mode_t old_mode; // SQL mode saved at construction time.
};
+class Switch_to_definer_security_ctx
+{
+ public:
+ Switch_to_definer_security_ctx(THD *thd, TABLE_LIST *table) :
+ m_thd(thd), m_sctx(thd->security_ctx)
+ {
+ if (table->security_ctx)
+ thd->security_ctx= table->security_ctx;
+ }
+ ~Switch_to_definer_security_ctx() { m_thd->security_ctx = m_sctx; }
+
+ private:
+ THD *m_thd;
+ Security_context *m_sctx;
+};
+
class Sql_mode_instant_set: public Sql_mode_save
{
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 8161a761486..0ea00a7d61c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -930,7 +930,7 @@ cleanup:
transactional_table, FALSE, FALSE,
errcode);
- if (log_result)
+ if (log_result > 0)
{
error=1;
}
@@ -1616,7 +1616,7 @@ bool multi_delete::send_eof()
if (unlikely(thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
transactional_tables, FALSE, FALSE,
- errcode)) &&
+ errcode) > 0) &&
!normal_tables)
{
local_error=1; // Log write failed: roll back the SQL statement
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 7be005bd79b..329b6a130b0 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1193,13 +1193,13 @@ values_loop_end:
else if (thd->binlog_query(THD::ROW_QUERY_TYPE,
log_query.c_ptr(), log_query.length(),
transactional_table, FALSE, FALSE,
- errcode))
+ errcode) > 0)
error= 1;
}
else if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
transactional_table, FALSE, FALSE,
- errcode))
+ errcode) > 0)
error= 1;
}
}
@@ -3964,6 +3964,7 @@ bool select_insert::prepare_eof()
int error;
bool const trans_table= table->file->has_transactions();
bool changed;
+ bool binary_logged= 0;
killed_state killed_status= thd->killed;
DBUG_ENTER("select_insert::prepare_eof");
@@ -4014,18 +4015,22 @@ bool select_insert::prepare_eof()
(likely(!error) || thd->transaction.stmt.modified_non_trans_table))
{
int errcode= 0;
+ int res;
if (likely(!error))
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == NOT_KILLED);
- if (thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query(), thd->query_length(),
- trans_table, FALSE, FALSE, errcode))
+ res= thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ trans_table, FALSE, FALSE, errcode);
+ if (res > 0)
{
table->file->ha_release_auto_increment();
DBUG_RETURN(true);
}
+ binary_logged= res == 0 || !table->s->tmp_table;
}
+ table->s->table_creation_was_logged|= binary_logged;
table->file->ha_release_auto_increment();
if (unlikely(error))
@@ -4082,8 +4087,9 @@ bool select_insert::send_eof()
DBUG_RETURN(res);
}
-void select_insert::abort_result_set() {
-
+void select_insert::abort_result_set()
+{
+ bool binary_logged= 0;
DBUG_ENTER("select_insert::abort_result_set");
/*
If the creation of the table failed (due to a syntax error, for
@@ -4135,16 +4141,20 @@ void select_insert::abort_result_set() {
if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
+ int res;
/* error of writing binary log is ignored */
- (void) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(),
- thd->query_length(),
- transactional_table, FALSE, FALSE, errcode);
+ res= thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(),
+ thd->query_length(),
+ transactional_table, FALSE, FALSE, errcode);
+ binary_logged= res == 0 || !table->s->tmp_table;
}
if (changed)
query_cache_invalidate3(thd, table, 1);
}
DBUG_ASSERT(transactional_table || !changed ||
thd->transaction.stmt.modified_non_trans_table);
+
+ table->s->table_creation_was_logged|= binary_logged;
table->file->ha_release_auto_increment();
}
@@ -4213,6 +4223,7 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
/* Add selected items to field list */
List_iterator_fast<Item> it(*items);
Item *item;
+ bool save_table_creation_was_logged;
DBUG_ENTER("select_create::create_table_from_items");
tmp_table.s= &share;
@@ -4367,6 +4378,14 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
table->reginfo.lock_type=TL_WRITE;
hooks->prelock(&table, 1); // Call prelock hooks
+
+ /*
+ Ensure that decide_logging_format(), called by mysql_lock_tables(), works
+ with temporary tables that will be logged later if needed.
+ */
+ save_table_creation_was_logged= table->s->table_creation_was_logged;
+ table->s->table_creation_was_logged= 1;
+
/*
mysql_lock_tables() below should never fail with request to reopen table
since it won't wait for the table lock (we have exclusive metadata lock on
@@ -4379,8 +4398,11 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
/*
This can happen in innodb when you get a deadlock when using same table
in insert and select or when you run out of memory.
+ It can also happen if there was a conflict in
+ THD::decide_logging_format()
*/
- my_error(ER_CANT_LOCK, MYF(0), my_errno);
+ if (!thd->is_error())
+ my_error(ER_CANT_LOCK, MYF(0), my_errno);
if (*lock)
{
mysql_unlock_tables(thd, *lock);
@@ -4390,6 +4412,7 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
DBUG_RETURN(0);
/* purecov: end */
}
+ table->s->table_creation_was_logged= save_table_creation_was_logged;
DBUG_RETURN(table);
}
@@ -4593,7 +4616,7 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
/* is_trans */ TRUE,
/* direct */ FALSE,
/* suppress_use */ FALSE,
- errcode);
+ errcode) > 0;
}
#ifdef WITH_WSREP
if (thd->wsrep_trx().active())
@@ -4717,8 +4740,6 @@ bool select_create::send_eof()
}
#endif /* WITH_WSREP */
}
- else if (!thd->is_current_stmt_binlog_format_row())
- table->s->table_creation_was_logged= 1;
/*
exit_done must only be set after last potential call to
@@ -4804,7 +4825,8 @@ void select_create::abort_result_set()
if (table)
{
bool tmp_table= table->s->tmp_table;
-
+ bool table_creation_was_logged= (!tmp_table ||
+ table->s->table_creation_was_logged);
if (tmp_table)
{
DBUG_ASSERT(saved_tmp_table_share);
@@ -4833,7 +4855,9 @@ void select_create::abort_result_set()
/* Remove logging of drop, create + insert rows */
binlog_reset_cache(thd);
/* Original table was deleted. We have to log it */
- log_drop_table(thd, &create_table->db, &create_table->table_name, tmp_table);
+ if (table_creation_was_logged)
+ log_drop_table(thd, &create_table->db, &create_table->table_name,
+ tmp_table);
}
}
DBUG_VOID_RETURN;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 34dcb0bcbe9..e5e6b1f3afd 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -7723,7 +7723,7 @@ uint binlog_unsafe_map[256];
#define UNSAFE(a, b, c) \
{ \
- DBUG_PRINT("unsafe_mixed_statement", ("SETTING BASE VALUES: %s, %s, %02X\n", \
+ DBUG_PRINT("unsafe_mixed_statement", ("SETTING BASE VALUES: %s, %s, %02X", \
LEX::stmt_accessed_table_string(a), \
LEX::stmt_accessed_table_string(b), \
c)); \
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index e34cd2ebfd7..7fc905528d6 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2208,6 +2208,14 @@ public:
((1U << STMT_READS_TEMP_TRANS_TABLE) |
(1U << STMT_WRITES_TEMP_TRANS_TABLE))) != 0);
}
+ inline bool stmt_writes_to_non_temp_table()
+ {
+ DBUG_ENTER("THD::stmt_writes_to_non_temp_table");
+
+ DBUG_RETURN((stmt_accessed_table_flag &
+ ((1U << STMT_WRITES_TRANS_TABLE) |
+ (1U << STMT_WRITES_NON_TRANS_TABLE))));
+ }
/**
Checks if a temporary non-transactional table is about to be accessed
@@ -2259,7 +2267,7 @@ public:
unsafe= (binlog_unsafe_map[stmt_accessed_table_flag] & condition);
#if !defined(DBUG_OFF)
- DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("RESULT %02X %02X %02X\n", condition,
+ DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("RESULT %02X %02X %02X", condition,
binlog_unsafe_map[stmt_accessed_table_flag],
(binlog_unsafe_map[stmt_accessed_table_flag] & condition)));
@@ -4593,6 +4601,8 @@ public:
const Lex_length_and_dec_st &attr);
bool set_cast_type_udt(Lex_cast_type_st *type,
const LEX_CSTRING &name);
+
+ void mark_first_table_as_inserting();
};
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 3fa6e095f10..89cc3f8da64 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -2053,7 +2053,7 @@ int READ_INFO::read_xml(THD *thd)
chr= read_value(delim, &value);
if (attribute.length() > 0 && value.length() > 0)
{
- DBUG_PRINT("read_xml", ("lev:%i att:%s val:%s\n",
+ DBUG_PRINT("read_xml", ("lev:%i att:%s val:%s",
level + 1,
attribute.c_ptr_safe(),
value.c_ptr_safe()));
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0493176b264..beda00592e1 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -610,11 +610,12 @@ void init_update_queries(void)
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED |
- CF_SP_BULK_SAFE;
+ CF_SP_BULK_SAFE | CF_DELETES_DATA;
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
- CF_CAN_BE_EXPLAINED;
+ CF_CAN_BE_EXPLAINED |
+ CF_DELETES_DATA;
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
@@ -3313,6 +3314,10 @@ mysql_execute_command(THD *thd)
#endif
DBUG_ENTER("mysql_execute_command");
+ // check that we correctly marked first table for data insertion
+ DBUG_ASSERT(!(sql_command_flags[lex->sql_command] & CF_INSERTS_DATA) ||
+ first_table->for_insert_data);
+
if (thd->security_ctx->password_expired &&
lex->sql_command != SQLCOM_SET_OPTION)
{
@@ -6840,11 +6845,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool check_single_table_access(THD *thd, ulong privilege,
TABLE_LIST *all_tables, bool no_errors)
{
- Security_context * backup_ctx= thd->security_ctx;
-
- /* we need to switch to the saved context (if any) */
- if (all_tables->security_ctx)
- thd->security_ctx= all_tables->security_ctx;
+ Switch_to_definer_security_ctx backup_sctx(thd, all_tables);
const char *db_name;
if ((all_tables->view || all_tables->field_translation) &&
@@ -6857,20 +6858,15 @@ bool check_single_table_access(THD *thd, ulong privilege,
&all_tables->grant.privilege,
&all_tables->grant.m_internal,
0, no_errors))
- goto deny;
+ return 1;
/* Show only 1 table for check_grant */
if (!(all_tables->belong_to_view &&
(thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
check_grant(thd, privilege, all_tables, FALSE, 1, no_errors))
- goto deny;
+ return 1;
- thd->security_ctx= backup_ctx;
return 0;
-
-deny:
- thd->security_ctx= backup_ctx;
- return 1;
}
/**
@@ -7045,7 +7041,6 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
{
TABLE_LIST *org_tables= tables;
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
- Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
uint i= 0;
/*
The check that first_not_own_table is not reached is for the case when
@@ -7057,12 +7052,9 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
{
TABLE_LIST *const table_ref= tables->correspondent_table ?
tables->correspondent_table : tables;
+ Switch_to_definer_security_ctx backup_ctx(thd, table_ref);
ulong want_access= requirements;
- if (table_ref->security_ctx)
- sctx= table_ref->security_ctx;
- else
- sctx= backup_ctx;
/*
Register access for view underlying table.
@@ -7073,7 +7065,7 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
if (table_ref->schema_table_reformed)
{
if (check_show_access(thd, table_ref))
- goto deny;
+ return 1;
continue;
}
@@ -7083,8 +7075,6 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
if (table_ref->is_anonymous_derived_table())
continue;
- thd->security_ctx= sctx;
-
if (table_ref->sequence)
{
/* We want to have either SELECT or INSERT rights to sequences depending
@@ -7098,15 +7088,11 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
&table_ref->grant.privilege,
&table_ref->grant.m_internal,
0, no_errors))
- goto deny;
+ return 1;
}
- thd->security_ctx= backup_ctx;
return check_grant(thd,requirements,org_tables,
any_combination_of_privileges_will_do,
number, no_errors);
-deny:
- thd->security_ctx= backup_ctx;
- return TRUE;
}
@@ -10401,3 +10387,14 @@ CHARSET_INFO *find_bin_collation(CHARSET_INFO *cs)
}
return cs;
}
+
+void LEX::mark_first_table_as_inserting()
+{
+ TABLE_LIST *t= first_select_lex()->table_list.first;
+ DBUG_ENTER("Query_tables_list::mark_tables_with_important_flags");
+ DBUG_ASSERT(sql_command_flags[sql_command] & CF_INSERTS_DATA);
+ t->for_insert_data= TRUE;
+ DBUG_PRINT("info", ("table_list: %p name: %s db: %s command: %u",
+ t, t->table_name.str,t->db.str, sql_command));
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index e5723cb3b78..424a039a5be 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -3303,7 +3303,7 @@ void mysql_sql_stmt_execute(THD *thd)
/* Query text for binary, general or slow log, if any of them is open */
String expanded_query;
DBUG_ENTER("mysql_sql_stmt_execute");
- DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int) name->length, name->str));
+ DBUG_PRINT("info", ("EXECUTE: %.*s", (int) name->length, name->str));
if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
@@ -3541,7 +3541,7 @@ void mysql_sql_stmt_close(THD *thd)
{
Prepared_statement* stmt;
const LEX_CSTRING *name= &thd->lex->prepared_stmt.name();
- DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", (int) name->length,
+ DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s", (int) name->length,
name->str));
if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 4b47f9683eb..43914a0003d 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2860,8 +2860,12 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
else
protocol->store_null();
protocol->store(thd_info->state_info, system_charset_info);
- protocol->store(thd_info->query_string.str(),
- thd_info->query_string.charset());
+ if (thd_info->query_string.length())
+ protocol->store(thd_info->query_string.str(),
+ thd_info->query_string.length(),
+ thd_info->query_string.charset());
+ else
+ protocol->store_null();
if (!thd->variables.old_mode &&
!(thd->variables.old_behavior & OLD_MODE_NO_PROGRESS_INFO))
protocol->store(thd_info->progress, 3, &store_buffer);
@@ -8019,8 +8023,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items);
- TMP_TABLE_PARAM *tmp_table_param =
- (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
+ TMP_TABLE_PARAM *tmp_table_param = new (thd->mem_root) TMP_TABLE_PARAM;
tmp_table_param->init();
tmp_table_param->table_charset= system_charset_info;
tmp_table_param->field_count= field_count;
@@ -8577,6 +8580,7 @@ bool get_schema_tables_result(JOIN *join,
cond= tab->cache_select->cond;
}
+ Switch_to_definer_security_ctx backup_ctx(thd, table_list);
if (table_list->schema_table->fill_table(thd, table_list, cond))
{
result= 1;
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index abf6a8a3cad..a94fb1196b4 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -230,10 +230,8 @@ index_stat_def= {INDEX_STAT_N_FIELDS, index_stat_fields, 4, index_stat_pk_col};
Open all statistical tables and lock them
*/
-static
-inline int open_stat_tables(THD *thd, TABLE_LIST *tables,
- Open_tables_backup *backup,
- bool for_write)
+static int open_stat_tables(THD *thd, TABLE_LIST *tables,
+ Open_tables_backup *backup, bool for_write)
{
int rc;
@@ -241,12 +239,14 @@ inline int open_stat_tables(THD *thd, TABLE_LIST *tables,
thd->push_internal_handler(&deh);
init_table_list_for_stat_tables(tables, for_write);
init_mdl_requests(tables);
+ thd->in_sub_stmt|= SUB_STMT_STAT_TABLES;
rc= open_system_tables_for_read(thd, tables, backup);
+ thd->in_sub_stmt&= ~SUB_STMT_STAT_TABLES;
thd->pop_internal_handler();
/* If the number of tables changes, we should revise the check below. */
- DBUG_ASSERT(STATISTICS_TABLES == 3);
+ compile_time_assert(STATISTICS_TABLES == 3);
if (!rc &&
(stat_table_intact.check(tables[TABLE_STAT].table, &table_stat_def) ||
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f824abbcabc..2917a320603 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1987,7 +1987,7 @@ int write_bin_log(THD *thd, bool clear_error,
errcode= query_error_code(thd, TRUE);
error= thd->binlog_query(THD::STMT_QUERY_TYPE,
query, query_length, is_trans, FALSE, FALSE,
- errcode);
+ errcode) > 0;
thd_proc_info(thd, 0);
}
return error;
@@ -2603,24 +2603,24 @@ err:
/* Chop of the last comma */
built_non_trans_tmp_query.chop();
built_non_trans_tmp_query.append(" /* generated by server */");
- error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
- built_non_trans_tmp_query.ptr(),
- built_non_trans_tmp_query.length(),
- FALSE, FALSE,
- is_drop_tmp_if_exists_added,
- 0);
+ error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
+ built_non_trans_tmp_query.ptr(),
+ built_non_trans_tmp_query.length(),
+ FALSE, FALSE,
+ is_drop_tmp_if_exists_added,
+ 0) > 0);
}
if (trans_tmp_table_deleted)
{
/* Chop of the last comma */
built_trans_tmp_query.chop();
built_trans_tmp_query.append(" /* generated by server */");
- error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
- built_trans_tmp_query.ptr(),
- built_trans_tmp_query.length(),
- TRUE, FALSE,
- is_drop_tmp_if_exists_added,
- 0);
+ error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
+ built_trans_tmp_query.ptr(),
+ built_trans_tmp_query.length(),
+ TRUE, FALSE,
+ is_drop_tmp_if_exists_added,
+ 0) > 0);
}
if (non_tmp_table_deleted)
{
@@ -2629,11 +2629,11 @@ err:
built_query.append(" /* generated by server */");
int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno()
: 0;
- error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
- built_query.ptr(),
- built_query.length(),
- TRUE, FALSE, FALSE,
- error_code);
+ error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
+ built_query.ptr(),
+ built_query.length(),
+ TRUE, FALSE, FALSE,
+ error_code) > 0);
}
}
}
@@ -2716,7 +2716,7 @@ bool log_drop_table(THD *thd, const LEX_CSTRING *db_name,
"failed CREATE OR REPLACE */"));
error= thd->binlog_query(THD::STMT_QUERY_TYPE,
query.ptr(), query.length(),
- FALSE, FALSE, temporary_table, 0);
+ FALSE, FALSE, temporary_table, 0) > 0;
DBUG_RETURN(error);
}
@@ -5281,9 +5281,13 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
}
err:
- /* In RBR we don't need to log CREATE TEMPORARY TABLE */
- if (!result && thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
+ /* In RBR or readonly server we don't need to log CREATE TEMPORARY TABLE */
+ if (!result && create_info->tmp_table() &&
+ (thd->is_current_stmt_binlog_format_row() || (opt_readonly && !thd->slave_thread)))
+ {
+ /* Note that table->s->table_creation_was_logged is not set! */
DBUG_RETURN(result);
+ }
if (create_info->tmp_table())
thd->transaction.stmt.mark_created_temp_table();
@@ -5300,11 +5304,13 @@ err:
*/
thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket);
}
- else if (likely(!result) && create_info->tmp_table() && create_info->table)
+ else if (likely(!result) && create_info->table)
{
/*
- Remember that tmp table creation was logged so that we know if
+ Remember that table creation was logged so that we know if
we should log a delete of it.
+ If create_info->table was not set, it's a normal table and
+ table_creation_was_logged will be set when the share is created.
*/
create_info->table->s->table_creation_was_logged= 1;
}
@@ -6893,7 +6899,7 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
}
if (field->vcol_info->is_in_partitioning_expr() ||
- field->flags & PART_KEY_FLAG)
+ field->flags & PART_KEY_FLAG || field->stored_in_db())
{
if (value_changes)
ha_alter_info->handler_flags|= ALTER_COLUMN_VCOL;
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index f43599d682b..323f693302f 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -4030,7 +4030,6 @@ uint32 Type_handler_temporal_result::max_display_length(const Item *item) const
return item->max_length;
}
-
uint32 Type_handler_string_result::max_display_length(const Item *item) const
{
return item->max_length;
@@ -4048,6 +4047,50 @@ uint32 Type_handler_bit::max_display_length(const Item *item) const
return item->max_length;
}
+/*************************************************************************/
+
+uint32
+Type_handler_decimal_result::Item_decimal_notation_int_digits(const Item *item)
+ const
+{
+ return item->decimal_int_part();
+}
+
+
+uint32
+Type_handler_temporal_result::Item_decimal_notation_int_digits(const Item *item)
+ const
+{
+ return item->decimal_int_part();
+}
+
+
+uint32
+Type_handler_bit::Item_decimal_notation_int_digits(const Item *item)
+ const
+{
+ return Bit_decimal_notation_int_digits(item);
+}
+
+
+uint32
+Type_handler_general_purpose_int::Item_decimal_notation_int_digits(
+ const Item *item) const
+{
+ return type_limits_int()->precision();
+}
+
+/*************************************************************************/
+
+/*
+ Decimal to binary digits ratio converges to log2(10) thus using 3 as
+ a divisor.
+*/
+uint32
+Type_handler_bit::Bit_decimal_notation_int_digits(const Item *item)
+{
+ return item->max_length/3+1;
+}
/*************************************************************************/
diff --git a/sql/sql_type.h b/sql/sql_type.h
index dda5768e753..3943a3f761f 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -3752,6 +3752,7 @@ public:
SORT_FIELD_ATTR *attr) const= 0;
virtual uint32 max_display_length(const Item *item) const= 0;
+ virtual uint32 Item_decimal_notation_int_digits(const Item *item) const { return 0; }
virtual uint32 calc_pack_length(uint32 length) const= 0;
virtual uint calc_key_length(const Column_definition &def) const;
virtual void Item_update_null_value(Item *item) const= 0;
@@ -4594,6 +4595,7 @@ public:
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const override;
uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
@@ -4908,6 +4910,7 @@ public:
{
return type_limits_int()->char_length();
}
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
bool partition_field_check(const LEX_CSTRING &field_name,
Item *item_expr) const override
{
@@ -4946,6 +4949,7 @@ public:
const Type_all_attributes *attr,
const st_value *value) const override;
uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
@@ -5043,6 +5047,12 @@ public:
Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
uchar *buff) const override;
uint32 max_display_length(const Item *item) const override;
+ /*
+ The next method returns 309 for long stringified doubles in scientific
+ notation, e.g. FORMAT('1e308', 2).
+ */
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override
+ { return 309; }
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
@@ -5472,6 +5482,8 @@ public:
return PROTOCOL_SEND_SHORT;
}
uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override
+ { return 4; };
uint32 max_display_length_for_field(const Conv_source &src) const override
{ return 4; }
uint32 calc_pack_length(uint32 length) const override { return 1; }
@@ -5522,6 +5534,8 @@ public:
return PROTOCOL_SEND_STRING;
}
uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
+ static uint32 Bit_decimal_notation_int_digits(const Item *item);
uint32 max_display_length_for_field(const Conv_source &src) const override;
uint32 calc_pack_length(uint32 length) const override { return length / 8; }
uint calc_key_length(const Column_definition &def) const override;
@@ -5634,6 +5648,8 @@ public:
}
bool type_can_have_auto_increment_attribute() const override { return true; }
uint32 max_display_length(const Item *item) const override { return 53; }
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override
+ { return 309; }
uint32 max_display_length_for_field(const Conv_source &src) const override
{ return 22; }
uint32 calc_pack_length(uint32 length) const override
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 1b589d941b2..9f298a51b72 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1262,7 +1262,7 @@ update_end:
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
- transactional_table, FALSE, FALSE, errcode))
+ transactional_table, FALSE, FALSE, errcode) > 0)
{
error=1; // Rollback update
}
@@ -2991,7 +2991,7 @@ bool multi_update::send_eof()
if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(),
thd->query_length(), transactional_tables, FALSE,
- FALSE, errcode))
+ FALSE, errcode) > 0)
local_error= 1; // Rollback update
thd->set_current_stmt_binlog_format(save_binlog_format);
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index ca66da1fd0d..2011abf79ba 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -698,7 +698,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
thd->reset_unsafe_warnings();
if (thd->binlog_query(THD::STMT_QUERY_TYPE,
buff.ptr(), buff.length(), FALSE, FALSE, FALSE,
- errcode))
+ errcode) > 0)
res= TRUE;
}
@@ -1498,6 +1498,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
privileges of top_view
*/
tbl->grant.want_privilege= SELECT_ACL;
+
/*
After unfolding the view we lose the list of tables referenced in it
(we will have only a list of underlying tables in case of MERGE
@@ -1548,6 +1549,18 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
views with subqueries in select list.
*/
view_main_select_tables= lex->first_select_lex()->table_list.first;
+ /*
+ Mergeable view can be used for inserting, so we move the flag down
+ */
+ if (table->for_insert_data)
+ {
+ for (TABLE_LIST *t= view_main_select_tables;
+ t;
+ t= t->next_local)
+ {
+ t->for_insert_data= TRUE;
+ }
+ }
/*
Let us set proper lock type for tables of the view's main
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e111b268e65..b06d2f5a80c 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -7836,6 +7836,7 @@ alter:
Lex->first_select_lex()->db=
(Lex->first_select_lex()->table_list.first)->db;
Lex->create_last_non_select_table= Lex->last_table();
+ Lex->mark_first_table_as_inserting();
}
alter_commands
{
@@ -13483,7 +13484,10 @@ insert:
Select->set_lock_for_tables($4, true);
}
insert_field_spec opt_insert_update opt_returning
- stmt_end {}
+ stmt_end
+ {
+ Lex->mark_first_table_as_inserting();
+ }
;
replace:
@@ -13497,7 +13501,10 @@ replace:
Select->set_lock_for_tables($4, true);
}
insert_field_spec opt_returning
- stmt_end {}
+ stmt_end
+ {
+ Lex->mark_first_table_as_inserting();
+ }
;
insert_start: {
@@ -15008,7 +15015,10 @@ load:
opt_xml_rows_identified_by
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
- stmt_end {}
+ stmt_end
+ {
+ Lex->mark_first_table_as_inserting();
+ }
;
data_or_xml:
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index c3727c4819d..c18acd3ef96 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -7799,6 +7799,7 @@ alter:
Lex->first_select_lex()->db=
(Lex->first_select_lex()->table_list.first)->db;
Lex->create_last_non_select_table= Lex->last_table();
+ Lex->mark_first_table_as_inserting();
}
alter_commands
{
@@ -13471,7 +13472,10 @@ insert:
Select->set_lock_for_tables($4, true);
}
insert_field_spec opt_insert_update opt_returning
- stmt_end {}
+ stmt_end
+ {
+ Lex->mark_first_table_as_inserting();
+ }
;
replace:
@@ -13485,7 +13489,10 @@ replace:
Select->set_lock_for_tables($4, true);
}
insert_field_spec opt_returning
- stmt_end {}
+ stmt_end
+ {
+ Lex->mark_first_table_as_inserting();
+ }
;
insert_start: {
@@ -15003,7 +15010,10 @@ load:
opt_xml_rows_identified_by
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
- stmt_end {}
+ stmt_end
+ {
+ Lex->mark_first_table_as_inserting();
+ }
;
data_or_xml:
diff --git a/sql/table.cc b/sql/table.cc
index 8dc4cc5e9a0..b745ce22946 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -695,7 +695,11 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
frmlen= read_length + sizeof(head);
share->init_from_binary_frm_image(thd, false, buf, frmlen);
- error_given= true; // init_from_binary_frm_image has already called my_error()
+ /*
+ Don't give any additional errors. If there would be a problem,
+ init_from_binary_frm_image would call my_error() itself.
+ */
+ error_given= true;
my_free(buf);
goto err_not_open;
@@ -704,6 +708,9 @@ err:
mysql_file_close(file, MYF(MY_WME));
err_not_open:
+ /* Mark that table was created earlier and thus should have been logged */
+ share->table_creation_was_logged= 1;
+
if (unlikely(share->error && !error_given))
{
share->open_errno= my_errno;
@@ -3324,6 +3331,8 @@ ret:
sql_copy);
DBUG_RETURN(HA_ERR_GENERIC);
}
+ /* Treat the table as normal table from binary logging point of view */
+ table_creation_was_logged= 1;
DBUG_RETURN(0);
}
diff --git a/sql/table.h b/sql/table.h
index 898c31c4aff..b9ab61e85fd 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -752,10 +752,15 @@ struct TABLE_SHARE
bool system; /* Set if system table (one record) */
bool not_usable_by_query_cache;
bool online_backup; /* Set if on-line backup supported */
+ /*
+ This is used by log tables, for tables that have their own internal
+ binary logging or for tables that doesn't support statement or row logging
+ */
bool no_replicate;
bool crashed;
bool is_view;
bool can_cmp_whole_record;
+ /* This is set for temporary tables where CREATE was binary logged */
bool table_creation_was_logged;
bool non_determinstic_insert;
bool vcols_need_refixing;
@@ -1989,7 +1994,8 @@ struct TABLE_LIST
prelocking_types prelocking_type,
TABLE_LIST *belong_to_view_arg,
uint8 trg_event_map_arg,
- TABLE_LIST ***last_ptr)
+ TABLE_LIST ***last_ptr,
+ my_bool insert_data)
{
init_one_table(db_arg, table_name_arg, alias_arg, lock_type_arg);
@@ -2004,6 +2010,7 @@ struct TABLE_LIST
**last_ptr= this;
prev_global= *last_ptr;
*last_ptr= &next_global;
+ for_insert_data= insert_data;
}
@@ -2430,6 +2437,8 @@ struct TABLE_LIST
return period_conditions.is_set();
}
+ my_bool for_insert_data;
+
/**
@brief
Find the bottom in the chain of embedded table VIEWs.
diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc
index cfa709b1055..a81503a50da 100644
--- a/sql/wsrep_binlog.cc
+++ b/sql/wsrep_binlog.cc
@@ -123,7 +123,7 @@ static int wsrep_write_cache_inc(THD* const thd,
DBUG_ENTER("wsrep_write_cache_inc");
my_off_t const saved_pos(my_b_tell(cache));
- if (reinit_io_cache(cache, READ_CACHE, thd->wsrep_sr().bytes_certified(), 0, 0))
+ if (reinit_io_cache(cache, READ_CACHE, thd->wsrep_sr().log_position(), 0, 0))
{
WSREP_ERROR("failed to initialize io-cache");
DBUG_RETURN(1);;
@@ -158,7 +158,7 @@ static int wsrep_write_cache_inc(THD* const thd,
}
if (ret == 0)
{
- assert(total_length + thd->wsrep_sr().bytes_certified() == saved_pos);
+ assert(total_length + thd->wsrep_sr().log_position() == saved_pos);
}
cleanup:
diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc
index 8d58f62bd03..696a097db21 100644
--- a/sql/wsrep_client_service.cc
+++ b/sql/wsrep_client_service.cc
@@ -137,7 +137,8 @@ void Wsrep_client_service::cleanup_transaction()
}
-int Wsrep_client_service::prepare_fragment_for_replication(wsrep::mutable_buffer& buffer)
+int Wsrep_client_service::prepare_fragment_for_replication(
+ wsrep::mutable_buffer& buffer, size_t& log_position)
{
DBUG_ASSERT(m_thd == current_thd);
THD* thd= m_thd;
@@ -151,7 +152,7 @@ int Wsrep_client_service::prepare_fragment_for_replication(wsrep::mutable_buffer
}
const my_off_t saved_pos(my_b_tell(cache));
- if (reinit_io_cache(cache, READ_CACHE, thd->wsrep_sr().bytes_certified(), 0, 0))
+ if (reinit_io_cache(cache, READ_CACHE, thd->wsrep_sr().log_position(), 0, 0))
{
DBUG_RETURN(1);
}
@@ -185,6 +186,7 @@ int Wsrep_client_service::prepare_fragment_for_replication(wsrep::mutable_buffer
while (cache->file >= 0 && (length= my_b_fill(cache)));
}
DBUG_ASSERT(total_length == buffer.size());
+ log_position= saved_pos;
cleanup:
if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
{
diff --git a/sql/wsrep_client_service.h b/sql/wsrep_client_service.h
index b1695b7aedf..aa58d99c3cf 100644
--- a/sql/wsrep_client_service.h
+++ b/sql/wsrep_client_service.h
@@ -43,7 +43,7 @@ public:
void cleanup_transaction();
bool statement_allowed_for_streaming() const;
size_t bytes_generated() const;
- int prepare_fragment_for_replication(wsrep::mutable_buffer&);
+ int prepare_fragment_for_replication(wsrep::mutable_buffer&, size_t&);
int remove_fragments();
void emergency_shutdown()
{ throw wsrep::not_implemented_error(); }
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 2ea434c092b..b5adef17442 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -66,7 +66,7 @@ const char *wsrep_thd_exec_mode_str(THD *)
{ return NULL; }
const char *wsrep_thd_query(const THD *)
-{ return 0; }
+{ return "NULL"; }
const char *wsrep_thd_query_state_str(THD *)
{ return 0; }
diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc
index 84c89ccb705..987a1765dcf 100644
--- a/sql/wsrep_high_priority_service.cc
+++ b/sql/wsrep_high_priority_service.cc
@@ -222,6 +222,12 @@ const wsrep::transaction& Wsrep_high_priority_service::transaction() const
DBUG_RETURN(m_thd->wsrep_trx());
}
+int Wsrep_high_priority_service::next_fragment(const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER(" Wsrep_high_priority_service::next_fragment");
+ DBUG_RETURN(m_thd->wsrep_cs().next_fragment(ws_meta));
+}
+
int Wsrep_high_priority_service::adopt_transaction(
const wsrep::transaction& transaction)
{
@@ -242,7 +248,8 @@ int Wsrep_high_priority_service::adopt_transaction(
int Wsrep_high_priority_service::append_fragment_and_commit(
const wsrep::ws_handle& ws_handle,
const wsrep::ws_meta& ws_meta,
- const wsrep::const_buffer& data)
+ const wsrep::const_buffer& data,
+ const wsrep::xid& xid WSREP_UNUSED)
{
DBUG_ENTER("Wsrep_high_priority_service::append_fragment_and_commit");
int ret= start_transaction(ws_handle, ws_meta);
diff --git a/sql/wsrep_high_priority_service.h b/sql/wsrep_high_priority_service.h
index 5657a2e82fc..a14498037d7 100644
--- a/sql/wsrep_high_priority_service.h
+++ b/sql/wsrep_high_priority_service.h
@@ -34,13 +34,15 @@ public:
~Wsrep_high_priority_service();
int start_transaction(const wsrep::ws_handle&,
const wsrep::ws_meta&);
+ int next_fragment(const wsrep::ws_meta&);
const wsrep::transaction& transaction() const;
int adopt_transaction(const wsrep::transaction&);
int apply_write_set(const wsrep::ws_meta&, const wsrep::const_buffer&,
wsrep::mutable_buffer&) = 0;
int append_fragment_and_commit(const wsrep::ws_handle&,
const wsrep::ws_meta&,
- const wsrep::const_buffer&);
+ const wsrep::const_buffer&,
+ const wsrep::xid&);
int remove_fragments(const wsrep::ws_meta&);
int commit(const wsrep::ws_handle&, const wsrep::ws_meta&);
int rollback(const wsrep::ws_handle&, const wsrep::ws_meta&);
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index a6f9d3a6b17..e35d13be4c6 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -627,6 +627,7 @@ static wsrep::gtid wsrep_server_initial_position()
*/
static void wsrep_init_provider_status_variables()
{
+ wsrep_inited= 1;
const wsrep::provider& provider=
Wsrep_server_state::instance().provider();
strncpy(provider_name,
@@ -711,9 +712,7 @@ int wsrep_init()
WSREP_ERROR("wsrep::init() failed: %d, must shutdown", err);
}
else
- {
wsrep_init_provider_status_variables();
- }
return err;
}
@@ -749,7 +748,6 @@ int wsrep_init()
Wsrep_server_state::instance().unload_provider();
return 1;
}
- wsrep_inited= 1;
wsrep_init_provider_status_variables();
wsrep_capabilities_export(Wsrep_server_state::instance().provider().capabilities(),
@@ -1705,26 +1703,6 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
}
}
-#if UNUSED /* 323f269d4099 (Jan Lindström 2018-07-19) */
-static const char* wsrep_get_query_or_msg(const THD* thd)
-{
- switch(thd->lex->sql_command)
- {
- case SQLCOM_CREATE_USER:
- return "CREATE USER";
- case SQLCOM_GRANT:
- return "GRANT";
- case SQLCOM_REVOKE:
- return "REVOKE";
- case SQLCOM_SET_OPTION:
- if (thd->lex->definer)
- return "SET PASSWORD";
- /* fallthrough */
- default:
- return thd->query();
- }
-}
-#endif //UNUSED
static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
{
@@ -2662,7 +2640,7 @@ void* start_wsrep_THD(void *arg)
need to know the start of the stack so that we could check for
stack overruns.
*/
- DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n",
+ DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld",
(long long)thd->thread_id));
/* now that we've called my_thread_init(), it is safe to call DBUG_* */
diff --git a/sql/wsrep_storage_service.cc b/sql/wsrep_storage_service.cc
index 6dfe3eee448..2ad817fe25a 100644
--- a/sql/wsrep_storage_service.cc
+++ b/sql/wsrep_storage_service.cc
@@ -100,7 +100,8 @@ void Wsrep_storage_service::adopt_transaction(const wsrep::transaction& transact
int Wsrep_storage_service::append_fragment(const wsrep::id& server_id,
wsrep::transaction_id transaction_id,
int flags,
- const wsrep::const_buffer& data)
+ const wsrep::const_buffer& data,
+ const wsrep::xid& xid WSREP_UNUSED)
{
DBUG_ENTER("Wsrep_storage_service::append_fragment");
DBUG_ASSERT(m_thd == current_thd);
diff --git a/sql/wsrep_storage_service.h b/sql/wsrep_storage_service.h
index 6208300930f..f39543a89bc 100644
--- a/sql/wsrep_storage_service.h
+++ b/sql/wsrep_storage_service.h
@@ -33,7 +33,8 @@ public:
int append_fragment(const wsrep::id&,
wsrep::transaction_id,
int flags,
- const wsrep::const_buffer&);
+ const wsrep::const_buffer&,
+ const wsrep::xid&);
int update_fragment_meta(const wsrep::ws_meta&);
int remove_fragments();
int commit(const wsrep::ws_handle&, const wsrep::ws_meta&);