summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/backup.cc6
-rw-r--r--sql/derived_handler.cc4
-rw-r--r--sql/field.h5
-rw-r--r--sql/filesort.cc29
-rw-r--r--sql/ha_partition.cc4
-rw-r--r--sql/handle_connections_win.cc66
-rw-r--r--sql/handler.cc157
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.h19
-rw-r--r--sql/item_cmpfunc.cc33
-rw-r--r--sql/item_cmpfunc.h19
-rw-r--r--sql/item_func.cc9
-rw-r--r--sql/item_geofunc.cc16
-rw-r--r--sql/item_jsonfunc.cc8
-rw-r--r--sql/item_jsonfunc.h3
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/item_subselect.h2
-rw-r--r--sql/item_timefunc.cc4
-rw-r--r--sql/item_timefunc.h2
-rw-r--r--sql/log.cc73
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/log_event.h6
-rw-r--r--sql/log_event_client.cc10
-rw-r--r--sql/mf_iocache_encr.cc10
-rw-r--r--sql/my_decimal.h6
-rw-r--r--sql/mysqld.cc19
-rw-r--r--sql/opt_range.cc20
-rw-r--r--sql/opt_subselect.cc13
-rw-r--r--sql/opt_sum.cc24
-rw-r--r--sql/protocol.cc8
-rw-r--r--sql/select_handler.cc77
-rw-r--r--sql/select_handler.h20
-rw-r--r--sql/session_tracker.cc3
-rw-r--r--sql/set_var.cc3
-rw-r--r--sql/share/errmsg-utf8.txt15
-rw-r--r--sql/sp_head.cc3
-rw-r--r--sql/sql_acl.cc91
-rw-r--r--sql/sql_base.cc44
-rw-r--r--sql/sql_class.cc72
-rw-r--r--sql/sql_class.h28
-rw-r--r--sql/sql_delete.cc3
-rw-r--r--sql/sql_insert.cc109
-rw-r--r--sql/sql_insert.h10
-rw-r--r--sql/sql_lex.cc16
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_parse.cc136
-rw-r--r--sql/sql_parse.h2
-rw-r--r--sql/sql_prepare.cc266
-rw-r--r--sql/sql_reload.cc10
-rw-r--r--sql/sql_rename.cc3
-rw-r--r--sql/sql_select.cc62
-rw-r--r--sql/sql_select.h26
-rw-r--r--sql/sql_show.cc175
-rw-r--r--sql/sql_sort.h50
-rw-r--r--sql/sql_string.cc6
-rw-r--r--sql/sql_string.h5
-rw-r--r--sql/sql_table.cc342
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_type.cc86
-rw-r--r--sql/sql_type.h61
-rw-r--r--sql/sql_udf.cc148
-rw-r--r--sql/sql_udf.h8
-rw-r--r--sql/sql_update.cc17
-rw-r--r--sql/sql_yacc.yy160
-rw-r--r--sql/sys_vars.ic8
-rw-r--r--sql/table.cc43
-rw-r--r--sql/table.h1
-rw-r--r--sql/threadpool_common.cc14
-rw-r--r--sql/wsrep_mysqld.h3
-rw-r--r--sql/wsrep_sst.cc42
-rw-r--r--sql/wsrep_var.cc3
-rw-r--r--sql/xa.cc2
73 files changed, 1857 insertions, 905 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 4be129ac9d0..f6ddfbfaf38 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -193,7 +193,7 @@ DTRACE_INSTRUMENT(sql)
TARGET_LINK_LIBRARIES(sql
mysys mysys_ssl dbug strings vio pcre2-8
tpool
- ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT}
+ ${LIBWRAP} ${LIBCRYPT} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT}
${SSL_LIBRARIES}
${LIBSYSTEMD})
diff --git a/sql/backup.cc b/sql/backup.cc
index 02570dfd30d..e89f9a108a7 100644
--- a/sql/backup.cc
+++ b/sql/backup.cc
@@ -378,7 +378,13 @@ bool backup_reset_alter_copy_lock(THD *thd)
bool backup_lock(THD *thd, TABLE_LIST *table)
{
+ /* We should leave the previous table unlocked in case of errors */
backup_unlock(thd);
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ return 1;
+ }
table->mdl_request.duration= MDL_EXPLICIT;
if (thd->mdl_context.acquire_lock(&table->mdl_request,
thd->variables.lock_wait_timeout))
diff --git a/sql/derived_handler.cc b/sql/derived_handler.cc
index 76fd736de2b..f48b95cbf76 100644
--- a/sql/derived_handler.cc
+++ b/sql/derived_handler.cc
@@ -120,8 +120,6 @@ void derived_handler::set_derived(TABLE_LIST *tbl)
table= tbl->table;
unit= tbl->derived;
select= unit->first_select();
- tmp_table_param= select->next_select() ?
- ((select_unit *)(unit->result))->get_tmp_table_param() :
- &select->join->tmp_table_param;
+ tmp_table_param= ((select_unit *)(unit->result))->get_tmp_table_param();
}
diff --git a/sql/field.h b/sql/field.h
index be4d279ce61..dfc02149f9d 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1151,8 +1151,9 @@ public:
virtual void reset_fields() {}
const uchar *ptr_in_record(const uchar *record) const
{
- my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]);
- return ptr + l_offset;
+ my_ptrdiff_t l_offset= (my_ptrdiff_t) (ptr - table->record[0]);
+ DBUG_ASSERT(l_offset >= 0 && table->s->rec_buff_length - l_offset > 0);
+ return record + l_offset;
}
virtual int set_default();
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 2a713ecf97b..0337325b544 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -2208,6 +2208,12 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys)
length=0;
uint nullable_cols=0;
+ if (sort_keys->is_parameters_computed())
+ {
+ *allow_packing_for_sortkeys= sort_keys->using_packed_sortkeys();
+ return sort_keys->get_sort_length_with_memcmp_values();
+ }
+
for (SORT_FIELD *sortorder= sort_keys->begin();
sortorder != sort_keys->end();
sortorder++)
@@ -2218,12 +2224,11 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys)
{
Field *field= sortorder->field;
CHARSET_INFO *cs= sortorder->field->sort_charset();
- sortorder->set_length_and_original_length(thd, field->sort_length());
-
- sortorder->suffix_length= sortorder->field->sort_suffix_length();
sortorder->type= field->is_packable() ?
SORT_FIELD_ATTR::VARIABLE_SIZE :
SORT_FIELD_ATTR::FIXED_SIZE;
+ sortorder->set_length_and_original_length(thd, field->sort_length());
+ sortorder->suffix_length= sortorder->field->sort_suffix_length();
sortorder->cs= cs;
if (use_strnxfrm((cs=sortorder->field->sort_charset())))
@@ -2242,11 +2247,11 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys)
}
else
{
- sortorder->item->type_handler()->sort_length(thd, sortorder->item,
- sortorder);
sortorder->type= sortorder->item->type_handler()->is_packable() ?
SORT_FIELD_ATTR::VARIABLE_SIZE :
SORT_FIELD_ATTR::FIXED_SIZE;
+ sortorder->item->type_handler()->sort_length(thd, sortorder->item,
+ sortorder);
sortorder->cs= sortorder->item->collation.collation;
if (sortorder->is_variable_sized() && allow_packing_for_keys)
{
@@ -2259,8 +2264,11 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys)
if ((sortorder->maybe_null= sortorder->item->maybe_null))
nullable_cols++; // Place for NULL marker
}
- set_if_smaller(sortorder->length, thd->variables.max_sort_length);
- set_if_smaller(sortorder->original_length, thd->variables.max_sort_length);
+ if (sortorder->is_variable_sized())
+ {
+ set_if_smaller(sortorder->length, thd->variables.max_sort_length);
+ set_if_smaller(sortorder->original_length, thd->variables.max_sort_length);
+ }
length+=sortorder->length;
sort_keys->increment_size_of_packable_fields(sortorder->length_bytes);
@@ -2269,6 +2277,8 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys)
// add bytes for nullable_cols
sort_keys->increment_original_sort_length(nullable_cols);
*allow_packing_for_sortkeys= allow_packing_for_keys;
+ sort_keys->set_sort_length_with_memcmp_values(length + nullable_cols);
+ sort_keys->set_parameters_computed(true);
DBUG_PRINT("info",("sort_length: %d",length));
return length + nullable_cols;
}
@@ -2527,7 +2537,7 @@ void Sort_param::try_to_pack_sortkeys()
return;
const uint sz= Sort_keys::size_of_length_field;
- uint sort_len= sort_keys->get_sort_length();
+ uint sort_len= sort_keys->get_sort_length_with_original_values();
/*
Heuristic introduced, skip packing sort keys if saving less than 128 bytes
@@ -2759,7 +2769,8 @@ bool SORT_FIELD_ATTR::check_if_packing_possible(THD *thd) const
void SORT_FIELD_ATTR::set_length_and_original_length(THD *thd, uint length_arg)
{
length= length_arg;
- set_if_smaller(length, thd->variables.max_sort_length);
+ if (is_variable_sized())
+ set_if_smaller(length, thd->variables.max_sort_length);
original_length= length_arg;
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index ece9d05c4fd..7f00a194698 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -2069,6 +2069,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
DBUG_ASSERT(part_elem->part_state == PART_TO_BE_REORGED);
part_elem->part_state= PART_TO_BE_DROPPED;
}
+ DBUG_ASSERT(m_new_file == 0);
m_new_file= new_file_array;
if (unlikely((error= copy_partitions(copied, deleted))))
{
@@ -2077,6 +2078,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
They will later be deleted through the ddl-log.
*/
cleanup_new_partition(part_count);
+ m_new_file= 0;
}
DBUG_RETURN(error);
}
@@ -2166,6 +2168,8 @@ int ha_partition::copy_partitions(ulonglong * const copied,
file->ha_rnd_end();
reorg_part++;
}
+ DBUG_EXECUTE_IF("debug_abort_copy_partitions",
+ DBUG_RETURN(HA_ERR_UNSUPPORTED); );
DBUG_RETURN(FALSE);
error:
m_reorged_file[reorg_part]->ha_rnd_end();
diff --git a/sql/handle_connections_win.cc b/sql/handle_connections_win.cc
index b12ea583230..debbce998fa 100644
--- a/sql/handle_connections_win.cc
+++ b/sql/handle_connections_win.cc
@@ -309,6 +309,64 @@ retry :
}
};
+/*
+ Create a security descriptor for pipe.
+ - Use low integrity level, so that it is possible to connect
+ from any process.
+ - Give current user read/write access to pipe.
+ - Give Everyone read/write access to pipe minus FILE_CREATE_PIPE_INSTANCE
+*/
+static void init_pipe_security_descriptor()
+{
+#define SDDL_FMT "S:(ML;; NW;;; LW) D:(A;; 0x%08x;;; WD)(A;; FRFW;;; %s)"
+#define EVERYONE_PIPE_ACCESS_MASK \
+ (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | \
+ SYNCHRONIZE | FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
+
+#ifndef SECURITY_MAX_SID_STRING_CHARACTERS
+/* Old SDK does not have this constant */
+#define SECURITY_MAX_SID_STRING_CHARACTERS 187
+#endif
+
+ /*
+ Figure out SID of the user that runs the server, then create SDDL string
+ for pipe permissions, and convert it to the security descriptor.
+ */
+ char sddl_string[sizeof(SDDL_FMT) + 8 + SECURITY_MAX_SID_STRING_CHARACTERS];
+ struct
+ {
+ TOKEN_USER token_user;
+ BYTE buffer[SECURITY_MAX_SID_SIZE];
+ } token_buffer;
+ HANDLE token;
+ DWORD tmp;
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
+ goto fail;
+
+ if (!GetTokenInformation(token, TokenUser, &token_buffer,
+ (DWORD) sizeof(token_buffer), &tmp))
+ goto fail;
+
+ CloseHandle(token);
+
+ char *current_user_string_sid;
+ if (!ConvertSidToStringSid(token_buffer.token_user.User.Sid,
+ &current_user_string_sid))
+ goto fail;
+
+ snprintf(sddl_string, sizeof(sddl_string), SDDL_FMT,
+ EVERYONE_PIPE_ACCESS_MASK, current_user_string_sid);
+ LocalFree(current_user_string_sid);
+
+ if (ConvertStringSecurityDescriptorToSecurityDescriptor(sddl_string,
+ SDDL_REVISION_1, &pipe_security.lpSecurityDescriptor, 0))
+ return;
+
+fail:
+ sql_perror("Can't start server : Initialize security descriptor");
+ unireg_abort(1);
+}
/**
Pipe Listener.
@@ -337,13 +395,7 @@ struct Pipe_Listener : public Listener
{
snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\%s", mysqld_unix_port);
open_mode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
- if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
- "S:(ML;; NW;;; LW) D:(A;; FRFW;;; WD)",
- 1, &pipe_security.lpSecurityDescriptor, NULL))
- {
- sql_perror("Can't start server : Initialize security descriptor");
- unireg_abort(1);
- }
+ init_pipe_security_descriptor();
pipe_security.nLength= sizeof(SECURITY_ATTRIBUTES);
pipe_security.bInheritHandle= FALSE;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 64d13d1601f..01825c13da6 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -188,7 +188,7 @@ private:
static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans,
- bool is_real_trans, bool rw_trans);
+ bool is_real_trans);
static plugin_ref ha_default_plugin(THD *thd)
@@ -1621,9 +1621,37 @@ int ha_commit_trans(THD *thd, bool all)
/* rw_trans is TRUE when we in a transaction changing data */
bool rw_trans= is_real_trans &&
(rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U));
+ MDL_request mdl_backup;
DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d",
is_real_trans, rw_trans, rw_ha_count));
+ if (rw_trans)
+ {
+ /*
+ Acquire a metadata lock which will ensure that COMMIT is blocked
+ by an active FLUSH TABLES WITH READ LOCK (and vice versa:
+ COMMIT in progress blocks FTWRL).
+
+ We allow the owner of FTWRL to COMMIT; we assume that it knows
+ what it does.
+ */
+ MDL_REQUEST_INIT(&mdl_backup, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_EXPLICIT);
+
+ if (!WSREP(thd))
+ {
+ if (thd->mdl_context.acquire_lock(&mdl_backup,
+ thd->variables.lock_wait_timeout))
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1);
+ ha_rollback_trans(thd, all);
+ DBUG_RETURN(1);
+ }
+ thd->backup_commit_lock= &mdl_backup;
+ }
+ DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock");
+ }
+
if (rw_trans &&
opt_readonly &&
!(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) &&
@@ -1663,7 +1691,7 @@ int ha_commit_trans(THD *thd, bool all)
// Here, the call will not commit inside InnoDB. It is only working
// around closing thd->transaction.stmt open by TR_table::open().
if (all)
- commit_one_phase_2(thd, false, &thd->transaction->stmt, false, false);
+ commit_one_phase_2(thd, false, &thd->transaction->stmt, false);
}
}
#endif
@@ -1683,7 +1711,7 @@ int ha_commit_trans(THD *thd, bool all)
goto wsrep_err;
}
#endif /* WITH_WSREP */
- error= ha_commit_one_phase(thd, all, rw_trans);
+ error= ha_commit_one_phase(thd, all);
#ifdef WITH_WSREP
// Here in case of error we must return 2 for inconsistency
if (run_wsrep_hooks && !error)
@@ -1720,7 +1748,7 @@ int ha_commit_trans(THD *thd, bool all)
if (!is_real_trans)
{
- error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans);
+ error= commit_one_phase_2(thd, all, trans, is_real_trans);
goto done;
}
@@ -1754,7 +1782,7 @@ int ha_commit_trans(THD *thd, bool all)
DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order");
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
- error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans) ? 2 : 0;
+ error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
#ifdef WITH_WSREP
if (run_wsrep_hooks &&
(error || (error = wsrep_after_commit(thd, all))))
@@ -1828,6 +1856,17 @@ err:
thd->rgi_slave->is_parallel_exec);
}
end:
+ if (mdl_backup.ticket)
+ {
+ /*
+ We do not always immediately release transactional locks
+ after ha_commit_trans() (see uses of ha_enable_transaction()),
+ thus we release the commit blocker lock as soon as it's
+ not needed.
+ */
+ thd->mdl_context.release_lock(mdl_backup.ticket);
+ }
+ thd->backup_commit_lock= 0;
#ifdef WITH_WSREP
if (wsrep_is_active(thd) && is_real_trans && !error &&
(rw_ha_count == 0 || all) &&
@@ -1842,8 +1881,8 @@ end:
/**
@note
- This function does not care about global read lock. A caller should.
- However backup locks are handled in commit_one_phase_2.
+ This function does not care about global read lock or backup locks,
+ the caller should.
@param[in] all Is set in case of explicit commit
(COMMIT statement), or implicit commit
@@ -1852,7 +1891,7 @@ end:
autocommit=1.
*/
-int ha_commit_one_phase(THD *thd, bool all, bool rw_trans)
+int ha_commit_one_phase(THD *thd, bool all)
{
THD_TRANS *trans=all ? &thd->transaction->all : &thd->transaction->stmt;
/*
@@ -1878,48 +1917,21 @@ int ha_commit_one_phase(THD *thd, bool all, bool rw_trans)
if ((res= thd->wait_for_prior_commit()))
DBUG_RETURN(res);
}
- res= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans);
+ res= commit_one_phase_2(thd, all, trans, is_real_trans);
DBUG_RETURN(res);
}
static int
-commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans,
- bool rw_trans)
+commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
{
int error= 0;
uint count= 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
- MDL_request mdl_request;
- mdl_request.ticket= 0;
DBUG_ENTER("commit_one_phase_2");
if (is_real_trans)
DEBUG_SYNC(thd, "commit_one_phase_2");
- if (rw_trans)
- {
- /*
- Acquire a metadata lock which will ensure that COMMIT is blocked
- by an active FLUSH TABLES WITH READ LOCK (and vice versa:
- COMMIT in progress blocks FTWRL).
-
- We allow the owner of FTWRL to COMMIT; we assume that it knows
- what it does.
- */
- MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
- MDL_EXPLICIT);
-
- if (!WSREP(thd) &&
- thd->mdl_context.acquire_lock(&mdl_request,
- thd->variables.lock_wait_timeout))
- {
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1);
- ha_rollback_trans(thd, all);
- DBUG_RETURN(1);
- }
- DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock");
- }
-
if (ha_info)
{
for (; ha_info; ha_info= ha_info_next)
@@ -1948,16 +1960,6 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans,
#endif
}
}
- if (mdl_request.ticket)
- {
- /*
- We do not always immediately release transactional locks
- after ha_commit_trans() (see uses of ha_enable_transaction()),
- thus we release the commit blocker lock as soon as it's
- not needed.
- */
- thd->mdl_context.release_lock(mdl_request.ticket);
- }
/* Free resources and perform other cleanup even for 'empty' transactions. */
if (is_real_trans)
@@ -2314,7 +2316,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
for (int i=0; i < got; i ++)
{
- my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ?
+ my_xid x= IF_WSREP(wsrep_is_wsrep_xid(&info->list[i]) ?
wsrep_xid_seqno(&info->list[i]) :
info->list[i].get_my_xid(),
info->list[i].get_my_xid());
@@ -2762,6 +2764,9 @@ int ha_delete_table(THD *thd, handlerton *hton, const char *path,
if (hton == NULL || hton == view_pseudo_hton)
DBUG_RETURN(0);
+ if (ha_check_if_updates_are_ignored(thd, hton, "DROP"))
+ DBUG_RETURN(0);
+
error= hton->drop_table(hton, path);
if (error > 0)
{
@@ -2799,7 +2804,8 @@ int ha_delete_table(THD *thd, handlerton *hton, const char *path,
error= -1;
}
}
-
+ if (error)
+ DBUG_PRINT("exit", ("error: %d", error));
DBUG_RETURN(error);
}
@@ -5006,7 +5012,8 @@ static my_bool delete_table_force(THD *thd, plugin_ref plugin, void *arg)
handlerton *hton = plugin_hton(plugin);
st_force_drop_table_params *param = (st_force_drop_table_params *)arg;
- if (param->discovering == (hton->discover_table != NULL))
+ if (param->discovering == (hton->discover_table != NULL) &&
+ !(thd->slave_thread && (hton->flags & HTON_IGNORE_UPDATES)))
{
int error;
error= ha_delete_table(thd, hton, param->path, param->db, param->alias, 0);
@@ -6316,6 +6323,7 @@ extern "C" check_result_t handler_index_cond_check(void* h_arg)
THD *thd= h->table->in_use;
check_result_t res;
+ DEBUG_SYNC(thd, "handler_index_cond_check");
enum thd_kill_levels abort_at= h->has_rollback() ?
THD_ABORT_SOFTLY : THD_ABORT_ASAP;
if (thd_kill_level(thd) > abort_at)
@@ -6349,6 +6357,7 @@ check_result_t handler_rowid_filter_check(void *h_arg)
if (!h->pushed_idx_cond)
{
THD *thd= h->table->in_use;
+ DEBUG_SYNC(thd, "handler_rowid_filter_check");
enum thd_kill_levels abort_at= h->has_transactions() ?
THD_ABORT_SOFTLY : THD_ABORT_ASAP;
if (thd_kill_level(thd) > abort_at)
@@ -6938,7 +6947,7 @@ int handler::ha_check_overlaps(const uchar *old_data, const uchar* new_data)
uchar *record_buffer= lookup_buffer + table_share->max_unique_length
+ table_share->null_fields;
- // Needs to compare record refs later is old_row_found()
+ // Needed to compare record refs later
if (is_update)
position(old_data);
@@ -6994,12 +7003,8 @@ int handler::ha_check_overlaps(const uchar *old_data, const uchar* new_data)
/* In case of update it could happen that the nearest neighbour is
a record we are updating. It means, that there are no overlaps
from this side.
-
- An assumption is made that during update we always have the last
- fetched row in old_data. Therefore, comparing ref's is enough
*/
DBUG_ASSERT(lookup_handler != this);
- DBUG_ASSERT(inited != NONE);
DBUG_ASSERT(ref_length == lookup_handler->ref_length);
lookup_handler->position(record_buffer);
@@ -7124,16 +7129,17 @@ int handler::ha_write_row(const uchar *buf)
if ((error= ha_check_overlaps(NULL, buf)))
DBUG_RETURN(error);
- MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
- mark_trx_read_write();
- increment_statistics(&SSV::ha_write_count);
-
if (table->s->long_unique_table && this == table->file)
{
DBUG_ASSERT(inited == NONE || lookup_handler != this);
if ((error= check_duplicate_long_entries(buf)))
DBUG_RETURN(error);
}
+
+ MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
+ mark_trx_read_write();
+ increment_statistics(&SSV::ha_write_count);
+
TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error,
{ error= write_row(buf); })
@@ -7173,17 +7179,19 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data)
DBUG_ASSERT(new_data == table->record[0]);
DBUG_ASSERT(old_data == table->record[1]);
- if ((error= ha_check_overlaps(old_data, new_data)))
+ uint saved_status= table->status;
+ error= ha_check_overlaps(old_data, new_data);
+
+ if (!error && table->s->long_unique_table && this == table->file)
+ error= check_duplicate_long_entries_update(new_data);
+ table->status= saved_status;
+
+ if (error)
return error;
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_update_count);
- if (table->s->long_unique_table && this == table->file &&
- (error= check_duplicate_long_entries_update(new_data)))
- {
- return error;
- }
TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0,
{ error= update_row(old_data, new_data);})
@@ -8075,6 +8083,8 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_
TABLE_LIST &src_table, TABLE_LIST &table)
{
List_iterator<Create_field> it(alter_info.create_list);
+ List_iterator<Key> key_it(alter_info.key_list);
+ List_iterator<Key_part_spec> kp_it;
Create_field *f, *f_start=NULL, *f_end= NULL;
DBUG_ASSERT(alter_info.create_list.elements > 2);
@@ -8089,6 +8099,23 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_
it.remove();
remove--;
}
+ key_it.rewind();
+ while (Key *key= key_it++)
+ {
+ kp_it.init(key->columns);
+ while (Key_part_spec *kp= kp_it++)
+ {
+ if (0 == lex_string_cmp(system_charset_info, &kp->field_name,
+ &f->field_name))
+ {
+ kp_it.remove();
+ }
+ }
+ if (0 == key->columns.elements)
+ {
+ key_it.remove();
+ }
+ }
}
DBUG_ASSERT(remove == 0);
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
diff --git a/sql/handler.h b/sql/handler.h
index 9ab84794277..b106b460c70 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -5179,7 +5179,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache);
/* transactions: interface to handlerton functions */
int ha_start_consistent_snapshot(THD *thd);
int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
-int ha_commit_one_phase(THD *thd, bool all, bool rw_trans);
+int ha_commit_one_phase(THD *thd, bool all);
int ha_commit_trans(THD *thd, bool all);
int ha_rollback_trans(THD *thd, bool all);
int ha_prepare(THD *thd);
diff --git a/sql/item.h b/sql/item.h
index 19b7b5d03e9..fb480b4c578 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -120,20 +120,19 @@ enum precedence {
XOR_PRECEDENCE, // XOR
AND_PRECEDENCE, // AND, &&
NOT_PRECEDENCE, // NOT (unless HIGH_NOT_PRECEDENCE)
- BETWEEN_PRECEDENCE, // BETWEEN, CASE, WHEN, THEN, ELSE
- CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
+ CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS
+ BETWEEN_PRECEDENCE, // BETWEEN
+ IN_PRECEDENCE, // IN, LIKE, REGEXP
BITOR_PRECEDENCE, // |
BITAND_PRECEDENCE, // &
SHIFT_PRECEDENCE, // <<, >>
- ADDINTERVAL_PRECEDENCE, // first argument in +INTERVAL
+ INTERVAL_PRECEDENCE, // first argument in +INTERVAL
ADD_PRECEDENCE, // +, -
MUL_PRECEDENCE, // *, /, DIV, %, MOD
BITXOR_PRECEDENCE, // ^
PIPES_PRECEDENCE, // || (if PIPES_AS_CONCAT)
- NEG_PRECEDENCE, // unary -, ~
- BANG_PRECEDENCE, // !, NOT (if HIGH_NOT_PRECEDENCE)
+ NEG_PRECEDENCE, // unary -, ~, !, NOT (if HIGH_NOT_PRECEDENCE)
COLLATE_PRECEDENCE, // BINARY, COLLATE
- INTERVAL_PRECEDENCE, // INTERVAL
DEFAULT_PRECEDENCE,
HIGHEST_PRECEDENCE
};
@@ -1716,6 +1715,8 @@ public:
mysql_register_view().
*/
virtual enum precedence precedence() const { return DEFAULT_PRECEDENCE; }
+ enum precedence higher_precedence() const
+ { return (enum precedence)(precedence() + 1); }
void print_parenthesised(String *str, enum_query_type query_type,
enum precedence parent_prec);
/**
@@ -5439,7 +5440,11 @@ public:
{
(*ref)->restore_to_before_no_rows_in_result();
}
- virtual void print(String *str, enum_query_type query_type);
+ void print(String *str, enum_query_type query_type);
+ enum precedence precedence() const
+ {
+ return ref ? (*ref)->precedence() : DEFAULT_PRECEDENCE;
+ }
void cleanup();
Item_field *field_for_view_update()
{ return (*ref)->field_for_view_update(); }
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index c753b963fd4..83eb605f463 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -868,6 +868,8 @@ int Arg_comparator::compare_decimal()
{
if (set_null)
owner->null_value= 0;
+ val1.round_self_if_needed((*a)->decimals, HALF_UP);
+ val2.round_self_if_needed((*b)->decimals, HALF_UP);
return val1.cmp(val2);
}
}
@@ -890,6 +892,8 @@ int Arg_comparator::compare_e_decimal()
VDec val1(*a), val2(*b);
if (val1.is_null() || val2.is_null())
return MY_TEST(val1.is_null() && val2.is_null());
+ val1.round_self_if_needed((*a)->decimals, HALF_UP);
+ val2.round_self_if_needed((*b)->decimals, HALF_UP);
return MY_TEST(val1.cmp(val2) == 0);
}
@@ -2331,7 +2335,7 @@ longlong Item_func_between::val_int_cmp_real()
void Item_func_between::print(String *str, enum_query_type query_type)
{
- args[0]->print_parenthesised(str, query_type, precedence());
+ args[0]->print_parenthesised(str, query_type, higher_precedence());
if (negated)
str->append(STRING_WITH_LEN(" not"));
str->append(STRING_WITH_LEN(" between "));
@@ -3348,27 +3352,28 @@ Item* Item_func_case_simple::propagate_equal_fields(THD *thd,
}
-void Item_func_case::print_when_then_arguments(String *str,
- enum_query_type query_type,
- Item **items, uint count)
+inline void Item_func_case::print_when_then_arguments(String *str,
+ enum_query_type
+ query_type,
+ Item **items, uint count)
{
- for (uint i=0 ; i < count ; i++)
+ for (uint i= 0; i < count; i++)
{
str->append(STRING_WITH_LEN("when "));
- items[i]->print_parenthesised(str, query_type, precedence());
+ items[i]->print(str, query_type);
str->append(STRING_WITH_LEN(" then "));
- items[i + count]->print_parenthesised(str, query_type, precedence());
+ items[i + count]->print(str, query_type);
str->append(' ');
}
}
-void Item_func_case::print_else_argument(String *str,
- enum_query_type query_type,
- Item *item)
+inline void Item_func_case::print_else_argument(String *str,
+ enum_query_type query_type,
+ Item *item)
{
str->append(STRING_WITH_LEN("else "));
- item->print_parenthesised(str, query_type, precedence());
+ item->print(str, query_type);
str->append(' ');
}
@@ -5600,12 +5605,14 @@ void Item_func_like::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN(" not "));
str->append(func_name());
str->append(' ');
- args[1]->print_parenthesised(str, query_type, precedence());
if (escape_used_in_parsing)
{
+ args[1]->print_parenthesised(str, query_type, precedence());
str->append(STRING_WITH_LEN(" escape "));
- escape_item->print(str, query_type);
+ escape_item->print_parenthesised(str, query_type, higher_precedence());
}
+ else
+ args[1]->print_parenthesised(str, query_type, higher_precedence());
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index fe6cba607a7..fa715badfc7 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1,7 +1,7 @@
#ifndef ITEM_CMPFUNC_INCLUDED
#define ITEM_CMPFUNC_INCLUDED
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2016, MariaDB
+ Copyright (c) 2009, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -608,7 +608,7 @@ public:
enum Functype functype() const override { return NOT_FUNC; }
const char *func_name() const override { return "not"; }
bool find_not_null_fields(table_map allowed) override { return false; }
- enum precedence precedence() const override { return BANG_PRECEDENCE; }
+ enum precedence precedence() const override { return NEG_PRECEDENCE; }
Item *neg_transformer(THD *thd) override;
bool fix_fields(THD *, Item **) override;
void print(String *str, enum_query_type query_type) override;
@@ -2184,9 +2184,11 @@ protected:
bool aggregate_then_and_else_arguments(THD *thd, uint count);
virtual Item **else_expr_addr() const= 0;
virtual Item *find_item()= 0;
- void print_when_then_arguments(String *str, enum_query_type query_type,
- Item **items, uint count);
- void print_else_argument(String *str, enum_query_type query_type, Item *item);
+ inline void print_when_then_arguments(String *str,
+ enum_query_type query_type,
+ Item **items, uint count);
+ inline void print_else_argument(String *str, enum_query_type query_type,
+ Item *item);
void reorder_args(uint start);
public:
Item_func_case(THD *thd, List<Item> &list)
@@ -2202,7 +2204,6 @@ public:
bool fix_fields(THD *thd, Item **ref);
table_map not_null_tables() const { return 0; }
const char *func_name() const { return "case"; }
- enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
CHARSET_INFO *compare_collation() const { return cmp_collation.collation; }
bool need_parentheses_in_default() { return true; }
};
@@ -2467,7 +2468,7 @@ public:
virtual void print(String *str, enum_query_type query_type);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return "in"; }
- enum precedence precedence() const { return CMP_PRECEDENCE; }
+ enum precedence precedence() const { return IN_PRECEDENCE; }
bool eval_not_null_tables(void *opt_arg);
bool find_not_null_fields(table_map allowed);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
@@ -2793,7 +2794,7 @@ public:
return this;
}
const char *func_name() const { return "like"; }
- enum precedence precedence() const { return CMP_PRECEDENCE; }
+ enum precedence precedence() const { return IN_PRECEDENCE; }
bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec()
{
@@ -2902,7 +2903,7 @@ public:
longlong val_int();
bool fix_length_and_dec();
const char *func_name() const { return "regexp"; }
- enum precedence precedence() const { return CMP_PRECEDENCE; }
+ enum precedence precedence() const { return IN_PRECEDENCE; }
Item *get_copy(THD *) { return 0; }
void print(String *str, enum_query_type query_type)
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 8a75d2c9946..027488e0279 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -640,8 +640,7 @@ void Item_func::print_op(String *str, enum_query_type query_type)
str->append(func_name());
str->append(' ');
}
- args[arg_count-1]->print_parenthesised(str, query_type,
- (enum precedence)(precedence() + 1));
+ args[arg_count-1]->print_parenthesised(str, query_type, higher_precedence());
}
@@ -1493,14 +1492,13 @@ double Item_func_div::real_op()
my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
{
int err;
- my_decimal tmp;
VDec2_lazy val(args[0], args[1]);
if ((null_value= val.has_null()))
return 0;
if ((err= check_decimal_overflow(my_decimal_div(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW &
~E_DEC_DIV_ZERO,
- &tmp,
+ decimal_value,
val.m_a.ptr(), val.m_b.ptr(),
prec_increment))) > 3)
{
@@ -1509,7 +1507,6 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
null_value= 1;
return 0;
}
- tmp.round_to(decimal_value, decimals, HALF_UP);
return decimal_value;
}
@@ -4017,6 +4014,8 @@ int Interruptible_wait::wait(mysql_cond_t *cond, mysql_mutex_t *mutex)
timeout= m_abs_timeout;
error= mysql_cond_timedwait(cond, mutex, &timeout);
+ if (m_thd->check_killed())
+ break;
if (error == ETIMEDOUT || error == ETIME)
{
/* Return error if timed out or connection is broken. */
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 4acf1c6525b..f1a4ac4ef8a 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2003, 2016, Oracle and/or its affiliates.
- Copyright (c) 2011, 2016, MariaDB
+ Copyright (c) 2011, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -443,16 +443,18 @@ String *Item_func_boundary::val_str(String *str_value)
DBUG_ASSERT(fixed == 1);
String arg_val;
String *swkb= args[0]->val_str(&arg_val);
+
+ if ((null_value= args[0]->null_value))
+ DBUG_RETURN(0);
+
Geometry_buffer buffer;
- Geometry *g;
uint32 srid= 0;
Transporter trn(&res_receiver);
-
- if ((null_value=
- args[0]->null_value ||
- !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
+
+ Geometry *g= Geometry::construct(&buffer, swkb->ptr(), swkb->length());
+ if (!g)
DBUG_RETURN(0);
-
+
if (g->store_shapes(&trn))
goto mem_error;
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index aec3e1edcd3..032ecb1bb91 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -2464,6 +2464,8 @@ String *Item_func_json_merge_patch::val_str(String *str)
uint n_arg;
bool empty_result, merge_to_null;
+ /* To report errors properly if some JSON is invalid. */
+ je1.s.error= je2.s.error= 0;
merge_to_null= args[0]->null_value;
for (n_arg=1; n_arg < arg_count; n_arg++)
@@ -3772,6 +3774,8 @@ Item_func_json_objectagg::fix_fields(THD *thd, Item **ref)
uint i; /* for loop variable */
DBUG_ASSERT(fixed == 0);
+ memcpy(orig_args, args, sizeof(Item*) * arg_count);
+
if (init_sum_func_check(thd))
return TRUE;
@@ -3867,7 +3871,3 @@ String* Item_func_json_objectagg::val_str(String* str)
}
-void Item_func_json_objectagg::print(String *str, enum_query_type query_type)
-{
-}
-
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
index 6bd2a81afc6..ec6c6696001 100644
--- a/sql/item_jsonfunc.h
+++ b/sql/item_jsonfunc.h
@@ -589,7 +589,7 @@ public:
void cleanup();
enum Sumfunctype sum_func () const {return JSON_OBJECTAGG_FUNC;}
- const char *func_name() const { return "json_objectagg("; }
+ const char *func_name() const { return "json_objectagg"; }
const Type_handler *type_handler() const
{
if (too_big_for_varchar())
@@ -618,7 +618,6 @@ public:
String* val_str(String* str);
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
- void print(String *str, enum_query_type query_type);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_objectagg>(thd, this); }
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 334fec2e048..cbde9599073 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -3357,7 +3357,7 @@ void Item_in_subselect::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN("<exists>"));
else
{
- left_expr->print(str, query_type);
+ left_expr->print_parenthesised(str, query_type, precedence());
str->append(STRING_WITH_LEN(" in "));
}
Item_subselect::print(str, query_type);
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 7e504d09565..ec4398b9a76 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -640,7 +640,7 @@ public:
bool val_bool() override;
bool test_limit(st_select_lex_unit *unit);
void print(String *str, enum_query_type query_type) override;
- enum precedence precedence() const override { return CMP_PRECEDENCE; }
+ enum precedence precedence() const override { return IN_PRECEDENCE; }
bool fix_fields(THD *thd, Item **ref) override;
bool fix_length_and_dec() override;
void fix_after_pullout(st_select_lex *new_parent, Item **ref,
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 6b5c6fa323c..b8650a5c7e9 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2095,9 +2095,9 @@ static const char *interval_names[]=
void Item_date_add_interval::print(String *str, enum_query_type query_type)
{
- args[0]->print_parenthesised(str, query_type, ADDINTERVAL_PRECEDENCE);
+ args[0]->print_parenthesised(str, query_type, INTERVAL_PRECEDENCE);
str->append(date_sub_interval?" - interval ":" + interval ");
- args[1]->print_parenthesised(str, query_type, INTERVAL_PRECEDENCE);
+ args[1]->print(str, query_type);
str->append(' ');
str->append(interval_names[int_type]);
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 35c9df533c4..a910b2cb723 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -948,7 +948,7 @@ public:
bool fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
void print(String *str, enum_query_type query_type);
- enum precedence precedence() const { return ADDINTERVAL_PRECEDENCE; }
+ enum precedence precedence() const { return INTERVAL_PRECEDENCE; }
bool need_parentheses_in_default() { return true; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_date_add_interval>(thd, this); }
diff --git a/sql/log.cc b/sql/log.cc
index 2a887a68606..2dd1a3a45ab 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -601,9 +601,11 @@ bool LOGGER::is_log_table_enabled(uint log_table_type)
{
switch (log_table_type) {
case QUERY_LOG_SLOW:
- return (table_log_handler != NULL) && global_system_variables.sql_log_slow;
+ return (table_log_handler != NULL) && global_system_variables.sql_log_slow
+ && (log_output_options & LOG_TABLE);
case QUERY_LOG_GENERAL:
- return (table_log_handler != NULL) && opt_log ;
+ return (table_log_handler != NULL) && opt_log
+ && (log_output_options & LOG_TABLE);
default:
DBUG_ASSERT(0);
return FALSE; /* make compiler happy */
@@ -1355,7 +1357,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, size_t query_length,
my_hrtime_t current_time= { hrtime_from_time(thd->start_time) +
thd->start_time_sec_part + query_utime };
- if (!query)
+ if (!query || thd->get_command() == COM_STMT_PREPARE)
{
is_command= TRUE;
query= command_name[thd->get_command()].str;
@@ -2151,6 +2153,12 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
DBUG_RETURN(0);
}
+ /*
+ This is true if we are doing an alter table that is replicated as
+ CREATE TABLE ... SELECT
+ */
+ if (thd->variables.option_bits & OPTION_BIN_COMMIT_OFF)
+ DBUG_RETURN(0);
DBUG_PRINT("debug",
("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
@@ -6574,11 +6582,26 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
if (direct)
{
+ /* We come here only for incident events */
int res;
uint64 commit_id= 0;
+ MDL_request mdl_request;
DBUG_PRINT("info", ("direct is set"));
+ DBUG_ASSERT(!thd->backup_commit_lock);
+
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_EXPLICIT);
+ thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout);
+ thd->backup_commit_lock= &mdl_request;
+
if ((res= thd->wait_for_prior_commit()))
+ {
+ if (mdl_request.ticket)
+ thd->mdl_context.release_lock(mdl_request.ticket);
+ thd->backup_commit_lock= 0;
DBUG_RETURN(res);
+ }
file= &log_file;
my_org_b_tell= my_b_tell(file);
mysql_mutex_lock(&LOCK_log);
@@ -6593,7 +6616,11 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
commit_name.length);
commit_id= entry->val_int(&null_value);
});
- if (write_gtid_event(thd, true, using_trans, commit_id))
+ res= write_gtid_event(thd, true, using_trans, commit_id);
+ if (mdl_request.ticket)
+ thd->mdl_context.release_lock(mdl_request.ticket);
+ thd->backup_commit_lock= 0;
+ if (res)
goto err;
}
else
@@ -7657,7 +7684,11 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
group_commit_entry *entry, *orig_queue, *last;
wait_for_commit *cur;
wait_for_commit *wfc;
+ bool backup_lock_released= 0;
+ int result= 0;
+ THD *thd= orig_entry->thd;
DBUG_ENTER("MYSQL_BIN_LOG::queue_for_group_commit");
+ DBUG_ASSERT(thd == current_thd);
/*
Check if we need to wait for another transaction to commit before us.
@@ -7689,6 +7720,21 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
{
PSI_stage_info old_stage;
+ /*
+ Release MDL_BACKUP_COMMIT LOCK while waiting for other threads to
+ commit.
+ This is needed to avoid deadlock between the other threads (which not
+ yet have the MDL_BACKUP_COMMIT_LOCK) and any threads using
+ BACKUP LOCK BLOCK_COMMIT.
+ */
+ if (thd->backup_commit_lock && thd->backup_commit_lock->ticket &&
+ !backup_lock_released)
+ {
+ backup_lock_released= 1;
+ thd->mdl_context.release_lock(thd->backup_commit_lock->ticket);
+ thd->backup_commit_lock->ticket= 0;
+ }
+
/*
By setting wfc->opaque_pointer to our own entry, we mark that we are
ready to commit, but waiting for another transaction to commit before
@@ -7749,7 +7795,8 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
wfc->wakeup_error= ER_QUERY_INTERRUPTED;
my_message(wfc->wakeup_error,
ER_THD(orig_entry->thd, wfc->wakeup_error), MYF(0));
- DBUG_RETURN(-1);
+ result= -1;
+ goto end;
}
}
orig_entry->thd->EXIT_COND(&old_stage);
@@ -7763,12 +7810,13 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
then there is nothing else to do.
*/
if (orig_entry->queued_by_other)
- DBUG_RETURN(0);
+ goto end;
if (wfc && wfc->wakeup_error)
{
my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
- DBUG_RETURN(-1);
+ result= -1;
+ goto end;
}
/* Now enqueue ourselves in the group commit queue. */
@@ -7929,7 +7977,13 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
DBUG_PRINT("info", ("Queued for group commit as %s",
(orig_queue == NULL) ? "leader" : "participant"));
- DBUG_RETURN(orig_queue == NULL);
+ result= orig_queue == NULL;
+
+end:
+ if (backup_lock_released)
+ thd->mdl_context.acquire_lock(thd->backup_commit_lock,
+ thd->variables.lock_wait_timeout);
+ DBUG_RETURN(result);
}
bool
@@ -10753,7 +10807,8 @@ binlog_checksum_update(MYSQL_THD thd, struct st_mysql_sys_var *var,
}
-static int show_binlog_vars(THD *thd, SHOW_VAR *var, char *buff)
+static int show_binlog_vars(THD *thd, SHOW_VAR *var, void *,
+ system_status_var *status_var, enum_var_type)
{
mysql_bin_log.set_status_variables(thd);
var->type= SHOW_ARRAY;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d66ece96eba..0388a2b19b1 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1074,7 +1074,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
else
DBUG_RETURN(NULL);
#else
- *error= ER(ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE);
+ *error= ER_THD_OR_DEFAULT(current_thd, ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE);
sql_print_error("%s", *error);
DBUG_RETURN(NULL);
#endif
diff --git a/sql/log_event.h b/sql/log_event.h
index 222e611ecae..4e193232f4b 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2227,8 +2227,10 @@ public:
virtual bool is_commit() { return false; }
virtual bool is_rollback() { return false; }
#ifdef MYSQL_SERVER
- Query_compressed_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
- bool using_trans, bool direct, bool suppress_use, int error);
+ Query_compressed_log_event(THD* thd_arg, const char* query_arg,
+ ulong query_length,
+ bool using_trans, bool direct, bool suppress_use,
+ int error);
virtual bool write();
#endif
};
diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc
index 4c26acd2cc1..0480a8fa59f 100644
--- a/sql/log_event_client.cc
+++ b/sql/log_event_client.cc
@@ -899,6 +899,16 @@ log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
fprintf(stderr, "\nError: Found Old DECIMAL (mysql-4.1 or earlier). "
"Not enough metadata to display the value.\n");
break;
+
+ case MYSQL_TYPE_GEOMETRY:
+ strmake(typestr, "GEOMETRY", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= uint4korr(ptr);
+ my_b_write_quoted(file, ptr + meta, length);
+ return length + meta;
+
default:
print_event_info->flush_for_error();
fprintf(stderr,
diff --git a/sql/mf_iocache_encr.cc b/sql/mf_iocache_encr.cc
index b27f10c7d72..072c0a48269 100644
--- a/sql/mf_iocache_encr.cc
+++ b/sql/mf_iocache_encr.cc
@@ -71,6 +71,16 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count)
DBUG_RETURN(1);
}
info->seek_not_done= 0;
+ if (info->next_file_user)
+ {
+ IO_CACHE *c;
+ for (c= info->next_file_user;
+ c!= info;
+ c= c->next_file_user)
+ {
+ c->seek_not_done= 1;
+ }
+ }
}
do
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index 2db08bf01e3..4c1f41463d5 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -217,15 +217,15 @@ public:
{
return to_string(to, 0, 0, 0);
}
- String *to_string_round(String *to, uint scale, my_decimal *round_buff) const
+ String *to_string_round(String *to, int scale, my_decimal *round_buff) const
{
(void) round_to(round_buff, scale, HALF_UP); // QQ: check result?
return round_buff->to_string(to);
}
- int round_to(my_decimal *to, uint scale, decimal_round_mode mode,
+ int round_to(my_decimal *to, int scale, decimal_round_mode mode,
int mask= E_DEC_FATAL_ERROR) const
{
- return check_result(mask, decimal_round(this, to, (int) scale, mode));
+ return check_result(mask, decimal_round(this, to, scale, mode));
}
int to_binary(uchar *bin, int prec, int scale,
uint mask= E_DEC_FATAL_ERROR) const;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 99ec7c1eb56..8417208d68f 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1884,13 +1884,10 @@ extern "C" void unireg_abort(int exit_code)
WSREP_INFO("Some threads may fail to exit.");
}
- if (WSREP_ON)
+ if (WSREP_ON && wsrep_inited)
{
- /* In bootstrap mode we deinitialize wsrep here. */
- if (opt_bootstrap || wsrep_recovery)
- {
- if (wsrep_inited) wsrep_deinit(true);
- }
+ wsrep_deinit(true);
+ wsrep_deinit_server();
}
#endif // WITH_WSREP
@@ -6950,8 +6947,8 @@ show_ssl_get_server_not_after(THD *thd, SHOW_VAR *var, char *buff,
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
-static int show_default_keycache(THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope)
+static int show_default_keycache(THD *thd, SHOW_VAR *var, void *buff,
+ system_status_var *, enum_var_type)
{
struct st_data {
KEY_CACHE_STATISTICS stats;
@@ -6984,7 +6981,7 @@ static int show_default_keycache(THD *thd, SHOW_VAR *var, char *buff,
v->name= 0;
- DBUG_ASSERT((char*)(v+1) <= buff + SHOW_VAR_FUNC_BUFF_SIZE);
+ DBUG_ASSERT((char*)(v+1) <= static_cast<char*>(buff) + SHOW_VAR_FUNC_BUFF_SIZE);
#undef set_one_keycache_var
@@ -7008,8 +7005,8 @@ static int show_memory_used(THD *thd, SHOW_VAR *var, char *buff,
#ifndef DBUG_OFF
-static int debug_status_func(THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope)
+static int debug_status_func(THD *thd, SHOW_VAR *var, void *buff,
+ system_status_var *, enum_var_type)
{
#define add_var(X,Y,Z) \
v->name= X; \
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index c674730d230..c13563f9263 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1872,6 +1872,9 @@ SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc()
next_key_part=arg.next_key_part;
max_part_no= arg.max_part_no;
use_count=1; elements=1;
+ next= 0;
+ if (next_key_part)
+ ++next_key_part->use_count;
}
@@ -9616,9 +9619,15 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
}
bool no_imerge_from_ranges= FALSE;
+ SEL_TREE *rt1= tree1;
+ SEL_TREE *rt2= tree2;
/* Build the range part of the tree for the formula (1) */
if (sel_trees_can_be_ored(param, tree1, tree2, &ored_keys))
{
+ if (no_merges1)
+ rt1= new SEL_TREE(tree1, TRUE, param);
+ if (no_merges2)
+ rt2= new SEL_TREE(tree2, TRUE, param);
bool must_be_ored= sel_trees_must_be_ored(param, tree1, tree2, ored_keys);
no_imerge_from_ranges= must_be_ored;
@@ -9676,12 +9685,6 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
else if (!no_ranges1 && !no_ranges2 && !no_imerge_from_ranges)
{
/* Build the imerge part of the tree for the formula (1) */
- SEL_TREE *rt1= tree1;
- SEL_TREE *rt2= tree2;
- if (no_merges1)
- rt1= new SEL_TREE(tree1, TRUE, param);
- if (no_merges2)
- rt2= new SEL_TREE(tree2, TRUE, param);
if (!rt1 || !rt2 ||
result->merges.push_back(imerge_from_ranges) ||
imerge_from_ranges->or_sel_tree(param, rt1) ||
@@ -10346,10 +10349,11 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
if (!tmp->next_key_part)
{
+ SEL_ARG *key2_next= key2->next;
if (key2->use_count)
{
SEL_ARG *key2_cpy= new SEL_ARG(*key2);
- if (key2_cpy)
+ if (!key2_cpy)
return 0;
key2= key2_cpy;
}
@@ -10370,7 +10374,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
Move on to next range in key2
*/
key2->increment_use_count(-1); // Free not used tree
- key2=key2->next;
+ key2=key2_next;
continue;
}
else
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 8ae3ce5c995..b7f5ffd02d1 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010, 2019, MariaDB
+ Copyright (c) 2010, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -2681,16 +2681,11 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables)
do
{
uint key= keyuse->key;
- KEY *keyinfo;
key_part_map bound_parts= 0;
- bool is_excluded_key= keyuse->is_for_hash_join();
- if (!is_excluded_key)
- {
- keyinfo= table->key_info + key;
- is_excluded_key= !MY_TEST(keyinfo->flags & HA_NOSAME);
- }
- if (!is_excluded_key)
+ if (!keyuse->is_for_hash_join() &&
+ (table->key_info[key].flags & HA_NOSAME))
{
+ KEY *keyinfo= table->key_info + key;
do /* For all equalities on all key parts */
{
/*
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 0a3c30a176d..af2d9ddc2e7 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -399,20 +399,28 @@ int opt_sum_query(THD *thd,
break;
}
longlong info_limit= 1;
- table->file->info_push(INFO_KIND_FORCE_LIMIT_BEGIN, &info_limit);
- if (likely(!(error= table->file->ha_index_init((uint) ref.key, 1))))
- error= (is_max ?
- get_index_max_value(table, &ref, range_fl) :
- get_index_min_value(table, &ref, item_field, range_fl,
- prefix_len));
+ error= 0;
+ table->file->info_push(INFO_KIND_FORCE_LIMIT_BEGIN, &info_limit);
+ if (!table->const_table)
+ {
+ if (likely(!(error= table->file->ha_index_init((uint) ref.key,
+ 1))))
+ error= (is_max ?
+ get_index_max_value(table, &ref, range_fl) :
+ get_index_min_value(table, &ref, item_field, range_fl,
+ prefix_len));
+ }
/* Verify that the read tuple indeed matches the search key */
if (!error &&
reckey_in_range(is_max, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
- table->file->ha_end_keyread();
- table->file->ha_index_end();
+ if (!table->const_table)
+ {
+ table->file->ha_end_keyread();
+ table->file->ha_index_end();
+ }
table->file->info_push(INFO_KIND_FORCE_LIMIT_END, NULL);
if (error)
{
diff --git a/sql/protocol.cc b/sql/protocol.cc
index d5e6a7b92bf..65443cafa65 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2008, 2012, Monty Program Ab
+ Copyright (c) 2008, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -57,7 +57,8 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
packet->realloc(packet_length+9+length))
return 1;
uchar *to= net_store_length((uchar*) packet->ptr()+packet_length, length);
- memcpy(to,from,length);
+ if (length)
+ memcpy(to,from,length);
packet->length((uint) (to+length-(uchar*) packet->ptr()));
return 0;
}
@@ -730,7 +731,8 @@ void net_send_progress_packet(THD *thd)
uchar *net_store_data(uchar *to, const uchar *from, size_t length)
{
to=net_store_length_fast(to,length);
- memcpy(to,from,length);
+ if (length)
+ memcpy(to,from,length);
return to+length;
}
diff --git a/sql/select_handler.cc b/sql/select_handler.cc
index 9a2f6398a86..795ed8eb641 100644
--- a/sql/select_handler.cc
+++ b/sql/select_handler.cc
@@ -21,10 +21,10 @@
/**
- The methods of the Pushdown_select class.
+ The methods of the select_handler class.
The objects of this class are used for pushdown of the select queries
- into engines. The main method of the class is Pushdown_select::execute()
+ into engines. The main method of the class is select_handler::execute()
that initiates execution of a select query by a foreign engine, receives the
rows of the result set, put it in a buffer of a temporary table and send
them from the buffer directly into output.
@@ -36,51 +36,55 @@
*/
-Pushdown_select::Pushdown_select(SELECT_LEX *sel, select_handler *h)
- : select(sel), handler(h)
-{
- is_analyze= handler->thd->lex->analyze_stmt;
-}
+select_handler::select_handler(THD *thd_arg, handlerton *ht_arg)
+ : thd(thd_arg), ht(ht_arg), table(NULL),
+ is_analyze(thd_arg->lex->analyze_stmt)
+{}
-Pushdown_select::~Pushdown_select()
+select_handler::~select_handler()
{
- if (handler->table)
- free_tmp_table(handler->thd, handler->table);
- delete handler;
- select->select_h= NULL;
+ if (table)
+ free_tmp_table(thd, table);
}
-bool Pushdown_select::init()
+TABLE *select_handler::create_tmp_table(THD *thd, SELECT_LEX *select)
{
+ DBUG_ENTER("select_handler::create_tmp_table");
List<Item> types;
TMP_TABLE_PARAM tmp_table_param;
- THD *thd= handler->thd;
- DBUG_ENTER("Pushdown_select::init");
if (select->master_unit()->join_union_item_types(thd, types, 1))
- DBUG_RETURN(true);
+ DBUG_RETURN(NULL);
tmp_table_param.init();
tmp_table_param.field_count= types.elements;
- handler->table= create_tmp_table(thd, &tmp_table_param, types,
+ TABLE *table= ::create_tmp_table(thd, &tmp_table_param, types,
(ORDER *) 0, false, 0,
TMP_TABLE_ALL_COLUMNS, 1,
&empty_clex_str, true, false);
- if (!handler->table)
- DBUG_RETURN(true);
- if (handler->table->fill_item_list(&result_columns))
+ DBUG_RETURN(table);
+}
+
+
+bool select_handler::prepare()
+{
+ DBUG_ENTER("select_handler::prepare");
+ /*
+ Some engines (e.g. XPand) initialize "table" on their own.
+ So we need to create a temporary table only if "table" is NULL.
+ */
+ if (!table && !(table= create_tmp_table(thd, select)))
DBUG_RETURN(true);
- DBUG_RETURN(false);
+ DBUG_RETURN(table->fill_item_list(&result_columns));
}
-bool Pushdown_select::send_result_set_metadata()
+bool select_handler::send_result_set_metadata()
{
- DBUG_ENTER("Pushdown_select::send_result_set_metadata");
+ DBUG_ENTER("select_handler::send_result_set_metadata");
#ifdef WITH_WSREP
- THD *thd= handler->thd;
if (WSREP(thd) && thd->wsrep_retry_query)
{
WSREP_DEBUG("skipping select metadata");
@@ -96,7 +100,7 @@ bool Pushdown_select::send_result_set_metadata()
}
-bool Pushdown_select::send_data()
+bool select_handler::send_data()
{
DBUG_ENTER("Pushdown_select::send_data");
@@ -107,9 +111,9 @@ bool Pushdown_select::send_data()
}
-bool Pushdown_select::send_eof()
+bool select_handler::send_eof()
{
- DBUG_ENTER("Pushdown_select::send_eof");
+ DBUG_ENTER("select_handler::send_eof");
if (select->join->result->send_eof())
DBUG_RETURN(true);
@@ -117,30 +121,29 @@ bool Pushdown_select::send_eof()
}
-int Pushdown_select::execute()
+int select_handler::execute()
{
int err;
- THD *thd= handler->thd;
- DBUG_ENTER("Pushdown_select::execute");
+ DBUG_ENTER("select_handler::execute");
- if ((err= handler->init_scan()))
+ if ((err= init_scan()))
goto error;
if (is_analyze)
{
- handler->end_scan();
+ end_scan();
DBUG_RETURN(0);
}
if (send_result_set_metadata())
DBUG_RETURN(-1);
- while (!(err= handler->next_row()))
+ while (!(err= next_row()))
{
if (thd->check_killed() || send_data())
{
- handler->end_scan();
+ end_scan();
DBUG_RETURN(-1);
}
}
@@ -148,7 +151,7 @@ int Pushdown_select::execute()
if (err != 0 && err != HA_ERR_END_OF_FILE)
goto error;
- if ((err= handler->end_scan()))
+ if ((err= end_scan()))
goto error_2;
if (send_eof())
@@ -157,9 +160,9 @@ int Pushdown_select::execute()
DBUG_RETURN(0);
error:
- handler->end_scan();
+ end_scan();
error_2:
- handler->print_error(err, MYF(0));
+ print_error(err, MYF(0));
DBUG_RETURN(-1); // Error not sent to client
}
diff --git a/sql/select_handler.h b/sql/select_handler.h
index e2ad13b7cdf..5cc63231641 100644
--- a/sql/select_handler.h
+++ b/sql/select_handler.h
@@ -41,12 +41,24 @@ class select_handler
The table is actually never filled. Only its record buffer is used.
*/
TABLE *table;
+ List<Item> result_columns;
- select_handler(THD *thd_arg, handlerton *ht_arg)
- : thd(thd_arg), ht(ht_arg), table(0) {}
+ bool is_analyze;
- virtual ~select_handler() {}
+ bool send_result_set_metadata();
+ bool send_data();
+ select_handler(THD *thd_arg, handlerton *ht_arg);
+
+ virtual ~select_handler();
+
+ int execute();
+
+ virtual bool prepare();
+
+ static TABLE *create_tmp_table(THD *thd, SELECT_LEX *sel);
+
+protected:
/*
Functions to scan the select result set.
All these returns 0 if ok, error code in case of error.
@@ -67,6 +79,8 @@ class select_handler
/* Report errors */
virtual void print_error(int error, myf errflag);
+
+ bool send_eof();
};
#endif /* SELECT_HANDLER_INCLUDED */
diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc
index 1e5e356a5ba..de82d8be90c 100644
--- a/sql/session_tracker.cc
+++ b/sql/session_tracker.cc
@@ -445,8 +445,11 @@ bool Session_sysvars_tracker::vars_list::store(THD *thd, String *buf)
show.name= svar->name.str;
show.value= (char *) svar;
+ mysql_mutex_lock(&LOCK_global_system_variables);
const char *value= get_one_variable(thd, &show, OPT_SESSION, SHOW_SYS, NULL,
&charset, val_buf, &val_length);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+
if (is_plugin)
mysql_mutex_unlock(&LOCK_plugin);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 38c8d1f1775..fe98d98fbd4 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1084,7 +1084,6 @@ static void store_var(Field *field, sys_var *var, enum_var_type scope,
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond)
{
char name_buffer[NAME_CHAR_LEN];
- enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
bool res= 1;
CHARSET_INFO *scs= system_charset_info;
StringBuffer<STRING_BUFFER_USUAL_SIZE> strbuf(scs);
@@ -1095,7 +1094,6 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_ASSERT(tables->table->in_use == thd);
cond= make_cond_for_info_schema(thd, cond, tables);
- thd->count_cuted_fields= CHECK_FIELD_WARN;
mysql_prlock_rdlock(&LOCK_system_variables_hash);
for (uint i= 0; i < system_variable_hash.records; i++)
@@ -1269,7 +1267,6 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond)
res= 0;
end:
mysql_prlock_unlock(&LOCK_system_variables_hash);
- thd->count_cuted_fields= save_count_cuted_fields;
return res;
}
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 63c3ee30444..2e08892166d 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -1800,9 +1800,10 @@ ER_WRONG_AUTO_KEY 42000 S1009
slo "Môžete mať iba jedno AUTO pole a to musí byť definované ako kľúč"
spa "Puede ser solamente un campo automatico y este debe ser definido como una clave"
swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
- ukr "Невірне визначення таблиці; Може бути лише один автоматичний стовбець, що повинен бути визначений як ключ"
+ ukr "Хибне визначення таблиці; Може бути лише один автоматичний стовбець, що повинен бути визначений як ключ"
ER_BINLOG_CANT_DELETE_GTID_DOMAIN
eng "Could not delete gtid domain. Reason: %s."
+ ukr "Не можу видалити домен gtid. Причина: %s."
ER_NORMAL_SHUTDOWN
cze "%s (%s): normální ukončení"
dan "%s (%s): Normal nedlukning"
@@ -2203,6 +2204,7 @@ ER_INSERT_INFO
ER_UPDATE_TABLE_USED
eng "Table '%-.192s' is specified twice, both as a target for '%s' and as a separate source for data"
swe "Table '%-.192s' är använd två gånger. Både för '%s' och för att hämta data"
+ ukr "Таблиця '%-.192s' вказується двічі, як цільова для '%s', так і як окреме джерело даних"
ER_NO_SUCH_THREAD
cze "Neznámá identifikace threadu: %lu"
dan "Ukendt tråd id: %lu"
@@ -2824,6 +2826,7 @@ ER_WRONG_OUTER_JOIN 42000
ER_NULL_COLUMN_IN_INDEX 42000
eng "Table handler doesn't support NULL in given index. Please change column '%-.192s' to be NOT NULL or use another handler"
swe "Tabell hanteraren kan inte indexera NULL kolumner för den givna index typen. Ändra '%-.192s' till NOT NULL eller använd en annan hanterare"
+ ukr "Вказівник таблиці не підтримує NULL у зазначенному індексі. Будь ласка, зменіть стовпчик '%-.192s' на NOT NULL або використайте інший вказівник таблиці."
ER_CANT_FIND_UDF
cze "Nemohu načíst funkci '%-.192s'"
dan "Kan ikke læse funktionen '%-.192s'"
@@ -4314,6 +4317,7 @@ ER_MASTER_INFO
jpn "'master info '%.*s''構造体の初期化ができませんでした。MariaDBエラーログでエラーメッセージを確認してください。"
serbian "Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info' '%.*s'"
swe "Kunde inte initialisera replikationsstrukturerna för '%.*s'. See MariaDB fel fil för mera information"
+ ukr "Інформаційна структура з'єднання головного і підлеглого (master.info) для '%.*s' не може бути ініціалізована"
ER_SLAVE_THREAD
dan "Kunne ikke danne en slave-tråd; check systemressourcerne"
nla "Kon slave thread niet aanmaken, controleer systeem resources"
@@ -4478,6 +4482,7 @@ ER_UNION_TABLES_IN_DIFFERENT_DIR
serbian "Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka"
spa "Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos"
swe "Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas"
+ ukr "Хибне визначення таблиці; всі MERGE-таблиці повинні належити до однієї бази ланних."
ER_LOCK_DEADLOCK 40001
nla "Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie"
eng "Deadlock found when trying to get lock; try restarting transaction"
@@ -4491,6 +4496,7 @@ ER_LOCK_DEADLOCK 40001
serbian "Unakrsno zaključavanje pronađeno kada sam pokušao da dobijem pravo na zaključavanje; Probajte da restartujete transakciju"
spa "Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición"
swe "Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen"
+ ukr "Взаємне блокування знайдено під час спроби отримати блокування; спробуйте перезапустити транзакцію."
ER_TABLE_CANT_HANDLE_FT
nla "Het gebruikte tabel type (%s) ondersteund geen FULLTEXT indexen"
eng "The storage engine %s doesn't support FULLTEXT indexes"
@@ -4517,6 +4523,7 @@ ER_CANNOT_ADD_FOREIGN
serbian "Ne mogu da dodam proveru spoljnog ključa na `%s`"
spa "No puede adicionar clave extranjera constraint para `%s`"
swe "Kan inte lägga till 'FOREIGN KEY constraint' för `%s`'"
+ ukr "Не можу додати обмеження зовнішнього ключа Ha `%s`"
ER_NO_REFERENCED_ROW 23000
nla "Kan onderliggende rij niet toevoegen: foreign key beperking gefaald"
eng "Cannot add or update a child row: a foreign key constraint fails"
@@ -4531,6 +4538,7 @@ ER_NO_REFERENCED_ROW 23000
rus "Невозможно добавить или обновить дочернюю строку: проверка ограничений внешнего ключа не выполняется"
spa "No puede adicionar una línea hijo: falla de clave extranjera constraint"
swe "FOREIGN KEY-konflikt: Kan inte skriva barn"
+ ukr "Не вдається додати або оновити дочірній рядок: невдала перевірка обмеження зовнішнього ключа"
ER_ROW_IS_REFERENCED 23000
eng "Cannot delete or update a parent row: a foreign key constraint fails"
fre "Impossible de supprimer un enregistrement père : une constrainte externe l'empèche"
@@ -5714,8 +5722,9 @@ ER_SP_RECURSION_LIMIT
eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s"
ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.192s überschritten"
ER_SP_PROC_TABLE_CORRUPT
- eng "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
- ger "Routine %-.192s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)"
+ eng "Failed to load routine %-.192s (internal code %d). For more details, run SHOW WARNINGS"
+ ger "Routine %-.192s (interner Code %d) konnte nicht geladen werden. Weitere Einzelheiten erhalten Sie, wenn Sie SHOW WARNINGS ausführen"
+ ukr "Невдала спроба завантажити процедуру %-.192s (внутрішний код %d). Для отримання детальної інформації використовуйте SHOW WARNINGS"
ER_SP_WRONG_NAME 42000
eng "Incorrect routine name '%-.192s'"
ger "Ungültiger Routinenname '%-.192s'"
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 49c8229c277..9e5b5bee0f2 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1211,6 +1211,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
Query_arena execute_arena(&execute_mem_root, STMT_INITIALIZED_FOR_SP),
backup_arena;
query_id_t old_query_id;
+ CSET_STRING old_query;
TABLE *old_derived_tables;
TABLE *old_rec_tables;
LEX *old_lex;
@@ -1291,6 +1292,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
be able properly do close_thread_tables() in instructions.
*/
old_query_id= thd->query_id;
+ old_query= thd->query_string;
old_derived_tables= thd->derived_tables;
thd->derived_tables= 0;
old_rec_tables= thd->rec_tables;
@@ -1567,6 +1569,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
old_change_list.move_elements_to(thd);
thd->lex= old_lex;
thd->set_query_id(old_query_id);
+ thd->set_query_inner(old_query);
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
thd->rec_tables= old_rec_tables;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 161ffc66641..2c96e0e9ff2 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -304,8 +304,9 @@ ulong role_global_merges= 0, role_db_merges= 0, role_table_merges= 0,
static void update_hostname(acl_host_and_ip *host, const char *hostname);
static bool show_proxy_grants (THD *, const char *, const char *,
char *, size_t);
-static bool show_role_grants(THD *, const char *, const char *,
+static bool show_role_grants(THD *, const char *,
ACL_USER_BASE *, char *, size_t);
+static bool show_default_role(THD *, ACL_USER *, char *, size_t);
static bool show_global_privileges(THD *, ACL_USER_BASE *,
bool, char *, size_t);
static bool show_database_privileges(THD *, const char *, const char *,
@@ -9000,7 +9001,7 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role)
{
char buff[1024];
- if (show_role_grants(thd, role->user.str, "", role, buff, sizeof(buff)))
+ if (show_role_grants(thd, "", role, buff, sizeof(buff)))
return TRUE;
if (show_global_privileges(thd, role, TRUE, buff, sizeof(buff)))
@@ -9245,7 +9246,7 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user)
}
/* Show granted roles to acl_user */
- if (show_role_grants(thd, username, hostname, acl_user, buff, sizeof(buff)))
+ if (show_role_grants(thd, hostname, acl_user, buff, sizeof(buff)))
goto end;
/* Add first global access grants */
@@ -9302,6 +9303,14 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user)
}
}
+ if (username)
+ {
+ /* Show default role to acl_user */
+ if (show_default_role(thd, acl_user, buff, sizeof(buff)))
+ goto end;
+ }
+
+
error= 0;
end:
mysql_mutex_unlock(&acl_cache->lock);
@@ -9328,15 +9337,44 @@ static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_CSTRING *u,
my_hash_search(&acl_roles_mappings, (uchar*)pair_key.ptr(), key_length);
}
-static bool show_role_grants(THD *thd, const char *username,
- const char *hostname, ACL_USER_BASE *acl_entry,
+static bool show_default_role(THD *thd, ACL_USER *acl_entry,
+ char *buff, size_t buffsize)
+{
+ Protocol *protocol= thd->protocol;
+ LEX_CSTRING def_rolename= acl_entry->default_rolename;
+
+ if (def_rolename.length)
+ {
+ String def_str(buff, buffsize, system_charset_info);
+ def_str.length(0);
+ def_str.append(STRING_WITH_LEN("SET DEFAULT ROLE "));
+ def_str.append(&def_rolename);
+ def_str.append(" FOR '");
+ def_str.append(&acl_entry->user);
+ DBUG_ASSERT(!(acl_entry->flags & IS_ROLE));
+ def_str.append(STRING_WITH_LEN("'@'"));
+ def_str.append(acl_entry->host.hostname, acl_entry->hostname_length,
+ system_charset_info);
+ def_str.append('\'');
+ protocol->prepare_for_resend();
+ protocol->store(def_str.ptr(),def_str.length(),def_str.charset());
+ if (protocol->write())
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static bool show_role_grants(THD *thd, const char *hostname,
+ ACL_USER_BASE *acl_entry,
char *buff, size_t buffsize)
{
uint counter;
Protocol *protocol= thd->protocol;
LEX_CSTRING host= {const_cast<char*>(hostname), strlen(hostname)};
- String grant(buff,sizeof(buff),system_charset_info);
+ String grant(buff, buffsize, system_charset_info);
for (counter= 0; counter < acl_entry->role_grants.elements; counter++)
{
grant.length(0);
@@ -9377,7 +9415,7 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry,
privilege_t want_access(NO_ACL);
Protocol *protocol= thd->protocol;
- String global(buff,sizeof(buff),system_charset_info);
+ String global(buff, buffsize, system_charset_info);
global.length(0);
global.append(STRING_WITH_LEN("GRANT "));
@@ -9471,7 +9509,7 @@ static bool show_database_privileges(THD *thd, const char *username,
want_access=acl_db->initial_access;
if (want_access)
{
- String db(buff,sizeof(buff),system_charset_info);
+ String db(buff, buffsize, system_charset_info);
db.length(0);
db.append(STRING_WITH_LEN("GRANT "));
@@ -14679,3 +14717,40 @@ maria_declare_plugin(mysql_password)
MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
}
maria_declare_plugin_end;
+
+
+/*
+ Exporting functions that allow plugins to do server-style
+ host/user matching. Used in server_audit2 plugin.
+*/
+extern "C" int maria_compare_hostname(
+ const char *wild_host, long wild_ip, long ip_mask,
+ const char *host, const char *ip)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ acl_host_and_ip h;
+ h.hostname= (char *) wild_host;
+ h.ip= wild_ip;
+ h.ip_mask= ip_mask;
+
+ return compare_hostname(&h, host, ip);
+#else
+ return 0;
+#endif
+}
+
+
+extern "C" void maria_update_hostname(
+ const char **wild_host, long *wild_ip, long *ip_mask,
+ const char *host)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ acl_host_and_ip h;
+ update_hostname(&h, host);
+ *wild_host= h.hostname;
+ *wild_ip= h.ip;
+ *ip_mask= h.ip_mask;
+#endif
+}
+
+
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 6a313616025..dec5bd91f36 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1316,7 +1316,12 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
table->s->tdc->flush(thd, true);
/* extra() call must come only after all instances above are closed */
if (function != HA_EXTRA_NOT_USED)
- DBUG_RETURN(table->file->extra(function));
+ {
+ int error= table->file->extra(function);
+ if (error)
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
DBUG_RETURN(FALSE);
}
@@ -1777,7 +1782,14 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
}
if (is_locked_view(thd, table_list))
+ {
+ if (table_list->sequence)
+ {
+ my_error(ER_NOT_SEQUENCE, MYF(0), table_list->db.str, table_list->alias.str);
+ DBUG_RETURN(true);
+ }
DBUG_RETURN(FALSE); // VIEW
+ }
/*
No table in the locked tables list. In case of explicit LOCK TABLES
@@ -1906,7 +1918,12 @@ retry_share:
DBUG_RETURN(FALSE);
}
+#ifdef WITH_WSREP
+ if (!((flags & MYSQL_OPEN_IGNORE_FLUSH) ||
+ (thd->wsrep_applier)))
+#else
if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
+#endif
{
if (share->tdc->flushed)
{
@@ -3900,7 +3917,8 @@ static bool upgrade_lock_if_not_exists(THD *thd,
{
DEBUG_SYNC(thd,"create_table_before_check_if_exists");
if (!create_info.or_replace() &&
- ha_table_exists(thd, &create_table->db, &create_table->table_name))
+ ha_table_exists(thd, &create_table->db, &create_table->table_name,
+ &create_table->db_type))
{
if (create_info.if_not_exists())
{
@@ -3948,7 +3966,8 @@ static bool upgrade_lock_if_not_exists(THD *thd,
Note that for CREATE TABLE IF EXISTS we only generate a warning
but still return TRUE (to abort the calling open_table() function).
On must check THD->is_error() if one wants to distinguish between warning
- and error.
+ and error. If table existed, tables_start->db_type is set to the handlerton
+ for the found table.
*/
bool
@@ -8734,14 +8753,17 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
goto err;
field->set_has_explicit_value();
}
- /* Update virtual fields */
- thd->abort_on_warning= FALSE;
- if (table->versioned())
- table->vers_update_fields();
- if (table->vfield &&
- table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE))
- goto err;
- thd->abort_on_warning= abort_on_warning_saved;
+ /* Update virtual fields if there wasn't any errors */
+ if (!thd->is_error())
+ {
+ thd->abort_on_warning= FALSE;
+ if (table->versioned())
+ table->vers_update_fields();
+ if (table->vfield &&
+ table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE))
+ goto err;
+ thd->abort_on_warning= abort_on_warning_saved;
+ }
DBUG_RETURN(thd->is_error());
err:
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index e32344115da..3db7ebc7997 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1298,6 +1298,7 @@ void THD::init()
first_successful_insert_id_in_prev_stmt_for_binlog= 0;
first_successful_insert_id_in_cur_stmt= 0;
current_backup_stage= BACKUP_FINISHED;
+ backup_commit_lock= 0;
#ifdef WITH_WSREP
wsrep_last_query_id= 0;
wsrep_xid.null();
@@ -2588,7 +2589,7 @@ void THD::give_protection_error()
my_error(ER_BACKUP_LOCK_IS_ACTIVE, MYF(0));
else
{
- DBUG_ASSERT(global_read_lock.is_acquired());
+ DBUG_ASSERT(global_read_lock.is_acquired() || mdl_backup_lock);
my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));
}
}
@@ -6552,8 +6553,8 @@ exit:;
/**
Check if we should log a table DDL to the binlog
- @@return true yes
- @@return false no
+ @retval true yes
+ @retval false no
*/
bool THD::binlog_table_should_be_logged(const LEX_CSTRING *db)
@@ -7442,14 +7443,14 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
*/
if (binlog_should_compress(query_len))
{
- Query_compressed_log_event qinfo(this, query_arg, query_len, is_trans, direct,
- suppress_use, errcode);
+ Query_compressed_log_event qinfo(this, query_arg, query_len, is_trans,
+ direct, suppress_use, errcode);
error= mysql_bin_log.write(&qinfo);
}
else
{
Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
- suppress_use, errcode);
+ suppress_use, errcode);
error= mysql_bin_log.write(&qinfo);
}
/*
@@ -7467,6 +7468,38 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
DBUG_RETURN(0);
}
+
+/**
+ Binlog current query as a statement, ignoring the binlog filter setting.
+
+ The filter is in decide_logging_format() to mark queries to not be stored
+ in the binary log, for example by a shared distributed engine like S3.
+ This function resets the filter to ensure the the query is logged if
+ the binlog is active.
+
+ Note that 'direct' is set to false, which means that the query will
+ not be directly written to the binary log but instead to the cache.
+
+ @retval false ok
+ @retval true error
+*/
+
+
+bool THD::binlog_current_query_unfiltered()
+{
+ if (!mysql_bin_log.is_open())
+ return 0;
+
+ reset_binlog_local_stmt_filter();
+ clear_binlog_local_stmt_filter();
+ return binlog_query(THD::STMT_QUERY_TYPE, query(), query_length(),
+ /* is_trans */ FALSE,
+ /* direct */ FALSE,
+ /* suppress_use */ FALSE,
+ /* Error */ 0) > 0;
+}
+
+
void
THD::wait_for_wakeup_ready()
{
@@ -7642,16 +7675,33 @@ wait_for_commit::register_wait_for_prior_commit(wait_for_commit *waitee)
}
-/*
- Wait for commit of another transaction to complete, as already registered
+/**
+ Waits for commit of another transaction to complete, as already registered
with register_wait_for_prior_commit(). If the commit already completed,
returns immediately.
+
+ If thd->backup_commit_lock is set, release it while waiting for other threads
*/
+
int
wait_for_commit::wait_for_prior_commit2(THD *thd)
{
PSI_stage_info old_stage;
wait_for_commit *loc_waitee;
+ bool backup_lock_released= 0;
+
+ /*
+ Release MDL_BACKUP_COMMIT LOCK while waiting for other threads to commit
+ This is needed to avoid deadlock between the other threads (which not
+ yet have the MDL_BACKUP_COMMIT_LOCK) and any threads using
+ BACKUP LOCK BLOCK_COMMIT.
+ */
+ if (thd->backup_commit_lock && thd->backup_commit_lock->ticket)
+ {
+ backup_lock_released= 1;
+ thd->mdl_context.release_lock(thd->backup_commit_lock->ticket);
+ thd->backup_commit_lock->ticket= 0;
+ }
mysql_mutex_lock(&LOCK_wait_commit);
DEBUG_SYNC(thd, "wait_for_prior_commit_waiting");
@@ -7701,10 +7751,16 @@ wait_for_commit::wait_for_prior_commit2(THD *thd)
use within enter_cond/exit_cond.
*/
DEBUG_SYNC(thd, "wait_for_prior_commit_killed");
+ if (backup_lock_released)
+ thd->mdl_context.acquire_lock(thd->backup_commit_lock,
+ thd->variables.lock_wait_timeout);
return wakeup_error;
end:
thd->EXIT_COND(&old_stage);
+ if (backup_lock_released)
+ thd->mdl_context.acquire_lock(thd->backup_commit_lock,
+ thd->variables.lock_wait_timeout);
return wakeup_error;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index b0f68aa8fab..f6b772ef439 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -284,8 +284,9 @@ class Key_part_spec :public Sql_alloc {
public:
LEX_CSTRING field_name;
uint length;
- Key_part_spec(const LEX_CSTRING *name, uint len)
- : field_name(*name), length(len)
+ bool generated;
+ Key_part_spec(const LEX_CSTRING *name, uint len, bool gen= false)
+ : field_name(*name), length(len), generated(gen)
{}
bool operator==(const Key_part_spec& other) const;
/**
@@ -2311,7 +2312,10 @@ public:
rpl_io_thread_info *rpl_io_info;
rpl_sql_thread_info *rpl_sql_info;
} system_thread_info;
+ /* Used for BACKUP LOCK */
MDL_ticket *mdl_backup_ticket, *mdl_backup_lock;
+ /* Used to register that thread has a MDL_BACKUP_WAIT_COMMIT lock */
+ MDL_request *backup_commit_lock;
void reset_for_next_command(bool do_clear_errors= 1);
/*
@@ -2758,10 +2762,14 @@ public:
{
free_root(&mem_root,MYF(0));
}
- my_bool is_active()
+ bool is_active()
{
return (all.ha_list != NULL);
}
+ bool is_empty()
+ {
+ return all.is_empty() && stmt.is_empty();
+ }
st_transactions()
{
bzero((char*)this, sizeof(*this));
@@ -3483,6 +3491,7 @@ public:
char const *query, ulong query_len, bool is_trans,
bool direct, bool suppress_use,
int errcode);
+ bool binlog_current_query_unfiltered();
#endif
inline void
@@ -3765,10 +3774,17 @@ public:
/* Commit both statement and full transaction */
int commit_whole_transaction_and_close_tables();
void give_protection_error();
+ /*
+ Give an error if any of the following is true for this connection
+ - BACKUP STAGE is active
+ - FLUSH TABLE WITH READ LOCK is active
+ - BACKUP LOCK table_name is active
+ */
inline bool has_read_only_protection()
{
if (current_backup_stage == BACKUP_FINISHED &&
- !global_read_lock.is_acquired())
+ !global_read_lock.is_acquired() &&
+ !mdl_backup_lock)
return FALSE;
give_protection_error();
return TRUE;
@@ -6873,11 +6889,11 @@ public:
/**
SP Bulk execution safe
*/
-#define CF_SP_BULK_SAFE (1U << 20)
+#define CF_PS_ARRAY_BINDING_SAFE (1U << 20)
/**
SP Bulk execution optimized
*/
-#define CF_SP_BULK_OPTIMIZED (1U << 21)
+#define CF_PS_ARRAY_BINDING_OPTIMIZED (1U << 21)
/**
If command creates or drops a table
*/
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 17f8995239c..35aa306c88c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -248,6 +248,7 @@ int update_portion_of_time(THD *thd, TABLE *table,
uint dst_fieldno= lcond ? table->s->period.end_fieldno
: table->s->period.start_fieldno;
+ table->file->store_auto_increment();
store_record(table, record[1]);
if (likely(!res))
res= src->save_in_field(table->field[dst_fieldno], true);
@@ -262,6 +263,8 @@ int update_portion_of_time(THD *thd, TABLE *table,
res= table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
TRG_ACTION_AFTER, true);
restore_record(table, record[1]);
+ if (res)
+ table->file->restore_auto_increment();
if (likely(!res) && lcond && rcond)
res= table->period_make_insert(period_conds.end.item,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 4ad4c478937..7833059438e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -724,6 +724,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
Item *unused_conds= 0;
DBUG_ENTER("mysql_insert");
+ bzero((char*) &info,sizeof(info));
create_explain_query(thd->lex, thd->mem_root);
/*
Upgrade lock type if the requested lock is incompatible with
@@ -764,16 +765,28 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
value_count= values->elements;
- if (mysql_prepare_insert(thd, table_list, table, fields, values,
- update_fields, update_values, duplic,
- &unused_conds, FALSE))
+ if ((res= mysql_prepare_insert(thd, table_list, fields, values,
+ update_fields, update_values, duplic,
+ &unused_conds, FALSE)))
+ {
+ retval= thd->is_error();
+ if (res < 0)
+ {
+ /*
+ Insert should be ignored but we have to log the query in statement
+ format in the binary log
+ */
+ if (thd->binlog_current_query_unfiltered())
+ retval= 1;
+ }
goto abort;
+ }
+ /* mysql_prepare_insert sets table_list->table if it was not set */
+ table= table_list->table;
/* Prepares LEX::returing_list if it is not empty */
if (returning)
result->prepare(returning->item_list, NULL);
- /* mysql_prepare_insert sets table_list->table if it was not set */
- table= table_list->table;
context= &thd->lex->first_select_lex()->context;
/*
@@ -828,7 +841,6 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
/*
Fill in the given fields and dump it to the table file
*/
- bzero((char*) &info,sizeof(info));
info.ignore= ignore;
info.handle_duplicates=duplic;
info.update_fields= &update_fields;
@@ -1199,7 +1211,7 @@ values_loop_end:
such case the flag is ignored for constructing binlog event.
*/
DBUG_ASSERT(thd->killed != KILL_BAD_DATA || error > 0);
- if (was_insert_delayed && table_list->lock_type == TL_WRITE)
+ if (was_insert_delayed && table_list->lock_type == TL_WRITE)
{
/* Binlog INSERT DELAYED as INSERT without DELAYED. */
String log_query;
@@ -1534,9 +1546,6 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables)
mysql_prepare_insert()
thd Thread handler
table_list Global/local table list
- table Table to insert into
- (can be NULL if table should
- be taken from table_list->table)
where Where clause (for insert ... select)
select_insert TRUE if INSERT ... SELECT statement
@@ -1551,15 +1560,16 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables)
before releasing the table object.
RETURN VALUE
- FALSE OK
- TRUE error
+ 0 OK
+ >0 error
+ <0 insert should be ignored
*/
-bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
- TABLE *table, List<Item> &fields, List_item *values,
- List<Item> &update_fields, List<Item> &update_values,
- enum_duplicates duplic, COND **where,
- bool select_insert)
+int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
+ List<Item> &fields, List_item *values,
+ List<Item> &update_fields, List<Item> &update_values,
+ enum_duplicates duplic, COND **where,
+ bool select_insert)
{
SELECT_LEX *select_lex= thd->lex->first_select_lex();
Name_resolution_context *context= &select_lex->context;
@@ -1567,29 +1577,34 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
bool insert_into_view= (table_list->view != 0);
bool res= 0;
table_map map= 0;
+ TABLE *table;
DBUG_ENTER("mysql_prepare_insert");
- DBUG_PRINT("enter", ("table_list: %p table: %p view: %d",
- table_list, table,
- (int)insert_into_view));
+ DBUG_PRINT("enter", ("table_list: %p view: %d",
+ table_list, (int) insert_into_view));
/* INSERT should have a SELECT or VALUES clause */
DBUG_ASSERT (!select_insert || !values);
if (mysql_handle_derived(thd->lex, DT_INIT))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
if (duplic == DUP_UPDATE)
{
/* it should be allocated before Item::fix_fields() */
if (table_list->set_insert_values(thd->mem_root))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
}
+ table= table_list->table;
+
+ if (table->file->check_if_updates_are_ignored("INSERT"))
+ DBUG_RETURN(-1);
+
if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
/* Prepare the fields in the statement. */
if (values)
@@ -1632,9 +1647,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
if (res)
DBUG_RETURN(res);
- if (!table)
- table= table_list->table;
-
if (check_duplic_insert_without_overlaps(thd, table, duplic) != 0)
DBUG_RETURN(true);
@@ -1642,7 +1654,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
{
// Additional memory may be required to create historical items.
if (table_list->set_insert_values(thd->mem_root))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
}
if (!select_insert)
@@ -1653,7 +1665,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
CHECK_DUP_ALLOW_DIFFERENT_ALIAS)))
{
update_non_unique_table_error(table_list, "INSERT", duplicate);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
}
select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds);
}
@@ -1663,7 +1675,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
*/
if (duplic == DUP_UPDATE || duplic == DUP_REPLACE)
prepare_for_positional_update(table, table_list);
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(0);
}
@@ -3703,12 +3715,14 @@ bool Delayed_insert::handle_inserts(void)
thd thread handler
RETURN
- FALSE OK
- TRUE Error
+ 0 OK
+ > 0 Error
+ < 0 Ok, ignore insert
*/
-bool mysql_insert_select_prepare(THD *thd, select_result *sel_res)
+int mysql_insert_select_prepare(THD *thd, select_result *sel_res)
{
+ int res;
LEX *lex= thd->lex;
SELECT_LEX *select_lex= lex->first_select_lex();
DBUG_ENTER("mysql_insert_select_prepare");
@@ -3718,11 +3732,11 @@ bool mysql_insert_select_prepare(THD *thd, select_result *sel_res)
clause if table is VIEW
*/
- if (mysql_prepare_insert(thd, lex->query_tables,
- lex->query_tables->table, lex->field_list, 0,
- lex->update_list, lex->value_list, lex->duplicates,
- &select_lex->where, TRUE))
- DBUG_RETURN(TRUE);
+ if ((res= mysql_prepare_insert(thd, lex->query_tables, lex->field_list, 0,
+ lex->update_list, lex->value_list,
+ lex->duplicates,
+ &select_lex->where, TRUE)))
+ DBUG_RETURN(res);
/*
If sel_res is not empty, it means we have items in returing_list.
@@ -3763,7 +3777,7 @@ bool mysql_insert_select_prepare(THD *thd, select_result *sel_res)
while ((table= ti++) && insert_tables--)
ti.remove();
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(0);
}
@@ -3809,15 +3823,18 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= lex->first_select_lex();
- res= setup_returning_fields(thd, table_list) ||
- setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0, 0) ||
- check_insert_fields(thd, table_list, *fields, values,
- !insert_into_view, 1, &map);
+ res= (setup_returning_fields(thd, table_list) ||
+ setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0,
+ 0) ||
+ check_insert_fields(thd, table_list, *fields, values,
+ !insert_into_view, 1, &map));
if (!res && fields->elements)
{
- Abort_on_warning_instant_set aws(thd, !info.ignore && thd->is_strict_mode());
- res= check_that_all_fields_are_given_values(thd, table_list->table, table_list);
+ Abort_on_warning_instant_set aws(thd,
+ !info.ignore && thd->is_strict_mode());
+ res= check_that_all_fields_are_given_values(thd, table_list->table,
+ table_list);
}
if (info.handle_duplicates == DUP_UPDATE && !res)
diff --git a/sql/sql_insert.h b/sql/sql_insert.h
index 14041976973..80666a81c50 100644
--- a/sql/sql_insert.h
+++ b/sql/sql_insert.h
@@ -23,11 +23,11 @@
typedef List<Item> List_item;
typedef struct st_copy_info COPY_INFO;
-bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
- List<Item> &fields, List_item *values,
- List<Item> &update_fields,
- List<Item> &update_values, enum_duplicates duplic,
- COND **where, bool select_insert);
+int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
+ List<Item> &fields, List_item *values,
+ List<Item> &update_fields,
+ List<Item> &update_values, enum_duplicates duplic,
+ COND **where, bool select_insert);
bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag,
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 592b53ceecf..61e3b89c9a3 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -3997,21 +3997,21 @@ bool LEX::can_not_use_merged()
}
}
-/*
- Detect that we need only table structure of derived table/view
+/**
+ Detect that we need only table structure of derived table/view.
- SYNOPSIS
- only_view_structure()
+ Also used by I_S tables (@see create_schema_table) to detect that
+ they need a full table structure and cannot optimize unused columns away
- RETURN
- TRUE yes, we need only structure
- FALSE no, we need data
+ @retval TRUE yes, we need only structure
+ @retval FALSE no, we need data
*/
bool LEX::only_view_structure()
{
switch (sql_command) {
case SQLCOM_SHOW_CREATE:
+ case SQLCOM_CHECKSUM:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_FIELDS:
case SQLCOM_REVOKE_ALL:
@@ -4019,6 +4019,8 @@ bool LEX::only_view_structure()
case SQLCOM_GRANT:
case SQLCOM_CREATE_VIEW:
return TRUE;
+ case SQLCOM_CREATE_TABLE:
+ return create_info.like();
default:
return FALSE;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a07121b9a58..3e59ad3afc9 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1334,10 +1334,8 @@ public:
table_value_constr *tvc;
bool in_tvc;
- /* The interface employed to execute the select query by a foreign engine */
- select_handler *select_h;
/* The object used to organize execution of the query by a foreign engine */
- Pushdown_select *pushdown_select;
+ select_handler *pushdown_select;
/** System Versioning */
public:
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 554c62f6538..0488b240bb2 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -98,6 +98,8 @@
#include "my_json_writer.h"
+#define PRIV_LOCK_TABLES (SELECT_ACL | LOCK_TABLES_ACL)
+
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
#ifdef WITH_ARIA_STORAGE_ENGINE
@@ -576,19 +578,21 @@ void init_update_queries(void)
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED |
- CF_UPDATES_DATA | CF_SP_BULK_SAFE;
+ CF_UPDATES_DATA |
+ CF_PS_ARRAY_BINDING_SAFE;
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED |
- CF_UPDATES_DATA | CF_SP_BULK_SAFE;
+ CF_UPDATES_DATA |
+ CF_PS_ARRAY_BINDING_SAFE;
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED |
CF_INSERTS_DATA |
- CF_SP_BULK_SAFE |
- CF_SP_BULK_OPTIMIZED;
+ CF_PS_ARRAY_BINDING_SAFE |
+ CF_PS_ARRAY_BINDING_OPTIMIZED;
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
@@ -598,7 +602,8 @@ void init_update_queries(void)
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED |
- CF_SP_BULK_SAFE | CF_DELETES_DATA;
+ CF_DELETES_DATA |
+ CF_PS_ARRAY_BINDING_SAFE;
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
@@ -608,8 +613,9 @@ void init_update_queries(void)
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
CF_CAN_BE_EXPLAINED |
- CF_INSERTS_DATA | CF_SP_BULK_SAFE |
- CF_SP_BULK_OPTIMIZED;
+ CF_INSERTS_DATA |
+ CF_PS_ARRAY_BINDING_SAFE |
+ CF_PS_ARRAY_BINDING_OPTIMIZED;
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
@@ -772,7 +778,7 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_BACKUP]= CF_AUTO_COMMIT_TRANS;
- sql_command_flags[SQLCOM_BACKUP_LOCK]= 0;
+ sql_command_flags[SQLCOM_BACKUP_LOCK]= CF_AUTO_COMMIT_TRANS;
/*
The following statements can deal with temporary tables,
@@ -1090,7 +1096,6 @@ int bootstrap(MYSQL_FILE *file)
thd->reset_kill_query(); /* Ensure that killed_errmsg is released */
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- thd->transaction->free();
thd->lex->restore_set_statement_var();
}
delete thd;
@@ -2825,6 +2830,36 @@ retry:
goto err;
}
}
+ /*
+ Check privileges of view tables here, after views were opened.
+ Either definer or invoker has to have PRIV_LOCK_TABLES to be able
+ to lock view and its tables. For mysqldump (that locks views
+ before dumping their structures) compatibility we allow locking
+ views that select from I_S or P_S tables, but downrade the lock
+ to TL_READ
+ */
+ if (table->belong_to_view &&
+ check_single_table_access(thd, PRIV_LOCK_TABLES, table, 1))
+ {
+ if (table->grant.m_internal.m_schema_access)
+ table->lock_type= TL_READ;
+ else
+ {
+ bool error= true;
+ if (Security_context *sctx= table->security_ctx)
+ {
+ table->security_ctx= 0;
+ error= check_single_table_access(thd, PRIV_LOCK_TABLES, table, 1);
+ table->security_ctx= sctx;
+ }
+ if (error)
+ {
+ my_error(ER_VIEW_INVALID, MYF(0), table->belong_to_view->view_db.str,
+ table->belong_to_view->view_name.str);
+ goto err;
+ }
+ }
+ }
}
if (lock_tables(thd, tables, counter, 0) ||
@@ -3683,6 +3718,7 @@ mysql_execute_command(THD *thd)
lex->sql_command != SQLCOM_BEGIN &&
lex->sql_command != SQLCOM_CALL &&
lex->sql_command != SQLCOM_EXECUTE &&
+ lex->sql_command != SQLCOM_EXECUTE_IMMEDIATE &&
!(sql_command_flags[lex->sql_command] & CF_AUTO_COMMIT_TRANS))
{
wsrep_start_trx_if_not_started(thd);
@@ -4255,6 +4291,11 @@ mysql_execute_command(THD *thd)
/* mysql_update return 2 if we need to switch to multi-update */
if (up_result != 2)
break;
+ if (thd->lex->period_conditions.is_set())
+ {
+ DBUG_ASSERT(0); // Should never happen
+ goto error;
+ }
}
/* fall through */
case SQLCOM_UPDATE_MULTI:
@@ -4569,6 +4610,14 @@ mysql_execute_command(THD *thd)
}
delete sel_result;
}
+ else if (res < 0)
+ {
+ /*
+ Insert should be ignored but we have to log the query in statement
+ format in the binary log
+ */
+ res= thd->binlog_current_query_unfiltered();
+ }
delete result;
if (save_protocol)
{
@@ -4924,6 +4973,13 @@ mysql_execute_command(THD *thd)
goto error;
}
+ /* Should not lock tables while BACKUP LOCK is active */
+ if (thd->mdl_backup_lock)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ goto error;
+ }
+
/*
Here we have to pre-open temporary tables for LOCK TABLES.
@@ -5217,7 +5273,7 @@ mysql_execute_command(THD *thd)
if (first_table && lex->type & (REFRESH_READ_LOCK|REFRESH_FOR_EXPORT))
{
/* Check table-level privileges. */
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
+ if (check_table_access(thd, PRIV_LOCK_TABLES, all_tables,
FALSE, UINT_MAX, FALSE))
goto error;
@@ -6328,24 +6384,21 @@ drop_routine(THD *thd, LEX *lex)
! lex->spname->m_explicit_name)
{
/* DROP FUNCTION <non qualified name> */
- udf_func *udf = find_udf(lex->spname->m_name.str,
- lex->spname->m_name.length);
- if (udf)
- {
- if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
- return 1;
-
- if (!mysql_drop_function(thd, &lex->spname->m_name))
- {
- my_ok(thd);
- return 0;
- }
- my_error(ER_SP_DROP_FAILED, MYF(0),
- "FUNCTION (UDF)", lex->spname->m_name.str);
+ enum drop_udf_result rc= mysql_drop_function(thd, &lex->spname->m_name);
+ switch (rc) {
+ case UDF_DEL_RESULT_DELETED:
+ my_ok(thd);
+ return 0;
+ case UDF_DEL_RESULT_ERROR:
return 1;
+ case UDF_DEL_RESULT_ABSENT:
+ goto absent;
}
- if (lex->spname->m_db.str == NULL)
+ DBUG_ASSERT("wrong return code" == 0);
+absent:
+ // If there was no current database, so it cannot be SP
+ if (!lex->spname->m_db.str)
{
if (lex->if_exists())
{
@@ -6681,7 +6734,7 @@ check_access(THD *thd, privilege_t want_access,
@param thd Thread handler
@param privilege requested privilege
- @param all_tables global table list of query
+ @param tables global table list of query
@param no_errors FALSE/TRUE - report/don't report error to
the client (using my_error() call).
@@ -6691,28 +6744,25 @@ check_access(THD *thd, privilege_t want_access,
1 access denied, error is sent to client
*/
-bool check_single_table_access(THD *thd, privilege_t privilege,
- TABLE_LIST *all_tables, bool no_errors)
+bool check_single_table_access(THD *thd, privilege_t privilege,
+ TABLE_LIST *tables, bool no_errors)
{
- Switch_to_definer_security_ctx backup_sctx(thd, all_tables);
+ Switch_to_definer_security_ctx backup_sctx(thd, tables);
const char *db_name;
- if ((all_tables->view || all_tables->field_translation) &&
- !all_tables->schema_table)
- db_name= all_tables->view_db.str;
+ if ((tables->view || tables->field_translation) && !tables->schema_table)
+ db_name= tables->view_db.str;
else
- db_name= all_tables->db.str;
+ db_name= tables->db.str;
- if (check_access(thd, privilege, db_name,
- &all_tables->grant.privilege,
- &all_tables->grant.m_internal,
- 0, no_errors))
+ if (check_access(thd, privilege, db_name, &tables->grant.privilege,
+ &tables->grant.m_internal, 0, no_errors))
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))
+ if (!(tables->belong_to_view &&
+ (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
+ check_grant(thd, privilege, tables, FALSE, 1, no_errors))
return 1;
return 0;
@@ -7755,7 +7805,6 @@ static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
void mysql_parse(THD *thd, char *rawbuf, uint length,
Parser_state *parser_state)
{
- int error __attribute__((unused));
DBUG_ENTER("mysql_parse");
DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on_MYSQLparse(););
DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on_ORAparse(););
@@ -7830,6 +7879,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
(char *) thd->security_ctx->host_or_ip,
0);
+ int error __attribute__((unused));
error= mysql_execute_command(thd);
MYSQL_QUERY_EXEC_DONE(error);
}
@@ -8928,8 +8978,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
SELECT_LEX *lex)
{
b->natural_join= a;
- a->part_of_natural_join= TRUE;
- b->part_of_natural_join= TRUE;
lex->prev_join_using= using_fields;
}
@@ -9795,7 +9843,7 @@ static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables)
if (is_temporary_table(table))
continue;
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, table,
+ if (check_table_access(thd, PRIV_LOCK_TABLES, table,
FALSE, 1, FALSE))
return TRUE;
}
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index 36dc68c292c..37861cf224f 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -41,7 +41,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
int mysql_multi_update_prepare(THD *thd);
int mysql_multi_delete_prepare(THD *thd);
-bool mysql_insert_select_prepare(THD *thd,select_result *sel_res);
+int mysql_insert_select_prepare(THD *thd,select_result *sel_res);
bool update_precheck(THD *thd, TABLE_LIST *tables);
bool delete_precheck(THD *thd, TABLE_LIST *tables);
bool insert_precheck(THD *thd, TABLE_LIST *tables);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 6753b857b54..57d6b27fcbb 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -124,6 +124,9 @@ When one supplies long data for a placeholder:
#include "mysql/psi/mysql_ps.h" // MYSQL_EXECUTE_PS
#include "wsrep_mysqld.h"
+/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */
+static const uint PARAMETER_FLAG_UNSIGNED = 128U << 8;
+
/**
A result class used to send cursor rows using the binary protocol.
*/
@@ -897,11 +900,73 @@ static bool insert_bulk_params(Prepared_statement *stmt,
DBUG_RETURN(0);
}
-static bool set_conversion_functions(Prepared_statement *stmt,
- uchar **data, uchar *data_end)
+
+/**
+ Checking if parameter type and flags are valid
+
+ @param typecode ushort value with type in low byte, and flags in high byte
+
+ @retval true this parameter is wrong
+ @retval false this parameter is OK
+*/
+
+static bool
+parameter_type_sanity_check(ushort typecode)
+{
+ /* Checking if type in lower byte is valid */
+ switch (typecode & 0xff) {
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ break;
+ /*
+ This types normally cannot be sent by client, so maybe it'd be
+ better to treat them like an error here.
+ */
+ case MYSQL_TYPE_TIMESTAMP2:
+ case MYSQL_TYPE_TIME2:
+ case MYSQL_TYPE_DATETIME2:
+ default:
+ return true;
+ };
+
+ // In Flags in high byte only unsigned bit may be set
+ if (typecode & ((~PARAMETER_FLAG_UNSIGNED) & 0x0000ff00))
+ {
+ return true;
+ }
+ return false;
+}
+
+static bool
+set_conversion_functions(Prepared_statement *stmt, uchar **data)
{
uchar *read_pos= *data;
- const uint signed_bit= 1 << 15;
+
DBUG_ENTER("set_conversion_functions");
/*
First execute or types altered by the client, setup the
@@ -914,12 +979,17 @@ static bool set_conversion_functions(Prepared_statement *stmt,
{
ushort typecode;
- if (read_pos >= data_end)
- DBUG_RETURN(1);
-
+ /*
+ stmt_execute_packet_sanity_check has already verified, that there
+ are enough data in the packet for data types
+ */
typecode= sint2korr(read_pos);
read_pos+= 2;
- (**it).unsigned_flag= MY_TEST(typecode & signed_bit);
+ if (parameter_type_sanity_check(typecode))
+ {
+ DBUG_RETURN(1);
+ }
+ (**it).unsigned_flag= MY_TEST(typecode & PARAMETER_FLAG_UNSIGNED);
(*it)->setup_conversion(thd, (uchar) (typecode & 0xff));
(*it)->sync_clones();
}
@@ -929,7 +999,7 @@ static bool set_conversion_functions(Prepared_statement *stmt,
static bool setup_conversion_functions(Prepared_statement *stmt,
- uchar **data, uchar *data_end,
+ uchar **data,
bool bulk_protocol= 0)
{
/* skip null bits */
@@ -942,7 +1012,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
if (*read_pos++) //types supplied / first execute
{
*data= read_pos;
- bool res= set_conversion_functions(stmt, data, data_end);
+ bool res= set_conversion_functions(stmt, data);
DBUG_RETURN(res);
}
*data= read_pos;
@@ -1243,9 +1313,8 @@ static bool mysql_test_insert(Prepared_statement *stmt,
table_list->table->insert_values=(uchar *)1;
}
- if (mysql_prepare_insert(thd, table_list, table_list->table,
- fields, values, update_fields, update_values,
- duplic, &unused_conds, FALSE))
+ if (mysql_prepare_insert(thd, table_list, fields, values, update_fields,
+ update_values, duplic, &unused_conds, FALSE))
goto error;
value_count= values->elements;
@@ -2618,6 +2687,15 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
if (stmt->prepare(packet, packet_length))
{
+ /*
+ Prepare failed and stmt will be freed.
+ Now we have to save the query_string in the so the
+ audit plugin later gets the meaningful notification.
+ */
+ if (alloc_query(thd, stmt->query_string.str(), stmt->query_string.length()))
+ {
+ thd->set_query(0, 0);
+ }
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
thd->clear_last_stmt();
@@ -2752,6 +2830,7 @@ bool Lex_prepared_stmt::get_dynamic_sql_string(THD *thd,
void mysql_sql_stmt_prepare(THD *thd)
{
LEX *lex= thd->lex;
+ CSET_STRING orig_query= thd->query_string;
const LEX_CSTRING *name= &lex->prepared_stmt.name();
Prepared_statement *stmt;
LEX_CSTRING query;
@@ -2822,7 +2901,16 @@ void mysql_sql_stmt_prepare(THD *thd)
thd->m_statement_psi,
stmt->name.str, stmt->name.length);
- if (stmt->prepare(query.str, (uint) query.length))
+ bool res= stmt->prepare(query.str, (uint) query.length);
+ /*
+ stmt->prepare() sets thd->query_string with the prepared
+ query, so the audit plugin gets adequate notification with the
+ mysqld_stmt_* set of functions.
+ But here we should restore the original query so it's mentioned in
+ logs properly.
+ */
+ thd->set_query(orig_query);
+ if (res)
{
/* Statement map deletes the statement on erase */
thd->stmt_map.erase(stmt);
@@ -2841,6 +2929,7 @@ void mysql_sql_stmt_prepare(THD *thd)
void mysql_sql_stmt_execute_immediate(THD *thd)
{
LEX *lex= thd->lex;
+ CSET_STRING orig_query= thd->query_string;
Prepared_statement *stmt;
LEX_CSTRING query;
DBUG_ENTER("mysql_sql_stmt_execute_immediate");
@@ -2889,6 +2978,14 @@ void mysql_sql_stmt_execute_immediate(THD *thd)
thd->free_items();
thd->free_list= free_list_backup;
+ /*
+ stmt->execute_immediately() sets thd->query_string with the executed
+ query, so the audit plugin gets adequate notification with the
+ mysqld_stmt_* set of functions.
+ But here we should restore the original query so it's mentioned in
+ logs properly.
+ */
+ thd->set_query_inner(orig_query);
stmt->lex->restore_set_statement_var();
delete stmt;
DBUG_VOID_RETURN;
@@ -3110,11 +3207,19 @@ static void mysql_stmt_execute_common(THD *thd,
void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
{
+ const uint packet_min_lenght= 9;
uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
+
+ DBUG_ENTER("mysqld_stmt_execute");
+
+ if (packet_length < packet_min_lenght)
+ {
+ my_error(ER_MALFORMED_PACKET, MYF(0));
+ DBUG_VOID_RETURN;
+ }
ulong stmt_id= uint4korr(packet);
ulong flags= (ulong) packet[4];
uchar *packet_end= packet + packet_length;
- DBUG_ENTER("mysqld_stmt_execute");
packet+= 9; /* stmt_id + 5 bytes of flags */
@@ -3170,6 +3275,84 @@ void mysqld_stmt_bulk_execute(THD *thd, char *packet_arg, uint packet_length)
DBUG_VOID_RETURN;
}
+/**
+ Additional packet checks for direct execution
+
+ @param thd THD handle
+ @param stmt prepared statement being directly executed
+ @param paket packet with parameters to bind
+ @param packet_end pointer to the byte after parameters end
+ @param bulk_op is it bulk operation
+ @param direct_exec is it direct execution
+ @param read_bytes need to read types (only with bulk_op)
+
+ @retval true this parameter is wrong
+ @retval false this parameter is OK
+*/
+
+static bool
+stmt_execute_packet_sanity_check(Prepared_statement *stmt,
+ uchar *packet, uchar *packet_end,
+ bool bulk_op, bool direct_exec,
+ bool read_types)
+{
+
+ DBUG_ASSERT((!read_types) || (read_types && bulk_op));
+ if (stmt->param_count > 0)
+ {
+ uint packet_length= static_cast<uint>(packet_end - packet);
+ uint null_bitmap_bytes= (bulk_op ? 0 : (stmt->param_count + 7)/8);
+ uint min_len_for_param_count = null_bitmap_bytes
+ + (bulk_op ? 0 : 1); /* sent types byte */
+
+ if (!bulk_op && packet_length >= min_len_for_param_count)
+ {
+ if ((read_types= packet[null_bitmap_bytes]))
+ {
+ /*
+ Should be 0 or 1. If the byte is not 1, that could mean,
+ e.g. that we read incorrect byte due to incorrect number
+ of sent parameters for direct execution (i.e. null bitmap
+ is shorter or longer, than it should be)
+ */
+ if (packet[null_bitmap_bytes] != '\1')
+ {
+ return true;
+ }
+ }
+ }
+
+ if (read_types)
+ {
+ /* 2 bytes per parameter of the type and flags */
+ min_len_for_param_count+= 2*stmt->param_count;
+ }
+ else
+ {
+ /*
+ If types are not sent, there is nothing to do here.
+ But for direct execution types should always be sent
+ */
+ return direct_exec;
+ }
+
+ /*
+ If true, the packet is guaranteed too short for the number of
+ parameters in the PS
+ */
+ return (packet_length < min_len_for_param_count);
+ }
+ else
+ {
+ /*
+ If there is no parameters, this should be normally already end
+ of the packet. If it's not - then error
+ */
+ return (packet_end > packet);
+ }
+ return false;
+}
+
/**
Common part of prepared statement execution
@@ -3205,10 +3388,33 @@ static void mysql_stmt_execute_common(THD *thd,
if (!(stmt= find_prepared_statement(thd, stmt_id)))
{
char llbuf[22];
+ /*
+ Did not find the statement with the provided stmt_id.
+ Set thd->query_string with the stmt_id so the
+ audit plugin gets the meaningful notification.
+ */
+ if (alloc_query(thd, llbuf, strlen(llbuf)))
+ thd->set_query(0, 0);
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast<int>(sizeof(llbuf)),
llstr(stmt_id, llbuf), "mysqld_stmt_execute");
DBUG_VOID_RETURN;
}
+
+ /*
+ In case of direct execution application decides how many parameters
+ to send.
+
+ Thus extra checks are required to prevent crashes caused by incorrect
+ interpretation of the packet data. Plus there can be always a broken
+ evil client.
+ */
+ if (stmt_execute_packet_sanity_check(stmt, packet, packet_end, bulk_op,
+ stmt_id == LAST_STMT_ID, read_types))
+ {
+ my_error(ER_MALFORMED_PACKET, MYF(0));
+ DBUG_VOID_RETURN;
+ }
+
stmt->read_types= read_types;
#if defined(ENABLED_PROFILING)
@@ -3969,6 +4175,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
DBUG_RETURN(TRUE);
}
+ /*
+ We'd like to have thd->query to be set to the actual query
+ after the function ends.
+ This value will be sent to audit plugins later.
+ As the statement is created, the query will be stored
+ in statement's arena. Normally the statement lives longer than
+ the end of this query, so we can just set thd->query_string to
+ be the stmt->query_string.
+ Though errors can result in statement to be freed. These cases
+ should be handled appropriately.
+ */
+ stmt_backup.query_string= thd->query_string;
+
old_stmt_arena= thd->stmt_arena;
thd->stmt_arena= this;
@@ -4131,7 +4350,7 @@ Prepared_statement::set_parameters(String *expanded_query,
{
#ifndef EMBEDDED_LIBRARY
uchar *null_array= packet;
- res= (setup_conversion_functions(this, &packet, packet_end) ||
+ res= (setup_conversion_functions(this, &packet) ||
set_params(this, null_array, packet, packet_end, expanded_query));
#else
/*
@@ -4321,7 +4540,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
return TRUE;
}
- if (!(sql_command_flags[lex->sql_command] & CF_SP_BULK_SAFE))
+ if (!(sql_command_flags[lex->sql_command] & CF_PS_ARRAY_BINDING_SAFE))
{
DBUG_PRINT("error", ("Command is not supported in bulk execution."));
my_error(ER_UNSUPPORTED_PS, MYF(0));
@@ -4331,7 +4550,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
#ifndef EMBEDDED_LIBRARY
if (read_types &&
- set_conversion_functions(this, &packet, packet_end))
+ set_conversion_functions(this, &packet))
#else
// bulk parameters are not supported for embedded, so it will an error
#endif
@@ -4353,7 +4572,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
Here we set parameters for not optimized commands,
optimized commands do it inside thier internal loop.
*/
- if (!(sql_command_flags[lex->sql_command] & CF_SP_BULK_OPTIMIZED))
+ if (!(sql_command_flags[lex->sql_command] & CF_PS_ARRAY_BINDING_OPTIMIZED))
{
if (set_bulk_parameters(TRUE))
{
@@ -4504,6 +4723,15 @@ Prepared_statement::reprepare()
*/
thd->get_stmt_da()->clear_warning_info(thd->query_id);
}
+ else
+ {
+ /*
+ Prepare failed and the 'copy' will be freed.
+ Now we have to restore the query_string in the so the
+ audit plugin later gets the meaningful notification.
+ */
+ thd->set_query(query(), query_length());
+ }
return error;
}
@@ -5127,7 +5355,7 @@ public:
Protocol_local(THD *thd_arg, ulong prealloc= 0) :
Protocol_text(thd_arg, prealloc),
- cur_data(0), first_data(0), data_tail(&first_data)
+ cur_data(0), first_data(0), data_tail(&first_data), alloc(0)
{}
protected:
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index ae5a26e1529..8f87d633d19 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -218,6 +218,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
thd->handler_tables_hash.records ||
thd->ull_hash.records ||
thd->global_read_lock.is_acquired() ||
+ thd->mdl_backup_lock ||
thd->current_backup_stage != BACKUP_FINISHED
);
@@ -530,7 +531,14 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
if (thd->current_backup_stage != BACKUP_FINISHED)
{
my_error(ER_BACKUP_LOCK_IS_ACTIVE, MYF(0));
- return true;
+ goto error;
+ }
+
+ /* Should not flush tables while BACKUP LOCK is active */
+ if (thd->mdl_backup_lock)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ goto error;
}
if (thd->lex->type & REFRESH_READ_LOCK)
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 0ac97bbeafd..77a1e46a75a 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -303,7 +303,8 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db,
DBUG_RETURN(skip_error || if_exists ? 0 : 1);
}
- if (ha_check_if_updates_are_ignored(thd, hton, "RENAME"))
+ if (hton != view_pseudo_hton &&
+ ha_check_if_updates_are_ignored(thd, hton, "RENAME"))
{
/*
Shared table. Just drop the old .frm as it's not correct anymore
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 420a64ba827..74b9b4dc393 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -439,11 +439,14 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
If LIMIT ROWS EXAMINED interrupted query execution, issue a warning,
continue with normal processing and produce an incomplete query result.
*/
+ bool saved_abort_on_warning= thd->abort_on_warning;
+ thd->abort_on_warning= false;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT,
ER_THD(thd, ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT),
thd->accessed_rows_and_keys,
thd->lex->limit_rows_examined->val_uint());
+ thd->abort_on_warning= saved_abort_on_warning;
thd->reset_killed();
}
/* Disable LIMIT ROWS EXAMINED after query execution. */
@@ -743,7 +746,7 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd)
void vers_select_conds_t::print(String *str, enum_query_type query_type) const
{
- switch (type) {
+ switch (orig_type) {
case SYSTEM_TIME_UNSPECIFIED:
break;
case SYSTEM_TIME_AS_OF:
@@ -991,6 +994,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
case SQLCOM_SELECT:
use_sysvar= true;
/* fall through */
+ case SQLCOM_CREATE_TABLE:
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_DELETE_MULTI:
@@ -1608,7 +1612,7 @@ int JOIN::optimize()
if (!(select_options & SELECT_DESCRIBE))
{
/* Prepare to execute the query pushed into a foreign engine */
- res= select_lex->pushdown_select->init();
+ res= select_lex->pushdown_select->prepare();
}
with_two_phase_optimization= false;
}
@@ -2781,6 +2785,10 @@ int JOIN::optimize_stage2()
(select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) |
(select_lex->ftfunc_list->elements ? SELECT_NO_JOIN_CACHE : 0);
+ if (select_lex->options & OPTION_SCHEMA_TABLE &&
+ optimize_schema_tables_reads(this))
+ DBUG_RETURN(1);
+
if (make_join_readinfo(this, select_opts_for_readinfo, no_jbuf_after))
DBUG_RETURN(1);
@@ -2957,10 +2965,6 @@ int JOIN::optimize_stage2()
having_is_correlated= MY_TEST(having->used_tables() & OUTER_REF_TABLE_BIT);
tmp_having= having;
- if ((select_lex->options & OPTION_SCHEMA_TABLE) &&
- optimize_schema_tables_reads(this))
- DBUG_RETURN(TRUE);
-
if (unlikely(thd->is_error()))
DBUG_RETURN(TRUE);
@@ -4642,19 +4646,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
}
/* Look for a table owned by an engine with the select_handler interface */
- select_lex->select_h= select_lex->find_select_handler(thd);
- if (select_lex->select_h)
- {
- /* Create a Pushdown_select object for later execution of the query */
- if (!(select_lex->pushdown_select=
- new (thd->mem_root) Pushdown_select(select_lex,
- select_lex->select_h)))
- {
- delete select_lex->select_h;
- select_lex->select_h= NULL;
- DBUG_RETURN(TRUE);
- }
- }
+ select_lex->pushdown_select= select_lex->find_select_handler(thd);
if ((err= join->optimize()))
{
@@ -18161,8 +18153,7 @@ public:
bool add_schema_fields(THD *thd, TABLE *table,
TMP_TABLE_PARAM *param,
- const ST_SCHEMA_TABLE &schema_table,
- const MY_BITMAP &bitmap);
+ const ST_SCHEMA_TABLE &schema_table);
bool finalize(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
bool do_not_open, bool keep_row_order);
@@ -18271,8 +18262,7 @@ TABLE *Create_tmp_table::start(THD *thd,
No need to change table name to lower case as we are only creating
MyISAM, Aria or HEAP tables here
*/
- fn_format(path, path, mysql_tmpdir, "",
- MY_REPLACE_EXT|MY_UNPACK_FILENAME);
+ fn_format(path, path, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME);
if (m_group)
{
@@ -19094,8 +19084,7 @@ err:
bool Create_tmp_table::add_schema_fields(THD *thd, TABLE *table,
TMP_TABLE_PARAM *param,
- const ST_SCHEMA_TABLE &schema_table,
- const MY_BITMAP &bitmap)
+ const ST_SCHEMA_TABLE &schema_table)
{
DBUG_ENTER("Create_tmp_table::add_schema_fields");
DBUG_ASSERT(table);
@@ -19114,11 +19103,9 @@ bool Create_tmp_table::add_schema_fields(THD *thd, TABLE *table,
for (fieldnr= 0; !defs[fieldnr].end_marker(); fieldnr++)
{
const ST_FIELD_INFO &def= defs[fieldnr];
- bool visible= bitmap_is_set(&bitmap, fieldnr);
Record_addr addr(def.nullable());
const Type_handler *h= def.type_handler();
- Field *field= h->make_schema_field(&table->mem_root, table,
- addr, def, visible);
+ Field *field= h->make_schema_field(&table->mem_root, table, addr, def);
if (!field)
{
thd->mem_root= mem_root_save;
@@ -19181,17 +19168,16 @@ TABLE *create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
TABLE *create_tmp_table_for_schema(THD *thd, TMP_TABLE_PARAM *param,
const ST_SCHEMA_TABLE &schema_table,
- const MY_BITMAP &bitmap,
longlong select_options,
const LEX_CSTRING &table_alias,
- bool keep_row_order)
+ bool do_not_open, bool keep_row_order)
{
TABLE *table;
Create_tmp_table maker(param, (ORDER *) NULL, false, false,
select_options, HA_POS_ERROR);
if (!(table= maker.start(thd, param, &table_alias)) ||
- maker.add_schema_fields(thd, table, param, schema_table, bitmap) ||
- maker.finalize(thd, table, param, false, keep_row_order))
+ maker.add_schema_fields(thd, table, param, schema_table) ||
+ maker.finalize(thd, table, param, do_not_open, keep_row_order))
{
maker.cleanup_on_failure(thd, table);
return NULL;
@@ -19572,14 +19558,10 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
}
}
- if (unlikely((error= maria_create(share->path.str,
- file_type,
- share->keys, &keydef,
- (uint) (*recinfo-start_recinfo),
- start_recinfo,
- share->uniques, &uniquedef,
- &create_info,
- create_flags))))
+ if (unlikely((error= maria_create(share->path.str, file_type, share->keys,
+ &keydef, (uint) (*recinfo-start_recinfo),
+ start_recinfo, share->uniques, &uniquedef,
+ &create_info, create_flags))))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
table->db_stat=0;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 2087438e086..2aba63ddc79 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -2436,10 +2436,9 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bool keep_row_order= FALSE);
TABLE *create_tmp_table_for_schema(THD *thd, TMP_TABLE_PARAM *param,
const ST_SCHEMA_TABLE &schema_table,
- const MY_BITMAP &bitmap,
longlong select_options,
const LEX_CSTRING &alias,
- bool keep_row_order);
+ bool do_not_open, bool keep_row_order);
void free_tmp_table(THD *thd, TABLE *entry);
bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
@@ -2517,29 +2516,6 @@ public:
class select_handler;
-class Pushdown_select: public Sql_alloc
-{
-private:
- bool is_analyze;
- List<Item> result_columns;
- bool send_result_set_metadata();
- bool send_data();
- bool send_eof();
-
-public:
- SELECT_LEX *select;
- select_handler *handler;
-
- Pushdown_select(SELECT_LEX *sel, select_handler *h);
-
- ~Pushdown_select();
-
- bool init();
-
- int execute();
-};
-
-
bool test_if_order_compatible(SQL_I_List<ORDER> &a, SQL_I_List<ORDER> &b);
int test_if_group_changed(List<Cached_item> &list);
int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1e32e8b2925..c00476871e4 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3675,8 +3675,6 @@ static bool show_status_array(THD *thd, const char *wild,
CHARSET_INFO *charset= system_charset_info;
DBUG_ENTER("show_status_array");
- thd->count_cuted_fields= CHECK_FIELD_WARN;
-
prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
if (*prefix)
*prefix_end++= '_';
@@ -3776,6 +3774,8 @@ static bool show_status_array(THD *thd, const char *wild,
pos= get_one_variable(thd, var, scope, show_type, status_var,
&charset, buff, &length);
+ if (table->field[1]->field_length)
+ thd->count_cuted_fields= CHECK_FIELD_WARN;
table->field[1]->store(pos, (uint32) length, charset);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
table->field[1]->set_notnull();
@@ -5251,6 +5251,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
free_root(&tmp_mem_root, MY_MARK_BLOCKS_FREE);
}
}
+ if (thd->killed == ABORT_QUERY)
+ {
+ error= 0;
+ goto err;
+ }
}
}
}
@@ -8041,51 +8046,6 @@ ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx)
return &schema_tables[schema_table_idx];
}
-static void
-mark_all_fields_used_in_query(THD *thd,
- ST_FIELD_INFO *schema_fields,
- MY_BITMAP *bitmap,
- Item *all_items)
-{
- Item *item;
- DBUG_ENTER("mark_all_fields_used_in_query");
-
- /* If not SELECT command, return all columns */
- if (thd->lex->sql_command != SQLCOM_SELECT &&
- thd->lex->sql_command != SQLCOM_SET_OPTION)
- {
- bitmap_set_all(bitmap);
- DBUG_VOID_RETURN;
- }
-
- for (item= all_items ; item ; item= item->next)
- {
- if (item->type() == Item::FIELD_ITEM)
- {
- ST_FIELD_INFO *fields= schema_fields;
- uint count;
- Item_field *item_field= (Item_field*) item;
-
- /* item_field can be '*' as this function is called before fix_fields */
- if (item_field->field_name.str == star_clex_str.str)
- {
- bitmap_set_all(bitmap);
- break;
- }
- for (count=0; !fields->end_marker(); fields++, count++)
- {
- if (!my_strcasecmp(system_charset_info, fields->name().str,
- item_field->field_name.str))
- {
- bitmap_set_bit(bitmap, count);
- break;
- }
- }
- }
- }
- DBUG_VOID_RETURN;
-}
-
/**
Create information_schema table using schema_table data.
@@ -8098,7 +8058,7 @@ mark_all_fields_used_in_query(THD *thd,
0<decimals<10 and 0<=length<100 .
@param
- thd thread handler
+ thd thread handler
@param table_list Used to pass I_S table information(fields info, tables
parameters etc) and table name.
@@ -8109,32 +8069,16 @@ mark_all_fields_used_in_query(THD *thd,
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
{
- uint field_count;
- Item *all_items;
+ uint field_count= 0;
TABLE *table;
ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
- ST_FIELD_INFO *fields_info= schema_table->fields_info;
- ST_FIELD_INFO *fields;
- MY_BITMAP bitmap;
- my_bitmap_map *buf;
+ ST_FIELD_INFO *fields= schema_table->fields_info;
+ bool need_all_fieds= table_list->schema_table_reformed || // SHOW command
+ thd->lex->only_view_structure(); // need table structure
DBUG_ENTER("create_schema_table");
- for (field_count= 0, fields= fields_info; !fields->end_marker(); fields++)
+ for (; !fields->end_marker(); fields++)
field_count++;
- if (!(buf= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count))))
- DBUG_RETURN(NULL);
- my_bitmap_init(&bitmap, buf, field_count, 0);
-
- if (!thd->stmt_arena->is_conventional() &&
- thd->mem_root != thd->stmt_arena->mem_root)
- all_items= thd->stmt_arena->free_list;
- else
- all_items= thd->free_list;
-
- if (table_list->part_of_natural_join)
- bitmap_set_all(&bitmap);
- else
- mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items);
TMP_TABLE_PARAM *tmp_table_param = new (thd->mem_root) TMP_TABLE_PARAM;
tmp_table_param->init();
@@ -8143,13 +8087,9 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
tmp_table_param->schema_table= 1;
SELECT_LEX *select_lex= table_list->select_lex;
bool keep_row_order= is_show_command(thd);
- if (!(table= create_tmp_table_for_schema(thd, tmp_table_param,
- *schema_table, bitmap,
- (select_lex->options |
- thd->variables.option_bits |
- TMP_TABLE_ALL_COLUMNS),
- table_list->alias,
- keep_row_order)))
+ if (!(table= create_tmp_table_for_schema(thd, tmp_table_param, *schema_table,
+ (select_lex->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS),
+ table_list->alias, !need_all_fieds, keep_row_order)))
DBUG_RETURN(0);
my_bitmap_map* bitmaps=
(my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
@@ -8541,6 +8481,68 @@ end:
}
+static int optimize_schema_tables_memory_usage(TABLE_LIST *table_list)
+{
+ TABLE *table= table_list->table;
+ THD *thd=table->in_use;
+ if (!table->is_created())
+ {
+ TMP_TABLE_PARAM *p= table_list->schema_table_param;
+ TMP_ENGINE_COLUMNDEF *from_recinfo, *to_recinfo;
+ DBUG_ASSERT(table->s->keys == 0);
+ DBUG_ASSERT(table->s->uniques == 0);
+
+ // XXX HACK HACK HACK: in a stored function, RETURN (SELECT ...)
+ // enables warnings (in THD::sp_eval_expr) for the whole val_xxx/store pair,
+ // while the intention is to warn only for store(). Until this is
+ // fixed let's avoid data truncation warnings in I_S->fill_table()
+ if (thd->count_cuted_fields == CHECK_FIELD_IGNORE)
+ {
+
+ uchar *cur= table->field[0]->ptr;
+ /* first recinfo could be a NULL bitmap, not an actual Field */
+ from_recinfo= to_recinfo= p->start_recinfo + (cur != table->record[0]);
+ for (uint i=0; i < table->s->fields; i++, from_recinfo++)
+ {
+ Field *field= table->field[i];
+ DBUG_ASSERT(field->vcol_info == 0);
+ DBUG_ASSERT(from_recinfo->length);
+ DBUG_ASSERT(from_recinfo->length == field->pack_length_in_rec());
+ if (bitmap_is_set(table->read_set, i))
+ {
+ field->move_field(cur);
+ *to_recinfo++= *from_recinfo;
+ cur+= from_recinfo->length;
+ }
+ else
+ {
+ field= new (thd->mem_root) Field_string(cur, 0, field->null_ptr,
+ field->null_bit, Field::NONE,
+ &field->field_name, field->dtcollation());
+ field->init(table);
+ field->field_index= i;
+ DBUG_ASSERT(field->pack_length_in_rec() == 0);
+ table->field[i]= field;
+ }
+ }
+ if ((table->s->reclength= (ulong)(cur - table->record[0])) == 0)
+ {
+ /* all fields were optimized away. Force a non-0-length row */
+ table->s->reclength= to_recinfo->length= 1;
+ to_recinfo++;
+ }
+ p->recinfo= to_recinfo;
+ } // XXX end of HACK HACK HACK
+
+ // TODO switch from Aria to Memory if all blobs were optimized away?
+ if (instantiate_tmp_table(table, p->keyinfo, p->start_recinfo, &p->recinfo,
+ table_list->select_lex->options | thd->variables.option_bits))
+ return 1;
+ }
+ return 0;
+}
+
+
/*
This is the optimizer part of get_schema_tables_result().
*/
@@ -8561,6 +8563,9 @@ bool optimize_schema_tables_reads(JOIN *join)
TABLE_LIST *table_list= tab->table->pos_in_table_list;
if (table_list->schema_table && thd->fill_information_schema_tables())
{
+ if (optimize_schema_tables_memory_usage(table_list))
+ DBUG_RETURN(1);
+
/* A value of 0 indicates a dummy implementation */
if (table_list->schema_table->fill_table == 0)
continue;
@@ -8583,10 +8588,10 @@ bool optimize_schema_tables_reads(JOIN *join)
cond= tab->cache_select->cond;
}
if (optimize_for_get_all_tables(thd, table_list, cond))
- DBUG_RETURN(TRUE); // Handle OOM
+ DBUG_RETURN(1); // Handle OOM
}
}
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(0);
}
@@ -8651,13 +8656,10 @@ bool get_schema_tables_result(JOIN *join,
continue;
/*
- If schema table is already processed and
- the statement is not a subselect then
- we don't need to fill this table again.
- If schema table is already processed and
- schema_table_state != executed_place then
- table is already processed and
- we should skip second data processing.
+ If schema table is already processed and the statement is not a
+ subselect then we don't need to fill this table again. If schema table
+ is already processed and schema_table_state != executed_place then
+ table is already processed and we should skip second data processing.
*/
if (table_list->schema_table_state &&
(!is_subselect || table_list->schema_table_state != executed_place))
@@ -8719,8 +8721,7 @@ bool get_schema_tables_result(JOIN *join,
It also means that an audit plugin cannot process the error correctly
either. See also thd->clear_error()
*/
- thd->get_stmt_da()->push_warning(thd,
- thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->push_warning(thd, thd->get_stmt_da()->sql_errno(),
thd->get_stmt_da()->get_sqlstate(),
Sql_condition::WARN_LEVEL_ERROR,
thd->get_stmt_da()->message());
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 3230052dd84..3b23328183c 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -255,10 +255,12 @@ class Sort_keys :public Sql_alloc,
{
public:
Sort_keys(SORT_FIELD* arr, size_t count):
- Sort_keys_array(arr, count),
- m_using_packed_sortkeys(false),
- size_of_packable_fields(0),
- sort_length(0)
+ Sort_keys_array(arr, count),
+ m_using_packed_sortkeys(false),
+ size_of_packable_fields(0),
+ sort_length_with_original_values(0),
+ sort_length_with_memcmp_values(0),
+ parameters_computed(false)
{
DBUG_ASSERT(!is_null());
}
@@ -280,14 +282,24 @@ public:
return size_of_packable_fields;
}
- void set_sort_length(uint len)
+ void set_sort_length_with_original_values(uint len)
{
- sort_length= len;
+ sort_length_with_original_values= len;
}
- uint get_sort_length()
+ uint get_sort_length_with_original_values()
{
- return sort_length;
+ return sort_length_with_original_values;
+ }
+
+ void set_sort_length_with_memcmp_values(uint len)
+ {
+ sort_length_with_memcmp_values= len;
+ }
+
+ uint get_sort_length_with_memcmp_values()
+ {
+ return sort_length_with_memcmp_values;
}
static void store_sortkey_length(uchar *p, uint sz)
@@ -307,9 +319,12 @@ public:
void increment_original_sort_length(uint len)
{
- sort_length+= len;
+ sort_length_with_original_values+= len;
}
+ bool is_parameters_computed() { return parameters_computed; }
+ void set_parameters_computed(bool val) { parameters_computed= val; }
+
static const uint size_of_length_field= 4;
private:
@@ -317,10 +332,21 @@ private:
uint size_of_packable_fields; // Total length bytes for packable columns
/*
- The length that would be needed if we stored non-packed mem-comparable
- images of fields?
+ The sort length for all the keyparts storing the original values
+ */
+ uint sort_length_with_original_values;
+
+ /*
+ The sort length for all the keyparts storing the mem-comparable images
+ */
+ uint sort_length_with_memcmp_values;
+
+ /*
+ TRUE parameters(like sort_length_* , size_of_packable_field)
+ are computed
+ FALSE otherwise.
*/
- uint sort_length;
+ bool parameters_computed;
};
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index e2defba434d..94f2e6fc8c6 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -767,10 +767,10 @@ void Static_binary_string::qs_append(double d)
NULL);
}
-void Static_binary_string::qs_append(double *d)
+void Static_binary_string::qs_append(const double *d)
{
double ld;
- float8get(ld, (char*) d);
+ float8get(ld, (const char*) d);
qs_append(ld);
}
@@ -858,7 +858,7 @@ int sortcmp(const String *s,const String *t, CHARSET_INFO *cs)
int stringcmp(const String *s,const String *t)
{
uint32 s_len=s->length(),t_len=t->length(),len=MY_MIN(s_len,t_len);
- int cmp= memcmp(s->ptr(), t->ptr(), len);
+ int cmp= len ? memcmp(s->ptr(), t->ptr(), len) : 0;
return (cmp) ? cmp : (int) (s_len - t_len);
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 2ef817ea0ad..b3eca118b63 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -314,7 +314,8 @@ public:
}
void q_append(const char *data, size_t data_len)
{
- memcpy(Ptr + str_length, data, data_len);
+ if (data_len)
+ memcpy(Ptr + str_length, data, data_len);
DBUG_ASSERT(str_length <= UINT_MAX32 - data_len);
str_length += (uint)data_len;
}
@@ -345,7 +346,7 @@ public:
void qs_append(const char *str, size_t len);
void qs_append_hex(const char *str, uint32 len);
void qs_append(double d);
- void qs_append(double *d);
+ void qs_append(const double *d);
inline void qs_append(const char c)
{
Ptr[str_length]= c;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 15d190c3139..c2ba9bcadfb 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -75,9 +75,8 @@ static int copy_data_between_tables(THD *, TABLE *,TABLE *,
ha_rows *, ha_rows *,
Alter_info::enum_enable_or_disable,
Alter_table_ctx *);
-static bool append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info,
- Alter_info *alter_info, KEY **key_info,
- uint key_count);
+static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info,
+ Key *key);
static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
uint *, handler *, KEY **, uint *, int);
static uint blob_length_by_type(enum_field_types type);
@@ -1823,10 +1822,6 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
if (flags & WFRM_WRITE_SHADOW)
{
- if (append_system_key_parts(lpt->thd, lpt->create_info, lpt->alter_info,
- &lpt->key_info_buffer, 0))
- DBUG_RETURN(true);
-
if (mysql_prepare_create_table(lpt->thd, lpt->create_info, lpt->alter_info,
&lpt->db_options, lpt->table->file,
&lpt->key_info_buffer, &lpt->key_count,
@@ -2828,6 +2823,12 @@ bool log_drop_table(THD *thd, const LEX_CSTRING *db_name,
append_identifier(thd, &query, table_name);
query.append(STRING_WITH_LEN("/* Generated to handle "
"failed CREATE OR REPLACE */"));
+
+ /*
+ In case of temporary tables we don't have to log the database name
+ in the binary log. We log this for non temporary tables, as the slave
+ may use a filter to ignore queries for a specific database.
+ */
error= thd->binlog_query(THD::STMT_QUERY_TYPE,
query.ptr(), query.length(),
FALSE, FALSE, temporary_table, 0) > 0;
@@ -3451,10 +3452,9 @@ Key *
mysql_add_invisible_index(THD *thd, List<Key> *key_list,
LEX_CSTRING* field_name, enum Key::Keytype type)
{
- Key *key= NULL;
- key= new (thd->mem_root) Key(type, &null_clex_str, HA_KEY_ALG_UNDEF,
- false, DDL_options(DDL_options::OPT_NONE));
- key->columns.push_back(new(thd->mem_root) Key_part_spec(field_name, 0),
+ Key *key= new (thd->mem_root) Key(type, &null_clex_str, HA_KEY_ALG_UNDEF,
+ false, DDL_options(DDL_options::OPT_NONE));
+ key->columns.push_back(new(thd->mem_root) Key_part_spec(field_name, 0, true),
thd->mem_root);
key_list->push_back(key, thd->mem_root);
return key;
@@ -3552,7 +3552,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
Create_field *sql_field,*dup_field;
uint field,null_fields,max_key_length;
ulong record_offset= 0;
- KEY *key_info;
KEY_PART_INFO *key_part_info;
int field_no,dup_no;
int select_field_pos,auto_increment=0;
@@ -3870,6 +3869,57 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
thd->abort_on_warning= sav_abort_on_warning;
}
}
+
+ KEY *key_info= *key_info_buffer= (KEY*)thd->calloc(sizeof(KEY) * (*key_count));
+ if (!*key_info_buffer)
+ DBUG_RETURN(true); // Out of memory
+
+ key_iterator.rewind();
+ while ((key=key_iterator++))
+ {
+ if (key->name.str == ignore_key || key->type == Key::FOREIGN_KEY)
+ continue;
+ /* Create the key->ame based on the first column (if not given) */
+ if (key->type == Key::PRIMARY)
+ {
+ if (primary_key)
+ {
+ my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY),
+ MYF(0));
+ DBUG_RETURN(true);
+ }
+ key_name=primary_key_name;
+ primary_key=1;
+ }
+ else if (!(key_name= key->name.str))
+ {
+ auto field_name= key->columns.elem(0)->field_name;
+ it.rewind();
+ while ((sql_field=it++) &&
+ lex_string_cmp(system_charset_info,
+ &field_name,
+ &sql_field->field_name));
+ if (sql_field)
+ field_name= sql_field->field_name;
+ key_name=make_unique_key_name(thd, field_name.str,
+ *key_info_buffer, key_info);
+ }
+ if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
+ {
+ my_error(ER_DUP_KEYNAME, MYF(0), key_name);
+ DBUG_RETURN(true);
+ }
+
+ key_info->name.str= (char*) key_name;
+ key_info->name.length= strlen(key_name);
+ key->name= key_info->name;
+
+ int parts_added= append_system_key_parts(thd, create_info, key);
+ if (parts_added < 0)
+ DBUG_RETURN(true);
+ key_parts += parts_added;
+ key_info++;
+ }
tmp=file->max_keys();
if (*key_count > tmp)
{
@@ -3877,11 +3927,11 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(TRUE);
}
- (*key_info_buffer)= key_info= (KEY*) thd->calloc(sizeof(KEY) * (*key_count));
key_part_info=(KEY_PART_INFO*) thd->calloc(sizeof(KEY_PART_INFO)*key_parts);
- if (!*key_info_buffer || ! key_part_info)
- DBUG_RETURN(TRUE); // Out of memory
+ if (!key_part_info)
+ DBUG_RETURN(true); // Out of memory
+ key_info= *key_info_buffer;
key_iterator.rewind();
key_number=0;
for (; (key=key_iterator++) ; key_number++)
@@ -4028,7 +4078,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
/*
Either field is not present or field visibility is > INVISIBLE_USER
*/
- if (!sql_field)
+ if (!sql_field || (sql_field->invisible > INVISIBLE_USER &&
+ !column->generated))
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
@@ -4251,32 +4302,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
key_length+= key_part_length;
key_part_info++;
-
- /* Create the key name based on the first column (if not given) */
- if (column_nr == 0)
- {
- if (key->type == Key::PRIMARY)
- {
- if (primary_key)
- {
- my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY),
- MYF(0));
- DBUG_RETURN(TRUE);
- }
- key_name=primary_key_name;
- primary_key=1;
- }
- else if (!(key_name= key->name.str))
- key_name=make_unique_key_name(thd, sql_field->field_name.str,
- *key_info_buffer, key_info);
- if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
- {
- my_error(ER_DUP_KEYNAME, MYF(0), key_name);
- DBUG_RETURN(TRUE);
- }
- key_info->name.str= (char*) key_name;
- key_info->name.length= strlen(key_name);
- }
}
if (!key_info->name.str || check_column_name(key_info->name.str))
{
@@ -4709,69 +4734,75 @@ bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root)
}
-static bool append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info,
- Alter_info *alter_info, KEY **key_info,
- uint key_count)
+/**
+ Appends key parts generated by mariadb server.
+ Adds row_end in UNIQUE keys for system versioning,
+ and period fields for WITHOUT OVERLAPS.
+ @param thd Thread data
+ @param create_info Table create info
+ @param key Parsed key
+ @return a number of key parts added to key.
+ */
+static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info,
+ Key *key)
{
const Lex_ident &row_start_field= create_info->vers_info.as_row.start;
const Lex_ident &row_end_field= create_info->vers_info.as_row.end;
DBUG_ASSERT(!create_info->versioned() || (row_start_field && row_end_field));
- List_iterator<Key> key_it(alter_info->key_list);
- Key *key= NULL;
-
- if (create_info->versioned())
+ int result = 0;
+ if (create_info->versioned() && (key->type == Key::PRIMARY
+ || key->type == Key::UNIQUE))
{
- while ((key=key_it++))
+ Key_part_spec *key_part=NULL;
+ List_iterator<Key_part_spec> part_it(key->columns);
+ while ((key_part=part_it++))
{
- if (key->type != Key::PRIMARY && key->type != Key::UNIQUE)
- continue;
-
- Key_part_spec *key_part=NULL;
- List_iterator<Key_part_spec> part_it(key->columns);
- while ((key_part=part_it++))
- {
- if (row_start_field.streq(key_part->field_name) ||
- row_end_field.streq(key_part->field_name))
- break;
- }
- if (!key_part)
- key->columns.push_back(new Key_part_spec(&row_end_field, 0));
+ if (row_start_field.streq(key_part->field_name) ||
+ row_end_field.streq(key_part->field_name))
+ break;
}
- key_it.rewind();
+ if (!key_part)
+ {
+ key->columns.push_back(new (thd->mem_root)
+ Key_part_spec(&row_end_field, 0, true));
+ result++;
+ }
+
}
- while ((key=key_it++))
+ if (key->without_overlaps)
{
- if (key->without_overlaps)
+ DBUG_ASSERT(key->type == Key::PRIMARY || key->type == Key::UNIQUE);
+ if (!create_info->period_info.is_set()
+ || !key->period.streq(create_info->period_info.name))
{
- DBUG_ASSERT(key->type == Key::PRIMARY || key->type == Key::UNIQUE);
- if (!create_info->period_info.is_set()
- || !key->period.streq(create_info->period_info.name))
- {
- my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str);
- return true;
- }
+ my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str);
+ return -1;
+ }
- const auto &period_start= create_info->period_info.period.start;
- const auto &period_end= create_info->period_info.period.end;
- List_iterator<Key_part_spec> part_it(key->columns);
- while (Key_part_spec *key_part= part_it++)
+ const auto &period_start= create_info->period_info.period.start;
+ const auto &period_end= create_info->period_info.period.end;
+ List_iterator<Key_part_spec> part_it(key->columns);
+ while (Key_part_spec *key_part= part_it++)
+ {
+ if (period_start.streq(key_part->field_name)
+ || period_end.streq(key_part->field_name))
{
- if (period_start.streq(key_part->field_name)
- || period_end.streq(key_part->field_name))
- {
- my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str,
- key_part->field_name);
- return true;
- }
+ my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str,
+ key_part->field_name.str);
+ return -1;
}
- key->columns.push_back(new Key_part_spec(&period_end, 0));
- key->columns.push_back(new Key_part_spec(&period_start, 0));
}
+ const auto &period= create_info->period_info.period;
+ key->columns.push_back(new (thd->mem_root)
+ Key_part_spec(&period.end, 0, true));
+ key->columns.push_back(new (thd->mem_root)
+ Key_part_spec(&period.start, 0, true));
+ result += 2;
}
- return false;
+ return result;
}
handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db,
@@ -5009,10 +5040,6 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db,
}
#endif
- if (append_system_key_parts(thd, create_info, alter_info, key_info,
- *key_count))
- goto err;
-
if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options,
file, key_info, key_count, create_table_mode))
goto err;
@@ -5079,6 +5106,7 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
int error= 1;
bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY;
bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only;
+ handlerton *exists_hton;
DBUG_ENTER("mysql_create_table_no_lock");
DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d path: %s",
db.str, table_name.str, internal_tmp_table, path));
@@ -5167,8 +5195,16 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
goto err;
}
- if (!internal_tmp_table && ha_table_exists(thd, &db, &table_name))
+ if (!internal_tmp_table && ha_table_exists(thd, &db, &table_name,
+ &exists_hton))
{
+ if (ha_check_if_updates_are_ignored(thd, exists_hton, "CREATE"))
+ {
+ /* Don't create table. CREATE will still be logged in binary log */
+ error= 0;
+ goto err;
+ }
+
if (options.or_replace())
{
(void) delete_statistics_for_table(thd, &db, &table_name);
@@ -5196,7 +5232,8 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
thd->variables.option_bits|= OPTION_KEEP_LOG;
thd->log_current_statement= 1;
create_info->table_was_deleted= 1;
- DBUG_EXECUTE_IF("send_kill_after_delete", thd->set_killed(KILL_QUERY); );
+ DBUG_EXECUTE_IF("send_kill_after_delete",
+ thd->set_killed(KILL_QUERY); );
/*
Restart statement transactions for the case of CREATE ... SELECT.
@@ -5206,7 +5243,20 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
goto err;
}
else if (options.if_not_exists())
+ {
+ /*
+ We never come here as part of normal create table as table existance
+ is checked in open_and_lock_tables(). We may come here as part of
+ ALTER TABLE when converting a table for a distributed engine to a
+ a local one.
+ */
+
+ /* Log CREATE IF NOT EXISTS on slave for distributed engines */
+ if (thd->slave_thread && (exists_hton && exists_hton->flags &
+ HTON_IGNORE_UPDATES))
+ thd->log_current_statement= 1;
goto warn;
+ }
else
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name.str);
@@ -5437,12 +5487,21 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
thd->lex->create_info.options|= create_info->options;
/* Open or obtain an exclusive metadata lock on table being created */
+ create_table->db_type= 0;
result= open_and_lock_tables(thd, *create_info, create_table, FALSE, 0);
thd->lex->create_info.options= save_thd_create_info_options;
if (result)
{
+ if (thd->slave_thread &&
+ !thd->is_error() && create_table->db_type &&
+ (create_table->db_type->flags & HTON_IGNORE_UPDATES))
+ {
+ /* Table existed in distributed engine. Log query to binary log */
+ result= 0;
+ goto err;
+ }
/* is_error() may be 0 if table existed and we generated a warning */
DBUG_RETURN(thd->is_error());
}
@@ -5714,7 +5773,8 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
DBUG_ENTER("mysql_rename_table");
DBUG_ASSERT(base);
DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'",
- old_db->str, old_name->str, new_db->str, new_name->str));
+ old_db->str, old_name->str, new_db->str,
+ new_name->str));
// Temporarily disable foreign key checks
if (flags & NO_FK_CHECKS)
@@ -5724,8 +5784,8 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
build_table_filename(from, sizeof(from) - 1, old_db->str, old_name->str, "",
flags & FN_FROM_IS_TMP);
- length= build_table_filename(to, sizeof(to) - 1, new_db->str, new_name->str, "",
- flags & FN_TO_IS_TMP);
+ length= build_table_filename(to, sizeof(to) - 1, new_db->str,
+ new_name->str, "", flags & FN_TO_IS_TMP);
// Check if we hit FN_REFLEN bytes along with file extension.
if (length+reg_ext_length > FN_REFLEN)
{
@@ -6677,7 +6737,7 @@ remove_key:
DBUG_ASSERT(key->or_replace());
Alter_drop::drop_type type= (key->type == Key::FOREIGN_KEY) ?
Alter_drop::FOREIGN_KEY : Alter_drop::KEY;
- Alter_drop *ad= new Alter_drop(type, key->name.str, FALSE);
+ Alter_drop *ad= new (thd->mem_root) Alter_drop(type, key->name.str, FALSE);
if (ad != NULL)
{
// Adding the index into the drop list for replacing
@@ -7171,9 +7231,8 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE;
}
- /* Check if field was renamed */
- if (lex_string_cmp(system_charset_info, &field->field_name,
- &new_field->field_name))
+ /* Check if field was renamed (case-sensitive for detecting case change) */
+ if (cmp(&field->field_name, &new_field->field_name))
{
field->flags|= FIELD_IS_RENAMED;
ha_alter_info->handler_flags|= ALTER_COLUMN_NAME;
@@ -8823,8 +8882,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
key_part_length= 0; // Use whole field
}
key_part_length /= kfield->charset()->mbmaxlen;
- key_parts.push_back(new (thd->mem_root) Key_part_spec(
- &cfield->field_name, key_part_length),
+ key_parts.push_back(new (thd->mem_root) Key_part_spec(&cfield->field_name,
+ key_part_length, true),
thd->mem_root);
}
if (table->s->tmp_table == NO_TMP_TABLE)
@@ -9709,6 +9768,22 @@ static int create_table_for_inplace_alter(THD *thd,
}
+/*
+ log query if slave thread and send my_ok()
+
+ Help function for mysql_alter_table()
+*/
+
+static bool log_and_ok(THD *thd)
+{
+ if (thd->slave_thread &&
+ write_bin_log(thd, true, thd->query(), thd->query_length()))
+ return(true);
+ my_ok(thd);
+ return(0);
+}
+
+
/**
Alter table
@@ -9778,7 +9853,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
mysql_prepare_create_table().
*/
bool varchar= create_info->varchar, table_creation_was_logged= 0;
- bool binlog_done= 0, log_if_exists= 0;
+ bool binlog_as_create_select= 0, log_if_exists= 0;
uint tables_opened;
handlerton *new_db_type, *old_db_type;
ha_rows copied=0, deleted=0;
@@ -9843,10 +9918,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
table_list->mdl_request.type= MDL_EXCLUSIVE;
/* This will only drop the .frm file and local tables, not shared ones */
error= mysql_rm_table(thd, table_list, 1, 0, 0, 1);
- if (write_bin_log(thd, true, thd->query(), thd->query_length()) || error)
- DBUG_RETURN(true);
- my_ok(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(log_and_ok(thd));
}
/*
@@ -9878,16 +9950,14 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
the statement as this slave may not have the table shared
*/
thd->clear_error();
- if (thd->slave_thread &&
- write_bin_log(thd, true, thd->query(), thd->query_length()))
- DBUG_RETURN(true);
- my_ok(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(log_and_ok(thd));
}
}
DBUG_RETURN(true);
}
+ table= table_list->table;
+
#ifdef WITH_WSREP
if (WSREP(thd) &&
(thd->lex->sql_command == SQLCOM_ALTER_TABLE ||
@@ -9899,7 +9969,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
DEBUG_SYNC(thd, "alter_table_after_open_tables");
- table= table_list->table;
if (table->versioned())
{
if (handlerton *hton1= create_info->db_type)
@@ -9938,12 +10007,17 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
Alter_table_ctx alter_ctx(thd, table_list, tables_opened, new_db, new_name);
mdl_ticket= table->mdl_ticket;
+ /*
+ We have to do a check also after table is opened as there could be no
+ ENGINE= on the command line or the table could a partitioned S3 table.
+ */
if (table->file->check_if_updates_are_ignored("ALTER"))
{
/*
Table is a shared table. Remove the .frm file. Discovery will create
a new one if needed.
*/
+ table->s->tdc->flushed= 1; // Force close of all instances
if (thd->mdl_context.upgrade_shared_lock(mdl_ticket,
MDL_EXCLUSIVE,
thd->variables.lock_wait_timeout))
@@ -10700,7 +10774,6 @@ do_continue:;
thd->variables.option_bits|= OPTION_BIN_COMMIT_OFF;
res= (binlog_drop_table(thd, table) ||
binlog_create_table(thd, new_table, 1));
- thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
new_table->s->tmp_table= org_tmp_table;
if (res)
goto err_new_table_cleanup;
@@ -10708,7 +10781,7 @@ do_continue:;
ha_write_row() will log inserted rows in copy_data_between_tables().
No additional logging of query is needed
*/
- binlog_done= 1;
+ binlog_as_create_select= 1;
DBUG_ASSERT(new_table->file->row_logging);
new_table->mark_columns_needed_for_insert();
thd->binlog_write_table_map(new_table, 1);
@@ -10764,10 +10837,21 @@ do_continue:;
if (thd->rename_temporary_table(new_table, &alter_ctx.new_db,
&alter_ctx.new_name))
goto err_new_table_cleanup;
+
+ if (binlog_as_create_select)
+ {
+ /*
+ The original table is now deleted. Copy the
+ DROP + CREATE + data statement to the binary log
+ */
+ thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
+ (binlog_hton->commit)(binlog_hton, thd, 1);
+ }
+
/* We don't replicate alter table statement on temporary tables */
if (!thd->is_current_stmt_binlog_format_row() &&
table_creation_was_logged &&
- !binlog_done &&
+ !binlog_as_create_select &&
write_bin_log_with_if_exists(thd, true, false, log_if_exists))
DBUG_RETURN(true);
my_free(const_cast<uchar*>(frm.str));
@@ -10927,6 +11011,15 @@ do_continue:;
NO_FRM_RENAME |
(engine_changed ? 0 : FN_IS_TMP));
}
+ if (binlog_as_create_select)
+ {
+ /*
+ The original table is now deleted. Copy the
+ DROP + CREATE + data statement to the binary log
+ */
+ thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
+ binlog_hton->commit(binlog_hton, thd, 1);
+ }
if (error)
{
@@ -10939,6 +11032,7 @@ do_continue:;
}
end_inplace:
+ thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
if (thd->locked_tables_list.reopen_tables(thd, false))
goto err_with_mdl_after_alter;
@@ -10950,7 +11044,7 @@ end_inplace:
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
thd->is_current_stmt_binlog_format_row() &&
(create_info->tmp_table())));
- if (!binlog_done)
+ if (!binlog_as_create_select)
{
if (write_bin_log_with_if_exists(thd, true, false, log_if_exists))
DBUG_RETURN(true);
@@ -10968,6 +11062,8 @@ end_inplace:
}
end_temporary:
+ thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
+
my_snprintf(alter_ctx.tmp_buff, sizeof(alter_ctx.tmp_buff),
ER_THD(thd, ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted,
@@ -10978,6 +11074,8 @@ end_temporary:
err_new_table_cleanup:
DBUG_PRINT("error", ("err_new_table_cleanup"));
+ thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
+
my_free(const_cast<uchar*>(frm.str));
/*
No default value was provided for a DATE/DATETIME field, the
@@ -11015,7 +11113,7 @@ err_with_mdl_after_alter:
We can't reset error as we will return 'true' below and the server
expects that error is set
*/
- if (!binlog_done)
+ if (!binlog_as_create_select)
write_bin_log_with_if_exists(thd, FALSE, FALSE, log_if_exists);
err_with_mdl:
@@ -11110,6 +11208,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
bool make_versioned= !from->versioned() && to->versioned();
bool make_unversioned= from->versioned() && !to->versioned();
bool keep_versioned= from->versioned() && to->versioned();
+ bool bulk_insert_started= 0;
Field *to_row_start= NULL, *to_row_end= NULL, *from_row_end= NULL;
MYSQL_TIME query_start;
DBUG_ENTER("copy_data_between_tables");
@@ -11148,6 +11247,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE);
to->file->ha_start_bulk_insert(from->file->stats.records,
ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT);
+ bulk_insert_started= 1;
mysql_stage_set_work_estimated(thd->m_stage_progress_psi, from->file->stats.records);
List_iterator<Create_field> it(create);
@@ -11416,6 +11516,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->print_error(my_errno,MYF(0));
error= 1;
}
+ bulk_insert_started= 0;
if (!ignore)
to->file->extra(HA_EXTRA_END_ALTER_COPY);
@@ -11429,7 +11530,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
error= 1;
err:
- /* Free resources */
+ if (bulk_insert_started)
+ (void) to->file->ha_end_bulk_insert();
+
+/* Free resources */
if (init_read_record_done)
end_read_record(&info);
delete [] copy;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 677e6cfa510..9417ec667ff 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1826,7 +1826,7 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, const LEX_CSTRING *db,
TABLE table;
char path[FN_REFLEN];
bool result= 0;
- DBUG_ENTER("Triggers::drop_all_triggers");
+ DBUG_ENTER("Table_triggers_list::drop_all_triggers");
table.reset();
init_sql_alloc(key_memory_Table_trigger_dispatcher,
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 22375d2962c..00b9c71cc37 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -2655,8 +2655,7 @@ Field *Type_handler_set::make_conversion_table_field(MEM_ROOT *root,
Field *Type_handler_enum::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
const Typelib *typelib= def.typelib();
@@ -3861,8 +3860,7 @@ Field *Type_handler_set::make_table_field(MEM_ROOT *root,
Field *Type_handler_float::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root)
@@ -3876,8 +3874,7 @@ Field *Type_handler_float::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_double::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root)
@@ -3892,8 +3889,7 @@ Field *Type_handler_double::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_decimal_result::make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
uint dec= def.decimal_scale();
@@ -3909,28 +3905,20 @@ Field *Type_handler_decimal_result::make_schema_field(MEM_ROOT *root,
Field *Type_handler_blob_common::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
- if (show_field)
- {
- return new (root)
- Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, &name, table->s,
- length_bytes(),
- &my_charset_bin);
- }
- else
- return new (root)
- Field_null(addr.ptr(), 0, Field::NONE, &name, &my_charset_bin);
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, table->s,
+ length_bytes(),
+ &my_charset_bin);
}
Field *Type_handler_varchar::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
DBUG_ASSERT(def.char_length());
LEX_CSTRING name= def.name();
@@ -3944,7 +3932,7 @@ Field *Type_handler_varchar::make_schema_field(MEM_ROOT *root, TABLE *table,
field->field_length= octet_length;
return field;
}
- else if (show_field)
+ else
{
return new (root)
Field_varstring(addr.ptr(), octet_length,
@@ -3953,16 +3941,12 @@ Field *Type_handler_varchar::make_schema_field(MEM_ROOT *root, TABLE *table,
Field::NONE, &name,
table->s, system_charset_info);
}
- else
- return new (root)
- Field_null(addr.ptr(), 0, Field::NONE, &name, system_charset_info);
}
Field *Type_handler_tiny::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root)
@@ -3974,8 +3958,7 @@ Field *Type_handler_tiny::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_short::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root)
@@ -3987,8 +3970,7 @@ Field *Type_handler_short::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_long::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root)
@@ -4000,8 +3982,7 @@ Field *Type_handler_long::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_longlong::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root)
@@ -4013,8 +3994,7 @@ Field *Type_handler_longlong::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_date_common::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root)
@@ -4025,8 +4005,7 @@ Field *Type_handler_date_common::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_time_common::make_schema_field(MEM_ROOT *root, TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new_Field_time(root,
@@ -4038,8 +4017,7 @@ Field *Type_handler_time_common::make_schema_field(MEM_ROOT *root, TABLE *table,
Field *Type_handler_datetime_common::make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
LEX_CSTRING name= def.name();
return new (root) Field_datetimef(addr.ptr(),
@@ -5703,10 +5681,12 @@ cmp_item *Type_handler_timestamp_common::make_cmp_item(THD *thd,
/***************************************************************************/
-static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
+static int srtcmp_in(const void *cs_, const void *x_, const void *y_)
{
- return cs->strnncollsp(x->ptr(), x->length(),
- y->ptr(), y->length());
+ const CHARSET_INFO *cs= static_cast<const CHARSET_INFO *>(cs_);
+ const String *x= static_cast<const String *>(x_);
+ const String *y= static_cast<const String *>(y_);
+ return cs->strnncollsp(x->ptr(), x->length(), y->ptr(), y->length());
}
in_vector *Type_handler_string_result::make_in_vector(THD *thd,
@@ -6956,6 +6936,24 @@ bool Type_handler_string_result::
/***************************************************************************/
+const Vers_type_handler* Type_handler_temporal_result::vers() const
+{
+ return &vers_type_timestamp;
+}
+
+const Vers_type_handler* Type_handler_string_result::vers() const
+{
+ return &vers_type_timestamp;
+}
+
+const Vers_type_handler* Type_handler_blob_common::vers() const
+
+{
+ return &vers_type_timestamp;
+}
+
+/***************************************************************************/
+
uint Type_handler::Item_time_precision(THD *thd, Item *item) const
{
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 41e840d9ed7..db4f67e343f 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -374,7 +374,7 @@ class Dec_ptr_and_buffer: public Dec_ptr
protected:
my_decimal m_buffer;
public:
- int round_to(my_decimal *to, uint scale, decimal_round_mode mode)
+ int round_to(my_decimal *to, int scale, decimal_round_mode mode)
{
DBUG_ASSERT(m_ptr);
return m_ptr->round_to(to, scale, mode);
@@ -383,6 +383,14 @@ public:
{
return round_to(&m_buffer, scale, mode);
}
+ int round_self_if_needed(int scale, decimal_round_mode mode)
+ {
+ if (scale >= m_ptr->frac)
+ return E_DEC_OK;
+ int res= m_ptr->round_to(&m_buffer, scale, mode);
+ m_ptr= &m_buffer;
+ return res;
+ }
String *to_string_round(String *to, uint dec)
{
/*
@@ -3934,8 +3942,7 @@ public:
virtual Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const
+ const ST_FIELD_INFO &def) const
{
DBUG_ASSERT(0);
return NULL;
@@ -3980,7 +3987,6 @@ public:
SORT_FIELD_ATTR *attr) const= 0;
virtual bool is_packable() const { return false; }
-
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;
@@ -4817,8 +4823,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *)
const override;
void make_sort_key_part(uchar *to, Item *item,
@@ -5249,7 +5254,7 @@ public:
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
- const Vers_type_handler *vers() const override { return &vers_type_timestamp; }
+ const Vers_type_handler *vers() const override;
};
@@ -5286,7 +5291,7 @@ public:
void sort_length(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const override;
- bool is_packable()const override { return true; }
+ bool is_packable() const override { return true; }
bool union_element_finalize(const Item * item) const override;
uint calc_key_length(const Column_definition &def) const override;
bool Column_definition_prepare_stage1(THD *thd,
@@ -5416,7 +5421,7 @@ public:
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
- const Vers_type_handler *vers() const override { return &vers_type_timestamp; }
+ const Vers_type_handler *vers() const override;
};
@@ -5477,8 +5482,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -5529,8 +5533,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -5581,8 +5584,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -5648,8 +5650,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -5879,8 +5880,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -5935,8 +5935,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -5991,8 +5990,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
CHARSET_INFO *cs, bool send_error)
const override;
@@ -6202,8 +6200,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
CHARSET_INFO *cs, bool send_error)
const override;
@@ -6333,8 +6330,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const override;
bool validate_implicit_default_value(THD *thd, const Column_definition &def)
@@ -6909,8 +6905,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -7030,8 +7025,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
@@ -7039,7 +7033,7 @@ public:
const Bit_addr &bit,
const Column_definition_attributes *attr,
uint32 flags) const override;
- const Vers_type_handler *vers() const override { return &vers_type_timestamp; }
+ const Vers_type_handler *vers() const override;
};
@@ -7214,8 +7208,7 @@ public:
Field *make_schema_field(MEM_ROOT *root,
TABLE *table,
const Record_addr &addr,
- const ST_FIELD_INFO &def,
- bool show_field) const override;
+ const ST_FIELD_INFO &def) const override;
};
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 5df9e7dd47d..07dd3b1f6ca 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -58,6 +58,8 @@ static udf_func *add_udf(LEX_CSTRING *name, Item_result ret,
const char *dl, Item_udftype typ);
static void del_udf(udf_func *udf);
static void *find_udf_dl(const char *dl);
+static bool find_udf_everywhere(THD* thd, const LEX_CSTRING &name,
+ TABLE *table);
static const char *init_syms(udf_func *tmp, char *nm)
{
@@ -430,6 +432,41 @@ static udf_func *add_udf(LEX_CSTRING *name, Item_result ret, const char *dl,
return tmp;
}
+/**
+ Find record with the udf in the udf func table
+
+ @param exact_name udf name
+ @param table table of mysql.func
+
+ @retval TRUE found
+ @retral FALSE not found
+*/
+
+static bool find_udf_in_table(const LEX_CSTRING &exact_name, TABLE *table)
+{
+ table->use_all_columns();
+ table->field[0]->store(exact_name.str, exact_name.length, &my_charset_bin);
+ return (!table->file->ha_index_read_idx_map(table->record[0], 0,
+ (uchar*) table->field[0]->ptr,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT));
+}
+
+static bool remove_udf_in_table(const LEX_CSTRING &exact_name, TABLE *table)
+{
+ if (find_udf_in_table(exact_name, table))
+ {
+ int error;
+ if ((error= table->file->ha_delete_row(table->record[0])))
+ {
+ table->file->print_error(error, MYF(0));
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
/*
Drop user defined function.
@@ -446,8 +483,7 @@ static int mysql_drop_function_internal(THD *thd, udf_func *udf, TABLE *table)
{
DBUG_ENTER("mysql_drop_function_internal");
- const char *exact_name_str= udf->name.str;
- size_t exact_name_len= udf->name.length;
+ const LEX_CSTRING exact_name= udf->name;
del_udf(udf);
/*
@@ -460,18 +496,17 @@ static int mysql_drop_function_internal(THD *thd, udf_func *udf, TABLE *table)
if (!table)
DBUG_RETURN(1);
- table->use_all_columns();
- table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
- if (!table->file->ha_index_read_idx_map(table->record[0], 0,
- (uchar*) table->field[0]->ptr,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
- {
- int error;
- if (unlikely((error= table->file->ha_delete_row(table->record[0]))))
- table->file->print_error(error, MYF(0));
- }
- DBUG_RETURN(0);
+ bool ret= remove_udf_in_table(exact_name, table);
+ DBUG_RETURN(ret);
+}
+
+
+static TABLE *open_udf_func_table(THD *thd)
+{
+ TABLE_LIST tables;
+ tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_FUNC_NAME,
+ &MYSQL_FUNC_NAME, TL_WRITE);
+ return open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
}
@@ -518,8 +553,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
if (check_ident_length(&udf->name))
DBUG_RETURN(1);
- tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_FUNC_NAME, 0, TL_WRITE);
- table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
+ table= open_udf_func_table(thd);
mysql_rwlock_wrlock(&THR_LOCK_udf);
DEBUG_SYNC(current_thd, "mysql_create_function_after_lock");
@@ -620,42 +654,65 @@ err:
}
-int mysql_drop_function(THD *thd, const LEX_CSTRING *udf_name)
+enum drop_udf_result mysql_drop_function(THD *thd, const LEX_CSTRING *udf_name)
{
TABLE *table;
- TABLE_LIST tables;
udf_func *udf;
DBUG_ENTER("mysql_drop_function");
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ DBUG_RETURN(UDF_DEL_RESULT_ERROR);
+ }
+
+ if (!(table= open_udf_func_table(thd)))
+ DBUG_RETURN(UDF_DEL_RESULT_ERROR);
+
+ // Fast pre-check
+ if (!mysql_rwlock_tryrdlock(&THR_LOCK_udf))
+ {
+ bool found= find_udf_everywhere(thd, *udf_name, table);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
+ if (!found)
+ {
+ close_mysql_tables(thd);
+ DBUG_RETURN(UDF_DEL_RESULT_ABSENT);
+ }
+ }
+
if (!initialized)
{
+ close_mysql_tables(thd);
if (opt_noacl)
- my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
- else
- my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES),
- MYF(0));
- DBUG_RETURN(1);
- }
+ DBUG_RETURN(UDF_DEL_RESULT_ABSENT); // SP should be checked
- tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_FUNC_NAME, 0, TL_WRITE);
- table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
+ my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES), MYF(0));
+ DBUG_RETURN(UDF_DEL_RESULT_ERROR);
+ }
mysql_rwlock_wrlock(&THR_LOCK_udf);
+
+ // re-check under protection
+ if (!find_udf_everywhere(thd, *udf_name, table))
+ {
+ close_mysql_tables(thd);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
+ DBUG_RETURN(UDF_DEL_RESULT_ABSENT);
+ }
+
+ if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
+ goto err;
+
+
DEBUG_SYNC(current_thd, "mysql_drop_function_after_lock");
+
if (!(udf= (udf_func*) my_hash_search(&udf_hash, (uchar*) udf_name->str,
(uint) udf_name->length)) )
{
- if (thd->lex->check_exists)
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_FUNCTION_NOT_DEFINED,
- ER_THD(thd, ER_FUNCTION_NOT_DEFINED),
- udf_name->str);
- goto done;
- }
-
- my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
- goto err;
+ if (remove_udf_in_table(*udf_name, table))
+ goto err;
+ goto done;
}
if (mysql_drop_function_internal(thd, udf, table))
@@ -669,13 +726,24 @@ done:
while binlogging, to avoid binlog inconsistency.
*/
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
- DBUG_RETURN(1);
+ DBUG_RETURN(UDF_DEL_RESULT_ERROR);
- DBUG_RETURN(0);
+ close_mysql_tables(thd);
+ DBUG_RETURN(UDF_DEL_RESULT_DELETED);
err:
+ close_mysql_tables(thd);
mysql_rwlock_unlock(&THR_LOCK_udf);
- DBUG_RETURN(1);
+ DBUG_RETURN(UDF_DEL_RESULT_ERROR);
+}
+
+static bool find_udf_everywhere(THD* thd, const LEX_CSTRING &name,
+ TABLE *table)
+{
+ if (initialized && my_hash_search(&udf_hash, (uchar*) name.str, name.length))
+ return true;
+
+ return find_udf_in_table(name, table);
}
#endif /* HAVE_DLOPEN */
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index ac58a176fed..cb1954353fa 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -155,7 +155,13 @@ void udf_init(void),udf_free(void);
udf_func *find_udf(const char *name, size_t size, bool mark_used=0);
void free_udf(udf_func *udf);
int mysql_create_function(THD *thd,udf_func *udf);
-int mysql_drop_function(THD *thd, const LEX_CSTRING *name);
+enum drop_udf_result
+{
+ UDF_DEL_RESULT_ABSENT,
+ UDF_DEL_RESULT_DELETED,
+ UDF_DEL_RESULT_ERROR
+};
+enum drop_udf_result mysql_drop_function(THD *thd, const LEX_CSTRING *name);
#else
static inline void udf_init(void) { }
static inline void udf_free(void) { }
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index fccc2a426c4..9e6a1cd3bb4 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -189,6 +189,13 @@ static bool check_fields(THD *thd, TABLE_LIST *table, List<Item> &items,
my_error(ER_IT_IS_A_VIEW, MYF(0), table->table_name.str);
return TRUE;
}
+ if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "updating and querying the same temporal periods table");
+
+ return true;
+ }
DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE);
for (List_iterator_fast<Item> it(items); (item=it++);)
{
@@ -419,6 +426,14 @@ int mysql_update(THD *thd,
DBUG_PRINT("info", ("Switch to multi-update"));
/* pass counter value */
thd->lex->table_count= table_count;
+ if (thd->lex->period_conditions.is_set())
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "updating and querying the same temporal periods table");
+
+ DBUG_RETURN(1);
+ }
+
/* convert to multiupdate */
DBUG_RETURN(2);
}
@@ -542,6 +557,8 @@ int mysql_update(THD *thd,
query_plan.set_no_partitions();
if (thd->lex->describe || thd->lex->analyze_stmt)
goto produce_explain_and_leave;
+ if (thd->is_error())
+ DBUG_RETURN(1);
my_ok(thd); // No matching records
DBUG_RETURN(0);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e54b335e418..1b37896f18b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2020, MariaDB Corporation.
+ Copyright (c) 2010, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -115,6 +115,14 @@ int yylex(void *yylval, void *yythd);
#endif
+static Item* escape(THD *thd)
+{
+ thd->lex->escape_used= false;
+ const char *esc= thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES ? "" : "\\";
+ return new (thd->mem_root) Item_string_ascii(thd, esc, MY_TEST(esc[0]));
+}
+
+
/**
@brief Bison callback to report a syntax/OOM error
@@ -325,16 +333,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- We should not introduce new conflicts any more.
+ We should not introduce any further shift/reduce conflicts.
*/
/* Start SQL_MODE_DEFAULT_SPECIFIC */
-%expect 37
+%expect 53
/* End SQL_MODE_DEFAULT_SPECIFIC */
/* Start SQL_MODE_ORACLE_SPECIFIC
-%expect 40
+%expect 56
End SQL_MODE_ORACLE_SPECIFIC */
@@ -1142,16 +1150,6 @@ End SQL_MODE_ORACLE_SPECIFIC */
%token <kwd> XML_SYM
%token <kwd> YEAR_SYM /* SQL-2003-R */
-
-/*
- Give ESCAPE (in LIKE) a very low precedence.
- This allows the concatenation operator || to be used on the right
- side of "LIKE" with sql_mode=PIPES_AS_CONCAT (without ORACLE):
- SELECT 'ab' LIKE 'a'||'b'||'c';
-*/
-%left PREC_BELOW_ESCAPE
-%left ESCAPE_SYM
-
/* A dummy token to force the priority of table_ref production in a join. */
%left CONDITIONLESS_JOIN
%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT ON_SYM USING
@@ -1162,10 +1160,12 @@ End SQL_MODE_ORACLE_SPECIFIC */
%left AND_SYM AND_AND_SYM
%left PREC_BELOW_NOT
-%left NOT_SYM
-%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE
-%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE SOUNDS_SYM REGEXP IN_SYM
+%nonassoc NOT_SYM
+%left '=' EQUAL_SYM GE '>' LE '<' NE
+%nonassoc IS
+%right BETWEEN_SYM
+%left LIKE SOUNDS_SYM REGEXP IN_SYM
%left '|'
%left '&'
%left SHIFT_LEFT SHIFT_RIGHT
@@ -1173,9 +1173,9 @@ End SQL_MODE_ORACLE_SPECIFIC */
%left '*' '/' '%' DIV_SYM MOD_SYM
%left '^'
%left MYSQL_CONCAT_SYM
-%left NEG '~' NOT2_SYM BINARY
-%left COLLATE_SYM
-%left SUBQUERY_AS_EXPR
+%nonassoc NEG '~' NOT2_SYM BINARY
+%nonassoc COLLATE_SYM
+%nonassoc SUBQUERY_AS_EXPR
/*
Tokens that can change their meaning from identifier to something else
@@ -1448,7 +1448,6 @@ End SQL_MODE_ORACLE_SPECIFIC */
select_sublist_qualified_asterisk
expr_or_default set_expr_or_default
signed_literal expr_or_literal
- opt_escape
sp_opt_default
simple_ident_nospvar
field_or_var limit_option
@@ -7757,6 +7756,8 @@ alter_list_item:
}
| ALTER opt_column opt_if_exists_table_element field_ident SET DEFAULT column_default_expr
{
+ if (check_expression($7, &$4, VCOL_DEFAULT))
+ MYSQL_YYABORT;
if (unlikely(Lex->add_alter_list($4, $7, $3)))
MYSQL_YYABORT;
}
@@ -9299,59 +9300,59 @@ expr:
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri IS TRUE_SYM %prec IS
+ | expr IS TRUE_SYM %prec IS
{
$$= new (thd->mem_root) Item_func_istrue(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri IS not TRUE_SYM %prec IS
+ | expr IS not TRUE_SYM %prec IS
{
$$= new (thd->mem_root) Item_func_isnottrue(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri IS FALSE_SYM %prec IS
+ | expr IS FALSE_SYM %prec IS
{
$$= new (thd->mem_root) Item_func_isfalse(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri IS not FALSE_SYM %prec IS
+ | expr IS not FALSE_SYM %prec IS
{
$$= new (thd->mem_root) Item_func_isnotfalse(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri IS UNKNOWN_SYM %prec IS
+ | expr IS UNKNOWN_SYM %prec IS
{
$$= new (thd->mem_root) Item_func_isnull(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri IS not UNKNOWN_SYM %prec IS
+ | expr IS not UNKNOWN_SYM %prec IS
{
$$= new (thd->mem_root) Item_func_isnotnull(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri %prec PREC_BELOW_NOT
- ;
-
-bool_pri:
- bool_pri IS NULL_SYM %prec IS
+ | expr IS NULL_SYM %prec PREC_BELOW_NOT
{
$$= new (thd->mem_root) Item_func_isnull(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri IS not NULL_SYM %prec IS
+ | expr IS not NULL_SYM %prec IS
{
$$= new (thd->mem_root) Item_func_isnotnull(thd, $1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bool_pri EQUAL_SYM predicate %prec EQUAL_SYM
+ | bool_pri
+ ;
+
+bool_pri:
+ bool_pri EQUAL_SYM predicate %prec EQUAL_SYM
{
$$= new (thd->mem_root) Item_func_equal(thd, $1, $3);
if (unlikely($$ == NULL))
@@ -9373,42 +9374,42 @@ bool_pri:
;
predicate:
- bit_expr IN_SYM subquery
+ predicate IN_SYM subquery
{
$$= new (thd->mem_root) Item_in_subselect(thd, $1, $3);
- if (unlikely($$ == NULL))
+ if (unlikely(!$$))
MYSQL_YYABORT;
}
- | bit_expr not IN_SYM subquery
+ | predicate not IN_SYM subquery
{
Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $4);
- if (unlikely(item == NULL))
+ if (unlikely(!item))
MYSQL_YYABORT;
$$= negate_expression(thd, item);
- if (unlikely($$ == NULL))
+ if (unlikely(!$$))
MYSQL_YYABORT;
}
- | bit_expr IN_SYM '(' expr ')'
+ | predicate IN_SYM '(' expr ')'
{
$$= handle_sql2003_note184_exception(thd, $1, true, $4);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr IN_SYM '(' expr ',' expr_list ')'
- {
+ | predicate IN_SYM '(' expr ',' expr_list ')'
+ {
$6->push_front($4, thd->mem_root);
$6->push_front($1, thd->mem_root);
$$= new (thd->mem_root) Item_func_in(thd, *$6);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr not IN_SYM '(' expr ')'
+ | predicate not IN_SYM '(' expr ')'
{
$$= handle_sql2003_note184_exception(thd, $1, false, $5);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr not IN_SYM '(' expr ',' expr_list ')'
+ | predicate not IN_SYM '(' expr ',' expr_list ')'
{
$7->push_front($5, thd->mem_root);
$7->push_front($1, thd->mem_root);
@@ -9417,13 +9418,13 @@ predicate:
MYSQL_YYABORT;
$$= item->neg_transformer(thd);
}
- | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
+ | predicate BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM
{
$$= new (thd->mem_root) Item_func_between(thd, $1, $3, $5);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
+ | predicate not BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM
{
Item_func_between *item;
item= new (thd->mem_root) Item_func_between(thd, $1, $4, $6);
@@ -9431,7 +9432,7 @@ predicate:
MYSQL_YYABORT;
$$= item->neg_transformer(thd);
}
- | bit_expr SOUNDS_SYM LIKE bit_expr
+ | predicate SOUNDS_SYM LIKE predicate
{
Item *item1= new (thd->mem_root) Item_func_soundex(thd, $1);
Item *item4= new (thd->mem_root) Item_func_soundex(thd, $4);
@@ -9441,28 +9442,41 @@ predicate:
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr LIKE bit_expr opt_escape
+ | predicate LIKE predicate
{
- $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $4,
- Lex->escape_used);
- if (unlikely($$ == NULL))
+ $$= new (thd->mem_root) Item_func_like(thd, $1, $3, escape(thd), false);
+ if (unlikely(!$$))
MYSQL_YYABORT;
}
- | bit_expr not LIKE bit_expr opt_escape
+ | predicate LIKE predicate ESCAPE_SYM predicate %prec LIKE
{
- Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $5,
- Lex->escape_used);
- if (unlikely(item == NULL))
+ Lex->escape_used= true;
+ $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $5, true);
+ if (unlikely(!$$))
+ MYSQL_YYABORT;
+ }
+ | predicate not LIKE predicate
+ {
+ Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, escape(thd), false);
+ if (unlikely(!item))
MYSQL_YYABORT;
$$= item->neg_transformer(thd);
}
- | bit_expr REGEXP bit_expr
+ | predicate not LIKE predicate ESCAPE_SYM predicate %prec LIKE
+ {
+ Lex->escape_used= true;
+ Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $6, true);
+ if (unlikely(!item))
+ MYSQL_YYABORT;
+ $$= item->neg_transformer(thd);
+ }
+ | predicate REGEXP predicate
{
$$= new (thd->mem_root) Item_func_regex(thd, $1, $3);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr not REGEXP bit_expr
+ | predicate not REGEXP predicate
{
Item *item= new (thd->mem_root) Item_func_regex(thd, $1, $4);
if (unlikely(item == NULL))
@@ -10592,18 +10606,19 @@ function_call_generic:
names are resolved with the following order:
- MySQL native functions,
- User Defined Functions,
+ - Constructors, like POINT(1,1)
- Stored Functions (assuming the current <use> database)
This will be revised with WL#2128 (SQL PATH)
*/
- if ((h= Type_handler::handler_by_name(thd, $1)) &&
- (item= h->make_constructor_item(thd, $4)))
+ if ((builder= find_native_function_builder(thd, &$1)))
{
- // Found a constructor with a proper argument count
+ item= builder->create_func(thd, &$1, $4);
}
- else if ((builder= find_native_function_builder(thd, &$1)))
+ else if ((h= Type_handler::handler_by_name(thd, $1)) &&
+ (item= h->make_constructor_item(thd, $4)))
{
- item= builder->create_func(thd, &$1, $4);
+ // Found a constructor with a proper argument count
}
else
{
@@ -11904,23 +11919,6 @@ opt_having_clause:
}
;
-opt_escape:
- ESCAPE_SYM simple_expr
- {
- Lex->escape_used= TRUE;
- $$= $2;
- }
- | /* empty */ %prec PREC_BELOW_ESCAPE
- {
- Lex->escape_used= FALSE;
- $$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ?
- new (thd->mem_root) Item_string_ascii(thd, "", 0) :
- new (thd->mem_root) Item_string_ascii(thd, "\\", 1));
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
/*
group by statement in select
*/
@@ -14181,6 +14179,8 @@ backup_statements:
}
| LOCK_SYM
{
+ if (unlikely(Lex->sphead))
+ my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP LOCK"));
if (Lex->main_select_push())
MYSQL_YYABORT;
}
@@ -14194,6 +14194,8 @@ backup_statements:
}
| UNLOCK_SYM
{
+ if (unlikely(Lex->sphead))
+ my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP UNLOCK"));
/* Table list is empty for unlock */
Lex->sql_command= SQLCOM_BACKUP_LOCK;
}
diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic
index c21a4a83165..2bd6ee6467d 100644
--- a/sql/sys_vars.ic
+++ b/sql/sys_vars.ic
@@ -769,8 +769,12 @@ public:
void session_save_default(THD *, set_var *) override
{ DBUG_ASSERT(FALSE); }
- void global_save_default(THD *, set_var *) override
- { DBUG_ASSERT(FALSE); }
+ void global_save_default(THD *thd, set_var *var) override
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
+ }
bool session_update(THD *, set_var *) override
{
diff --git a/sql/table.cc b/sql/table.cc
index 779ce768eee..c48a6fed89a 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2367,7 +2367,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
comment_pos+= comment_length;
}
- if ((uchar) strpos[13] == (uchar) MYSQL_TYPE_VIRTUAL)
+ if ((uchar) strpos[13] == (uchar) MYSQL_TYPE_VIRTUAL
+ && likely(share->mysql_version >= 100000))
{
/*
MariaDB version 10.0 version.
@@ -2417,7 +2418,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
interval_nr= (uint) strpos[12];
enum_field_types field_type= (enum_field_types) strpos[13];
if (!(handler= Type_handler::get_handler_by_real_type(field_type)))
- goto err; // Not supported field type
+ {
+ if (field_type == 245 &&
+ share->mysql_version >= 50700) // a.k.a MySQL 5.7 JSON
+ {
+ share->incompatible_version|= HA_CREATE_USED_ENGINE;
+ const LEX_CSTRING mysql_json{STRING_WITH_LEN("MYSQL_JSON")};
+ handler= Type_handler::handler_by_name_or_error(thd, mysql_json);
+ }
+
+ if (!handler)
+ goto err; // Not supported field type
+ }
handler= handler->type_handler_frm_unpack(strpos);
if (handler->Column_definition_attributes_frm_unpack(&attr, share,
strpos,
@@ -8498,28 +8510,39 @@ public:
@details
The function computes the values of the virtual columns of the table and
stores them in the table record buffer.
+ This will be done even if is_error() is set either when function was called
+ or by calculating the virtual function, as most calls to this
+ function doesn't check the result. We also want to ensure that as many
+ fields as possible has the right value so that we can optionally
+ return the partly-faulty-row from a storage engine with a virtual
+ field that gives an error on storage for an existing row.
+
+ @todo
+ Ensure that all caller checks the value of this function and
+ either properly ignores it (and resets the error) or sends the
+ error forward to the caller.
@retval
0 Success
@retval
- >0 Error occurred when storing a virtual field value
+ >0 Error occurred when storing a virtual field value or potentially
+ is_error() was set when function was called.
*/
int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
{
DBUG_ENTER("TABLE::update_virtual_fields");
- DBUG_PRINT("enter", ("update_mode: %d", update_mode));
+ DBUG_PRINT("enter", ("update_mode: %d is_error: %d", update_mode,
+ in_use->is_error()));
Field **vfield_ptr, *vf;
Query_arena backup_arena;
Turn_errors_to_warnings_handler Suppress_errors;
- int error;
bool handler_pushed= 0, update_all_columns= 1;
DBUG_ASSERT(vfield);
if (h->keyread_enabled())
DBUG_RETURN(0);
- error= 0;
in_use->set_n_backup_active_arena(expr_arena, &backup_arena);
/* When reading or deleting row, ignore errors from virtual columns */
@@ -8542,7 +8565,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
}
/* Iterate over virtual fields in the table */
- for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++)
+ for (vfield_ptr= vfield; *vfield_ptr ; vfield_ptr++)
{
vf= (*vfield_ptr);
Virtual_column_info *vcol_info= vf->vcol_info;
@@ -8593,8 +8616,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
int field_error __attribute__((unused)) = 0;
/* Compute the actual value of the virtual fields */
DBUG_FIX_WRITE_SET(vf);
- if (vcol_info->expr->save_in_field(vf, 0))
- field_error= error= 1;
+ field_error= vcol_info->expr->save_in_field(vf, 0);
DBUG_RESTORE_WRITE_SET(vf);
DBUG_PRINT("info", ("field '%s' - updated error: %d",
vf->field_name.str, field_error));
@@ -8719,6 +8741,7 @@ int TABLE::period_make_insert(Item *src, Field *dst)
{
THD *thd= in_use;
+ file->store_auto_increment();
store_record(this, record[1]);
int res= src->save_in_field(dst, true);
@@ -8737,6 +8760,8 @@ int TABLE::period_make_insert(Item *src, Field *dst)
TRG_ACTION_AFTER, true);
restore_record(this, record[1]);
+ if (res)
+ file->restore_auto_increment();
return res;
}
diff --git a/sql/table.h b/sql/table.h
index 63bcc69b6bc..71884c919ad 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2244,7 +2244,6 @@ struct TABLE_LIST
parsing 'this' is a NATURAL/USING join iff (natural_join != NULL).
*/
TABLE_LIST *natural_join;
- bool part_of_natural_join;
/*
True if 'this' represents a nested join that is a NATURAL JOIN.
For one of the operands of 'this', the member 'natural_join' points
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index b26f41c6e9a..168579d984b 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -317,6 +317,16 @@ static void handle_wait_timeout(THD *thd)
thd->net.error= 2;
}
+/** Check if some client data is cached in thd->net or thd->net.vio */
+static bool has_unread_data(THD* thd)
+{
+ NET *net= &thd->net;
+ if (net->compress && net->remain_in_buf)
+ return true;
+ Vio *vio= net->vio;
+ return vio->has_data(vio);
+}
+
/**
Process a single client request or a single batch.
@@ -351,7 +361,6 @@ static int threadpool_process_request(THD *thd)
*/
for(;;)
{
- Vio *vio;
thd->net.reading_or_writing= 0;
if (mysql_audit_release_required(thd))
mysql_audit_release(thd);
@@ -367,8 +376,7 @@ static int threadpool_process_request(THD *thd)
set_thd_idle(thd);
- vio= thd->net.vio;
- if (!vio->has_data(vio))
+ if (!has_unread_data(thd))
{
/* More info on this debug sync is in sql_parse.cc*/
DEBUG_SYNC(thd, "before_do_command_net_read");
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 51c23085717..4461d73a928 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -158,7 +158,8 @@ extern const char* wsrep_provider_vendor;
extern char* wsrep_provider_capabilities;
extern char* wsrep_cluster_capabilities;
-int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff);
+int wsrep_show_status(THD *thd, SHOW_VAR *var, void *buff,
+ system_status_var *status_var, enum_var_type scope);
int wsrep_show_ready(THD *thd, SHOW_VAR *var, char *buff);
void wsrep_free_status(THD *thd);
void wsrep_update_cluster_state_uuid(const char* str);
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index f8c3f4d299b..25992459060 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -1825,6 +1825,35 @@ static int sst_donate_other (const char* method,
return arg.err;
}
+/* return true if character can be a part of a filename */
+static bool filename_char(int const c)
+{
+ return isalnum(c) || (c == '-') || (c == '_') || (c == '.');
+}
+
+/* return true if character can be a part of an address string */
+static bool address_char(int const c)
+{
+ return filename_char(c) ||
+ (c == ':') || (c == '[') || (c == ']') || (c == '/');
+}
+
+static bool check_request_str(const char* const str,
+ bool (*check) (int c))
+{
+ for (size_t i(0); str[i] != '\0'; ++i)
+ {
+ if (!check(str[i]))
+ {
+ WSREP_WARN("Illegal character in state transfer request: %i (%c).",
+ str[i], str[i]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
int wsrep_sst_donate(const std::string& msg,
const wsrep::gtid& current_gtid,
const bool bypass)
@@ -1836,8 +1865,21 @@ int wsrep_sst_donate(const std::string& msg,
const char* method= msg.data();
size_t method_len= strlen (method);
+
+ if (check_request_str(method, filename_char))
+ {
+ WSREP_ERROR("Bad SST method name. SST canceled.");
+ return WSREP_CB_FAILURE;
+ }
+
const char* data= method + method_len + 1;
+ if (check_request_str(data, address_char))
+ {
+ WSREP_ERROR("Bad SST address string. SST canceled.");
+ return WSREP_CB_FAILURE;
+ }
+
wsp::env env(NULL);
if (env.error())
{
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index 8c9170a3745..97aca456369 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -921,7 +921,8 @@ static void export_wsrep_status_to_mysql(THD* thd)
mysql_status_vars[wsrep_status_len].type = SHOW_LONG;
}
-int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff)
+int wsrep_show_status (THD *thd, SHOW_VAR *var, void *,
+ system_status_var *, enum_var_type)
{
/* Note that we should allow show status like 'wsrep%' even
when WSREP(thd) is false. */
diff --git a/sql/xa.cc b/sql/xa.cc
index e8e6dc43c56..15833377fb6 100644
--- a/sql/xa.cc
+++ b/sql/xa.cc
@@ -689,7 +689,7 @@ bool trans_xa_commit(THD *thd)
{
DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
- res= MY_TEST(ha_commit_one_phase(thd, 1, 1));
+ res= MY_TEST(ha_commit_one_phase(thd, 1));
if (res)
my_error(ER_XAER_RMERR, MYF(0));
else