summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt57
-rw-r--r--sql/backup.cc7
-rw-r--r--sql/ddl_log.cc83
-rw-r--r--sql/ddl_log.h10
-rw-r--r--sql/discover.cc2
-rw-r--r--sql/encryption.cc10
-rw-r--r--sql/field.cc8
-rw-r--r--sql/gcalc_slicescan.cc2
-rw-r--r--sql/ha_partition.cc12
-rw-r--r--sql/handler.cc27
-rw-r--r--sql/handler.h85
-rw-r--r--sql/hostname.cc2
-rw-r--r--sql/item.cc6
-rw-r--r--sql/item.h51
-rw-r--r--sql/item_cmpfunc.cc45
-rw-r--r--sql/item_cmpfunc.h41
-rw-r--r--sql/item_create.cc143
-rw-r--r--sql/item_func.cc3
-rw-r--r--sql/item_jsonfunc.cc107
-rw-r--r--sql/item_jsonfunc.h35
-rw-r--r--sql/item_strfunc.cc433
-rw-r--r--sql/item_strfunc.h70
-rw-r--r--sql/item_subselect.cc38
-rw-r--r--sql/item_subselect.h5
-rw-r--r--sql/item_xmlfunc.cc4
-rw-r--r--sql/json_table.cc3
-rw-r--r--sql/lex.h4
-rw-r--r--sql/lock.cc5
-rw-r--r--sql/log.cc21
-rw-r--r--sql/log_event.cc6
-rw-r--r--sql/log_event_client.cc2
-rw-r--r--sql/log_event_old.cc6
-rw-r--r--sql/log_event_server.cc14
-rw-r--r--sql/mdl.cc16
-rw-r--r--sql/mysqld.cc81
-rw-r--r--sql/mysqld.h13
-rw-r--r--sql/opt_range.cc42
-rw-r--r--sql/opt_split.cc2
-rw-r--r--sql/opt_subselect.cc6
-rw-r--r--sql/opt_table_elimination.cc2
-rw-r--r--sql/partition_element.h4
-rw-r--r--sql/partition_info.cc10
-rw-r--r--sql/partition_info.h8
-rw-r--r--sql/rpl_gtid.cc84
-rw-r--r--sql/rpl_mi.cc27
-rw-r--r--sql/rpl_mi.h2
-rw-r--r--sql/rpl_parallel.cc7
-rw-r--r--sql/rpl_rli.cc3
-rw-r--r--sql/rpl_utility.cc2
-rw-r--r--sql/semisync_master_ack_receiver.cc4
-rw-r--r--sql/semisync_slave.cc9
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/share/errmsg-utf8.txt18
-rw-r--r--sql/slave.cc12
-rw-r--r--sql/sp_head.h2
-rw-r--r--sql/sp_rcontext.cc3
-rw-r--r--sql/sp_rcontext.h7
-rw-r--r--sql/sql_acl.cc62
-rw-r--r--sql/sql_admin.cc3
-rw-r--r--sql/sql_alter.cc2
-rw-r--r--sql/sql_alter.h6
-rw-r--r--sql/sql_array.h20
-rw-r--r--sql/sql_audit.cc11
-rw-r--r--sql/sql_base.cc8
-rw-r--r--sql/sql_class.cc81
-rw-r--r--sql/sql_class.h67
-rw-r--r--sql/sql_cmd.h1
-rw-r--r--sql/sql_db.cc16
-rw-r--r--sql/sql_delete.cc5
-rw-r--r--sql/sql_error.cc18
-rw-r--r--sql/sql_error.h36
-rw-r--r--sql/sql_get_diagnostics.cc2
-rw-r--r--sql/sql_get_diagnostics.h3
-rw-r--r--sql/sql_insert.cc29
-rw-r--r--sql/sql_lex.cc27
-rw-r--r--sql/sql_lex.h8
-rw-r--r--sql/sql_load.cc1
-rw-r--r--sql/sql_parse.cc18
-rw-r--r--sql/sql_partition.cc705
-rw-r--r--sql/sql_partition.h16
-rw-r--r--sql/sql_partition_admin.cc57
-rw-r--r--sql/sql_plugin.cc75
-rw-r--r--sql/sql_plugin.h2
-rw-r--r--sql/sql_plugin_services.ic96
-rw-r--r--sql/sql_prepare.cc423
-rw-r--r--sql/sql_prepare.h2
-rw-r--r--sql/sql_priv.h10
-rw-r--r--sql/sql_reload.cc2
-rw-r--r--sql/sql_select.cc66
-rw-r--r--sql/sql_show.cc36
-rw-r--r--sql/sql_signal.cc24
-rw-r--r--sql/sql_string.h5
-rw-r--r--sql/sql_table.cc173
-rw-r--r--sql/sql_table.h9
-rw-r--r--sql/sql_tablespace.cc72
-rw-r--r--sql/sql_tablespace.h24
-rw-r--r--sql/sql_test.cc2
-rw-r--r--sql/sql_type_fixedbin.h1912
-rw-r--r--sql/sql_type_fixedbin_storage.h173
-rw-r--r--sql/sql_update.cc3
-rw-r--r--sql/sql_yacc.yy556
-rw-r--r--sql/sys_vars.cc37
-rw-r--r--sql/table.cc21
-rw-r--r--sql/thread_pool_info.cc2
-rw-r--r--sql/tztime.cc2
-rw-r--r--sql/uniques.cc2
-rw-r--r--sql/wsrep_mysqld.cc67
-rw-r--r--sql/wsrep_mysqld.h2
-rw-r--r--sql/wsrep_trans_observer.h6
-rw-r--r--sql/wsrep_var.cc24
-rw-r--r--sql/wsrep_var.h4
111 files changed, 4896 insertions, 1851 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index c63e4ecde9e..9ec686ef9d9 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -52,6 +52,7 @@ ENDIF()
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/sql
+${LIBFMT_INCLUDE_DIR}
${PCRE_INCLUDES}
${ZLIB_INCLUDE_DIR}
${SSL_INCLUDE_DIRS}
@@ -97,9 +98,9 @@ SET (SQL_SOURCE
filesort.cc gstream.cc
signal_handler.cc
handler.cc
- hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
- item_create.cc item_func.cc item_geofunc.cc item_row.cc
- item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc
+ hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
+ item_create.cc item_func.cc item_geofunc.cc item_row.cc
+ item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc
key.cc log.cc lock.cc
log_event.cc log_event_server.cc
rpl_record.cc rpl_reporting.cc
@@ -108,33 +109,33 @@ SET (SQL_SOURCE
mysqld.cc net_serv.cc keycaches.cc
../sql-common/client_plugin.c
opt_range.cc opt_sum.cc
- ../sql-common/pack.c parse_file.cc password.c procedure.cc
+ ../sql-common/pack.c parse_file.cc password.c procedure.cc
protocol.cc records.cc repl_failsafe.cc rpl_filter.cc
session_tracker.cc
- set_var.cc
- slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc
- sp_rcontext.cc spatial.cc sql_acl.cc sql_analyse.cc sql_base.cc
+ set_var.cc
+ slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc
+ sp_rcontext.cc spatial.cc sql_acl.cc sql_analyse.cc sql_base.cc
sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc
sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc
- sql_digest.cc sql_do.cc
+ sql_digest.cc sql_do.cc
sql_error.cc sql_handler.cc sql_get_diagnostics.cc
- sql_help.cc sql_insert.cc sql_lex.cc
+ sql_help.cc sql_insert.cc sql_lex.cc
sql_list.cc sql_load.cc sql_manager.cc
sql_parse.cc sql_bootstrap.cc
- sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc
+ sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc
debug_sync.cc debug.cc
sql_repl.cc sql_select.cc sql_show.cc sql_state.c
group_by_handler.cc derived_handler.cc select_handler.cc
sql_statistics.cc sql_string.cc lex_string.h
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
ddl_log.cc ddl_log.h
- sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
- sql_time.cc tztime.cc unireg.cc item_xmlfunc.cc
+ sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
+ sql_time.cc tztime.cc unireg.cc item_xmlfunc.cc
uniques.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc
event_data_objects.cc
- event_queue.cc event_db_repository.cc
- sql_tablespace.cc events.cc ../sql-common/my_user.c
+ event_queue.cc event_db_repository.cc
+ events.cc ../sql-common/my_user.c
partition_info.cc rpl_utility.cc rpl_utility_server.cc
rpl_injector.cc sql_locale.cc
rpl_rli.cc rpl_mi.cc sql_servers.cc sql_audit.cc
@@ -178,7 +179,7 @@ SET (SQL_SOURCE
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
-
+
IF ((CMAKE_SYSTEM_NAME MATCHES "Linux" OR
CMAKE_SYSTEM_NAME MATCHES "SunOS" OR
WIN32 OR
@@ -312,24 +313,24 @@ ENDIF()
# On Solaris, some extra effort is required in order to get dtrace probes
# from static libraries
-DTRACE_INSTRUMENT_STATIC_LIBS(mariadbd
+DTRACE_INSTRUMENT_STATIC_LIBS(mariadbd
"sql;mysys;mysys_ssl;${MYSQLD_STATIC_PLUGIN_LIBS}")
-
+
SET(WITH_MYSQLD_LDFLAGS "" CACHE STRING "Additional linker flags for mysqld")
MARK_AS_ADVANCED(WITH_MYSQLD_LDFLAGS)
IF(WITH_MYSQLD_LDFLAGS)
GET_TARGET_PROPERTY(MYSQLD_LINK_FLAGS mariadbd LINK_FLAGS)
IF(NOT MYSQLD_LINK_FLAGS)
- SET(MYSQLD_LINK_FLAGS)
- ENDIF()
- SET_TARGET_PROPERTIES(mariadbd PROPERTIES LINK_FLAGS
+ SET(MYSQLD_LINK_FLAGS)
+ ENDIF()
+ SET_TARGET_PROPERTIES(mariadbd PROPERTIES LINK_FLAGS
"${MYSQLD_LINK_FLAGS} ${WITH_MYSQLD_LDFLAGS}")
ENDIF()
-# Handle out-of-source build from source package with possibly broken
-# bison. Copy bison output to from source to build directory, if not already
+# Handle out-of-source build from source package with possibly broken
+# bison. Copy bison output to from source to build directory, if not already
# there
IF (NOT BISON_FOUND)
IF (NOT ${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
@@ -391,6 +392,10 @@ ADD_CUSTOM_TARGET(
)
ADD_DEPENDENCIES(sql GenServerSource)
+IF(TARGET libfmt)
+ ADD_DEPENDENCIES(sql libfmt)
+ENDIF()
+
IF(WIN32 OR HAVE_DLOPEN AND NOT DISABLE_SHARED)
ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def)
SET_TARGET_PROPERTIES(udf_example PROPERTIES PREFIX "")
@@ -440,9 +445,9 @@ IF(TARGET mariadbd AND (NOT CMAKE_CROSSCOMPILING OR DEFINED CMAKE_CROSSCOMPILING
ELSE()
SET(ALL_ON_WINDOWS)
ENDIF()
- ADD_CUSTOM_TARGET(initial_database
+ ADD_CUSTOM_TARGET(initial_database
${ALL_ON_WINDOWS}
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep
)
ENDIF()
@@ -451,7 +456,7 @@ IF(WIN32)
FILE(TO_NATIVE_PATH ${my_bootstrap_sql} native_outfile)
# Create bootstrapper SQL script
- ADD_CUSTOM_COMMAND(OUTPUT
+ ADD_CUSTOM_COMMAND(OUTPUT
${my_bootstrap_sql}
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/scripts
cmd /c copy mysql_system_tables.sql+mysql_system_tables_data.sql+fill_help_tables.sql+mysql_performance_tables.sql+mysql_test_db.sql+mysql_sys_schema.sql ${native_outfile}
@@ -474,7 +479,7 @@ IF(WIN32)
DEPENDS comp_sql ${my_bootstrap_sql}
)
- MYSQL_ADD_EXECUTABLE(mariadb-install-db
+ MYSQL_ADD_EXECUTABLE(mariadb-install-db
mysql_install_db.cc
${CMAKE_CURRENT_BINARY_DIR}/mysql_bootstrap_sql.c
COMPONENT Server
diff --git a/sql/backup.cc b/sql/backup.cc
index 84c3788a4d4..89cc9b6ee15 100644
--- a/sql/backup.cc
+++ b/sql/backup.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, 2020, MariaDB Corporation.
+/* Copyright (c) 2018, 2021, 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
the Free Software Foundation; version 2 of the License.
@@ -381,6 +381,9 @@ bool backup_end(THD *thd)
if (WSREP_NNULL(thd) && thd->wsrep_desynced_backup_stage)
{
Wsrep_server_state &server_state= Wsrep_server_state::instance();
+ THD_STAGE_INFO(thd, stage_waiting_flow);
+ WSREP_DEBUG("backup_end: waiting for flow control for %s",
+ wsrep_thd_query(thd));
server_state.resume_and_resync();
thd->wsrep_desynced_backup_stage= false;
}
@@ -532,7 +535,7 @@ static char *add_id_to_buffer(char *ptr, const LEX_CUSTRING *from)
tmp.str= buff;
tmp.length= MY_UUID_STRING_LENGTH;
- my_uuid2str(from->str, buff);
+ my_uuid2str(from->str, buff, 1);
return add_str_to_buffer(ptr, &tmp);
}
diff --git a/sql/ddl_log.cc b/sql/ddl_log.cc
index 951a7abd95f..418b5f3b5b0 100644
--- a/sql/ddl_log.cc
+++ b/sql/ddl_log.cc
@@ -77,6 +77,8 @@
#define DDL_LOG_MAGIC_LENGTH 4
/* How many times to try to execute a ddl log entry that causes crashes */
#define DDL_LOG_MAX_RETRY 3
+#define DDL_LOG_RETRY_MASK 0xFF
+#define DDL_LOG_RETRY_BITS 8
uchar ddl_log_file_magic[]=
{ (uchar) 254, (uchar) 254, (uchar) 11, (uchar) 2 };
@@ -155,7 +157,7 @@ mysql_mutex_t LOCK_gdl;
#define DDL_LOG_XID_POS 10
/* Used to store unique uuid from the .frm file */
#define DDL_LOG_UUID_POS 18
-/* ID_POS can be used to store something unique, like file size (4 bytes) */
+/* ID_POS can be used to store something unique, like file size (8 bytes) */
#define DDL_LOG_ID_POS DDL_LOG_UUID_POS + MY_UUID_SIZE
#define DDL_LOG_END_POS DDL_LOG_ID_POS + 8
@@ -335,7 +337,7 @@ static bool write_ddl_log_file_entry(uint entry_pos)
static bool update_phase(uint entry_pos, uchar phase)
{
DBUG_ENTER("update_phase");
- DBUG_PRINT("enter", ("phase: %d", (int) phase));
+ DBUG_PRINT("ddl_log", ("pos: %u phase: %u", entry_pos, (uint) phase));
DBUG_RETURN(mysql_file_pwrite(global_ddl_log.file_id, &phase, 1,
global_ddl_log.io_size * entry_pos +
@@ -369,6 +371,8 @@ static bool update_next_entry_pos(uint entry_pos, uint next_entry)
uchar buff[4];
DBUG_ENTER("update_next_entry_pos");
+ DBUG_PRINT("ddl_log", ("pos: %u->%u", entry_pos, next_entry));
+
int4store(buff, next_entry);
DBUG_RETURN(mysql_file_pwrite(global_ddl_log.file_id, buff, sizeof(buff),
global_ddl_log.io_size * entry_pos +
@@ -420,6 +424,7 @@ static bool disable_execute_entry(uint entry_pos)
{
uchar buff[1];
DBUG_ENTER("disable_execute_entry");
+ DBUG_PRINT("ddl_log", ("pos: {%u}", entry_pos));
buff[0]= DDL_LOG_IGNORE_ENTRY_CODE;
DBUG_RETURN(mysql_file_pwrite(global_ddl_log.file_id, buff, sizeof(buff),
@@ -1296,13 +1301,15 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
mysql_mutex_assert_owner(&LOCK_gdl);
DBUG_PRINT("ddl_log",
- ("entry type: %u action type: %u (%s) phase: %u next: %u "
+ ("pos: %u=>%u->%u type: %u action: %u (%s) phase: %u "
"handler: '%s' name: '%s' from_name: '%s' tmp_name: '%s'",
+ recovery_state.execute_entry_pos,
+ ddl_log_entry->entry_pos,
+ ddl_log_entry->next_entry,
(uint) ddl_log_entry->entry_type,
(uint) ddl_log_entry->action_type,
ddl_log_action_name[ddl_log_entry->action_type],
(uint) ddl_log_entry->phase,
- ddl_log_entry->next_entry,
ddl_log_entry->handler_name.str,
ddl_log_entry->name.str,
ddl_log_entry->from_name.str,
@@ -2470,13 +2477,13 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
error= FALSE;
DBUG_PRINT("ddl_log",
- ("entry type: %u action type: %u (%s) phase: %u next: %u "
+ ("pos: %u->%u action: %u (%s) phase: %u "
"handler: '%s' name: '%s' from_name: '%s' tmp_name: '%s'",
- (uint) ddl_log_entry->entry_type,
+ (*active_entry)->entry_pos,
+ (uint) ddl_log_entry->next_entry,
(uint) ddl_log_entry->action_type,
ddl_log_action_name[ddl_log_entry->action_type],
(uint) ddl_log_entry->phase,
- ddl_log_entry->next_entry,
ddl_log_entry->handler_name.str,
ddl_log_entry->name.str,
ddl_log_entry->from_name.str,
@@ -2510,6 +2517,7 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
@param first_entry First entry in linked list of entries
to execute.
+ @param cond_entry Check and don't execute if cond_entry is active
@param[in,out] active_entry Entry to execute, 0 = NULL if the entry
is written first time and needs to be
returned. In this case the entry written
@@ -2520,6 +2528,7 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
*/
bool ddl_log_write_execute_entry(uint first_entry,
+ uint cond_entry,
DDL_LOG_MEMORY_ENTRY **active_entry)
{
uchar *file_entry_buf= global_ddl_log.file_entry_buf;
@@ -2536,13 +2545,17 @@ bool ddl_log_write_execute_entry(uint first_entry,
file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (uchar)DDL_LOG_EXECUTE_CODE;
int4store(file_entry_buf + DDL_LOG_NEXT_ENTRY_POS, first_entry);
+ int8store(file_entry_buf + DDL_LOG_ID_POS, ((ulonglong)cond_entry << DDL_LOG_RETRY_BITS));
if (!(*active_entry))
{
if (ddl_log_get_free_entry(active_entry))
DBUG_RETURN(TRUE);
got_free_entry= TRUE;
- }
+ }
+ DBUG_PRINT("ddl_log",
+ ("pos: %u=>%u",
+ (*active_entry)->entry_pos, first_entry));
if (write_ddl_log_file_entry((*active_entry)->entry_pos))
{
if (got_free_entry)
@@ -2575,6 +2588,7 @@ bool ddl_log_increment_phase(uint entry_pos)
{
bool error;
DBUG_ENTER("ddl_log_increment_phase");
+ DBUG_PRINT("ddl_log", ("pos: %u", entry_pos));
mysql_mutex_lock(&LOCK_gdl);
error= ddl_log_increment_phase_no_lock(entry_pos);
@@ -2754,13 +2768,13 @@ int ddl_log_execute_recovery()
recovery_state.xid= ddl_log_entry.xid;
/* purecov: begin tested */
- if (ddl_log_entry.unique_id > DDL_LOG_MAX_RETRY)
+ if ((ddl_log_entry.unique_id & DDL_LOG_RETRY_MASK) > DDL_LOG_MAX_RETRY)
{
error= -1;
continue;
}
update_unique_id(i, ++ddl_log_entry.unique_id);
- if (ddl_log_entry.unique_id > DDL_LOG_MAX_RETRY)
+ if ((ddl_log_entry.unique_id & DDL_LOG_RETRY_MASK) > DDL_LOG_MAX_RETRY)
{
sql_print_error("DDL_LOG: Aborting executing entry %u after %llu "
"retries", i, ddl_log_entry.unique_id);
@@ -2769,6 +2783,15 @@ int ddl_log_execute_recovery()
}
/* purecov: end tested */
+ uint cond_entry= (uint)(ddl_log_entry.unique_id >> DDL_LOG_RETRY_BITS);
+
+ if (cond_entry && is_execute_entry_active(cond_entry))
+ {
+ if (disable_execute_entry(i))
+ error= -1;
+ continue;
+ }
+
if (ddl_log_execute_entry_no_lock(thd, ddl_log_entry.next_entry))
{
/* Real unpleasant scenario but we have to continue anyway */
@@ -2848,8 +2871,7 @@ void ddl_log_release()
Methods for DDL_LOG_STATE
*/
-static void add_log_entry(DDL_LOG_STATE *state,
- DDL_LOG_MEMORY_ENTRY *log_entry)
+void ddl_log_add_entry(DDL_LOG_STATE *state, DDL_LOG_MEMORY_ENTRY *log_entry)
{
log_entry->next_active_log_entry= state->list;
state->main_entry= state->list= log_entry;
@@ -3028,7 +3050,7 @@ static bool ddl_log_write(DDL_LOG_STATE *ddl_state,
ddl_log_release_memory_entry(log_entry);
DBUG_RETURN(1);
}
- add_log_entry(ddl_state, log_entry);
+ ddl_log_add_entry(ddl_state, log_entry);
ddl_state->flags|= ddl_log_entry->flags; // Update cache
DBUG_RETURN(0);
}
@@ -3178,7 +3200,7 @@ static bool ddl_log_drop(THD *thd, DDL_LOG_STATE *ddl_state,
}
mysql_mutex_unlock(&LOCK_gdl);
- add_log_entry(ddl_state, log_entry);
+ ddl_log_add_entry(ddl_state, log_entry);
DBUG_RETURN(0);
error:
@@ -3478,7 +3500,7 @@ bool ddl_log_store_query(THD *thd, DDL_LOG_STATE *ddl_state,
goto err;
parent_entry_pos= ddl_state->list->entry_pos;
entry_pos= first_entry->entry_pos;
- add_log_entry(ddl_state, first_entry);
+ ddl_log_add_entry(ddl_state, first_entry);
while (length)
{
@@ -3494,7 +3516,7 @@ bool ddl_log_store_query(THD *thd, DDL_LOG_STATE *ddl_state,
if (ddl_log_get_free_entry(&next_entry))
goto err;
ddl_log_entry.next_entry= next_entry_pos= next_entry->entry_pos;
- add_log_entry(ddl_state, next_entry);
+ ddl_log_add_entry(ddl_state, next_entry);
}
else
{
@@ -3526,3 +3548,32 @@ err:
mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(1);
}
+
+
+/*
+ Log an delete frm file
+*/
+
+/*
+ TODO: Partitioning atomic DDL refactoring: this should be replaced with
+ ddl_log_create_table().
+*/
+bool ddl_log_delete_frm(DDL_LOG_STATE *ddl_state, const char *to_path)
+{
+ DDL_LOG_ENTRY ddl_log_entry;
+ DDL_LOG_MEMORY_ENTRY *log_entry;
+ DBUG_ENTER("ddl_log_delete_frm");
+ bzero(&ddl_log_entry, sizeof(ddl_log_entry));
+ ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
+ ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0;
+
+ lex_string_set(&ddl_log_entry.handler_name, reg_ext);
+ lex_string_set(&ddl_log_entry.name, to_path);
+
+ mysql_mutex_assert_owner(&LOCK_gdl);
+ if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
+ DBUG_RETURN(1);
+
+ ddl_log_add_entry(ddl_state, log_entry);
+ DBUG_RETURN(0);
+}
diff --git a/sql/ddl_log.h b/sql/ddl_log.h
index a2a6af76a77..9960855a813 100644
--- a/sql/ddl_log.h
+++ b/sql/ddl_log.h
@@ -262,8 +262,14 @@ int ddl_log_execute_recovery();
bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
DDL_LOG_MEMORY_ENTRY **active_entry);
+bool ddl_log_write_execute_entry(uint first_entry, uint cond_entry,
+ DDL_LOG_MEMORY_ENTRY** active_entry);
+inline
bool ddl_log_write_execute_entry(uint first_entry,
- DDL_LOG_MEMORY_ENTRY **active_entry);
+ DDL_LOG_MEMORY_ENTRY **active_entry)
+{
+ return ddl_log_write_execute_entry(first_entry, 0, active_entry);
+}
bool ddl_log_disable_execute_entry(DDL_LOG_MEMORY_ENTRY **active_entry);
void ddl_log_complete(DDL_LOG_STATE *ddl_log_state);
@@ -279,6 +285,7 @@ void ddl_log_release_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry);
bool ddl_log_sync();
bool ddl_log_execute_entry(THD *thd, uint first_entry);
+void ddl_log_add_entry(DDL_LOG_STATE *state, DDL_LOG_MEMORY_ENTRY *log_entry);
void ddl_log_release_entries(DDL_LOG_STATE *ddl_log_state);
bool ddl_log_rename_table(THD *thd, DDL_LOG_STATE *ddl_state,
handlerton *hton,
@@ -348,5 +355,6 @@ bool ddl_log_alter_table(THD *thd, DDL_LOG_STATE *ddl_state,
bool is_renamed);
bool ddl_log_store_query(THD *thd, DDL_LOG_STATE *ddl_log_state,
const char *query, size_t length);
+bool ddl_log_delete_frm(DDL_LOG_STATE *ddl_state, const char *to_path);
extern mysql_mutex_t LOCK_gdl;
#endif /* DDL_LOG_INCLUDED */
diff --git a/sql/discover.cc b/sql/discover.cc
index 4267f97cf59..9b524760b63 100644
--- a/sql/discover.cc
+++ b/sql/discover.cc
@@ -232,7 +232,7 @@ int extension_based_table_discovery(MY_DIR *dirp, const char *ext_meta,
cur++;
}
advance(from, to, cur, skip);
- dirp->number_of_files= (uint)(to - dirp->dir_entry);
+ dirp->number_of_files= to - dirp->dir_entry;
return 0;
}
diff --git a/sql/encryption.cc b/sql/encryption.cc
index 13239b91910..3c7ba2e997b 100644
--- a/sql/encryption.cc
+++ b/sql/encryption.cc
@@ -109,6 +109,7 @@ int initialize_encryption_plugin(st_plugin_int *plugin)
int finalize_encryption_plugin(st_plugin_int *plugin)
{
+ int deinit_status= 0;
bool used= plugin_ref_to_int(encryption_manager) == plugin;
if (used)
@@ -118,18 +119,15 @@ int finalize_encryption_plugin(st_plugin_int *plugin)
encryption_handler.encryption_ctx_size_func= zero_size;
}
- if (plugin && plugin->plugin->deinit && plugin->plugin->deinit(NULL))
- {
- DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
- plugin->name.str));
- }
+ if (plugin && plugin->plugin->deinit)
+ deinit_status= plugin->plugin->deinit(NULL);
if (used)
{
plugin_unlock(NULL, encryption_manager);
encryption_manager= 0;
}
- return 0;
+ return deinit_status;
}
/******************************************************************
diff --git a/sql/field.cc b/sql/field.cc
index 63d39c77d95..b72b0357c23 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -11101,6 +11101,14 @@ Field::set_warning(Sql_condition::enum_warning_level level, uint code,
will have table == NULL.
*/
THD *thd= get_thd();
+
+ /*
+ In INPLACE ALTER, server can't know which row has generated
+ the warning, so the value of current row is supplied by the engine.
+ */
+ if (current_row)
+ thd->get_stmt_da()->reset_current_row_for_warning(current_row);
+
if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
thd->cuted_fields+= cut_increment;
diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc
index 93561f5fe97..e35f9155967 100644
--- a/sql/gcalc_slicescan.cc
+++ b/sql/gcalc_slicescan.cc
@@ -168,7 +168,7 @@ static void GCALC_DBUG_PRINT_SLICE(const char *header,
Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item):
- m_blk_size(blk_size - ALLOC_ROOT_MIN_BLOCK_SIZE),
+ m_blk_size(blk_size),
m_sizeof_item(ALIGN_SIZE(sizeof_item)),
m_points_per_blk((uint)((m_blk_size - PH_DATA_OFFSET) / m_sizeof_item)),
m_blk_hook(&m_first_blk),
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index f6c4b95dcbd..f17abed82ff 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -3537,31 +3537,31 @@ bool ha_partition::init_partition_bitmaps()
DBUG_ENTER("ha_partition::init_partition_bitmaps");
/* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */
- if (my_bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE))
+ if (my_bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1))
DBUG_RETURN(true);
/* Initialize the bitmap we use to keep track of locked partitions */
- if (my_bitmap_init(&m_locked_partitions, NULL, m_tot_parts, FALSE))
+ if (my_bitmap_init(&m_locked_partitions, NULL, m_tot_parts))
DBUG_RETURN(true);
/*
Initialize the bitmap we use to keep track of partitions which may have
something to reset in ha_reset().
*/
- if (my_bitmap_init(&m_partitions_to_reset, NULL, m_tot_parts, FALSE))
+ if (my_bitmap_init(&m_partitions_to_reset, NULL, m_tot_parts))
DBUG_RETURN(true);
/*
Initialize the bitmap we use to keep track of partitions which returned
HA_ERR_KEY_NOT_FOUND from index_read_map.
*/
- if (my_bitmap_init(&m_key_not_found_partitions, NULL, m_tot_parts, FALSE))
+ if (my_bitmap_init(&m_key_not_found_partitions, NULL, m_tot_parts))
DBUG_RETURN(true);
- if (bitmap_init(&m_mrr_used_partitions, NULL, m_tot_parts, TRUE))
+ if (my_bitmap_init(&m_mrr_used_partitions, NULL, m_tot_parts))
DBUG_RETURN(true);
- if (my_bitmap_init(&m_opened_partitions, NULL, m_tot_parts, FALSE))
+ if (my_bitmap_init(&m_opened_partitions, NULL, m_tot_parts))
DBUG_RETURN(true);
m_file_sample= NULL;
diff --git a/sql/handler.cc b/sql/handler.cc
index 2b6d8cad190..9c4c6287950 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -581,6 +581,7 @@ static int hton_drop_table(handlerton *hton, const char *path)
int ha_finalize_handlerton(st_plugin_int *plugin)
{
+ int deinit_status= 0;
handlerton *hton= (handlerton *)plugin->data;
DBUG_ENTER("ha_finalize_handlerton");
@@ -595,18 +596,7 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
hton->panic(hton, HA_PANIC_CLOSE);
if (plugin->plugin->deinit)
- {
- /*
- Today we have no defined/special behavior for uninstalling
- engine plugins.
- */
- DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
- if (plugin->plugin->deinit(NULL))
- {
- DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
- plugin->name.str));
- }
- }
+ deinit_status= plugin->plugin->deinit(NULL);
free_sysvar_table_options(hton);
update_discovery_counters(hton, -1);
@@ -627,7 +617,7 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
my_free(hton);
end:
- DBUG_RETURN(0);
+ DBUG_RETURN(deinit_status);
}
@@ -1746,6 +1736,13 @@ int ha_commit_trans(THD *thd, bool all)
if (ha_info->ht()->prepare_commit_versioned)
{
trx_end_id= ha_info->ht()->prepare_commit_versioned(thd, &trx_start_id);
+
+ if (trx_end_id == ULONGLONG_MAX)
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1);
+ goto err;
+ }
+
if (trx_end_id)
break; // FIXME: use a common ID for cross-engine transactions
}
@@ -8229,7 +8226,7 @@ static Create_field *vers_init_sys_field(THD *thd, const char *field_name, int f
f->set_handler(&type_handler_timestamp2);
f->length= MAX_DATETIME_PRECISION;
}
- f->invisible= DBUG_EVALUATE_IF("sysvers_show", VISIBLE, INVISIBLE_SYSTEM);
+ f->invisible= DBUG_IF("sysvers_show") ? VISIBLE : INVISIBLE_SYSTEM;
if (f->check(thd))
return NULL;
@@ -8374,7 +8371,7 @@ bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info,
if (!need_check(alter_info) && !share->versioned)
return false;
- if (DBUG_EVALUATE_IF("sysvers_force", 0, share->tmp_table))
+ if (!DBUG_IF("sysvers_force") && share->tmp_table)
{
my_error(ER_VERS_NOT_SUPPORTED, MYF(0), "CREATE TEMPORARY TABLE");
return true;
diff --git a/sql/handler.h b/sql/handler.h
index 14a306f7774..fe61666bf20 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -829,7 +829,9 @@ typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
// Set by Sql_cmd_alter_table_truncate_partition::execute()
#define ALTER_PARTITION_TRUNCATE (1ULL << 11)
// Set for REORGANIZE PARTITION
-#define ALTER_PARTITION_TABLE_REORG (1ULL << 12)
+#define ALTER_PARTITION_TABLE_REORG (1ULL << 12)
+#define ALTER_PARTITION_CONVERT_IN (1ULL << 13)
+#define ALTER_PARTITION_CONVERT_OUT (1ULL << 14)
/*
This is master database for most of system tables. However there
@@ -974,39 +976,6 @@ struct xid_recovery_member
#define MIN_XID_LIST_SIZE 128
#define MAX_XID_LIST_SIZE (1024*128)
-/*
- These structures are used to pass information from a set of SQL commands
- on add/drop/change tablespace definitions to the proper hton.
-*/
-#define UNDEF_NODEGROUP 65535
-enum ts_command_type
-{
- TS_CMD_NOT_DEFINED = -1,
- CREATE_TABLESPACE = 0,
- ALTER_TABLESPACE = 1,
- CREATE_LOGFILE_GROUP = 2,
- ALTER_LOGFILE_GROUP = 3,
- DROP_TABLESPACE = 4,
- DROP_LOGFILE_GROUP = 5,
- CHANGE_FILE_TABLESPACE = 6,
- ALTER_ACCESS_MODE_TABLESPACE = 7
-};
-
-enum ts_alter_tablespace_type
-{
- TS_ALTER_TABLESPACE_TYPE_NOT_DEFINED = -1,
- ALTER_TABLESPACE_ADD_FILE = 1,
- ALTER_TABLESPACE_DROP_FILE = 2
-};
-
-enum tablespace_access_mode
-{
- TS_NOT_DEFINED= -1,
- TS_READ_ONLY = 0,
- TS_READ_WRITE = 1,
- TS_NOT_ACCESSIBLE = 2
-};
-
/* Statistics about batch operations like bulk_insert */
struct ha_copy_info
{
@@ -1017,50 +986,6 @@ struct ha_copy_info
ha_rows updated;
};
-struct handlerton;
-class st_alter_tablespace : public Sql_alloc
-{
- public:
- const char *tablespace_name;
- const char *logfile_group_name;
- enum ts_command_type ts_cmd_type;
- enum ts_alter_tablespace_type ts_alter_tablespace_type;
- const char *data_file_name;
- const char *undo_file_name;
- const char *redo_file_name;
- ulonglong extent_size;
- ulonglong undo_buffer_size;
- ulonglong redo_buffer_size;
- ulonglong initial_size;
- ulonglong autoextend_size;
- ulonglong max_size;
- uint nodegroup_id;
- handlerton *storage_engine;
- bool wait_until_completed;
- const char *ts_comment;
- enum tablespace_access_mode ts_access_mode;
- st_alter_tablespace()
- {
- tablespace_name= NULL;
- logfile_group_name= "DEFAULT_LG"; //Default log file group
- ts_cmd_type= TS_CMD_NOT_DEFINED;
- data_file_name= NULL;
- undo_file_name= NULL;
- redo_file_name= NULL;
- extent_size= 1024*1024; //Default 1 MByte
- undo_buffer_size= 8*1024*1024; //Default 8 MByte
- redo_buffer_size= 8*1024*1024; //Default 8 MByte
- initial_size= 128*1024*1024; //Default 128 MByte
- autoextend_size= 0; //No autoextension as default
- max_size= 0; //Max size == initial size => no extension
- storage_engine= NULL;
- nodegroup_id= UNDEF_NODEGROUP;
- wait_until_completed= TRUE;
- ts_comment= NULL;
- ts_access_mode= TS_NOT_DEFINED;
- }
-};
-
/* The handler for a table type. Will be included in the TABLE structure */
struct TABLE;
@@ -1124,6 +1049,7 @@ typedef bool (stat_print_fn)(THD *thd, const char *type, size_t type_len,
enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX };
extern MYSQL_PLUGIN_IMPORT st_plugin_int *hton2plugin[MAX_HA];
+struct handlerton;
#define view_pseudo_hton ((handlerton *)1)
/* Transaction log maintains type definitions */
@@ -1554,8 +1480,7 @@ struct handlerton
bool (*show_status)(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat);
uint (*partition_flags)();
alter_table_operations (*alter_table_flags)(alter_table_operations flags);
- int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info);
- int (*fill_is_table)(handlerton *hton, THD *thd, TABLE_LIST *tables,
+ int (*fill_is_table)(handlerton *hton, THD *thd, TABLE_LIST *tables,
class Item *cond,
enum enum_schema_tables);
uint32 flags; /* global handler flags */
diff --git a/sql/hostname.cc b/sql/hostname.cc
index 7b07ab620a6..35948db3d23 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -191,7 +191,7 @@ Host_entry *hostname_cache_first()
static inline Host_entry *hostname_cache_search(const char *ip_key)
{
- return hostname_cache->search((uchar *) ip_key, 0);
+ return hostname_cache->search((uchar *) ip_key, HOST_ENTRY_KEY_SIZE);
}
static void add_hostname_impl(const char *ip_key, const char *hostname,
diff --git a/sql/item.cc b/sql/item.cc
index 125d1848506..e0456edfee0 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -55,8 +55,8 @@ const char *item_empty_name="";
const char *item_used_name= "\0";
static int save_field_in_field(Field *, bool *, Field *, bool);
-const Item_bool_static Item_false("FALSE", 0);
-const Item_bool_static Item_true("TRUE", 1);
+Item_bool_static *Item_false;
+Item_bool_static *Item_true;
/**
Compare two Items for List<Item>::add_unique()
@@ -446,7 +446,7 @@ Item::Item(THD *thd):
Item::Item():
name(null_clex_str), orig_name(0), is_expensive_cache(-1)
{
- DBUG_ASSERT(my_progname == NULL); // before main()
+ DBUG_ASSERT(!mysqld_server_started); // Created early
base_flags= item_base_t::FIXED;
with_flags= item_with_t::NONE;
null_value= 0;
diff --git a/sql/item.h b/sql/item.h
index 468b9932f02..636ec47b43e 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -769,8 +769,8 @@ enum class item_base_t : item_flags_t
FIXED= (1<<2), // Was fixed with fix_fields().
IS_EXPLICIT_NAME= (1<<3), // The name of this Item was set by the user
// (or was auto generated otherwise)
- IS_IN_WITH_CYCLE= (1<<4) // This item is in CYCLE clause
- // of WITH.
+ IS_IN_WITH_CYCLE= (1<<4), // This item is in CYCLE clause of WITH.
+ AT_TOP_LEVEL= (1<<5) // At top (AND) level of item tree
};
@@ -1319,6 +1319,25 @@ public:
{
set_maybe_null(maybe_null_arg);
}
+ /*
+ Mark the item that it is a top level item, or part of a top level AND item,
+ for WHERE and ON clauses:
+ Example: ... WHERE a=5 AND b=6; Both a=5 and b=6 are top level items
+
+ This is used to indicate that there is no distinction between if the
+ value of the item is FALSE or NULL..
+ This enables Item_cond_and and subquery related items to do special
+ "top level" optimizations.
+ */
+ virtual void top_level_item()
+ {
+ base_flags|= item_base_t::AT_TOP_LEVEL;
+ }
+ /*
+ Return TRUE if this item of top WHERE level (AND/OR)
+ */
+ bool is_top_level_item() const
+ { return (bool) (base_flags & item_base_t::AT_TOP_LEVEL); }
void set_typelib(const TYPELIB *typelib) override
{
@@ -2035,25 +2054,6 @@ public:
{
return type_handler()->Item_update_null_value(this);
}
-
- /*
- Inform the item that there will be no distinction between its result
- being FALSE or NULL.
-
- NOTE
- This function will be called for eg. Items that are top-level AND-parts
- of the WHERE clause. Items implementing this function (currently
- Item_cond_and and subquery-related item) enable special optimizations
- when they are "top level".
- */
- virtual void top_level_item() {}
- /*
- Return TRUE if it is item of top WHERE level (AND/OR) and it is
- important, return FALSE if it not important (we can not use to simplify
- calculations) or not top level
- */
- virtual bool is_top_level_item() const
- { return FALSE; /* not important */}
/*
return IN/ALL/ANY subquery or NULL
*/
@@ -2647,7 +2647,7 @@ public:
bool depends_only_on(table_map view_map)
{ return marker & MARKER_FULL_EXTRACTION; }
- int get_extraction_flag()
+ int get_extraction_flag() const
{ return marker & MARKER_EXTRACTION_MASK; }
void set_extraction_flag(int16 flags)
{
@@ -4430,11 +4430,16 @@ public:
Item_bool_static(const char *str_arg, longlong i):
Item_bool(str_arg, i) {};
+ /* Don't mark static items as top level item */
+ virtual void top_level_item() override {}
void set_join_tab_idx(uint8 join_tab_idx_arg) override
{ DBUG_ASSERT(0); }
+
+ void cleanup() override {}
};
-extern const Item_bool_static Item_false, Item_true;
+/* The following variablese are stored in a read only segment */
+extern Item_bool_static *Item_false, *Item_true;
class Item_uint :public Item_int
{
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 5f21da17d8b..0d22465af6b 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1065,14 +1065,14 @@ int Arg_comparator::compare_row()
// NULL was compared
switch (((Item_func*)owner)->functype()) {
case Item_func::NE_FUNC:
- break; // NE never aborts on NULL even if abort_on_null is set
+ break; // NE never aborts on NULL
case Item_func::LT_FUNC:
case Item_func::LE_FUNC:
case Item_func::GT_FUNC:
case Item_func::GE_FUNC:
return -1; // <, <=, > and >= always fail on NULL
case Item_func::EQ_FUNC:
- if (((Item_func_eq*)owner)->abort_on_null)
+ if (owner->is_top_level_item())
return -1; // We do not need correct NULL returning
break;
default:
@@ -1189,12 +1189,6 @@ longlong Item_func_truth::val_int()
}
-bool Item_in_optimizer::is_top_level_item() const
-{
- return args[1]->is_top_level_item();
-}
-
-
void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent,
Item **ref, bool merge)
{
@@ -1379,7 +1373,8 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
}
base_flags|= (item_base_t::FIXED |
- (args[1]->base_flags & item_base_t::MAYBE_NULL));
+ (args[1]->base_flags & (item_base_t::MAYBE_NULL |
+ item_base_t::AT_TOP_LEVEL)));
with_flags|= (item_with_t::SUBQUERY |
args[1]->with_flags |
(args[0]->with_flags &
@@ -2065,7 +2060,7 @@ bool Item_func_between::eval_not_null_tables(void *opt_arg)
return 1;
/* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */
- if (pred_level && !negated)
+ if (is_top_level_item() && !negated)
return 0;
/* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */
@@ -2467,6 +2462,10 @@ bool
Item_func_if::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed() == 0);
+ /*
+ Mark that we don't care if args[0] is NULL or FALSE, we regard both cases as
+ false.
+ */
args[0]->top_level_item();
if (Item_func::fix_fields(thd, ref))
@@ -4342,7 +4341,7 @@ Item_func_in::eval_not_null_tables(void *opt_arg)
return 1;
/* not_null_tables_cache == union(T1(e),union(T1(ei))) */
- if (pred_level && negated)
+ if (is_top_level_item() && negated)
return 0;
/* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */
@@ -4796,9 +4795,10 @@ bool Item_func_bit_and::fix_length_and_dec()
Item_cond::Item_cond(THD *thd, Item_cond *item)
:Item_bool_func(thd, item),
- abort_on_null(item->abort_on_null),
and_tables_cache(item->and_tables_cache)
{
+ base_flags|= (item->base_flags & item_base_t::AT_TOP_LEVEL);
+
/*
item->list will be copied by copy_andor_arguments() call
*/
@@ -4806,7 +4806,7 @@ Item_cond::Item_cond(THD *thd, Item_cond *item)
Item_cond::Item_cond(THD *thd, Item *i1, Item *i2):
- Item_bool_func(thd), abort_on_null(0)
+ Item_bool_func(thd)
{
list.push_back(i1, thd->mem_root);
list.push_back(i2, thd->mem_root);
@@ -4874,7 +4874,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
((Item_cond*) item)->list.empty();
item= *li.ref(); // new current item
}
- if (abort_on_null)
+ if (is_top_level_item())
item->top_level_item();
/*
@@ -4901,7 +4901,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
if (item->can_eval_in_optimize() && !item->with_sp_var() &&
!cond_has_datetime_is_null(item))
{
- if (item->eval_const_cond() == is_and_cond && top_level())
+ if (item->eval_const_cond() == is_and_cond && is_top_level_item())
{
/*
a. This is "... AND true_cond AND ..."
@@ -4958,7 +4958,7 @@ Item_cond::eval_not_null_tables(void *opt_arg)
if (item->can_eval_in_optimize() && !item->with_sp_var() &&
!cond_has_datetime_is_null(item))
{
- if (item->eval_const_cond() == is_and_cond && top_level())
+ if (item->eval_const_cond() == is_and_cond && is_top_level_item())
{
/*
a. This is "... AND true_cond AND ..."
@@ -5393,17 +5393,18 @@ void Item_cond_and::mark_as_condition_AND_part(TABLE_LIST *embedding)
Evaluation of AND(expr, expr, expr ...).
@note
- abort_if_null is set for AND expressions for which we don't care if the
- result is NULL or 0. This is set for:
+ There are AND expressions for which we don't care if the
+ result is NULL or 0. This is the case for:
- WHERE clause
- HAVING clause
- IF(expression)
+ For these we mark them as "top_level_items"
@retval
1 If all expressions are true
@retval
- 0 If all expressions are false or if we find a NULL expression and
- 'abort_on_null' is set.
+ 0 If any of the expressions are false or if we find a NULL expression and
+ this is a top_level_item.
@retval
NULL if all expression are either 1 or NULL
*/
@@ -5419,8 +5420,8 @@ longlong Item_cond_and::val_int()
{
if (!item->val_bool())
{
- if (abort_on_null || !(null_value= item->null_value))
- return 0; // return FALSE
+ if (is_top_level_item() || !(null_value= item->null_value))
+ return 0;
}
}
return null_value ? 0 : 1;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index bc7441c2530..3767c2172e8 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -411,7 +411,6 @@ public:
void set_join_tab_idx(uint8 join_tab_idx_arg) override
{ args[1]->set_join_tab_idx(join_tab_idx_arg); }
void get_cache_parameters(List<Item> &parameters) override;
- bool is_top_level_item() const override;
bool eval_not_null_tables(void *opt_arg) override;
bool find_not_null_fields(table_map allowed) override;
void fix_after_pullout(st_select_lex *new_parent, Item **ref,
@@ -631,12 +630,8 @@ public:
class Item_func_not :public Item_bool_func
{
- bool abort_on_null;
public:
- Item_func_not(THD *thd, Item *a):
- Item_bool_func(thd, a), abort_on_null(FALSE) {}
- void top_level_item() override { abort_on_null= 1; }
- bool is_top_level_item() const override { return abort_on_null; }
+ Item_func_not(THD *thd, Item *a): Item_bool_func(thd, a) {}
longlong val_int() override;
enum Functype functype() const override { return NOT_FUNC; }
LEX_CSTRING func_name_cstring() const override
@@ -755,11 +750,10 @@ public:
class Item_func_eq :public Item_bool_rowready_func2
{
- bool abort_on_null;
public:
Item_func_eq(THD *thd, Item *a, Item *b):
Item_bool_rowready_func2(thd, a, b),
- abort_on_null(false), in_equality_no(UINT_MAX)
+ in_equality_no(UINT_MAX)
{}
longlong val_int() override;
enum Functype functype() const override { return EQ_FUNC; }
@@ -770,7 +764,6 @@ public:
static LEX_CSTRING name= {STRING_WITH_LEN("=") };
return name;
}
- void top_level_item() override { abort_on_null= true; }
Item *negated_item(THD *thd) override;
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
@@ -956,15 +949,12 @@ protected:
DTCollation cmp_collation;
public:
bool negated; /* <=> the item represents NOT <func> */
- bool pred_level; /* <=> [NOT] <func> is used on a predicate level */
public:
Item_func_opt_neg(THD *thd, Item *a, Item *b, Item *c):
- Item_bool_func(thd, a, b, c), negated(0), pred_level(0) {}
+ Item_bool_func(thd, a, b, c), negated(0) {}
Item_func_opt_neg(THD *thd, List<Item> &list):
- Item_bool_func(thd, list), negated(0), pred_level(0) {}
+ Item_bool_func(thd, list), negated(0) {}
public:
- void top_level_item() override { pred_level= 1; }
- bool is_top_level_item() const override { return pred_level; }
Item *neg_transformer(THD *thd) override
{
negated= !negated;
@@ -2800,11 +2790,9 @@ public:
class Item_func_isnotnull :public Item_func_null_predicate
{
- bool abort_on_null;
public:
Item_func_isnotnull(THD *thd, Item *a):
- Item_func_null_predicate(thd, a), abort_on_null(0)
- { }
+ Item_func_null_predicate(thd, a) {}
longlong val_int() override;
enum Functype functype() const override { return ISNOTNULL_FUNC; }
LEX_CSTRING func_name_cstring() const override
@@ -2814,10 +2802,9 @@ public:
}
enum precedence precedence() const override { return CMP_PRECEDENCE; }
table_map not_null_tables() const override
- { return abort_on_null ? not_null_tables_cache : 0; }
+ { return is_top_level_item() ? not_null_tables_cache : 0; }
Item *neg_transformer(THD *thd) override;
void print(String *str, enum_query_type query_type) override;
- void top_level_item() override { abort_on_null=1; }
Item *get_copy(THD *thd) override
{ return get_item_copy<Item_func_isnotnull>(thd, this); }
};
@@ -3128,17 +3115,19 @@ class Item_cond :public Item_bool_func
{
protected:
List<Item> list;
- bool abort_on_null;
table_map and_tables_cache;
public:
- /* Item_cond() is only used to create top level items */
- Item_cond(THD *thd): Item_bool_func(thd), abort_on_null(1)
- { const_item_cache=0; }
+ Item_cond(THD *thd): Item_bool_func(thd)
+ {
+ /* Item_cond() is only used to create top level items */
+ top_level_item();
+ const_item_cache=0;
+ }
Item_cond(THD *thd, Item *i1, Item *i2);
Item_cond(THD *thd, Item_cond *item);
Item_cond(THD *thd, List<Item> &nlist):
- Item_bool_func(thd), list(nlist), abort_on_null(0) {}
+ Item_bool_func(thd), list(nlist) {}
bool add(Item *item, MEM_ROOT *root)
{
DBUG_ASSERT(item);
@@ -3185,8 +3174,6 @@ public:
List<Item> &fields, uint flags) override;
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
COND **conds);
- void top_level_item() override { abort_on_null=1; }
- bool top_level() { return abort_on_null; }
void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, bool walk_subquery, void *arg) override;
Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override;
@@ -3542,7 +3529,7 @@ public:
}
enum precedence precedence() const override { return AND_PRECEDENCE; }
table_map not_null_tables() const override
- { return abort_on_null ? not_null_tables_cache: and_tables_cache; }
+ { return is_top_level_item() ? not_null_tables_cache: and_tables_cache; }
Item *copy_andor_structure(THD *thd) override;
Item *neg_transformer(THD *thd) override;
void mark_as_condition_AND_part(TABLE_LIST *embedding) override;
diff --git a/sql/item_create.cc b/sql/item_create.cc
index c80cf7b03d7..1aa7d02e76b 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -902,6 +902,32 @@ protected:
};
+class Create_func_json_normalize : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_json_normalize s_singleton;
+
+protected:
+ Create_func_json_normalize() {}
+ virtual ~Create_func_json_normalize() {}
+};
+
+
+class Create_func_json_equals : public Create_func_arg2
+{
+public:
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
+
+ static Create_func_json_equals s_singleton;
+
+protected:
+ Create_func_json_equals() {}
+ virtual ~Create_func_json_equals() {}
+};
+
+
class Create_func_json_exists : public Create_func_arg2
{
public:
@@ -1596,6 +1622,15 @@ protected:
virtual ~Create_func_name_const() {}
};
+class Create_func_natural_sort_key : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1) override;
+ static Create_func_natural_sort_key s_singleton;
+protected:
+ Create_func_natural_sort_key() {}
+ virtual ~Create_func_natural_sort_key() {}
+};
class Create_func_nullif : public Create_func_arg2
{
@@ -1896,6 +1931,16 @@ protected:
virtual ~Create_func_sec_to_time() {}
};
+class Create_func_sformat : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list);
+ static Create_func_sformat s_singleton;
+protected:
+ Create_func_sformat() {}
+ virtual ~Create_func_sformat() {}
+};
class Create_func_sha : public Create_func_arg1
{
@@ -2235,30 +2280,6 @@ protected:
};
-class Create_func_uuid : public Create_func_arg0
-{
-public:
- virtual Item *create_builder(THD *thd);
-
- static Create_func_uuid s_singleton;
-
-protected:
- Create_func_uuid() {}
- virtual ~Create_func_uuid() {}
-};
-
-class Create_func_sys_guid : public Create_func_arg0
-{
-public:
- virtual Item *create_builder(THD *thd);
-
- static Create_func_sys_guid s_singleton;
-
-protected:
- Create_func_sys_guid() {}
- virtual ~Create_func_sys_guid() {}
-};
-
class Create_func_uuid_short : public Create_func_arg0
{
public:
@@ -3596,6 +3617,25 @@ Create_func_isnull::create_1_arg(THD *thd, Item *arg1)
return new (thd->mem_root) Item_func_isnull(thd, arg1);
}
+Create_func_json_normalize Create_func_json_normalize::s_singleton;
+
+Item*
+Create_func_json_normalize::create_1_arg(THD *thd, Item *arg1)
+{
+ status_var_increment(thd->status_var.feature_json);
+ return new (thd->mem_root) Item_func_json_normalize(thd, arg1);
+}
+
+
+Create_func_json_equals Create_func_json_equals::s_singleton;
+
+Item*
+Create_func_json_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
+{
+ status_var_increment(thd->status_var.feature_json);
+ return new (thd->mem_root) Item_func_json_equals(thd, arg1, arg2);
+}
+
Create_func_json_exists Create_func_json_exists::s_singleton;
@@ -4597,6 +4637,12 @@ Create_func_md5::create_1_arg(THD *thd, Item *arg1)
return new (thd->mem_root) Item_func_md5(thd, arg1);
}
+Create_func_natural_sort_key Create_func_natural_sort_key::s_singleton;
+
+Item *Create_func_natural_sort_key::create_1_arg(THD *thd, Item* arg1)
+{
+ return new (thd->mem_root) Item_func_natural_sort_key(thd, arg1);
+}
Create_func_monthname Create_func_monthname::s_singleton;
@@ -4965,6 +5011,26 @@ Create_func_sec_to_time::create_1_arg(THD *thd, Item *arg1)
return new (thd->mem_root) Item_func_sec_to_time(thd, arg1);
}
+Create_func_sformat Create_func_sformat::s_singleton;
+
+Item*
+Create_func_sformat::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ if (unlikely(arg_count < 1))
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ return NULL;
+ }
+
+ return new (thd->mem_root) Item_func_sformat(thd, *item_list);
+}
+
Create_func_sha Create_func_sha::s_singleton;
@@ -5283,29 +5349,6 @@ Create_func_unix_timestamp::create_native(THD *thd, LEX_CSTRING *name,
}
-Create_func_uuid Create_func_uuid::s_singleton;
-
-Item*
-Create_func_uuid::create_builder(THD *thd)
-{
- DBUG_ENTER("Create_func_uuid::create");
- thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- thd->lex->safe_to_cache_query= 0;
- DBUG_RETURN(new (thd->mem_root) Item_func_uuid(thd, 0));
-}
-
-Create_func_sys_guid Create_func_sys_guid::s_singleton;
-
-Item*
-Create_func_sys_guid::create_builder(THD *thd)
-{
- DBUG_ENTER("Create_func_sys_guid::create");
- thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- thd->lex->safe_to_cache_query= 0;
- DBUG_RETURN(new (thd->mem_root) Item_func_uuid(thd, 1));
-}
-
-
Create_func_uuid_short Create_func_uuid_short::s_singleton;
Item*
@@ -5552,6 +5595,7 @@ Native_func_registry func_array[] =
{ { STRING_WITH_LEN("JSON_CONTAINS_PATH") }, BUILDER(Create_func_json_contains_path)},
{ { STRING_WITH_LEN("JSON_DEPTH") }, BUILDER(Create_func_json_depth)},
{ { STRING_WITH_LEN("JSON_DETAILED") }, BUILDER(Create_func_json_detailed)},
+ { { STRING_WITH_LEN("JSON_EQUALS") }, BUILDER(Create_func_json_equals)},
{ { STRING_WITH_LEN("JSON_EXISTS") }, BUILDER(Create_func_json_exists)},
{ { STRING_WITH_LEN("JSON_EXTRACT") }, BUILDER(Create_func_json_extract)},
{ { STRING_WITH_LEN("JSON_INSERT") }, BUILDER(Create_func_json_insert)},
@@ -5561,6 +5605,7 @@ Native_func_registry func_array[] =
{ { STRING_WITH_LEN("JSON_MERGE") }, BUILDER(Create_func_json_merge)},
{ { STRING_WITH_LEN("JSON_MERGE_PATCH") }, BUILDER(Create_func_json_merge_patch)},
{ { STRING_WITH_LEN("JSON_MERGE_PRESERVE") }, BUILDER(Create_func_json_merge)},
+ { { STRING_WITH_LEN("JSON_NORMALIZE") }, BUILDER(Create_func_json_normalize)},
{ { STRING_WITH_LEN("JSON_QUERY") }, BUILDER(Create_func_json_query)},
{ { STRING_WITH_LEN("JSON_QUOTE") }, BUILDER(Create_func_json_quote)},
{ { STRING_WITH_LEN("JSON_OBJECT") }, BUILDER(Create_func_json_object)},
@@ -5601,6 +5646,7 @@ Native_func_registry func_array[] =
{ { STRING_WITH_LEN("MD5") }, BUILDER(Create_func_md5)},
{ { STRING_WITH_LEN("MONTHNAME") }, BUILDER(Create_func_monthname)},
{ { STRING_WITH_LEN("NAME_CONST") }, BUILDER(Create_func_name_const)},
+ { {STRING_WITH_LEN("NATURAL_SORT_KEY")}, BUILDER(Create_func_natural_sort_key)},
{ { STRING_WITH_LEN("NVL") }, BUILDER(Create_func_ifnull)},
{ { STRING_WITH_LEN("NVL2") }, BUILDER(Create_func_nvl2)},
{ { STRING_WITH_LEN("NULLIF") }, BUILDER(Create_func_nullif)},
@@ -5630,6 +5676,7 @@ Native_func_registry func_array[] =
{ { STRING_WITH_LEN("RTRIM") }, BUILDER(Create_func_rtrim)},
{ { STRING_WITH_LEN("RTRIM_ORACLE") }, BUILDER(Create_func_rtrim_oracle)},
{ { STRING_WITH_LEN("SEC_TO_TIME") }, BUILDER(Create_func_sec_to_time)},
+ { { STRING_WITH_LEN("SFORMAT") }, BUILDER(Create_func_sformat)},
{ { STRING_WITH_LEN("SHA") }, BUILDER(Create_func_sha)},
{ { STRING_WITH_LEN("SHA1") }, BUILDER(Create_func_sha)},
{ { STRING_WITH_LEN("SHA2") }, BUILDER(Create_func_sha2)},
@@ -5645,7 +5692,6 @@ Native_func_registry func_array[] =
BUILDER(Create_func_substr_oracle)},
{ { STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
{ { STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)},
- { { STRING_WITH_LEN("SYS_GUID") }, BUILDER(Create_func_sys_guid)},
{ { STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)},
{ { STRING_WITH_LEN("TIMEDIFF") }, BUILDER(Create_func_timediff)},
{ { STRING_WITH_LEN("TIME_FORMAT") }, BUILDER(Create_func_time_format)},
@@ -5661,7 +5707,6 @@ Native_func_registry func_array[] =
{ { STRING_WITH_LEN("UNIX_TIMESTAMP") }, BUILDER(Create_func_unix_timestamp)},
{ { STRING_WITH_LEN("UPDATEXML") }, BUILDER(Create_func_xml_update)},
{ { STRING_WITH_LEN("UPPER") }, BUILDER(Create_func_ucase)},
- { { STRING_WITH_LEN("UUID") }, BUILDER(Create_func_uuid)},
{ { STRING_WITH_LEN("UUID_SHORT") }, BUILDER(Create_func_uuid_short)},
{ { STRING_WITH_LEN("VERSION") }, BUILDER(Create_func_version)},
{ { STRING_WITH_LEN("WEEKDAY") }, BUILDER(Create_func_weekday)},
diff --git a/sql/item_func.cc b/sql/item_func.cc
index ed49733d15d..5b8a9f1fbfd 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1004,7 +1004,8 @@ err:
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
ER_THD(thd, ER_WARN_DATA_OUT_OF_RANGE),
- name.str, 1L);
+ name.str,
+ thd->get_stmt_da()->current_row_for_warning());
return dec;
}
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 25f2c54cec0..fefb2a1c662 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -393,6 +393,66 @@ longlong Item_func_json_valid::val_int()
}
+bool Item_func_json_equals::fix_length_and_dec()
+{
+ if (Item_bool_func::fix_length_and_dec())
+ return TRUE;
+ set_maybe_null();
+ return FALSE;
+}
+
+
+longlong Item_func_json_equals::val_int()
+{
+ longlong result= 0;
+
+ String a_tmp, b_tmp;
+
+ String *a= args[0]->val_json(&a_tmp);
+ String *b= args[1]->val_json(&b_tmp);
+
+ DYNAMIC_STRING a_res;
+ if (init_dynamic_string(&a_res, NULL, 0, 0))
+ {
+ null_value= 1;
+ return 1;
+ }
+
+ DYNAMIC_STRING b_res;
+ if (init_dynamic_string(&b_res, NULL, 0, 0))
+ {
+ dynstr_free(&a_res);
+ null_value= 1;
+ return 1;
+ }
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ {
+ null_value= 1;
+ goto end;
+ }
+
+ if (json_normalize(&a_res, a->ptr(), a->length(), a->charset()))
+ {
+ null_value= 1;
+ goto end;
+ }
+
+ if (json_normalize(&b_res, b->ptr(), b->length(), b->charset()))
+ {
+ null_value= 1;
+ goto end;
+ }
+
+ result= strcmp(a_res.str, b_res.str) ? 0 : 1;
+
+end:
+ dynstr_free(&b_res);
+ dynstr_free(&a_res);
+ return result;
+}
+
+
bool Item_func_json_exists::fix_length_and_dec()
{
if (Item_bool_func::fix_length_and_dec())
@@ -986,7 +1046,7 @@ my_decimal *Item_func_json_extract::val_decimal(my_decimal *to)
case JSON_VALUE_ARRAY:
case JSON_VALUE_FALSE:
case JSON_VALUE_NULL:
- case JSON_VALUE_UNINITALIZED:
+ case JSON_VALUE_UNINITIALIZED:
break;
};
}
@@ -3886,3 +3946,48 @@ String* Item_func_json_objectagg::val_str(String* str)
}
+String *Item_func_json_normalize::val_str(String *buf)
+{
+ String tmp;
+ String *raw_json= args[0]->val_str(&tmp);
+
+ DYNAMIC_STRING normalized_json;
+ if (init_dynamic_string(&normalized_json, NULL, 0, 0))
+ {
+ null_value= 1;
+ return NULL;
+ }
+
+ null_value= args[0]->null_value;
+ if (null_value)
+ goto end;
+
+ if (json_normalize(&normalized_json,
+ raw_json->ptr(), raw_json->length(),
+ raw_json->charset()))
+ {
+ null_value= 1;
+ goto end;
+ }
+
+ buf->length(0);
+ if (buf->append(normalized_json.str, normalized_json.length))
+ {
+ null_value= 1;
+ goto end;
+ }
+
+end:
+ dynstr_free(&normalized_json);
+ return null_value ? NULL : buf;
+}
+
+
+bool Item_func_json_normalize::fix_length_and_dec()
+{
+ collation.set(&my_charset_utf8mb4_bin);
+ /* 0 becomes 0.0E0, thus one character becomes 5 chars */
+ fix_char_length_ulonglong((ulonglong) args[0]->max_char_length() * 5);
+ set_maybe_null();
+ return FALSE;
+}
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
index 60600108320..e87b971269b 100644
--- a/sql/item_jsonfunc.h
+++ b/sql/item_jsonfunc.h
@@ -107,6 +107,23 @@ public:
};
+class Item_func_json_equals: public Item_bool_func
+{
+public:
+ Item_func_json_equals(THD *thd, Item *a, Item *b):
+ Item_bool_func(thd, a, b) {}
+ LEX_CSTRING func_name_cstring() const override
+ {
+ static LEX_CSTRING name= {STRING_WITH_LEN("json_equals") };
+ return name;
+ }
+ bool fix_length_and_dec() override;
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_func_json_equals>(thd, this); }
+ longlong val_int() override;
+};
+
+
class Item_func_json_exists: public Item_bool_func
{
protected:
@@ -443,6 +460,24 @@ public:
{ return get_item_copy<Item_func_json_merge_patch>(thd, this); }
};
+
+class Item_func_json_normalize: public Item_json_func
+{
+public:
+ Item_func_json_normalize(THD *thd, Item *a):
+ Item_json_func(thd, a) {}
+ String *val_str(String *) override;
+ LEX_CSTRING func_name_cstring() const override
+ {
+ static LEX_CSTRING name= {STRING_WITH_LEN("json_normalize") };
+ return name;
+ }
+ bool fix_length_and_dec() override;
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_func_json_normalize>(thd, this); }
+};
+
+
class Item_func_json_length: public Item_long_func
{
bool check_arguments() const override
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index eb9c59d31f7..d4bf28a9c21 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -55,6 +55,11 @@ C_MODE_END
#include <sql_repl.h>
#include "sql_statistics.h"
+/* fmtlib include (https://fmt.dev/). */
+#define FMT_STATIC_THOUSANDS_SEPARATOR ','
+#define FMT_HEADER_ONLY 1
+#include "fmt/format-inl.h"
+
size_t username_char_length= USERNAME_CHAR_LENGTH;
/*
@@ -1303,6 +1308,138 @@ bool Item_func_replace::fix_length_and_dec()
return FALSE;
}
+/*
+ this is done in the constructor to be in the same memroot as
+ the item itself
+*/
+Item_func_sformat::Item_func_sformat(THD *thd, List<Item> &list)
+ : Item_str_func(thd, list)
+{
+ val_arg= new (thd->mem_root) String[arg_count];
+}
+
+
+bool Item_func_sformat::fix_length_and_dec()
+{
+ if (!val_arg)
+ return TRUE;
+
+ ulonglong char_length= 0;
+
+ uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
+ MY_COLL_ALLOW_COERCIBLE_CONV |
+ MY_COLL_ALLOW_NUMERIC_CONV;
+
+ if (Type_std_attributes::agg_item_collations(collation, func_name_cstring(),
+ args, arg_count, flags, 1))
+ return TRUE;
+
+ DTCollation c= collation;
+ if (c.collation->mbminlen > 1)
+ c.collation= &my_charset_utf8mb4_bin;
+
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ char_length+= args[i]->max_char_length();
+ if (args[i]->result_type() == STRING_RESULT &&
+ Type_std_attributes::agg_item_set_converter(c, func_name_cstring(),
+ args+i, 1, flags, 1))
+ return TRUE;
+ }
+
+ fix_char_length_ulonglong(char_length);
+ return FALSE;
+}
+
+/*
+ allow fmt to take String arguments directly.
+ Inherit from string_view, so all string formatting works.
+ but {:p} doesn't, because it's not char*, not a pointer.
+*/
+namespace fmt {
+ template <> struct formatter<String>: formatter<string_view> {
+ template <typename FormatContext>
+ auto format(String c, FormatContext& ctx) -> decltype(ctx.out()) {
+ string_view name = { c.ptr(), c.length() };
+ return formatter<string_view>::format(name, ctx);
+ };
+ };
+};
+
+/*
+ SFORMAT(format_string, ...)
+ This function receives a formatting specification string and N parameters
+ (N >= 0), and it returns string formatted using the rules the user passed
+ in the specification. It uses fmtlib (https://fmt.dev/).
+*/
+String *Item_func_sformat::val_str(String *res)
+{
+ DBUG_ASSERT(fixed());
+ using ctx= fmt::format_context;
+ String *fmt_arg= NULL;
+ String *parg= NULL;
+ fmt::format_args::format_arg *vargs= NULL;
+
+ null_value= true;
+ if (!(fmt_arg= args[0]->val_str(res)))
+ return NULL;
+
+ if (!(vargs= new fmt::format_args::format_arg[arg_count - 1]))
+ return NULL;
+
+ /* Creates the array of arguments for vformat */
+ for (uint carg= 1; carg < arg_count; carg++)
+ {
+ switch (args[carg]->result_type())
+ {
+ case INT_RESULT:
+ vargs[carg-1]= fmt::detail::make_arg<ctx>(args[carg]->val_int());
+ break;
+ case DECIMAL_RESULT: // TODO
+ case REAL_RESULT:
+ if (args[carg]->field_type() == MYSQL_TYPE_FLOAT)
+ vargs[carg-1]= fmt::detail::make_arg<ctx>((float)args[carg]->val_real());
+ else
+ vargs[carg-1]= fmt::detail::make_arg<ctx>(args[carg]->val_real());
+ break;
+ case STRING_RESULT:
+ if (!(parg= args[carg]->val_str(&val_arg[carg-1])))
+ {
+ delete [] vargs;
+ return NULL;
+ }
+ vargs[carg-1]= fmt::detail::make_arg<ctx>(*parg);
+ break;
+ case TIME_RESULT: // TODO
+ case ROW_RESULT: // TODO
+ default:
+ DBUG_ASSERT(0);
+ delete [] vargs;
+ return NULL;
+ }
+ }
+
+ null_value= false;
+ /* Create the string output */
+ try
+ {
+ auto text = fmt::vformat(fmt_arg->c_ptr_safe(),
+ fmt::format_args(vargs, arg_count-1));
+ res->length(0);
+ res->set_charset(collation.collation);
+ res->append(text.c_str(), text.size(), fmt_arg->charset());
+ }
+ catch (const fmt::format_error &ex)
+ {
+ THD *thd= current_thd;
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ WARN_SFORMAT_ERROR,
+ ER_THD(thd, WARN_SFORMAT_ERROR), ex.what());
+ null_value= true;
+ }
+ delete [] vargs;
+ return null_value ? NULL : res;
+}
/*********************************************************************/
bool Item_func_regexp_replace::fix_length_and_dec()
@@ -4379,26 +4516,6 @@ err:
#endif
-String *Item_func_uuid::val_str(String *str)
-{
- DBUG_ASSERT(fixed());
- uchar guid[MY_UUID_SIZE];
- size_t length= (without_separators ?
- MY_UUID_ORACLE_STRING_LENGTH :
- MY_UUID_STRING_LENGTH);
-
- str->alloc(length+1);
- str->length(length);
- str->set_charset(system_charset_info);
- my_uuid(guid);
- if (without_separators)
- my_uuid2str_oracle(guid, (char *)str->ptr());
- else
- my_uuid2str(guid, (char *)str->ptr());
- return str;
-}
-
-
Item_func_dyncol_create::Item_func_dyncol_create(THD *thd, List<Item> &args,
DYNCALL_CREATE_DEF *dfs):
Item_str_func(thd, args), defs(dfs), vals(0), keys_num(NULL), keys_str(NULL),
@@ -5304,6 +5421,282 @@ String *Item_temptable_rowid::val_str(String *str)
return &str_value;
}
+/**
+ Helper routine to encode length prefix
+ in natsort_encode_numeric_string().
+
+ The idea is so that bigger input numbers correspond
+ lexicographically bigger output strings.
+
+ Note, that in real use the number would typically
+ small, as it only computes variable *length prefixes*.
+
+ @param[in] n - the number
+ @param[in] s - output string
+
+ @return - length of encoding
+
+ Here is how encoding works
+
+ - n is from 0 to 8
+ Output string calculated as '0'+n (range '0' - '8')
+
+ - n is from 9 to 17
+ Output calculated as concat('9', '0' + n -9)'
+ Output range: '90'-'98'
+
+ -n is from 18 to 26
+ Output calculated as concat('99', '0' + n -18)'
+ Output range '990'-'998'
+
+ - n is from 27 to SIZE_T_MAX
+ Output starts with '999',
+ then log10(n) is encoded as 2-digit decimal number
+ then the number itself is added.
+ Example : for 28 key is concat('999', '01' , '28')
+ i.e '9990128'
+
+ Key length is 5 + ceil(log10(n))
+
+ Output range is
+ (64bit)'9990128' - '9991918446744073709551615'
+ (32bit)'9990128' - '999094294967295'
+*/
+
+/* Largest length of encoded string.*/
+static size_t natsort_encode_length_max(size_t n)
+{
+ return (n < 27) ? n/9+1 : 26;
+}
+
+static void natsort_encode_length(size_t n, String* out)
+{
+ if (n < 27)
+ {
+ if (n >= 9)
+ out->fill(out->length() + n/9,'9');
+ out->append(char(n % 9 + '0'));
+ return;
+ }
+
+ size_t log10n= 0;
+ for (size_t tmp= n / 10; tmp; tmp/= 10)
+ log10n++;
+ out->fill(out->length() + 3, '9');
+ out->append('0' + (char) (log10n / 10));
+ out->append('0' + (char) (log10n % 10));
+ out->append_ulonglong(n);
+}
+
+enum class NATSORT_ERR
+{
+ SUCCESS= 0,
+ KEY_TOO_LARGE= 1,
+ ALLOC_ERROR= 2
+};
+
+/*
+ Encode numeric string for natural sorting.
+
+ @param[in] in - start of the numeric string
+ skipping leading zeros
+
+ @param[in] n_digits - length of the string,
+ in characters, not counting leading zeros.
+
+ @param[out] out - String to write to. The string should
+ have enough preallocated space to fit the encoded key.
+
+ @return
+ NATSORT_ERR::SUCCESS - success
+ NATSORT_ERR::KEY_TOO_LARGE - out string does not have enough
+ space left to accomodate the key.
+
+
+ The resulting encoding of the numeric string is then
+
+ CONCAT(natsort_encode_length(n_digits), in)
+*/
+static NATSORT_ERR natsort_encode_numeric_string(const char *in,
+ size_t n_digits,
+ String *out)
+{
+ DBUG_ASSERT(in);
+ DBUG_ASSERT(n_digits);
+
+ if (out->length() + natsort_encode_length_max(n_digits - 1) + n_digits >
+ out->alloced_length())
+ return NATSORT_ERR::KEY_TOO_LARGE;
+
+ natsort_encode_length(n_digits - 1, out);
+ out->append(in, n_digits);
+ return NATSORT_ERR::SUCCESS;
+}
+
+/*
+ Calculate max size of the natsort key.
+
+ A digit in string expands to 2 chars length_prefix , and the digit
+
+ With even length L=2N, the largest key corresponds to input string
+ in form REPEAT(<digit><letter>,N) and the length of a key is
+ 2N + N = 3N
+
+ With odd input length L=2N+1, largest key is built by appending
+ a digit at the end, with key length 3N+2
+
+*/
+static size_t natsort_max_key_size(size_t input_size)
+{
+ return input_size + (input_size + 1)/2 ;
+}
+
+/**
+ Convert a string to natural sort key.
+ @param[in] in - input string
+ @param[out] out - output string
+ @param[in] max_key_size - the maximum size of the output
+ key, in bytes.
+ @return NATSORT_ERR::SUCCESS - successful completion
+ NATSORT_ERR::ALLOC_ERROR - memory allocation error
+ NATSORT_ERR::KEY_TOO_LARGE - resulting key would exceed max_key_size
+*/
+static NATSORT_ERR to_natsort_key(const String *in, String *out,
+ size_t max_key_size)
+{
+ size_t n_digits= 0;
+ size_t n_lead_zeros= 0;
+ size_t num_start;
+ size_t reserve_length= std::min(
+ natsort_max_key_size(in->length()) + MAX_BIGINT_WIDTH + 2, max_key_size);
+
+ out->length(0);
+ out->set_charset(in->charset());
+
+ if (out->alloc((uint32) reserve_length))
+ return NATSORT_ERR::ALLOC_ERROR;
+
+ for (size_t pos= 0;; pos++)
+ {
+ char c= pos < in->length() ? (*in)[pos] : 0;
+ bool is_digit= (c >= '0' && c <= '9');
+ if (!is_digit && (n_digits || n_lead_zeros))
+ {
+ /* Handle end of digits run.*/
+ if (!n_digits)
+ {
+ /*We only have zeros.*/
+ n_lead_zeros--;
+ num_start= pos - 1;
+ n_digits= 1;
+ }
+ NATSORT_ERR err= natsort_encode_numeric_string(
+ in->ptr() + num_start, n_digits, out);
+ if (err != NATSORT_ERR::SUCCESS)
+ return err;
+
+ /* Reset state.*/
+ n_digits= 0;
+ num_start= size_t(-1);
+ n_lead_zeros= 0;
+ }
+
+ if (pos == in->length())
+ break;
+
+ if (!is_digit)
+ {
+ if (out->length() == max_key_size)
+ return NATSORT_ERR::KEY_TOO_LARGE;
+ out->append(c);
+ }
+ else if (c == '0' && !n_digits)
+ n_lead_zeros++;
+ else if (!n_digits++)
+ num_start= pos;
+ }
+ return NATSORT_ERR::SUCCESS;
+}
+
+String *Item_func_natural_sort_key::val_str(String *out)
+{
+ String *in= args[0]->val_str();
+ if (args[0]->null_value || !in)
+ {
+ null_value= true;
+ return nullptr;
+ }
+ NATSORT_ERR err= NATSORT_ERR::SUCCESS;
+ CHARSET_INFO *cs= in->charset();
+ ulong max_allowed_packet= current_thd->variables.max_allowed_packet;
+ uint errs;
+ String tmp;
+ /*
+ to_natsort_key() only support charsets where digits are represented by
+ a single byte in range 0x30-0x39. Almost everything is OK, just utf16/32
+ won't do. Full ASCII compatibility is not required, so that SJIS and SWE7
+ are fine.
+ */
+ if (cs->mbminlen != 1)
+ {
+ if (tmp.copy(in, &my_charset_utf8mb4_bin, &errs))
+ goto error_exit;
+ in= &tmp;
+ }
+
+ err= to_natsort_key(in, out, max_allowed_packet / cs->mbminlen);
+
+ if (err != NATSORT_ERR::SUCCESS)
+ {
+ if (err == NATSORT_ERR::KEY_TOO_LARGE)
+ {
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_ALLOWED_PACKET_OVERFLOWED,
+ ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
+ max_allowed_packet);
+ }
+ goto error_exit;
+ }
+
+ if (cs->mbminlen != 1)
+ {
+ /* output string is now utf8, convert to input charset.*/
+ if (tmp.copy(out, cs, &errs) || out->copy(tmp))
+ goto error_exit;
+ }
+ null_value= false;
+ return out;
+
+error_exit:
+ null_value= true;
+ return nullptr;
+}
+
+bool Item_func_natural_sort_key::fix_length_and_dec(void)
+{
+ if (agg_arg_charsets_for_string_result(collation, args, 1))
+ return true;
+ DBUG_ASSERT(collation.collation != NULL);
+ uint32 max_char_len=
+ (uint32) natsort_max_key_size(args[0]->max_char_length());
+ fix_char_length(max_char_len);
+
+ set_maybe_null(args[0]->maybe_null() ||
+ max_char_len * collation.collation->mbmaxlen >
+ current_thd->variables.max_allowed_packet);
+ return false;
+}
+
+/**
+ Disable use in stored virtual functions. Temporarily(?), until
+ the encoding is stable.
+*/
+bool Item_func_natural_sort_key::check_vcol_func_processor(void *arg)
+{
+ return mark_unsupported_function(func_name(), "()", arg,
+ VCOL_NON_DETERMINISTIC);
+}
+
#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 3384cf5b369..ba61206d8d9 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -271,6 +271,25 @@ public:
{ return get_item_copy<Item_func_aes_decrypt>(thd, this); }
};
+class Item_func_natural_sort_key : public Item_str_func
+{
+public:
+ Item_func_natural_sort_key(THD *thd, Item *a)
+ : Item_str_func(thd, a){};
+ String *val_str(String *) override;
+ LEX_CSTRING func_name_cstring() const override
+ {
+ static LEX_CSTRING name= {STRING_WITH_LEN("natural_sort_key")};
+ return name;
+ }
+ bool fix_length_and_dec(void) override;
+ Item *get_copy(THD *thd) override
+ {
+ return get_item_copy<Item_func_natural_sort_key>(thd, this);
+ }
+
+ bool check_vcol_func_processor(void *arg) override;
+};
class Item_func_concat :public Item_str_func
{
@@ -586,6 +605,23 @@ public:
{ return get_item_copy<Item_func_substr>(thd, this); }
};
+class Item_func_sformat :public Item_str_func
+{
+ String *val_arg;
+public:
+ Item_func_sformat(THD *thd, List<Item> &list);
+ ~Item_func_sformat() { delete [] val_arg; }
+ String *val_str(String*) override;
+ bool fix_length_and_dec() override;
+ LEX_CSTRING func_name_cstring() const override
+ {
+ static LEX_CSTRING name= {STRING_WITH_LEN("sformat") };
+ return name;
+ }
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_func_sformat>(thd, this); }
+};
+
class Item_func_substr_oracle :public Item_func_substr
{
protected:
@@ -1996,40 +2032,6 @@ public:
};
-class Item_func_uuid: public Item_str_func
-{
- /* Set if uuid should be returned without separators (Oracle sys_guid) */
- bool without_separators;
-public:
-Item_func_uuid(THD *thd, bool without_separators_arg): Item_str_func(thd),
- without_separators(without_separators_arg)
- {}
- bool fix_length_and_dec() override
- {
- collation.set(DTCollation_numeric());
- fix_char_length(without_separators ? MY_UUID_ORACLE_STRING_LENGTH :
- MY_UUID_STRING_LENGTH);
- return FALSE;
- }
- bool const_item() const override { return false; }
- table_map used_tables() const override { return RAND_TABLE_BIT; }
- LEX_CSTRING func_name_cstring() const override
- {
- static LEX_CSTRING mariadb_name= {STRING_WITH_LEN("uuid") };
- static LEX_CSTRING oracle_name= {STRING_WITH_LEN("sys_guid") };
- return without_separators ? oracle_name : mariadb_name;
- }
- String *val_str(String *) override;
- bool check_vcol_func_processor(void *arg) override
- {
- return mark_unsupported_function(func_name(), "()", arg,
- VCOL_NON_DETERMINISTIC);
- }
- Item *get_copy(THD *thd) override
- { return get_item_copy<Item_func_uuid>(thd, this); }
-};
-
-
class Item_func_dyncol_create: public Item_str_func
{
protected:
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index bafb81139e1..58680384f55 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1602,7 +1602,7 @@ bool Item_singlerow_subselect::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t
Item_exists_subselect::Item_exists_subselect(THD *thd,
st_select_lex *select_lex):
- Item_subselect(thd), upper_not(NULL), abort_on_null(0),
+ Item_subselect(thd), upper_not(NULL),
emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
{
DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
@@ -1687,7 +1687,6 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
func= func_creator(all_arg);
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
max_columns= 1;
- abort_on_null= 0;
reset();
//if test_limit will fail then error will be reported to client
test_limit(select_lex->master_unit());
@@ -2262,8 +2261,11 @@ bool Item_allany_subselect::is_maxmin_applicable(JOIN *join)
Check if max/min optimization applicable: It is top item of
WHERE condition.
*/
- return (abort_on_null || (upper_item && upper_item->is_top_level_item())) &&
- !(join->select_lex->master_unit()->uncacheable & ~UNCACHEABLE_EXPLAIN) && !func->eqne_op();
+ return ((is_top_level_item() ||
+ (upper_item && upper_item->is_top_level_item())) &&
+ !(join->select_lex->master_unit()->uncacheable &
+ ~UNCACHEABLE_EXPLAIN) &&
+ !func->eqne_op());
}
@@ -2333,7 +2335,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
ref_pointer_array[0],
{STRING_WITH_LEN("<ref>")},
field_name));
- if (!abort_on_null && left_expr->maybe_null())
+ if (!is_top_level_item() && left_expr->maybe_null())
{
/*
We can encounter "NULL IN (SELECT ...)". Wrap the added condition
@@ -2366,7 +2368,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
Item *orig_item= item;
item= func->create(thd, expr, item);
- if (!abort_on_null && orig_item->maybe_null())
+ if (!is_top_level_item() && orig_item->maybe_null())
{
having= new (thd->mem_root) Item_is_not_null_test(thd, this, having);
if (left_expr->maybe_null())
@@ -2388,7 +2390,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
If we may encounter NULL IN (SELECT ...) and care whether subquery
result is NULL or FALSE, wrap condition in a trig_cond.
*/
- if (!abort_on_null && left_expr->maybe_null())
+ if (!is_top_level_item() && left_expr->maybe_null())
{
disable_cond_guard_for_const_null_left_expr(0);
if (!(item= new (thd->mem_root) Item_func_trig_cond(thd, item,
@@ -2418,7 +2420,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
&select_lex->ref_pointer_array[0],
no_matter_name,
field_name));
- if (!abort_on_null && left_expr->maybe_null())
+ if (!is_top_level_item() && left_expr->maybe_null())
{
disable_cond_guard_for_const_null_left_expr(0);
if (!(new_having= new (thd->mem_root)
@@ -2617,7 +2619,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
list_ref));
Item *col_item= new (thd->mem_root)
Item_cond_or(thd, item_eq, item_isnull);
- if (!abort_on_null && left_expr->element_index(i)->maybe_null() &&
+ if (!is_top_level_item() && left_expr->element_index(i)->maybe_null() &&
get_cond_guard(i))
{
disable_cond_guard_for_const_null_left_expr(i);
@@ -2636,7 +2638,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
ref_pointer_array[i],
no_matter_name,
list_ref));
- if (!abort_on_null && left_expr->element_index(i)->maybe_null() &&
+ if (!is_top_level_item() && left_expr->element_index(i)->maybe_null() &&
get_cond_guard(i) )
{
disable_cond_guard_for_const_null_left_expr(i);
@@ -2677,7 +2679,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
ref_pointer_array[i],
no_matter_name,
list_ref));
- if (!abort_on_null && select_lex->ref_pointer_array[i]->maybe_null())
+ if (!is_top_level_item() && select_lex->ref_pointer_array[i]->maybe_null())
{
Item *having_col_item=
new (thd->mem_root)
@@ -2709,7 +2711,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
}
*having_item= and_items(thd, *having_item, having_col_item);
}
- if (!abort_on_null && left_expr->element_index(i)->maybe_null() &&
+ if (!is_top_level_item() && left_expr->element_index(i)->maybe_null() &&
get_cond_guard(i))
{
if (!(item= new (thd->mem_root)
@@ -3678,7 +3680,7 @@ bool Item_in_subselect::init_cond_guards()
{
DBUG_ASSERT(thd);
uint cols_num= left_expr->cols();
- if (!abort_on_null && !pushed_cond_guards &&
+ if (!is_top_level_item() && !pushed_cond_guards &&
(left_expr->maybe_null() || cols_num > 1))
{
if (!(pushed_cond_guards= (bool*)thd->alloc(sizeof(bool) * cols_num)))
@@ -4260,9 +4262,9 @@ bool subselect_uniquesubquery_engine::copy_ref_key(bool skip_constants)
- NULL if select produces empty row set
- FALSE otherwise.
- In some cases (IN subselect is a top level item, i.e. abort_on_null==TRUE)
- the caller doesn't distinguish between NULL and FALSE result and we just
- return FALSE.
+ In some cases (IN subselect is a top level item, i.e.
+ is_top_level_item() == TRUE, the caller doesn't distinguish between NULL and
+ FALSE result and we just return FALSE.
Otherwise we make a full table scan to see if there is at least one
matching row.
@@ -5117,7 +5119,7 @@ my_bitmap_init_memroot(MY_BITMAP *map, uint n_bits, MEM_ROOT *mem_root)
if (!(bitmap_buf= (my_bitmap_map*) alloc_root(mem_root,
bitmap_buffer_size(n_bits))) ||
- my_bitmap_init(map, bitmap_buf, n_bits, FALSE))
+ my_bitmap_init(map, bitmap_buf, n_bits))
return TRUE;
bitmap_clear_all(map);
return FALSE;
@@ -6010,7 +6012,7 @@ bool Ordered_key::alloc_keys_buffers()
lookup offset.
*/
/* Notice that max_null_row is max array index, we need count, so +1. */
- if (my_bitmap_init(&null_key, NULL, (uint)(max_null_row + 1), FALSE))
+ if (my_bitmap_init(&null_key, NULL, (uint)(max_null_row + 1)))
return TRUE;
cur_key_idx= HA_POS_ERROR;
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 426b76f8067..54e4f8f0ced 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -373,7 +373,6 @@ class Item_exists_subselect :public Item_subselect
protected:
Item_func_not *upper_not;
bool value; /* value of this item (boolean: exists/not-exists) */
- bool abort_on_null;
void init_length_and_dec();
bool select_prepare_to_be_in();
@@ -397,7 +396,7 @@ public:
Item_exists_subselect(THD *thd_arg, st_select_lex *select_lex);
Item_exists_subselect(THD *thd_arg):
- Item_subselect(thd_arg), upper_not(NULL), abort_on_null(0),
+ Item_subselect(thd_arg), upper_not(NULL),
emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
{}
@@ -424,8 +423,6 @@ public:
bool fix_length_and_dec() override;
void print(String *str, enum_query_type query_type) override;
bool select_transformer(JOIN *join) override;
- void top_level_item() override { abort_on_null=1; }
- bool is_top_level_item() const override { return abort_on_null; }
bool exists2in_processor(void *opt_arg) override;
Item* expr_cache_insert_transformer(THD *thd, uchar *unused) override;
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 2f4d34afc6d..a130be4f973 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -1232,13 +1232,13 @@ my_xpath_keyword(MY_XPATH *x,
static Item *create_func_true(MY_XPATH *xpath, Item **args, uint nargs)
{
- return (Item*) &Item_true;
+ return (Item*) Item_true;
}
static Item *create_func_false(MY_XPATH *xpath, Item **args, uint nargs)
{
- return (Item*) &Item_false;
+ return (Item*) Item_false;
}
diff --git a/sql/json_table.cc b/sql/json_table.cc
index aebc52b0832..e57dccd00c4 100644
--- a/sql/json_table.cc
+++ b/sql/json_table.cc
@@ -835,8 +835,7 @@ TABLE *create_table_for_function(THD *thd, TABLE_LIST *sql_table)
my_bitmap_map* bitmaps=
(my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
- my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
- FALSE);
+ my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count);
table->read_set= &table->def_read_set;
bitmap_clear_all(table->read_set);
table->alias_name_used= true;
diff --git a/sql/lex.h b/sql/lex.h
index cbf9d9d51b2..4ce88ccc2ee 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -110,6 +110,7 @@ SYMBOL symbols[] = {
{ "CHAIN", SYM(CHAIN_SYM)},
{ "CHANGE", SYM(CHANGE)},
{ "CHANGED", SYM(CHANGED)},
+ { "CHANNEL", SYM(CHANNEL_SYM)},
{ "CHAR", SYM(CHAR_SYM)},
{ "CHARACTER", SYM(CHAR_SYM)},
{ "CHARSET", SYM(CHARSET)},
@@ -567,6 +568,8 @@ SYMBOL symbols[] = {
{ "ROWTYPE", SYM(ROWTYPE_MARIADB_SYM)},
{ "ROW_COUNT", SYM(ROW_COUNT_SYM)},
{ "ROW_FORMAT", SYM(ROW_FORMAT_SYM)},
+ /** sql_function and condition_property_name for GET DIAGNOSTICS */
+ { "ROW_NUMBER", SYM(ROW_NUMBER_SYM)},
{ "RTREE", SYM(RTREE_SYM)},
{ "SAVEPOINT", SYM(SAVEPOINT_SYM)},
{ "SCHEDULE", SYM(SCHEDULE_SYM)},
@@ -781,7 +784,6 @@ SYMBOL sql_functions[] = {
{ "PERCENTILE_CONT", SYM(PERCENTILE_CONT_SYM)},
{ "PERCENTILE_DISC", SYM(PERCENTILE_DISC_SYM)},
{ "RANK", SYM(RANK_SYM)},
- { "ROW_NUMBER", SYM(ROW_NUMBER_SYM)},
{ "SESSION_USER", SYM(USER_SYM)},
{ "STD", SYM(STD_SYM)},
{ "STDDEV", SYM(STD_SYM)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 9f53ffb3a69..ef8e93cdfcc 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2020, MariaDB
+ Copyright (c) 2020, 2021, 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
@@ -1138,6 +1138,9 @@ void Global_read_lock::unlock_global_read_lock(THD *thd)
else if (WSREP_NNULL(thd) &&
server_state.state() == Wsrep_server_state::s_synced)
{
+ THD_STAGE_INFO(thd, stage_waiting_flow);
+ WSREP_DEBUG("unlock_global_read_lock: waiting for flow control for %s",
+ wsrep_thd_query(thd));
server_state.resume_and_resync();
wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
}
diff --git a/sql/log.cc b/sql/log.cc
index 1714c70f557..da7b2dbda71 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2622,12 +2622,11 @@ static void setup_windows_event_source()
static int find_uniq_filename(char *name, ulong min_log_number_to_use,
ulong *last_used_log_number)
{
- uint i;
char buff[FN_REFLEN], ext_buf[FN_REFLEN];
struct st_my_dir *dir_info;
struct fileinfo *file_info;
ulong max_found= 0, next= 0, number= 0;
- size_t buf_length, length;
+ size_t i, buf_length, length;
char *start, *end;
int error= 0;
DBUG_ENTER("find_uniq_filename");
@@ -2958,7 +2957,7 @@ int MYSQL_BIN_LOG::generate_new_name(char *new_name, const char *log_name,
fn_format(new_name, log_name, mysql_data_home, "", 4);
if (!fn_ext(log_name)[0])
{
- if (DBUG_EVALUATE_IF("binlog_inject_new_name_error", TRUE, FALSE) ||
+ if (DBUG_IF("binlog_inject_new_name_error") ||
unlikely(find_uniq_filename(new_name, next_log_number,
&last_used_log_number)))
{
@@ -3528,7 +3527,7 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
0, MYF(MY_WME | MY_WAIT_IF_FULL),
m_key_file_log_index_cache) ||
- DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
+ DBUG_IF("fault_injection_openning_index"))
{
/*
TODO: all operations creating/deleting the index file or a log, should
@@ -3554,7 +3553,7 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
open_purge_index_file(FALSE) ||
purge_index_entry(NULL, NULL, need_mutex) ||
close_purge_index_file() ||
- DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0))
+ DBUG_IF("fault_injection_recovering_index"))
{
sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
"file.");
@@ -3622,7 +3621,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (open_purge_index_file(TRUE) ||
register_create_index_entry(log_file_name) ||
sync_purge_index_file() ||
- DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
+ DBUG_IF("fault_injection_registering_index"))
{
/**
TODO:
@@ -3903,7 +3902,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
As this is a new log file, we write the file name to the index
file. As every time we write to the index file, we sync it.
*/
- if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
+ if (DBUG_IF("fault_injection_updating_index") ||
my_b_write(&index_file, (uchar*) log_file_name,
strlen(log_file_name)) ||
my_b_write(&index_file, (uchar*) "\n", 1) ||
@@ -5316,8 +5315,8 @@ int MYSQL_BIN_LOG::new_file_impl()
r.checksum_alg= relay_log_checksum_alg;
DBUG_ASSERT(!is_relay_log ||
relay_log_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
- if (DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event",
- (error= close_on_error= TRUE), FALSE) ||
+ if ((DBUG_IF("fault_injection_new_file_rotate_event") &&
+ (error= close_on_error= TRUE)) ||
(error= write_event(&r)))
{
DBUG_EXECUTE_IF("fault_injection_new_file_rotate_event", errno= 2;);
@@ -6710,7 +6709,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
Write the event.
*/
if (write_event(event_info, cache_data, file) ||
- DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
+ DBUG_IF("injecting_fault_writing"))
goto err;
error= 0;
@@ -8467,7 +8466,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
DEBUG_SYNC(leader->thd, "commit_loop_entry_commit_ordered");
++num_commits;
if (current->cache_mngr->using_xa && likely(!current->error) &&
- DBUG_EVALUATE_IF("skip_commit_ordered", 0, 1))
+ !DBUG_IF("skip_commit_ordered"))
run_commit_ordered(current->thd, current->all);
current->thd->wakeup_subsequent_commits(current->error);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index b0d47ff496b..afca79b008a 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -3321,8 +3321,7 @@ Rows_log_event::Rows_log_event(const uchar *buf, uint event_len,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
- m_width,
- false)))
+ m_width)))
{
DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
memcpy(m_cols.bitmap, ptr_after_width, (m_width + 7) / 8);
@@ -3346,8 +3345,7 @@ Rows_log_event::Rows_log_event(const uchar *buf, uint event_len,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols_ai,
m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
- m_width,
- false)))
+ m_width)))
{
DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
memcpy(m_cols_ai.bitmap, ptr_after_width, (m_width + 7) / 8);
diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc
index 067bfb7c54b..7e0bf7d8e4c 100644
--- a/sql/log_event_client.cc
+++ b/sql/log_event_client.cc
@@ -1184,7 +1184,7 @@ void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_inf
}
/* Copying rows from the end to the begining into event */
- for (uint i= rows_arr.elements; i > 0; --i)
+ for (size_t i= rows_arr.elements; i > 0; --i)
{
LEX_STRING *one_row= dynamic_element(&rows_arr, i - 1, LEX_STRING*);
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 4e6b9e3f1c8..1990103598e 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1156,8 +1156,7 @@ Old_rows_log_event::Old_rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
- m_width,
- false)))
+ m_width)))
{
/* Cols can be zero if this is a dummy binrows event */
if (likely(cols != NULL))
@@ -1232,8 +1231,7 @@ Old_rows_log_event::Old_rows_log_event(const uchar *buf, uint event_len,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
- m_width,
- false)))
+ m_width)))
{
DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
memcpy(m_cols.bitmap, ptr_after_width, (m_width + 7) / 8);
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
index ab9366bd651..cc103751b13 100644
--- a/sql/log_event_server.cc
+++ b/sql/log_event_server.cc
@@ -470,7 +470,7 @@ static void cleanup_load_tmpdir(LEX_CSTRING *connection_name)
{
MY_DIR *dirp;
FILEINFO *file;
- uint i;
+ size_t i;
char dir[FN_REFLEN], fname[FN_REFLEN];
char prefbuf[31 + MAX_CONNECTION_NAME* MAX_FILENAME_MBWIDTH + 1];
DBUG_ENTER("cleanup_load_tmpdir");
@@ -491,7 +491,7 @@ static void cleanup_load_tmpdir(LEX_CSTRING *connection_name)
load_data_tmp_prefix(prefbuf, connection_name);
DBUG_PRINT("enter", ("dir: '%s' prefix: '%s'", dir, prefbuf));
- for (i=0 ; i < (uint)dirp->number_of_files; i++)
+ for (i=0 ; i < dirp->number_of_files; i++)
{
file=dirp->dir_entry+i;
if (is_prefix(file->name, prefbuf))
@@ -5226,8 +5226,7 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
- m_width,
- false)))
+ m_width)))
{
/* Cols can be zero if this is a dummy binrows event */
if (likely(cols != NULL))
@@ -6457,7 +6456,7 @@ int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
LEX_CSTRING tmp_tbl_name= {tname_mem, tname_mem_length };
table_list->init_one_table(&tmp_db_name, &tmp_tbl_name, 0, TL_WRITE);
- table_list->table_id= DBUG_EVALUATE_IF("inject_tblmap_same_id_maps_diff_table", 0, m_table_id);
+ table_list->table_id= DBUG_IF("inject_tblmap_same_id_maps_diff_table") ? 0 : m_table_id;
table_list->updating= 1;
table_list->required_type= TABLE_TYPE_NORMAL;
@@ -6697,7 +6696,7 @@ void Table_map_log_event::init_metadata_fields()
if (binlog_row_metadata == BINLOG_ROW_METADATA_FULL)
{
- if (DBUG_EVALUATE_IF("dont_log_column_name", 0, init_column_name_field()) ||
+ if ((!DBUG_IF("dont_log_column_name") && init_column_name_field()) ||
init_charset_field(&is_enum_or_set_field, ENUM_AND_SET_DEFAULT_CHARSET,
ENUM_AND_SET_COLUMN_CHARSET) ||
init_set_str_value_field() ||
@@ -8279,8 +8278,7 @@ void Update_rows_log_event::init(MY_BITMAP const *cols)
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols_ai,
m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
- m_width,
- false)))
+ m_width)))
{
/* Cols can be zero if this is a dummy binrows event */
if (likely(cols != NULL))
diff --git a/sql/mdl.cc b/sql/mdl.cc
index bd5d6aa7db3..c2475bb3b91 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2007, 2012, Oracle and/or its affiliates.
- Copyright (c) 2020, MariaDB
+ Copyright (c) 2020, 2021, 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
@@ -2304,6 +2304,20 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout)
DBUG_RETURN(TRUE);
}
+#ifdef WITH_WSREP
+ if (WSREP(get_thd()))
+ {
+ THD* requester= get_thd();
+ bool requester_toi= wsrep_thd_is_toi(requester) || wsrep_thd_is_applying(requester);
+ WSREP_DEBUG("::acquire_lock is TOI %d for %s", requester_toi,
+ wsrep_thd_query(requester));
+ if (requester_toi)
+ THD_STAGE_INFO(requester, stage_waiting_ddl);
+ else
+ THD_STAGE_INFO(requester, stage_waiting_isolation);
+ }
+#endif /* WITH_WSREP */
+
lock->m_waiting.add_ticket(ticket);
/*
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 0bfb2f3640d..e7e5af8a2c8 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -369,6 +369,7 @@ uint volatile global_disable_checkpoint;
ulong slow_start_timeout;
#endif
static MEM_ROOT startup_root;
+MEM_ROOT read_only_root;
/**
@brief 'grant_option' is used to indicate if privileges needs
@@ -641,7 +642,23 @@ struct system_variables max_system_variables;
struct system_status_var global_status_var;
MY_TMPDIR mysql_tmpdir_list;
-MY_BITMAP temp_pool;
+static MY_BITMAP temp_pool;
+static mysql_mutex_t LOCK_temp_pool;
+
+void temp_pool_clear_bit(uint bit)
+{
+ mysql_mutex_lock(&LOCK_temp_pool);
+ bitmap_clear_bit(&temp_pool, bit);
+ mysql_mutex_unlock(&LOCK_temp_pool);
+}
+
+uint temp_pool_set_next()
+{
+ mysql_mutex_lock(&LOCK_temp_pool);
+ uint res= bitmap_set_next(&temp_pool);
+ mysql_mutex_unlock(&LOCK_temp_pool);
+ return res;
+}
CHARSET_INFO *system_charset_info, *files_charset_info ;
CHARSET_INFO *national_charset_info, *table_alias_charset;
@@ -888,7 +905,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_manager, key_LOCK_backup_log,
key_LOCK_prepared_stmt_count,
key_LOCK_rpl_status, key_LOCK_server_started,
- key_LOCK_status,
+ key_LOCK_status, key_LOCK_temp_pool,
key_LOCK_system_variables_hash, key_LOCK_thd_data, key_LOCK_thd_kill,
key_LOCK_user_conn, key_LOCK_uuid_short_generator, key_LOG_LOCK_log,
key_master_info_data_lock, key_master_info_run_lock,
@@ -946,6 +963,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_hash_filo_lock, "hash_filo::lock", 0},
{ &key_LOCK_active_mi, "LOCK_active_mi", PSI_FLAG_GLOBAL},
{ &key_LOCK_backup_log, "LOCK_backup_log", PSI_FLAG_GLOBAL},
+ { &key_LOCK_temp_pool, "LOCK_temp_pool", PSI_FLAG_GLOBAL},
{ &key_LOCK_thread_id, "LOCK_thread_id", PSI_FLAG_GLOBAL},
{ &key_LOCK_crypt, "LOCK_crypt", PSI_FLAG_GLOBAL},
{ &key_LOCK_delayed_create, "LOCK_delayed_create", PSI_FLAG_GLOBAL},
@@ -1510,6 +1528,16 @@ static void end_ssl();
#ifndef EMBEDDED_LIBRARY
+extern Atomic_counter<uint32_t> local_connection_thread_count;
+
+uint THD_count::connection_thd_count()
+{
+ return value() -
+ binlog_dump_thread_count -
+ local_connection_thread_count;
+}
+
+
/****************************************************************************
** Code to end mysqld
****************************************************************************/
@@ -1533,7 +1561,7 @@ static my_bool kill_thread_phase_1(THD *thd, void *)
if (thd->slave_thread || thd->is_binlog_dump_thread())
return 0;
- if (DBUG_EVALUATE_IF("only_kill_system_threads", !thd->system_thread, 0))
+ if (DBUG_IF("only_kill_system_threads") ? !thd->system_thread : 0)
return 0;
thd->awake(KILL_SERVER_HARD);
return 0;
@@ -1741,7 +1769,7 @@ static void close_connections(void)
*/
DBUG_PRINT("info", ("THD_count: %u", THD_count::value()));
- for (int i= 0; (THD_count::value() - binlog_dump_thread_count) && i < 1000; i++)
+ for (int i= 0; (THD_count::connection_thd_count()) && i < 1000; i++)
my_sleep(20000);
if (global_system_variables.log_warnings)
@@ -1756,12 +1784,12 @@ static void close_connections(void)
/* All threads has now been aborted */
DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)", THD_count::value()));
- while (THD_count::value() - binlog_dump_thread_count)
+ while (THD_count::connection_thd_count())
my_sleep(1000);
/* Kill phase 2 */
server_threads.iterate(kill_thread_phase_2);
- for (uint64 i= 0; THD_count::value(); i++)
+ for (uint64 i= 0; THD_count::value() > local_connection_thread_count; i++)
{
/*
This time the warnings are emitted within the loop to provide a
@@ -1973,6 +2001,8 @@ static void clean_up(bool print_message)
mysql_library_end();
finish_client_errs();
free_root(&startup_root, MYF(0));
+ protect_root(&read_only_root, PROT_READ | PROT_WRITE);
+ free_root(&read_only_root, MYF(0));
cleanup_errmsgs();
free_error_messages();
/* Tell main we are ready */
@@ -2052,6 +2082,7 @@ static void clean_up_mutexes()
mysql_mutex_destroy(&LOCK_active_mi);
mysql_rwlock_destroy(&LOCK_ssl_refresh);
mysql_mutex_destroy(&LOCK_backup_log);
+ mysql_mutex_destroy(&LOCK_temp_pool);
mysql_rwlock_destroy(&LOCK_sys_init_connect);
mysql_rwlock_destroy(&LOCK_sys_init_slave);
mysql_mutex_destroy(&LOCK_global_system_variables);
@@ -3240,7 +3271,7 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
{
if (unlikely(MyFlags & ME_FATAL))
thd->is_fatal_error= 1;
- (void) thd->raise_condition(error, NULL, level, str);
+ (void) thd->raise_condition(error, "\0\0\0\0\0", level, str);
}
else
mysql_audit_general(0, MYSQL_AUDIT_GENERAL_ERROR, error, str);
@@ -3354,7 +3385,6 @@ SHOW_VAR com_status_vars[]= {
{"alter_server", STMT_STATUS(SQLCOM_ALTER_SERVER)},
{"alter_sequence", STMT_STATUS(SQLCOM_ALTER_SEQUENCE)},
{"alter_table", STMT_STATUS(SQLCOM_ALTER_TABLE)},
- {"alter_tablespace", STMT_STATUS(SQLCOM_ALTER_TABLESPACE)},
{"alter_user", STMT_STATUS(SQLCOM_ALTER_USER)},
{"analyze", STMT_STATUS(SQLCOM_ANALYZE)},
{"assign_to_keycache", STMT_STATUS(SQLCOM_ASSIGN_TO_KEYCACHE)},
@@ -3723,6 +3753,8 @@ static int init_early_variables()
set_malloc_size_cb(my_malloc_size_cb_func);
global_status_var.global_memory_used= 0;
init_alloc_root(PSI_NOT_INSTRUMENTED, &startup_root, 1024, 0, MYF(0));
+ init_alloc_root(PSI_NOT_INSTRUMENTED, &read_only_root, 1024, 0,
+ MYF(MY_ROOT_USE_MPROTECT));
return 0;
}
@@ -4227,7 +4259,7 @@ static int init_common_variables()
#endif /* defined(ENABLED_DEBUG_SYNC) */
#if (ENABLE_TEMP_POOL)
- if (use_temp_pool && my_bitmap_init(&temp_pool,0,1024,1))
+ if (use_temp_pool && my_bitmap_init(&temp_pool,0,1024))
return 1;
#else
use_temp_pool= 0;
@@ -4354,6 +4386,7 @@ static int init_thread_environment()
mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered,
MY_MUTEX_INIT_SLOW);
mysql_mutex_init(key_LOCK_backup_log, &LOCK_backup_log, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_temp_pool, &LOCK_temp_pool, MY_MUTEX_INIT_FAST);
#ifdef HAVE_OPENSSL
mysql_mutex_init(key_LOCK_des_key_file,
@@ -5035,6 +5068,7 @@ static int init_server_components()
init_global_table_stats();
init_global_index_stats();
+ init_update_queries();
/* Allow storage engine to give real error messages */
if (unlikely(ha_init_errors()))
@@ -5042,6 +5076,9 @@ static int init_server_components()
tc_log= 0; // ha_initialize_handlerton() needs that
+ if (!opt_abort && ddl_log_initialize())
+ unireg_abort(1);
+
if (plugin_init(&remaining_argc, remaining_argv,
(opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
(opt_abort ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
@@ -5286,9 +5323,6 @@ static int init_server_components()
}
#endif
- if (ddl_log_initialize())
- unireg_abort(1);
-
tc_log= get_tc_log_implementation();
if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
@@ -5369,12 +5403,15 @@ static int init_server_components()
ft_init_stopwords();
init_max_user_conn();
- init_update_queries();
init_global_user_stats();
init_global_client_stats();
if (!opt_bootstrap)
servers_init(0);
init_status_vars();
+ Item_false= new (&read_only_root) Item_bool_static("FALSE", 0);
+ Item_true= new (&read_only_root) Item_bool_static("TRUE", 1);
+ DBUG_ASSERT(Item_false);
+
DBUG_RETURN(0);
}
@@ -5738,6 +5775,9 @@ int mysqld_main(int argc, char **argv)
}
#endif /* WITH_WSREP */
+ /* Protect read_only_root against writes */
+ protect_root(&read_only_root, PROT_READ);
+
if (opt_bootstrap)
{
select_thread_in_use= 0; // Allow 'kill' to work
@@ -9161,6 +9201,14 @@ PSI_stage_info stage_starting= { 0, "starting", 0};
PSI_stage_info stage_waiting_for_flush= { 0, "Waiting for non trans tables to be flushed", 0};
PSI_stage_info stage_waiting_for_ddl= { 0, "Waiting for DDLs", 0};
+#ifdef WITH_WSREP
+// Aditional Galera thread states
+PSI_stage_info stage_waiting_isolation= { 0, "Waiting to execute in isolation", 0};
+PSI_stage_info stage_waiting_certification= {0, "Waiting for certification", 0};
+PSI_stage_info stage_waiting_ddl= {0, "Waiting for TOI DDL", 0};
+PSI_stage_info stage_waiting_flow= {0, "Waiting for flow control", 0};
+#endif /* WITH_WSREP */
+
PSI_memory_key key_memory_DATE_TIME_FORMAT;
PSI_memory_key key_memory_DDL_LOG_MEMORY_ENTRY;
PSI_memory_key key_memory_Event_queue_element_for_exec_names;
@@ -9380,6 +9428,13 @@ PSI_stage_info *all_server_stages[]=
& stage_reading_semi_sync_ack,
& stage_waiting_for_deadlock_kill,
& stage_starting
+#ifdef WITH_WSREP
+ ,
+ & stage_waiting_isolation,
+ & stage_waiting_certification,
+ & stage_waiting_ddl,
+ & stage_waiting_flow
+#endif /* WITH_WSREP */
};
PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection;
diff --git a/sql/mysqld.h b/sql/mysqld.h
index d0a33fabb51..8c0b92c6446 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2006, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2020, MariaDB Corporation.
+ Copyright (c) 2010, 2021, 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
@@ -100,7 +100,9 @@ extern CHARSET_INFO *error_message_charset_info;
extern CHARSET_INFO *character_set_filesystem;
-extern MY_BITMAP temp_pool;
+void temp_pool_clear_bit(uint bit);
+uint temp_pool_set_next();
+
extern bool opt_large_files;
extern bool opt_update_log, opt_bin_log, opt_error_log, opt_bin_log_compress;
extern uint opt_bin_log_compress_min_len;
@@ -677,6 +679,13 @@ extern PSI_stage_info stage_slave_background_process_request;
extern PSI_stage_info stage_slave_background_wait_request;
extern PSI_stage_info stage_waiting_for_deadlock_kill;
extern PSI_stage_info stage_starting;
+#ifdef WITH_WSREP
+// Aditional Galera thread states
+extern PSI_stage_info stage_waiting_isolation;
+extern PSI_stage_info stage_waiting_certification;
+extern PSI_stage_info stage_waiting_ddl;
+extern PSI_stage_info stage_waiting_flow;
+#endif /* WITH_WSREP */
#ifdef HAVE_PSI_STATEMENT_INTERFACE
/**
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 80944e97eb7..06063cb9ae1 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1308,7 +1308,7 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
*create_error= 1;
}
else
- my_bitmap_init(&column_bitmap, bitmap, head->s->fields, FALSE);
+ my_bitmap_init(&column_bitmap, bitmap, head->s->fields);
DBUG_VOID_RETURN;
}
@@ -2577,7 +2577,7 @@ static int fill_used_fields_bitmap(PARAM *param)
param->fields_bitmap_size= table->s->column_bitmap_size;
if (!(tmp= (my_bitmap_map*) alloc_root(param->mem_root,
param->fields_bitmap_size)) ||
- my_bitmap_init(&param->needed_fields, tmp, table->s->fields, FALSE))
+ my_bitmap_init(&param->needed_fields, tmp, table->s->fields))
return 1;
bitmap_copy(&param->needed_fields, table->read_set);
@@ -3347,7 +3347,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
my_bitmap_map* buf;
if (!(buf= (my_bitmap_map*)thd->alloc(table->s->column_bitmap_size)))
DBUG_RETURN(TRUE);
- my_bitmap_init(&handled_columns, buf, table->s->fields, FALSE);
+ my_bitmap_init(&handled_columns, buf, table->s->fields);
/*
Calculate the selectivity of the range conditions supported by indexes.
@@ -4137,7 +4137,7 @@ static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar,
*/
return find_used_partitions_imerge(ppar, merges.head());
}
- my_bitmap_init(&all_merges, bitmap_buf, n_bits, FALSE);
+ my_bitmap_init(&all_merges, bitmap_buf, n_bits);
bitmap_set_prefix(&all_merges, n_bits);
List_iterator<SEL_IMERGE> it(merges);
@@ -4793,8 +4793,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
uint32 bufsize= bitmap_buffer_size(ppar->part_info->num_subparts);
if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize)))
return TRUE;
- my_bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts,
- FALSE);
+ my_bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts);
}
range_par->key_parts= key_part;
Field **field= (ppar->part_fields)? part_info->part_field_array :
@@ -5621,7 +5620,7 @@ bool create_fields_bitmap(PARAM *param, MY_BITMAP *fields_bitmap)
if (!(bitmap_buf= (my_bitmap_map *) alloc_root(param->mem_root,
param->fields_bitmap_size)))
return TRUE;
- if (my_bitmap_init(fields_bitmap, bitmap_buf, param->table->s->fields, FALSE))
+ if (my_bitmap_init(fields_bitmap, bitmap_buf, param->table->s->fields))
return TRUE;
return FALSE;
@@ -6533,7 +6532,7 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg)
DBUG_RETURN(NULL);
if (my_bitmap_init(&ror_scan->covered_fields, bitmap_buf,
- param->table->s->fields, FALSE))
+ param->table->s->fields))
DBUG_RETURN(NULL);
bitmap_clear_all(&ror_scan->covered_fields);
@@ -6650,8 +6649,7 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param)
if (!(buf= (my_bitmap_map*) alloc_root(param->mem_root,
param->fields_bitmap_size)))
return NULL;
- if (my_bitmap_init(&info->covered_fields, buf, param->table->s->fields,
- FALSE))
+ if (my_bitmap_init(&info->covered_fields, buf, param->table->s->fields))
return NULL;
info->is_covering= FALSE;
info->index_scan_costs= 0.0;
@@ -7296,7 +7294,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
param->fields_bitmap_size);
if (!covered_fields->bitmap ||
my_bitmap_init(covered_fields, covered_fields->bitmap,
- param->table->s->fields, FALSE))
+ param->table->s->fields))
DBUG_RETURN(0);
bitmap_clear_all(covered_fields);
@@ -12611,10 +12609,10 @@ int QUICK_RANGE_SELECT::reset()
if (!mrr_buf_desc)
empty_buf.buffer= empty_buf.buffer_end= empty_buf.end_of_used_area= NULL;
-
- error= file->multi_range_read_init(&seq_funcs, (void*)this, ranges.elements,
- mrr_flags, mrr_buf_desc? mrr_buf_desc:
- &empty_buf);
+
+ error= file->multi_range_read_init(&seq_funcs, (void*)this,
+ (uint)ranges.elements, mrr_flags,
+ mrr_buf_desc? mrr_buf_desc: &empty_buf);
err:
/* Restore bitmaps set on entry */
if (in_ror_merged_scan)
@@ -12726,7 +12724,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length,
}
}
- uint count= ranges.elements - (uint)(cur_range - (QUICK_RANGE**) ranges.buffer);
+ size_t count= ranges.elements - (size_t)(cur_range - (QUICK_RANGE**) ranges.buffer);
if (count == 0)
{
/* Ranges have already been used up before. None is left for read. */
@@ -12771,7 +12769,7 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
DBUG_RETURN(result);
}
- uint count= ranges.elements - (uint)(cur_range - (QUICK_RANGE**) ranges.buffer);
+ size_t count= ranges.elements - (size_t)(cur_range - (QUICK_RANGE**) ranges.buffer);
if (count == 0)
{
/* Ranges have already been used up before. None is left for read. */
@@ -12812,9 +12810,9 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
bool QUICK_RANGE_SELECT::row_in_ranges()
{
QUICK_RANGE *res;
- uint min= 0;
- uint max= ranges.elements - 1;
- uint mid= (max + min)/2;
+ size_t min= 0;
+ size_t max= ranges.elements - 1;
+ size_t mid= (max + min)/2;
while (min != max)
{
@@ -15800,7 +15798,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
DBUG_ASSERT(min_max_ranges.elements > 0);
- for (uint range_idx= min_max_ranges.elements; range_idx > 0; range_idx--)
+ for (size_t range_idx= min_max_ranges.elements; range_idx > 0; range_idx--)
{ /* Search from the right-most range to the left. */
get_dynamic(&min_max_ranges, (uchar*)&cur_range, range_idx - 1);
@@ -16346,7 +16344,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
}
if (min_max_ranges.elements > 0)
{
- fprintf(DBUG_FILE, "%*susing %d quick_ranges for MIN/MAX:\n",
+ fprintf(DBUG_FILE, "%*susing %zu quick_ranges for MIN/MAX:\n",
indent, "", min_max_ranges.elements);
}
}
diff --git a/sql/opt_split.cc b/sql/opt_split.cc
index 41b8acf5dcb..ad90bf32315 100644
--- a/sql/opt_split.cc
+++ b/sql/opt_split.cc
@@ -704,7 +704,7 @@ double spl_postjoin_oper_cost(THD *thd, double join_record_count, uint rec_len)
void JOIN::add_keyuses_for_splitting()
{
uint i;
- uint idx;
+ size_t idx;
KEYUSE_EXT *keyuse_ext;
KEYUSE_EXT keyuse_ext_end;
double oper_cost;
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 99f75d9ad2f..596b5169659 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4485,7 +4485,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
STEP 1: Get temporary table name
*/
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
- temp_pool_slot = bitmap_lock_set_next(&temp_pool);
+ temp_pool_slot = temp_pool_set_next();
if (temp_pool_slot != MY_BIT_NONE) // we got a slot
sprintf(path, "%s-subquery-%lx-%i", tmp_file_prefix,
@@ -4522,7 +4522,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
NullS))
{
if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
+ temp_pool_clear_bit(temp_pool_slot);
DBUG_RETURN(TRUE);
}
strmov(tmpname,path);
@@ -4732,7 +4732,7 @@ err:
thd->mem_root= mem_root_save;
free_tmp_table(thd,table); /* purecov: inspected */
if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
+ temp_pool_clear_bit(temp_pool_slot);
DBUG_RETURN(TRUE); /* purecov: inspected */
}
diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc
index a6f0ac24719..8c4720bdec4 100644
--- a/sql/opt_table_elimination.cc
+++ b/sql/opt_table_elimination.cc
@@ -1070,7 +1070,7 @@ bool Dep_analysis_context::setup_equality_modules_deps(List<Dep_module>
void *buf;
if (!(buf= thd->alloc(bitmap_buffer_size(offset))) ||
- my_bitmap_init(&expr_deps, (my_bitmap_map*)buf, offset, FALSE))
+ my_bitmap_init(&expr_deps, (my_bitmap_map*)buf, offset))
{
DBUG_RETURN(TRUE); /* purecov: inspected */
}
diff --git a/sql/partition_element.h b/sql/partition_element.h
index e0a519065cc..c551baa3092 100644
--- a/sql/partition_element.h
+++ b/sql/partition_element.h
@@ -111,7 +111,6 @@ public:
ha_rows part_min_rows;
longlong range_value;
const char *partition_name;
- const char *tablespace_name;
struct st_ddl_log_memory_entry *log_entry;
const char* part_comment;
const char* data_file_name;
@@ -129,7 +128,7 @@ public:
partition_element()
: part_max_rows(0), part_min_rows(0), range_value(0),
- partition_name(NULL), tablespace_name(NULL),
+ partition_name(NULL),
log_entry(NULL), part_comment(NULL),
data_file_name(NULL), index_file_name(NULL),
engine_type(NULL), connect_string(null_clex_str), part_state(PART_NORMAL),
@@ -143,7 +142,6 @@ public:
: part_max_rows(part_elem->part_max_rows),
part_min_rows(part_elem->part_min_rows),
range_value(0), partition_name(NULL),
- tablespace_name(part_elem->tablespace_name),
log_entry(NULL),
part_comment(part_elem->part_comment),
data_file_name(part_elem->data_file_name),
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index fd92e437cac..62a3092f369 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -2426,7 +2426,7 @@ bool partition_info::has_same_partitioning(partition_info *new_part_info)
partition_element *new_part_elem= new_part_it++;
/*
The following must match:
- partition_name, tablespace_name, data_file_name, index_file_name,
+ partition_name, data_file_name, index_file_name,
engine_type, part_max_rows, part_min_rows, nodegroup_id.
(max_value, signed_flag, has_null_value only on partition level,
RANGE/LIST)
@@ -2512,9 +2512,7 @@ bool partition_info::has_same_partitioning(partition_info *new_part_info)
if (strcmp_null(sub_part_elem->data_file_name,
new_sub_part_elem->data_file_name) ||
strcmp_null(sub_part_elem->index_file_name,
- new_sub_part_elem->index_file_name) ||
- strcmp_null(sub_part_elem->tablespace_name,
- new_sub_part_elem->tablespace_name))
+ new_sub_part_elem->index_file_name))
DBUG_RETURN(false);
} while (++j < num_subparts);
@@ -2530,9 +2528,7 @@ bool partition_info::has_same_partitioning(partition_info *new_part_info)
if (strcmp_null(part_elem->data_file_name,
new_part_elem->data_file_name) ||
strcmp_null(part_elem->index_file_name,
- new_part_elem->index_file_name) ||
- strcmp_null(part_elem->tablespace_name,
- new_part_elem->tablespace_name))
+ new_part_elem->index_file_name))
DBUG_RETURN(false);
}
} while (++i < num_parts);
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 0656238ec07..995147d6766 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -79,7 +79,7 @@ struct Vers_part_info : public Sql_alloc
partition_element *hist_part;
};
-class partition_info : public Sql_alloc
+class partition_info : public DDL_LOG_STATE, public Sql_alloc
{
public:
/*
@@ -154,10 +154,6 @@ public:
Item *item_free_list;
- struct st_ddl_log_memory_entry *first_log_entry;
- struct st_ddl_log_memory_entry *exec_log_entry;
- struct st_ddl_log_memory_entry *frm_log_entry;
-
/*
Bitmaps of partitions used by the current query.
* read_partitions - partitions to be used for reading.
@@ -297,7 +293,6 @@ public:
part_field_buffers(NULL), subpart_field_buffers(NULL),
restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL),
part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
- first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL),
bitmaps_are_initialized(FALSE),
list_array(NULL), vers_info(NULL), err_value(0),
part_info_string(NULL),
@@ -319,6 +314,7 @@ public:
is_auto_partitioned(FALSE),
has_null_value(FALSE), column_list(FALSE)
{
+ bzero((DDL_LOG_STATE *) this, sizeof(DDL_LOG_STATE));
all_fields_in_PF.clear_all();
all_fields_in_PPF.clear_all();
all_fields_in_SPF.clear_all();
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index eecc6040051..306ae878060 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -249,8 +249,9 @@ rpl_slave_state::rpl_slave_state()
{
mysql_mutex_init(key_LOCK_slave_state, &LOCK_slave_state,
MY_MUTEX_INIT_SLOW);
- my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(element, domain_id),
- sizeof(uint32), NULL, rpl_slave_state_free_element, HASH_UNIQUE);
+ my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
+ offsetof(element, domain_id), sizeof(element::domain_id),
+ NULL, rpl_slave_state_free_element, HASH_UNIQUE);
my_init_dynamic_array(PSI_INSTRUMENT_ME, &gtid_sort_array, sizeof(rpl_gtid),
8, 8, MYF(0));
}
@@ -366,7 +367,8 @@ rpl_slave_state::get_element(uint32 domain_id)
{
struct element *elem;
- elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0);
+ elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
+ sizeof(domain_id));
if (elem)
return elem;
@@ -402,7 +404,8 @@ rpl_slave_state::put_back_list(list_element *list)
list_element *next= list->next;
if ((!e || e->domain_id != list->domain_id) &&
- !(e= (element *)my_hash_search(&hash, (const uchar *)&list->domain_id, 0)))
+ !(e= (element *)my_hash_search(&hash, (const uchar *)&list->domain_id,
+ sizeof(list->domain_id))))
{
err= 1;
goto end;
@@ -1107,8 +1110,8 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
bool locked= false;
my_hash_init(PSI_INSTRUMENT_ME, &gtid_hash, &my_charset_bin, 32,
- offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, NULL,
- HASH_UNIQUE);
+ offsetof(rpl_gtid, domain_id), sizeof(rpl_gtid::domain_id),
+ NULL, NULL, HASH_UNIQUE);
for (i= 0; i < num_extra; ++i)
if (extra_gtids[i].server_id == global_system_variables.server_id &&
my_hash_insert(&gtid_hash, (uchar *)(&extra_gtids[i])))
@@ -1143,7 +1146,8 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
}
/* Check if we have something newer in the extra list. */
- rec= my_hash_search(&gtid_hash, (const uchar *)&best_gtid.domain_id, 0);
+ rec= my_hash_search(&gtid_hash, (const uchar *)&best_gtid.domain_id,
+ sizeof(best_gtid.domain_id));
if (rec)
{
gtid= (rpl_gtid *)rec;
@@ -1243,7 +1247,8 @@ rpl_slave_state::domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid)
uint64 best_sub_id;
mysql_mutex_lock(&LOCK_slave_state);
- elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0);
+ elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
+ sizeof(domain_id));
if (!elem || !(list= elem->list))
{
mysql_mutex_unlock(&LOCK_slave_state);
@@ -1477,8 +1482,9 @@ rpl_slave_state::alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton,
void rpl_binlog_state::init()
{
- my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(element, domain_id),
- sizeof(uint32), NULL, my_free, HASH_UNIQUE);
+ my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
+ offsetof(element, domain_id), sizeof(element::domain_id),
+ NULL, my_free, HASH_UNIQUE);
my_init_dynamic_array(PSI_INSTRUMENT_ME, &gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
mysql_mutex_init(key_LOCK_binlog_state, &LOCK_binlog_state,
MY_MUTEX_INIT_SLOW);
@@ -1580,7 +1586,8 @@ rpl_binlog_state::update_nolock(const struct rpl_gtid *gtid, bool strict)
element *elem;
if ((elem= (element *)my_hash_search(&hash,
- (const uchar *)(&gtid->domain_id), 0)))
+ (const uchar *)(&gtid->domain_id),
+ sizeof(gtid->domain_id))))
{
if (strict && elem->last_gtid && elem->last_gtid->seq_no >= gtid->seq_no)
{
@@ -1628,7 +1635,8 @@ rpl_binlog_state::update_with_next_gtid(uint32 domain_id, uint32 server_id,
gtid->server_id= server_id;
mysql_mutex_lock(&LOCK_binlog_state);
- if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id), 0)))
+ if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id),
+ sizeof(domain_id))))
{
gtid->seq_no= ++elem->seq_no_counter;
if (!elem->update_element(gtid))
@@ -1667,7 +1675,8 @@ rpl_binlog_state::element::update_element(const rpl_gtid *gtid)
}
lookup_gtid= (rpl_gtid *)
- my_hash_search(&hash, (const uchar *)&gtid->server_id, 0);
+ my_hash_search(&hash, (const uchar *)&gtid->server_id,
+ sizeof(gtid->server_id));
if (lookup_gtid)
{
lookup_gtid->seq_no= gtid->seq_no;
@@ -1705,8 +1714,8 @@ rpl_binlog_state::alloc_element_nolock(const rpl_gtid *gtid)
{
elem->domain_id= gtid->domain_id;
my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32,
- offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free,
- HASH_UNIQUE);
+ offsetof(rpl_gtid, server_id), sizeof(rpl_gtid::domain_id),
+ NULL, my_free, HASH_UNIQUE);
elem->last_gtid= lookup_gtid;
elem->seq_no_counter= gtid->seq_no;
memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid));
@@ -1741,7 +1750,8 @@ rpl_binlog_state::check_strict_sequence(uint32 domain_id, uint32 server_id,
mysql_mutex_lock(&LOCK_binlog_state);
if ((elem= (element *)my_hash_search(&hash,
- (const uchar *)(&domain_id), 0)) &&
+ (const uchar *)(&domain_id),
+ sizeof(domain_id))) &&
elem->last_gtid && elem->last_gtid->seq_no >= seq_no)
{
my_error(ER_GTID_STRICT_OUT_OF_ORDER, MYF(0), domain_id, server_id, seq_no,
@@ -1768,7 +1778,8 @@ rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no)
int res;
mysql_mutex_lock(&LOCK_binlog_state);
- if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id), 0)))
+ if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id),
+ sizeof(domain_id))))
{
if (elem->seq_no_counter < seq_no)
elem->seq_no_counter= seq_no;
@@ -1786,8 +1797,8 @@ rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no)
elem->domain_id= domain_id;
my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32,
- offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free,
- HASH_UNIQUE);
+ offsetof(rpl_gtid, server_id), sizeof(rpl_gtid::server_id),
+ NULL, my_free, HASH_UNIQUE);
elem->last_gtid= NULL;
elem->seq_no_counter= seq_no;
if (0 == my_hash_insert(&hash, (const uchar *)elem))
@@ -1891,9 +1902,11 @@ rpl_gtid *
rpl_binlog_state::find_nolock(uint32 domain_id, uint32 server_id)
{
element *elem;
- if (!(elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0)))
+ if (!(elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
+ sizeof(domain_id))))
return NULL;
- return (rpl_gtid *)my_hash_search(&elem->hash, (const uchar *)&server_id, 0);
+ return (rpl_gtid *)my_hash_search(&elem->hash, (const uchar *)&server_id,
+ sizeof(server_id));
}
rpl_gtid *
@@ -1913,7 +1926,8 @@ rpl_binlog_state::find_most_recent(uint32 domain_id)
rpl_gtid *gtid= NULL;
mysql_mutex_lock(&LOCK_binlog_state);
- elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0);
+ elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
+ sizeof(domain_id));
if (elem && elem->last_gtid)
gtid= elem->last_gtid;
mysql_mutex_unlock(&LOCK_binlog_state);
@@ -2182,7 +2196,8 @@ rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids,
ptr_domain_id= (uint32*) dynamic_array_ptr(ids, i);
elem= (rpl_binlog_state::element *)
- my_hash_search(&hash, (const uchar *) ptr_domain_id, 0);
+ my_hash_search(&hash, (const uchar *) ptr_domain_id,
+ sizeof(ptr_domain_id[0]));
if (!elem)
{
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -2243,7 +2258,7 @@ slave_connection_state::slave_connection_state()
{
my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
offsetof(entry, gtid) + offsetof(rpl_gtid, domain_id),
- sizeof(uint32), NULL, my_free, HASH_UNIQUE);
+ sizeof(rpl_gtid::domain_id), NULL, my_free, HASH_UNIQUE);
my_init_dynamic_array(PSI_INSTRUMENT_ME, &gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
}
@@ -2298,7 +2313,8 @@ slave_connection_state::load(const char *slave_request, size_t len)
return 1;
}
if ((e= (const entry *)
- my_hash_search(&hash, (const uchar *)(&gtid->domain_id), 0)))
+ my_hash_search(&hash, (const uchar *)(&gtid->domain_id),
+ sizeof(gtid->domain_id))))
{
my_error(ER_DUPLICATE_GTID_DOMAIN, MYF(0), gtid->domain_id,
gtid->server_id, (ulonglong)gtid->seq_no, e->gtid.domain_id,
@@ -2365,7 +2381,8 @@ slave_connection_state::load(rpl_slave_state *state,
slave_connection_state::entry *
slave_connection_state::find_entry(uint32 domain_id)
{
- return (entry *) my_hash_search(&hash, (const uchar *)(&domain_id), 0);
+ return (entry *) my_hash_search(&hash, (const uchar *)(&domain_id),
+ sizeof(domain_id));
}
@@ -2383,7 +2400,8 @@ int
slave_connection_state::update(const rpl_gtid *in_gtid)
{
entry *e;
- uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id), 0);
+ uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id),
+ sizeof(in_gtid->domain_id));
if (rec)
{
e= (entry *)rec;
@@ -2408,7 +2426,8 @@ slave_connection_state::update(const rpl_gtid *in_gtid)
void
slave_connection_state::remove(const rpl_gtid *in_gtid)
{
- uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id), 0);
+ uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id),
+ sizeof(in_gtid->domain_id));
#ifdef DBUG_ASSERT_EXISTS
bool err;
rpl_gtid *slave_gtid= &((entry *)rec)->gtid;
@@ -2425,7 +2444,8 @@ slave_connection_state::remove(const rpl_gtid *in_gtid)
void
slave_connection_state::remove_if_present(const rpl_gtid *in_gtid)
{
- uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id), 0);
+ uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id),
+ sizeof(in_gtid->domain_id));
if (rec)
my_hash_delete(&hash, rec);
}
@@ -2869,7 +2889,8 @@ void
gtid_waiting::init()
{
my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
- offsetof(hash_element, domain_id), sizeof(uint32), NULL,
+ offsetof(hash_element, domain_id),
+ sizeof(hash_element::domain_id), NULL,
free_hash_element, HASH_UNIQUE);
mysql_mutex_init(key_LOCK_gtid_waiting, &LOCK_gtid_waiting, 0);
}
@@ -2902,7 +2923,8 @@ gtid_waiting::get_entry(uint32 domain_id)
{
hash_element *e;
- if ((e= (hash_element *)my_hash_search(&hash, (const uchar *)&domain_id, 0)))
+ if ((e= (hash_element *)my_hash_search(&hash, (const uchar *)&domain_id,
+ sizeof(domain_id))))
return e;
if (!(e= (hash_element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*e), MYF(MY_WME))))
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index cdd56976549..4fd36891a4b 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -749,7 +749,7 @@ int flush_master_info(Master_info* mi,
(1 + mi->ignore_server_ids.elements), MYF(MY_WME));
if (!ignore_server_ids_buf)
DBUG_RETURN(1); /* error */
- ulong cur_len= sprintf(ignore_server_ids_buf, "%u",
+ ulong cur_len= sprintf(ignore_server_ids_buf, "%zu",
mi->ignore_server_ids.elements);
for (ulong i= 0; i < mi->ignore_server_ids.elements; i++)
{
@@ -1455,11 +1455,32 @@ bool Master_info_index::add_master_info(Master_info *mi, bool write_to_file)
atomic
*/
-bool Master_info_index::remove_master_info(Master_info *mi)
+bool Master_info_index::remove_master_info(Master_info *mi, bool clear_log_files)
{
+ char tmp_name[FN_REFLEN];
DBUG_ENTER("remove_master_info");
mysql_mutex_assert_owner(&LOCK_active_mi);
+ if (clear_log_files)
+ {
+ /* This code is only executed when change_master() failes to create a new master info */
+
+ // Delete any temporary relay log files that could have been created by change_master()
+ mi->rli.relay_log.reset_logs(current_thd, 0, (rpl_gtid*) 0, 0, 0);
+ /* Delete master-'connection'.info */
+ create_logfile_name_with_suffix(tmp_name,
+ sizeof(tmp_name),
+ master_info_file, 0,
+ &mi->cmp_connection_name);
+ my_delete(tmp_name, MYF(0));
+ /* Delete relay-log-'connection'.info */
+ create_logfile_name_with_suffix(tmp_name,
+ sizeof(tmp_name),
+ relay_log_info_file, 0,
+ &mi->cmp_connection_name);
+ my_delete(tmp_name, MYF(0));
+ }
+
// Delete Master_info and rewrite others to file
if (!my_hash_delete(&master_info_hash, (uchar*) mi))
{
@@ -1916,7 +1937,7 @@ char *Domain_id_filter::as_string(enum_list_type type)
return NULL;
// Store the total number of elements followed by the individual elements.
- size_t cur_len= sprintf(buf, "%u", ids->elements);
+ size_t cur_len= sprintf(buf, "%zu", ids->elements);
sz-= cur_len;
for (uint i= 0; i < ids->elements; i++)
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index ce2d3cc9ad5..a4a06d42a5c 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -390,7 +390,7 @@ public:
bool check_duplicate_master_info(LEX_CSTRING *connection_name,
const char *host, uint port);
bool add_master_info(Master_info *mi, bool write_to_file);
- bool remove_master_info(Master_info *mi);
+ bool remove_master_info(Master_info *mi, bool clear_log_files);
Master_info *get_master_info(const LEX_CSTRING *connection_name,
Sql_condition::enum_warning_level warning);
bool start_all_slaves(THD *thd);
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 8be1964b762..49ec08a9cea 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -807,9 +807,7 @@ do_retry:
{
mysql_mutex_lock(&entry->LOCK_parallel_entry);
if (entry->stop_on_error_sub_id == (uint64) ULONGLONG_MAX ||
-#ifndef DBUG_OFF
- (DBUG_EVALUATE_IF("simulate_mdev_12746", 1, 0)) ||
-#endif
+ DBUG_IF("simulate_mdev_12746") ||
rgi->gtid_sub_id < entry->stop_on_error_sub_id)
{
register_wait_for_prior_event_group_commit(rgi, entry);
@@ -2347,7 +2345,8 @@ rpl_parallel::find(uint32 domain_id)
struct rpl_parallel_entry *e;
if (!(e= (rpl_parallel_entry *)my_hash_search(&domain_hash,
- (const uchar *)&domain_id, 0)))
+ (const uchar *)&domain_id,
+ sizeof(domain_id))))
{
/* Allocate a new, empty one. */
ulong count= opt_slave_domain_parallel_threads;
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 05ba449d96d..4ba843a51ab 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1632,7 +1632,8 @@ scan_one_gtid_slave_pos_table(THD *thd, HASH *hash, DYNAMIC_ARRAY *array,
goto end;
}
- if ((rec= my_hash_search(hash, (const uchar *)&domain_id, 0)))
+ if ((rec= my_hash_search(hash, (const uchar *)&domain_id,
+ sizeof(domain_id))))
{
entry= (struct gtid_pos_element *)rec;
if (entry->sub_id >= sub_id)
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 9ea8bb3b822..04a2efb3750 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -338,7 +338,7 @@ bool event_checksum_test(uchar *event_buf, ulong event_len,
DBUG_ASSERT(event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT);
event_buf[FLAGS_OFFSET]= (uchar) flags;
}
- res= DBUG_EVALUATE_IF("simulate_checksum_test_failure", TRUE, computed != incoming);
+ res= (DBUG_IF("simulate_checksum_test_failure") || computed != incoming);
}
return res;
}
diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc
index b65b7824a0e..b54ad58d153 100644
--- a/sql/semisync_master_ack_receiver.cc
+++ b/sql/semisync_master_ack_receiver.cc
@@ -72,7 +72,7 @@ bool Ack_receiver::start()
m_status= ST_UP;
- if (DBUG_EVALUATE_IF("rpl_semisync_simulate_create_thread_failure", 1, 0) ||
+ if (DBUG_IF("rpl_semisync_simulate_create_thread_failure") ||
pthread_attr_init(&attr) != 0 ||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) != 0 ||
#ifndef _WIN32
@@ -247,7 +247,7 @@ void Ack_receiver::run()
{
mysql_mutex_unlock(&m_mutex);
- ret= DBUG_EVALUATE_IF("rpl_semisync_simulate_select_error", -1, ret);
+ ret= DBUG_IF("rpl_semisync_simulate_select_error") ? -1 : ret;
if (ret == -1 && errno != EINTR)
sql_print_information("Failed to wait on semi-sync sockets, "
diff --git a/sql/semisync_slave.cc b/sql/semisync_slave.cc
index ccfda7576c2..684199031ee 100644
--- a/sql/semisync_slave.cc
+++ b/sql/semisync_slave.cc
@@ -63,7 +63,7 @@ int Repl_semi_sync_slave::slave_read_sync_header(const uchar *header,
if (rpl_semi_sync_slave_status)
{
- if (DBUG_EVALUATE_IF("semislave_corrupt_log", 0, 1)
+ if (!DBUG_IF("semislave_corrupt_log")
&& header[0] == k_packet_magic_num)
{
semi_sync_need_reply = (header[1] & k_packet_flag_sync);
@@ -140,7 +140,7 @@ void Repl_semi_sync_slave::kill_connection(MYSQL *mysql)
bool ret= (!mysql_real_connect(kill_mysql, mysql->host,
mysql->user, mysql->passwd,0, mysql->port, mysql->unix_socket, 0));
- if (DBUG_EVALUATE_IF("semisync_slave_failed_kill", 1, 0) || ret)
+ if (DBUG_IF("semisync_slave_failed_kill") || ret)
{
sql_print_information("cannot connect to master to kill slave io_thread's "
"connection");
@@ -172,8 +172,7 @@ int Repl_semi_sync_slave::request_transmit(Master_info *mi)
}
row= mysql_fetch_row(res);
- if (DBUG_EVALUATE_IF("master_not_support_semisync", 1, 0)
- || !row)
+ if (DBUG_IF("master_not_support_semisync") || !row)
{
/* Master does not support semi-sync */
sql_print_warning("Master server does not support semi-sync, "
@@ -234,7 +233,7 @@ int Repl_semi_sync_slave::slave_reply(Master_info *mi)
name_len + REPLY_BINLOG_NAME_OFFSET);
if (!reply_res)
{
- reply_res = DBUG_EVALUATE_IF("semislave_failed_net_flush", 1, net_flush(net));
+ reply_res = (DBUG_IF("semislave_failed_net_flush") || net_flush(net));
if (reply_res)
sql_print_error("Semi-sync slave net_flush() reply failed");
rpl_semi_sync_slave_send_ack++;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 3dd97527433..aa9ec5ab5ca 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -85,7 +85,7 @@ uint sys_var_elements()
int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags)
{
- uint saved_elements= long_options->elements;
+ size_t saved_elements= long_options->elements;
DBUG_ENTER("sys_var_add_options");
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 31070d04303..2d90793b90f 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -1721,7 +1721,7 @@ ER_TOO_LONG_KEY 42000 S1009
spa "Declaración de clave demasiado larga. La máxima longitud de clave es de %d"
swe "För lång nyckel. Högsta tillåtna nyckellängd är %d"
ukr "Зазначений ключ задовгий. Найбільша довжина ключа %d байтів"
-ER_KEY_COLUMN_DOES_NOT_EXITS 42000 S1009
+ER_KEY_COLUMN_DOES_NOT_EXIST 42000 S1009
cze "Klíčový sloupec '%-.192s' v tabulce neexistuje"
dan "Nøglefeltet '%-.192s' eksisterer ikke i tabellen"
nla "Zoeksleutel kolom '%-.192s' bestaat niet in tabel"
@@ -6127,11 +6127,11 @@ ER_PARTITION_MGMT_ON_NONPARTITIONED
ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING
eng "Partitioned tables do not support %s"
spa "Las tablas particionadas no soportan %s"
-ER_DROP_PARTITION_NON_EXISTENT
- eng "Error in list of partitions to %-.64s"
- ger "Fehler in der Partitionsliste bei %-.64s"
- spa "Error en lista de particiones para %-.64s"
- swe "Fel i listan av partitioner att %-.64s"
+ER_PARTITION_DOES_NOT_EXIST
+ eng "Wrong partition name or partition list"
+ ger "Falscher Name einer Partition oder Fehler in der Partitionsliste"
+ spa "Error en lista de particiones"
+ swe "Fel namn av en partition eller fel i listan av partitioner"
ER_DROP_LAST_PARTITION
eng "Cannot remove all partitions, use DROP TABLE instead"
ger "Es lassen sich nicht sämtliche Partitionen löschen, benutzen Sie statt dessen DROP TABLE"
@@ -8907,3 +8907,9 @@ ER_REMOVED_ORPHAN_TRIGGER
ER_STORAGE_ENGINE_DISABLED
eng "Storage engine %s is disabled"
spa "El motor de almacenaje %s está desactivado"
+WARN_SFORMAT_ERROR
+ eng "SFORMAT error: %s"
+ER_PARTITION_CONVERT_SUBPARTITIONED
+ eng "Convert partition is not supported for subpartitioned table."
+ER_PROVIDER_NOT_LOADED
+ eng "MariaDB tried to use the %s, but its provider plugin is not loaded"
diff --git a/sql/slave.cc b/sql/slave.cc
index 5ff40d8fb25..3c5b830fbe2 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -788,7 +788,7 @@ bool init_slave_skip_errors(const char* arg)
if (!arg || !*arg) // No errors defined
goto end;
- if (unlikely(my_bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0)))
+ if (my_bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR))
DBUG_RETURN(1);
use_slave_mask= 1;
@@ -2329,11 +2329,11 @@ past_checksum:
/* Announce MariaDB slave capabilities. */
DBUG_EXECUTE_IF("simulate_slave_capability_none", goto after_set_capability;);
{
- int rc= DBUG_EVALUATE_IF("simulate_slave_capability_old_53",
+ int rc= DBUG_IF("simulate_slave_capability_old_53") ?
mysql_real_query(mysql, STRING_WITH_LEN("SET @mariadb_slave_capability="
- STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_ANNOTATE))),
+ STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_ANNOTATE))) :
mysql_real_query(mysql, STRING_WITH_LEN("SET @mariadb_slave_capability="
- STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_MINE))));
+ STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_MINE)));
if (unlikely(rc))
{
err_code= mysql_errno(mysql);
@@ -4665,7 +4665,7 @@ pthread_handler_t handle_slave_io(void *arg)
}
thd->variables.wsrep_on= 0;
- if (DBUG_EVALUATE_IF("failed_slave_start", 1, 0)
+ if (DBUG_IF("failed_slave_start")
|| repl_semisync_slave.slave_start(mi))
{
mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL,
@@ -4941,7 +4941,7 @@ Stopping slave I/O thread due to out-of-memory error from master");
(!repl_semisync_slave.get_slave_enabled() ||
(!(mi->semi_ack & SEMI_SYNC_SLAVE_DELAY_SYNC) ||
(mi->semi_ack & (SEMI_SYNC_NEED_ACK)))) &&
- (DBUG_EVALUATE_IF("failed_flush_master_info", 1, 0) ||
+ (DBUG_IF("failed_flush_master_info") ||
flush_master_info(mi, TRUE, TRUE)))
{
sql_print_error("Failed to flush master info file");
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 601d41ab04a..475f1e0d424 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -561,7 +561,7 @@ public:
{ return m_flags & MODIFIES_DATA; }
inline uint instructions()
- { return m_instr.elements; }
+ { return (uint)m_instr.elements; }
inline sp_instr *
last_instruction()
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index c4c19dd39f6..619218f3b68 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -518,7 +518,8 @@ bool sp_rcontext::handle_sql_condition(THD *thd,
found_condition=
new (callers_arena->mem_root) Sql_condition(callers_arena->mem_root,
da->get_error_condition_identity(),
- da->message());
+ da->message(),
+ da->current_row_for_warning());
}
}
else if (da->current_statement_warn_count())
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 0e0e8921f86..ea669b2d1d8 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -111,15 +111,18 @@ public:
/// Text message.
char *message;
+ /** Row number where the condition has happened */
+ ulong m_row_number;
+
/// The constructor.
///
/// @param _sql_condition The SQL condition.
/// @param arena Query arena for SP
- Sql_condition_info(const Sql_condition *_sql_condition,
- Query_arena *arena)
+ Sql_condition_info(const Sql_condition *_sql_condition, Query_arena *arena)
:Sql_condition_identity(*_sql_condition)
{
message= strdup_root(arena->mem_root, _sql_condition->get_message_text());
+ m_row_number= _sql_condition->m_row_number;
}
};
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 9c71f8b7149..2d7f62cd725 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2168,24 +2168,26 @@ static bool has_validation_plugins()
MariaDB_PASSWORD_VALIDATION_PLUGIN, NULL);
}
-struct validation_data { const LEX_CSTRING *user, *password; };
+struct validation_data { const LEX_CSTRING *user, *password, *host; };
static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
{
struct validation_data *data= (struct validation_data *)arg;
struct st_mariadb_password_validation *handler=
(st_mariadb_password_validation *)plugin_decl(plugin)->info;
- return handler->validate_password(data->user, data->password);
+ return handler->validate_password(data->user, data->password, data->host);
}
static bool validate_password(THD *thd, const LEX_CSTRING &user,
+ const LEX_CSTRING &host,
const LEX_CSTRING &pwtext, bool has_hash)
{
if (pwtext.length || !has_hash)
{
struct validation_data data= { &user,
- pwtext.str ? &pwtext : &empty_clex_str };
+ pwtext.str ? &pwtext : &empty_clex_str,
+ &host };
if (plugin_foreach(NULL, do_validate,
MariaDB_PASSWORD_VALIDATION_PLUGIN, &data))
{
@@ -2239,6 +2241,7 @@ static int set_user_salt(ACL_USER::AUTH *auth, plugin_ref plugin)
not loaded, if the auth_string is invalid, if the password is not applicable
*/
static int set_user_auth(THD *thd, const LEX_CSTRING &user,
+ const LEX_CSTRING &host,
ACL_USER::AUTH *auth, const LEX_CSTRING &pwtext)
{
const char *plugin_name= auth->plugin.str;
@@ -2264,7 +2267,7 @@ static int set_user_auth(THD *thd, const LEX_CSTRING &user,
}
if (info->hash_password &&
- validate_password(thd, user, pwtext, auth->auth_string.length))
+ validate_password(thd, user, host, pwtext, auth->auth_string.length))
{
res= ER_NOT_VALID_PASSWORD;
goto end;
@@ -3374,7 +3377,9 @@ static int acl_user_update(THD *thd, ACL_USER *acl_user, uint nauth,
auth->auth_str);
if (fix_user_plugin_ptr(work_copy + i))
work_copy[i].plugin= safe_lexcstrdup_root(&acl_memroot, auth->plugin);
- if (set_user_auth(thd, acl_user->user, work_copy + i, auth->pwtext))
+ if (set_user_auth(thd, acl_user->user,
+ {acl_user->host.hostname, acl_user->hostname_length},
+ work_copy + i, auth->pwtext))
return 1;
}
}
@@ -3642,14 +3647,14 @@ static void init_check_host(void)
(my_hash_get_key) check_get_key, 0, 0);
if (!allow_all_hosts)
{
- for (uint i=0 ; i < acl_users.elements ; i++)
+ for (size_t i=0 ; i < acl_users.elements ; i++)
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
if (strchr(acl_user->host.hostname,wild_many) ||
strchr(acl_user->host.hostname,wild_one) ||
acl_user->host.ip_mask)
{ // Has wildcard
- uint j;
+ size_t j;
for (j=0 ; j < acl_wild_hosts.elements ; j++)
{ // Check if host already exists
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
@@ -3768,7 +3773,7 @@ static bool add_role_user_mapping(const char *uname, const char *hname,
static void remove_ptr_from_dynarray(DYNAMIC_ARRAY *array, void *ptr)
{
bool found __attribute__((unused))= false;
- for (uint i= 0; i < array->elements; i++)
+ for (size_t i= 0; i < array->elements; i++)
{
if (ptr == *dynamic_element(array, i, void**))
{
@@ -3817,7 +3822,7 @@ static void rebuild_role_grants(void)
/*
Reset every user's and role's role_grants array
*/
- for (uint i=0; i < acl_users.elements; i++) {
+ for (size_t i=0; i < acl_users.elements; i++) {
ACL_USER *user= dynamic_element(&acl_users, i, ACL_USER *);
reset_dynamic(&user->role_grants);
}
@@ -3843,7 +3848,7 @@ bool acl_check_host(const char *host, const char *ip)
mysql_mutex_unlock(&acl_cache->lock);
return 0; // Found host
}
- for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
+ for (size_t i=0 ; i < acl_wild_hosts.elements ; i++)
{
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
if (compare_hostname(acl, host, ip))
@@ -4000,7 +4005,8 @@ bool change_password(THD *thd, LEX_USER *user)
{
auth= acl_user->auth[i];
auth.auth_string= safe_lexcstrdup_root(&acl_memroot, user->auth->auth_str);
- int r= set_user_auth(thd, user->user, &auth, user->auth->pwtext);
+ int r= set_user_auth(thd, user->user, user->host,
+ &auth, user->auth->pwtext);
if (r == ER_SET_PASSWORD_AUTH_PLUGIN)
password_plugin= auth.plugin.str;
else if (r)
@@ -4283,14 +4289,18 @@ static ACL_USER * find_user_wild(const char *host, const char *user, const char
*/
static ACL_ROLE *find_acl_role(const char *role)
{
+ size_t length= strlen(role);
DBUG_ENTER("find_acl_role");
DBUG_PRINT("enter",("role: '%s'", role));
DBUG_PRINT("info", ("Hash elements: %ld", acl_roles.records));
mysql_mutex_assert_owner(&acl_cache->lock);
+ if (!length)
+ DBUG_RETURN(NULL);
+
ACL_ROLE *r= (ACL_ROLE *)my_hash_search(&acl_roles, (uchar *)role,
- strlen(role));
+ length);
DBUG_RETURN(r);
}
@@ -5042,7 +5052,7 @@ acl_update_proxy_user(ACL_PROXY_USER *new_value, bool is_revoke)
mysql_mutex_assert_owner(&acl_cache->lock);
DBUG_ENTER("acl_update_proxy_user");
- for (uint i= 0; i < acl_proxy_users.elements; i++)
+ for (size_t i= 0; i < acl_proxy_users.elements; i++)
{
ACL_PROXY_USER *acl_user=
dynamic_element(&acl_proxy_users, i, ACL_PROXY_USER *);
@@ -6314,7 +6324,7 @@ static int traverse_role_graph_impl(ACL_USER_BASE *user, void *context,
end:
/* Cleanup */
- for (uint i= 0; i < to_clear.elements(); i++)
+ for (size_t i= 0; i < to_clear.elements(); i++)
{
ACL_USER_BASE *current= to_clear.at(i);
DBUG_ASSERT(current->flags & (ROLE_EXPLORED | ROLE_ON_STACK | ROLE_OPENED));
@@ -6382,7 +6392,7 @@ static bool merge_role_global_privileges(ACL_ROLE *grantee)
DBUG_EXECUTE_IF("role_merge_stats", role_global_merges++;);
- for (uint i= 0; i < grantee->role_grants.elements; i++)
+ for (size_t i= 0; i < grantee->role_grants.elements; i++)
{
ACL_ROLE *r= *dynamic_element(&grantee->role_grants, i, ACL_ROLE**);
grantee->access|= r->access;
@@ -6521,8 +6531,8 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname,
if (update_flags & 4)
{
// Remove elements marked for deletion.
- uint count= 0;
- for(uint i= 0; i < acl_dbs.elements(); i++)
+ size_t count= 0;
+ for(size_t i= 0; i < acl_dbs.elements(); i++)
{
ACL_DB *acl_db= &acl_dbs.at(i);
if (acl_db->sort)
@@ -6885,7 +6895,7 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)),
if (data->what != PRIVS_TO_MERGE::GLOBAL)
{
role_hash.insert(grantee);
- for (uint i= 0; i < grantee->role_grants.elements; i++)
+ for (size_t i= 0; i < grantee->role_grants.elements; i++)
role_hash.insert(*dynamic_element(&grantee->role_grants, i, ACL_ROLE**));
}
@@ -9460,7 +9470,7 @@ static bool show_role_grants(THD *thd, const char *hostname,
ACL_USER_BASE *acl_entry,
char *buff, size_t buffsize)
{
- uint counter;
+ size_t counter;
Protocol *protocol= thd->protocol;
LEX_CSTRING host= {const_cast<char*>(hostname), strlen(hostname)};
@@ -9573,7 +9583,7 @@ static bool show_database_privileges(THD *thd, const char *username,
privilege_t want_access(NO_ACL);
Protocol *protocol= thd->protocol;
- for (uint i=0 ; i < acl_dbs.elements() ; i++)
+ for (size_t i=0 ; i < acl_dbs.elements() ; i++)
{
const char *user, *host;
@@ -10265,14 +10275,14 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
propagate_role_grants(acl_role, PRIVS_TO_MERGE::ALL);
// delete the role from cross-reference arrays
- for (uint i=0; i < acl_role->role_grants.elements; i++)
+ for (size_t i=0; i < acl_role->role_grants.elements; i++)
{
ACL_ROLE *grant= *dynamic_element(&acl_role->role_grants,
i, ACL_ROLE**);
remove_ptr_from_dynarray(&grant->parent_grantee, acl_role);
}
- for (uint i=0; i < acl_role->parent_grantee.elements; i++)
+ for (size_t i=0; i < acl_role->parent_grantee.elements; i++)
{
ACL_USER_BASE *grantee= *dynamic_element(&acl_role->parent_grantee,
i, ACL_USER_BASE**);
@@ -10293,7 +10303,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
/* Get the number of elements in the in-memory structure. */
switch (struct_no) {
case USER_ACL:
- elements= acl_users.elements;
+ elements= int(acl_users.elements);
break;
case DB_ACL:
elements= int(acl_dbs.elements());
@@ -10319,7 +10329,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
elements= grant_name_hash->records;
break;
case PROXY_USERS_ACL:
- elements= acl_proxy_users.elements;
+ elements= int(acl_proxy_users.elements);
break;
case ROLES_MAPPINGS_HASH:
roles_mappings_hash= &acl_roles_mappings;
@@ -12182,11 +12192,11 @@ SHOW_VAR acl_statistics[] = {
{"procedure_grants", (char*)&proc_priv_hash.records, SHOW_ULONG},
{"package_spec_grants", (char*)&package_spec_priv_hash.records, SHOW_ULONG},
{"package_body_grants", (char*)&package_body_priv_hash.records, SHOW_ULONG},
- {"proxy_users", (char*)&acl_proxy_users.elements, SHOW_UINT},
+ {"proxy_users", (char*)&acl_proxy_users.elements, SHOW_SIZE_T},
{"role_grants", (char*)&acl_roles_mappings.records, SHOW_ULONG},
{"roles", (char*)&acl_roles.records, SHOW_ULONG},
{"table_grants", (char*)&column_priv_hash.records, SHOW_ULONG},
- {"users", (char*)&acl_users.elements, SHOW_UINT},
+ {"users", (char*)&acl_users.elements, SHOW_SIZE_T},
#endif
{NullS, NullS, SHOW_LONG},
};
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 6ba08ebd55a..26e3d67641d 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -713,8 +713,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
protocol->store(operator_name, system_charset_info);
protocol->store(&error_clex_str, system_charset_info);
length= my_snprintf(buff, sizeof(buff),
- ER_THD(thd, ER_DROP_PARTITION_NON_EXISTENT),
- table_name.str);
+ ER_THD(thd, ER_PARTITION_DOES_NOT_EXIST));
protocol->store(buff, length, system_charset_info);
if(protocol->write())
goto err;
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index be305267076..e28308b4ff6 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -427,6 +427,8 @@ bool Sql_cmd_alter_table::execute(THD *thd)
as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
*/
if ((alter_info.partition_flags & ALTER_PARTITION_DROP) ||
+ (alter_info.partition_flags & ALTER_PARTITION_CONVERT_IN) ||
+ (alter_info.partition_flags & ALTER_PARTITION_CONVERT_OUT) ||
(alter_info.flags & ALTER_RENAME))
priv_needed|= DROP_ACL;
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index d91984d4b26..bf1edd4c964 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -250,13 +250,15 @@ public:
const LEX_CSTRING *new_db_arg, const LEX_CSTRING *new_name_arg);
/**
- @return true if the table is moved to another database, false otherwise.
+ @return true if the table is moved to another database or a new table
+ created by ALTER_PARTITION_CONVERT_OUT, false otherwise.
*/
bool is_database_changed() const
{ return (new_db.str != db.str); };
/**
- @return true if the table is renamed, false otherwise.
+ @return true if the table is renamed or a new table created by
+ ALTER_PARTITION_CONVERT_OUT, false otherwise.
*/
bool is_table_renamed() const
{ return (is_database_changed() || new_name.str != table_name.str); };
diff --git a/sql/sql_array.h b/sql/sql_array.h
index 8610e971016..85a53ae1a6f 100644
--- a/sql/sql_array.h
+++ b/sql/sql_array.h
@@ -114,19 +114,19 @@ template <class Elem> class Dynamic_array
{
DYNAMIC_ARRAY array;
public:
- Dynamic_array(PSI_memory_key psi_key, uint prealloc=16, uint increment=16)
+ Dynamic_array(PSI_memory_key psi_key, size_t prealloc=16, size_t increment=16)
{
init(psi_key, prealloc, increment);
}
- Dynamic_array(MEM_ROOT *root, uint prealloc=16, uint increment=16)
+ Dynamic_array(MEM_ROOT *root, size_t prealloc=16, size_t increment=16)
{
void *init_buffer= alloc_root(root, sizeof(Elem) * prealloc);
- init_dynamic_array2(root->m_psi_key, &array, sizeof(Elem), init_buffer,
- prealloc, increment, MYF(0));
+ init_dynamic_array2(root->psi_key, &array, sizeof(Elem), init_buffer,
+ prealloc, increment, MYF(0));
}
- void init(PSI_memory_key psi_key, uint prealloc=16, uint increment=16)
+ void init(PSI_memory_key psi_key, size_t prealloc=16, size_t increment=16)
{
init_dynamic_array2(psi_key, &array, sizeof(Elem), 0, prealloc, increment, MYF(0));
}
@@ -217,7 +217,7 @@ public:
void del(size_t idx)
{
DBUG_ASSERT(idx <= array.max_element);
- delete_dynamic_element(&array, (uint)idx);
+ delete_dynamic_element(&array, idx);
}
size_t elements() const
@@ -228,7 +228,7 @@ public:
void elements(size_t num_elements)
{
DBUG_ASSERT(num_elements <= array.max_element);
- array.elements= (uint)num_elements;
+ array.elements= num_elements;
}
void clear()
@@ -236,7 +236,7 @@ public:
elements(0);
}
- void set(uint idx, const Elem &el)
+ void set(size_t idx, const Elem &el)
{
set_dynamic(&array, &el, idx);
}
@@ -248,7 +248,7 @@ public:
bool reserve(size_t new_size)
{
- return allocate_dynamic(&array, (uint)new_size);
+ return allocate_dynamic(&array, new_size);
}
@@ -260,7 +260,7 @@ public:
if (new_size > old_size)
{
- set_dynamic(&array, (uchar*)&default_val, (uint)(new_size - 1));
+ set_dynamic(&array, (uchar*)&default_val, new_size - 1);
/*for (size_t i= old_size; i != new_size; i++)
{
at(i)= default_val;
diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc
index 3e9379ebe33..cbf3f971088 100644
--- a/sql/sql_audit.cc
+++ b/sql/sql_audit.cc
@@ -350,14 +350,11 @@ static my_bool calc_class_mask(THD *thd, plugin_ref plugin, void *arg)
*/
int finalize_audit_plugin(st_plugin_int *plugin)
{
+ int deinit_status= 0;
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
- if (plugin->plugin->deinit && plugin->plugin->deinit(NULL))
- {
- DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
- plugin->name.str));
- DBUG_EXECUTE("finalize_audit_plugin", return 1; );
- }
+ if (plugin->plugin->deinit)
+ deinit_status= plugin->plugin->deinit(NULL);
plugin->data= NULL;
bzero(&event_class_mask, sizeof(event_class_mask));
@@ -376,7 +373,7 @@ int finalize_audit_plugin(st_plugin_int *plugin)
bmove(mysql_global_audit_mask, event_class_mask, sizeof(event_class_mask));
mysql_mutex_unlock(&LOCK_audit_mask);
- return 0;
+ return deinit_status;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 8d213ce103b..414bb5efa25 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -6047,7 +6047,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, size_t length,
if (field)
{
if (field->invisible == INVISIBLE_FULL &&
- DBUG_EVALUATE_IF("test_completely_invisible", 0, 1))
+ !DBUG_IF("test_completely_invisible"))
DBUG_RETURN((Field*)0);
if (field->invisible == INVISIBLE_SYSTEM &&
@@ -7440,7 +7440,7 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref,
/* Add a TRUE condition to outer joins that have no common columns. */
if (table_ref_2->outer_join &&
!table_ref_1->on_expr && !table_ref_2->on_expr)
- table_ref_2->on_expr= (Item*) &Item_true;
+ table_ref_2->on_expr= (Item*) Item_true;
/* Change this table reference to become a leaf for name resolution. */
if (left_neighbor)
@@ -8936,7 +8936,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **ptr,
my_bool mysql_rm_tmp_tables(void)
{
- uint i, idx;
+ size_t i, idx;
char path[FN_REFLEN], *tmpdir, path_copy[FN_REFLEN];
MY_DIR *dirp;
FILEINFO *file;
@@ -8958,7 +8958,7 @@ my_bool mysql_rm_tmp_tables(void)
/* Remove all SQLxxx tables from directory */
- for (idx=0 ; idx < (uint) dirp->number_of_files ; idx++)
+ for (idx=0 ; idx < dirp->number_of_files ; idx++)
{
file=dirp->dir_entry+idx;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 6b7c4442204..29824301e9d 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -293,7 +293,7 @@ bool Foreign_key::validate(List<Create_field> &table_fields)
&sql_field->field_name)) {}
if (!sql_field)
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXIST, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
if (type == Key::FOREIGN_KEY && sql_field->vcol_info)
@@ -748,8 +748,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
will be re-initialized in init_for_queries().
*/
init_sql_alloc(key_memory_thd_main_mem_root,
- &main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0,
- MYF(MY_THREAD_SPECIFIC));
+ &main_mem_root, 64, 0, MYF(MY_THREAD_SPECIFIC));
/*
Allocation of user variables for binary logging is always done with main
@@ -966,10 +965,8 @@ Internal_error_handler *THD::pop_internal_handler()
void THD::raise_error(uint sql_errno)
{
const char* msg= ER_THD(this, sql_errno);
- (void) raise_condition(sql_errno,
- NULL,
- Sql_condition::WARN_LEVEL_ERROR,
- msg);
+ (void) raise_condition(sql_errno, "\0\0\0\0\0",
+ Sql_condition::WARN_LEVEL_ERROR, msg);
}
void THD::raise_error_printf(uint sql_errno, ...)
@@ -982,20 +979,16 @@ void THD::raise_error_printf(uint sql_errno, ...)
va_start(args, sql_errno);
my_vsnprintf(ebuff, sizeof(ebuff), format, args);
va_end(args);
- (void) raise_condition(sql_errno,
- NULL,
- Sql_condition::WARN_LEVEL_ERROR,
- ebuff);
+ (void) raise_condition(sql_errno, "\0\0\0\0\0",
+ Sql_condition::WARN_LEVEL_ERROR, ebuff);
DBUG_VOID_RETURN;
}
void THD::raise_warning(uint sql_errno)
{
const char* msg= ER_THD(this, sql_errno);
- (void) raise_condition(sql_errno,
- NULL,
- Sql_condition::WARN_LEVEL_WARN,
- msg);
+ (void) raise_condition(sql_errno, "\0\0\0\0\0",
+ Sql_condition::WARN_LEVEL_WARN, msg);
}
void THD::raise_warning_printf(uint sql_errno, ...)
@@ -1008,10 +1001,8 @@ void THD::raise_warning_printf(uint sql_errno, ...)
va_start(args, sql_errno);
my_vsnprintf(ebuff, sizeof(ebuff), format, args);
va_end(args);
- (void) raise_condition(sql_errno,
- NULL,
- Sql_condition::WARN_LEVEL_WARN,
- ebuff);
+ (void) raise_condition(sql_errno, "\0\0\0\0\0",
+ Sql_condition::WARN_LEVEL_WARN, ebuff);
DBUG_VOID_RETURN;
}
@@ -1022,10 +1013,8 @@ void THD::raise_note(uint sql_errno)
if (!(variables.option_bits & OPTION_SQL_NOTES))
DBUG_VOID_RETURN;
const char* msg= ER_THD(this, sql_errno);
- (void) raise_condition(sql_errno,
- NULL,
- Sql_condition::WARN_LEVEL_NOTE,
- msg);
+ (void) raise_condition(sql_errno, "\0\0\0\0\0",
+ Sql_condition::WARN_LEVEL_NOTE, msg);
DBUG_VOID_RETURN;
}
@@ -1041,21 +1030,20 @@ void THD::raise_note_printf(uint sql_errno, ...)
va_start(args, sql_errno);
my_vsnprintf(ebuff, sizeof(ebuff), format, args);
va_end(args);
- (void) raise_condition(sql_errno,
- NULL,
- Sql_condition::WARN_LEVEL_NOTE,
- ebuff);
+ (void) raise_condition(sql_errno, "\0\0\0\0\0",
+ Sql_condition::WARN_LEVEL_NOTE, ebuff);
DBUG_VOID_RETURN;
}
-Sql_condition* THD::raise_condition(uint sql_errno,
- const char* sqlstate,
- Sql_condition::enum_warning_level level,
- const Sql_user_condition_identity &ucid,
- const char* msg)
+Sql_condition* THD::raise_condition(const Sql_condition *cond)
{
+ uint sql_errno= cond->get_sql_errno();
+ const char *sqlstate= cond->get_sqlstate();
+ Sql_condition::enum_warning_level level= cond->get_level();
+ const char *msg= cond->get_message_text();
+
Diagnostics_area *da= get_stmt_da();
- Sql_condition *cond= NULL;
+ Sql_condition *raised= NULL;
DBUG_ENTER("THD::raise_condition");
DBUG_ASSERT(level < Sql_condition::WARN_LEVEL_END);
@@ -1083,22 +1071,18 @@ Sql_condition* THD::raise_condition(uint sql_errno,
sql_errno= ER_UNKNOWN_ERROR;
if (msg == NULL)
msg= ER_THD(this, sql_errno);
- if (sqlstate == NULL)
+ if (!*sqlstate)
sqlstate= mysql_errno_to_sqlstate(sql_errno);
- if ((level == Sql_condition::WARN_LEVEL_WARN) &&
- really_abort_on_warning())
+ if ((level == Sql_condition::WARN_LEVEL_WARN) && really_abort_on_warning())
{
- /*
- FIXME:
- push_warning and strict SQL_MODE case.
- */
+ /* FIXME: push_warning and strict SQL_MODE case. */
level= Sql_condition::WARN_LEVEL_ERROR;
}
if (!is_fatal_error &&
- handle_condition(sql_errno, sqlstate, &level, msg, &cond))
- DBUG_RETURN(cond);
+ handle_condition(sql_errno, sqlstate, &level, msg, &raised))
+ goto ret;
switch (level) {
case Sql_condition::WARN_LEVEL_NOTE:
@@ -1123,8 +1107,7 @@ Sql_condition* THD::raise_condition(uint sql_errno,
With wsrep we allow converting BF abort error to warning if
errors are ignored.
*/
- if (!is_fatal_error &&
- no_errors &&
+ if (!is_fatal_error && no_errors &&
(wsrep_trx().bf_aborted() || wsrep_retry_counter))
{
WSREP_DEBUG("BF abort error converted to warning");
@@ -1135,7 +1118,7 @@ Sql_condition* THD::raise_condition(uint sql_errno,
if (!da->is_error())
{
set_row_count_func(-1);
- da->set_error_status(sql_errno, msg, sqlstate, ucid, cond);
+ da->set_error_status(sql_errno, msg, sqlstate, *cond, raised);
}
}
}
@@ -1150,9 +1133,13 @@ Sql_condition* THD::raise_condition(uint sql_errno,
if (likely(!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY ||
sql_errno == ER_OUTOFMEMORY))))
{
- cond= da->push_warning(this, sql_errno, sqlstate, level, ucid, msg);
+ raised= da->push_warning(this, sql_errno, sqlstate, level, *cond, msg,
+ cond->m_row_number);
}
- DBUG_RETURN(cond);
+ret:
+ if (raised)
+ raised->copy_opt_attributes(cond);
+ DBUG_RETURN(raised);
}
extern "C"
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f5a0d6abc9e..df9d89b5aff 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -560,7 +560,8 @@ typedef enum enum_diag_condition_item_name
DIAG_CURSOR_NAME= 9,
DIAG_MESSAGE_TEXT= 10,
DIAG_MYSQL_ERRNO= 11,
- LAST_DIAG_SET_PROPERTY= DIAG_MYSQL_ERRNO
+ DIAG_ROW_NUMBER= 12,
+ LAST_DIAG_SET_PROPERTY= DIAG_ROW_NUMBER
} Diag_condition_item_name;
/**
@@ -1131,6 +1132,7 @@ struct THD_count
{
static Atomic_counter<uint32_t> count;
static uint value() { return static_cast<uint>(count); }
+ static uint connection_thd_count();
THD_count() { count++; }
~THD_count() { count--; }
};
@@ -3049,8 +3051,8 @@ public:
{
bzero((char*)this, sizeof(*this));
implicit_xid.null();
- init_sql_alloc(key_memory_thd_transactions, &mem_root,
- ALLOC_ROOT_MIN_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_thd_transactions, &mem_root, 256,
+ 0, MYF(MY_THREAD_SPECIFIC));
}
} default_transaction, *transaction;
Global_read_lock global_read_lock;
@@ -3918,6 +3920,11 @@ public:
user_time= t;
set_time();
}
+ inline void force_set_time(my_time_t t, ulong sec_part)
+ {
+ start_time= system_time.sec= t;
+ start_time_sec_part= system_time.sec_part= sec_part;
+ }
/*
this is only used by replication and BINLOG command.
usecs > TIME_MAX_SECOND_PART means "was not in binlog"
@@ -3929,15 +3936,9 @@ public:
else
{
if (sec_part <= TIME_MAX_SECOND_PART)
- {
- start_time= system_time.sec= t;
- start_time_sec_part= system_time.sec_part= sec_part;
- }
+ force_set_time(t, sec_part);
else if (t != system_time.sec)
- {
- start_time= system_time.sec= t;
- start_time_sec_part= system_time.sec_part= 0;
- }
+ force_set_time(t, 0);
else
{
start_time= t;
@@ -4800,45 +4801,17 @@ private:
@param msg the condition message text
@return The condition raised, or NULL
*/
- Sql_condition*
- raise_condition(uint sql_errno,
- const char* sqlstate,
- Sql_condition::enum_warning_level level,
- const char* msg)
+ Sql_condition* raise_condition(uint sql_errno, const char* sqlstate,
+ Sql_condition::enum_warning_level level, const char* msg)
{
- return raise_condition(sql_errno, sqlstate, level,
- Sql_user_condition_identity(), msg);
+ Sql_condition cond(NULL, // don't strdup the msg
+ Sql_condition_identity(sql_errno, sqlstate, level,
+ Sql_user_condition_identity()),
+ msg, get_stmt_da()->current_row_for_warning());
+ return raise_condition(&cond);
}
- /**
- Raise a generic or a user defined SQL condition.
- @param ucid - the user condition identity
- (or an empty identity if not a user condition)
- @param sql_errno - the condition error number
- @param sqlstate - the condition SQLSTATE
- @param level - the condition level
- @param msg - the condition message text
- @return The condition raised, or NULL
- */
- Sql_condition*
- raise_condition(uint sql_errno,
- const char* sqlstate,
- Sql_condition::enum_warning_level level,
- const Sql_user_condition_identity &ucid,
- const char* msg);
-
- Sql_condition*
- raise_condition(const Sql_condition *cond)
- {
- Sql_condition *raised= raise_condition(cond->get_sql_errno(),
- cond->get_sqlstate(),
- cond->get_level(),
- *cond/*Sql_user_condition_identity*/,
- cond->get_message_text());
- if (raised)
- raised->copy_opt_attributes(cond);
- return raised;
- }
+ Sql_condition* raise_condition(const Sql_condition *cond);
private:
void push_warning_truncated_priv(Sql_condition::enum_warning_level level,
diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h
index ce34852117f..430afadb491 100644
--- a/sql/sql_cmd.h
+++ b/sql/sql_cmd.h
@@ -75,7 +75,6 @@ enum enum_sql_command {
SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE,
- SQLCOM_ALTER_TABLESPACE,
SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN,
SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT,
SQLCOM_SHOW_PLUGINS, SQLCOM_SHOW_CONTRIBUTORS,
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 37e136927f2..c5defc1959c 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1363,9 +1363,7 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
*tables= tot_list;
/* and at last delete all non-table files */
- for (uint idx=0 ;
- idx < (uint) dirp->number_of_files && !thd->killed ;
- idx++)
+ for (size_t idx=0; idx < dirp->number_of_files && !thd->killed; idx++)
{
FILEINFO *file=dirp->dir_entry+idx;
char *extension;
@@ -1488,9 +1486,7 @@ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path)
DBUG_ENTER("mysql_rm_arc_files");
DBUG_PRINT("enter", ("path: %s", org_path));
- for (uint idx=0 ;
- idx < (uint) dirp->number_of_files && !thd->killed ;
- idx++)
+ for (size_t idx=0; idx < dirp->number_of_files && !thd->killed; idx++)
{
FILEINFO *file=dirp->dir_entry+idx;
char *extension, *revision;
@@ -1970,8 +1966,8 @@ bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db)
/* Step2: Move tables to the new database */
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
{
- uint nfiles= (uint) dirp->number_of_files;
- for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++)
+ size_t nfiles= dirp->number_of_files;
+ for (size_t idx=0 ; idx < nfiles && !thd->killed ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
char *extension, tname[FN_REFLEN + 1];
@@ -2060,8 +2056,8 @@ bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db)
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
{
- uint nfiles= (uint) dirp->number_of_files;
- for (uint idx=0 ; idx < nfiles ; idx++)
+ size_t nfiles= dirp->number_of_files;
+ for (size_t idx=0 ; idx < nfiles ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
char oldname[FN_REFLEN + 1], newname[FN_REFLEN + 1];
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index e35cf17b182..0403d6e73c3 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -728,6 +728,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
explain= (Explain_delete*)thd->lex->explain->get_upd_del_plan();
explain->tracker.on_scan_init();
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
+
if (!delete_while_scanning)
{
/*
@@ -793,9 +795,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
THD_STAGE_INFO(thd, stage_updating);
fix_rownum_pointers(thd, thd->lex->current_select, &deleted);
+ thd->get_stmt_da()->reset_current_row_for_warning(0);
while (likely(!(error=info.read_record())) && likely(!thd->killed) &&
likely(!thd->is_error()))
{
+ thd->get_stmt_da()->inc_current_row_for_warning();
if (delete_while_scanning)
delete_record= record_should_be_deleted(thd, table, select, explain,
delete_history);
@@ -871,6 +875,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
else
break;
}
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
terminate_delete:
killed_status= thd->killed;
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index cef9e6cec00..85be61c34ef 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -204,6 +204,7 @@ Sql_condition::copy_opt_attributes(const Sql_condition *cond)
copy_string(m_mem_root, & m_table_name, & cond->m_table_name);
copy_string(m_mem_root, & m_column_name, & cond->m_column_name);
copy_string(m_mem_root, & m_cursor_name, & cond->m_cursor_name);
+ m_row_number= cond->m_row_number;
}
@@ -216,7 +217,7 @@ Sql_condition::set_builtin_message_text(const char* str)
*/
const char* copy;
- copy= strdup_root(m_mem_root, str);
+ copy= m_mem_root ? strdup_root(m_mem_root, str) : str;
m_message_text.set(copy, strlen(copy), error_message_charset_info);
DBUG_ASSERT(! m_message_text.is_alloced());
}
@@ -500,7 +501,7 @@ Diagnostics_area::disable_status()
Warning_info::Warning_info(ulonglong warn_id_arg,
bool allow_unlimited_warnings, bool initialize)
:m_current_statement_warn_count(0),
- m_current_row_for_warning(1),
+ m_current_row_for_warning(0),
m_warn_id(warn_id_arg),
m_error_condition(NULL),
m_allow_unlimited_warnings(allow_unlimited_warnings),
@@ -557,7 +558,7 @@ void Warning_info::clear(ulonglong new_id)
free_memory();
memset(m_warn_count, 0, sizeof(m_warn_count));
m_current_statement_warn_count= 0;
- m_current_row_for_warning= 1; /* Start counting from the first row */
+ m_current_row_for_warning= 0;
clear_error_condition();
}
@@ -663,7 +664,8 @@ void Warning_info::reserve_space(THD *thd, uint count)
Sql_condition *Warning_info::push_warning(THD *thd,
const Sql_condition_identity *value,
- const char *msg)
+ const char *msg,
+ ulong current_row_number)
{
Sql_condition *cond= NULL;
@@ -672,7 +674,8 @@ Sql_condition *Warning_info::push_warning(THD *thd,
if (m_allow_unlimited_warnings ||
m_warn_list.elements() < thd->variables.max_error_count)
{
- cond= new (& m_warn_root) Sql_condition(& m_warn_root, *value, msg);
+ cond= new (& m_warn_root) Sql_condition(& m_warn_root, *value, msg,
+ current_row_number);
if (cond)
m_warn_list.push_back(cond);
}
@@ -688,7 +691,8 @@ Sql_condition *Warning_info::push_warning(THD *thd,
const Sql_condition *sql_condition)
{
Sql_condition *new_condition= push_warning(thd, sql_condition,
- sql_condition->get_message_text());
+ sql_condition->get_message_text(),
+ sql_condition->m_row_number);
if (new_condition)
new_condition->copy_opt_attributes(sql_condition);
@@ -723,7 +727,7 @@ void push_warning(THD *thd, Sql_condition::enum_warning_level level,
if (level == Sql_condition::WARN_LEVEL_ERROR)
level= Sql_condition::WARN_LEVEL_WARN;
- (void) thd->raise_condition(code, NULL, level, msg);
+ (void) thd->raise_condition(code, "\0\0\0\0\0", level, msg);
/* Make sure we also count warnings pushed after calling set_ok_status(). */
thd->get_stmt_da()->increment_warning();
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 6b0d4d7749c..d9d7f420baa 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -306,6 +306,9 @@ protected:
/** SQL CURSOR_NAME condition item. */
String m_cursor_name;
+ /** SQL ROW_NUMBER condition item. */
+ ulong m_row_number;
+
Sql_condition_items()
:m_class_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin),
m_subclass_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin),
@@ -316,7 +319,8 @@ protected:
m_schema_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
m_table_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
m_column_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
- m_cursor_name((const char*) NULL, 0, & my_charset_utf8mb3_bin)
+ m_cursor_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_row_number(0)
{ }
void clear()
@@ -331,6 +335,7 @@ protected:
m_table_name.length(0);
m_column_name.length(0);
m_cursor_name.length(0);
+ m_row_number= 0;
}
};
@@ -434,16 +439,14 @@ private:
@param level - the error level for this condition
@param msg - the message text for this condition
*/
- Sql_condition(MEM_ROOT *mem_root,
- const Sql_condition_identity &value,
- const char *msg)
- :Sql_condition_identity(value),
- m_mem_root(mem_root)
+ Sql_condition(MEM_ROOT *mem_root, const Sql_condition_identity &value,
+ const char *msg, ulong current_row_for_warning)
+ : Sql_condition_identity(value), m_mem_root(mem_root)
{
- DBUG_ASSERT(mem_root != NULL);
DBUG_ASSERT(value.get_sql_errno() != 0);
DBUG_ASSERT(msg != NULL);
set_builtin_message_text(msg);
+ m_row_number= current_row_for_warning;
}
/** Destructor. */
@@ -720,7 +723,7 @@ private:
void inc_current_row_for_warning() { m_current_row_for_warning++; }
/** Reset the current row counter. Start counting from the first row. */
- void reset_current_row_for_warning() { m_current_row_for_warning= 1; }
+ void reset_current_row_for_warning(int n) { m_current_row_for_warning= n; }
/** Return the current counter value. */
ulong current_row_for_warning() const { return m_current_row_for_warning; }
@@ -742,9 +745,8 @@ private:
@return a pointer to the added SQL-condition.
*/
- Sql_condition *push_warning(THD *thd,
- const Sql_condition_identity *identity,
- const char* msg);
+ Sql_condition *push_warning(THD *thd, const Sql_condition_identity *identity,
+ const char* msg, ulong current_row_number);
/**
Add a new SQL-condition to the current list and increment the respective
@@ -1143,8 +1145,8 @@ public:
void inc_current_row_for_warning()
{ get_warning_info()->inc_current_row_for_warning(); }
- void reset_current_row_for_warning()
- { get_warning_info()->reset_current_row_for_warning(); }
+ void reset_current_row_for_warning(int n)
+ { get_warning_info()->reset_current_row_for_warning(n); }
bool is_warning_info_read_only() const
{ return get_warning_info()->is_read_only(); }
@@ -1175,10 +1177,12 @@ public:
const char* sqlstate,
Sql_condition::enum_warning_level level,
const Sql_user_condition_identity &ucid,
- const char* msg)
+ const char* msg,
+ ulong current_row_number)
{
Sql_condition_identity tmp(sql_errno_arg, sqlstate, level, ucid);
- return get_warning_info()->push_warning(thd, &tmp, msg);
+ return get_warning_info()->push_warning(thd, &tmp, msg,
+ current_row_number);
}
Sql_condition *push_warning(THD *thd,
@@ -1188,7 +1192,7 @@ public:
const char* msg)
{
return push_warning(thd, sqlerrno, sqlstate, level,
- Sql_user_condition_identity(), msg);
+ Sql_user_condition_identity(), msg, 0);
}
void mark_sql_conditions_for_removal()
{ get_warning_info()->mark_sql_conditions_for_removal(); }
diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc
index 197bf5e7a00..240975d2974 100644
--- a/sql/sql_get_diagnostics.cc
+++ b/sql/sql_get_diagnostics.cc
@@ -338,6 +338,8 @@ Condition_information_item::get_value(THD *thd, const Sql_condition *cond)
str.set_ascii(cond->get_sqlstate(), strlen(cond->get_sqlstate()));
value= make_utf8_string_item(thd, &str);
break;
+ case ROW_NUMBER:
+ value= new (thd->mem_root) Item_uint(thd, cond->m_row_number);
}
DBUG_RETURN(value);
diff --git a/sql/sql_get_diagnostics.h b/sql/sql_get_diagnostics.h
index f283aa5b2c6..efe526d7c61 100644
--- a/sql/sql_get_diagnostics.h
+++ b/sql/sql_get_diagnostics.h
@@ -254,7 +254,8 @@ public:
CURSOR_NAME,
MESSAGE_TEXT,
MYSQL_ERRNO,
- RETURNED_SQLSTATE
+ RETURNED_SQLSTATE,
+ ROW_NUMBER
};
/**
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 4f57d6f98de..707b8a0d3bf 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -229,6 +229,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
if (values.elements != table->s->visible_fields)
{
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
DBUG_RETURN(-1);
}
@@ -253,6 +254,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (fields.elements != values.elements)
{
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
DBUG_RETURN(-1);
}
@@ -699,7 +701,6 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
const bool was_insert_delayed= (table_list->lock_type == TL_WRITE_DELAYED);
bool using_bulk_insert= 0;
uint value_count;
- ulong counter = 1;
/* counter of iteration in bulk PS operation*/
ulonglong iteration= 0;
ulonglong id;
@@ -830,10 +831,11 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
while ((values= its++))
{
- counter++;
+ thd->get_stmt_da()->inc_current_row_for_warning();
if (values->elements != value_count)
{
- my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0),
+ thd->get_stmt_da()->current_row_for_warning());
goto abort;
}
if (setup_fields(thd, Ref_ptr_array(),
@@ -842,6 +844,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
switch_to_nullable_trigger_fields(*values, table);
}
its.rewind ();
+ thd->get_stmt_da()->reset_current_row_for_warning(0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -1008,6 +1011,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
while ((values= its++))
{
+ thd->get_stmt_da()->inc_current_row_for_warning();
if (fields.elements || !value_count)
{
/*
@@ -1124,7 +1128,6 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
if (unlikely(error))
break;
info.accepted_rows++;
- thd->get_stmt_da()->inc_current_row_for_warning();
}
its.rewind();
iteration++;
@@ -1157,8 +1160,13 @@ values_loop_end:
table->file->ha_release_auto_increment();
if (using_bulk_insert)
{
- if (unlikely(table->file->ha_end_bulk_insert()) &&
- !error)
+ /*
+ if my_error() wasn't called yet on some specific row, end_bulk_insert()
+ can still do it, but the error shouldn't be for any specific row number
+ */
+ if (!error)
+ thd->get_stmt_da()->reset_current_row_for_warning(0);
+ if (unlikely(table->file->ha_end_bulk_insert()) && !error)
{
table->file->print_error(my_errno,MYF(0));
error=1;
@@ -1413,7 +1421,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
- (void) my_bitmap_init(&used_fields, used_fields_buff, table->s->fields, 0);
+ (void) my_bitmap_init(&used_fields, used_fields_buff, table->s->fields);
bitmap_clear_all(&used_fields);
view->contain_auto_increment= 0;
@@ -1683,6 +1691,8 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
ctx_state.restore_state(context, table_list);
}
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
+
if (res)
DBUG_RETURN(res);
@@ -2785,7 +2795,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
my_bitmap_init(&copy->has_value_set,
(my_bitmap_map*) (bitmap +
bitmaps_used*share->column_bitmap_size),
- share->fields, FALSE);
+ share->fields);
}
copy->tmp_set.bitmap= 0; // To catch errors
bzero((char*) bitmap, share->column_bitmap_size * bitmaps_used);
@@ -5070,7 +5080,8 @@ bool select_create::send_eof()
{
WSREP_DEBUG("select_create commit failed, thd: %llu err: %s %s",
thd->thread_id,
- wsrep_thd_transaction_state_str(thd), wsrep_thd_query(thd));
+ wsrep_thd_transaction_state_str(thd),
+ wsrep_thd_query(thd));
mysql_mutex_unlock(&thd->LOCK_thd_data);
abort_result_set();
DBUG_RETURN(true);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 3ef45de2e8e..b5f8cf4a886 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1342,7 +1342,7 @@ void lex_unlock_plugins(LEX *lex)
/* release used plugins */
if (lex->plugins.elements) /* No function call and no mutex if no plugins. */
{
- plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer,
+ plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer,
lex->plugins.elements);
}
reset_dynamic(&lex->plugins);
@@ -6042,8 +6042,10 @@ int st_select_lex_unit::save_union_explain_part2(Explain_query *output)
bool LEX::is_partition_management() const
{
return (sql_command == SQLCOM_ALTER_TABLE &&
- (alter_info.partition_flags == ALTER_PARTITION_ADD ||
- alter_info.partition_flags == ALTER_PARTITION_REORGANIZE));
+ (alter_info.partition_flags & (ALTER_PARTITION_ADD |
+ ALTER_PARTITION_CONVERT_IN |
+ ALTER_PARTITION_CONVERT_OUT |
+ ALTER_PARTITION_REORGANIZE)));
}
@@ -11252,6 +11254,25 @@ bool LEX::stmt_alter_table_exchange_partition(Table_ident *table)
}
+bool LEX::stmt_alter_table(Table_ident *table)
+{
+ DBUG_ASSERT(sql_command == SQLCOM_ALTER_TABLE);
+ first_select_lex()->db= table->db;
+ if (first_select_lex()->db.str == NULL &&
+ copy_db_to(&first_select_lex()->db))
+ return true;
+ if (unlikely(check_table_name(table->table.str, table->table.length,
+ false)) ||
+ (table->db.str && unlikely(check_db_name((LEX_STRING*) &table->db))))
+ {
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
+ return true;
+ }
+ name= table->table;
+ return false;
+}
+
+
void LEX::stmt_purge_to(const LEX_CSTRING &to)
{
type= 0;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 1fe8b869c11..14cf90caa04 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -290,7 +290,6 @@ class sp_pcontext;
class sp_variable;
class sp_expr_lex;
class sp_assignment_lex;
-class st_alter_tablespace;
class partition_info;
class Event_parse_data;
class set_var_base;
@@ -3521,12 +3520,6 @@ public:
/*
- Reference to a struct that contains information in various commands
- to add/create/drop/change table spaces.
- */
- st_alter_tablespace *alter_tablespace_info;
-
- /*
The set of those tables whose fields are referenced in all subqueries
of the query.
TODO: possibly this it is incorrect to have used tables in LEX because
@@ -4668,6 +4661,7 @@ public:
void stmt_deallocate_prepare(const Lex_ident_sys_st &ident);
bool stmt_alter_table_exchange_partition(Table_ident *table);
+ bool stmt_alter_table(Table_ident *table);
void stmt_purge_to(const LEX_CSTRING &to);
bool stmt_purge_before(Item *item);
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 2f1ee0b11bd..fe574db528f 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -659,6 +659,7 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list,
table->copy_blobs=1;
thd->abort_on_warning= !ignore && thd->is_strict_mode();
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
bool create_lookup_handler= handle_duplicates != DUP_ERROR;
if ((table_list->table->file->ha_table_flags() & HA_DUPLICATE_POS))
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0886fc85151..18629f4bd22 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -54,7 +54,6 @@
// check_mqh,
// reset_mqh
#include "sql_rename.h" // mysql_rename_tables
-#include "sql_tablespace.h" // mysql_alter_tablespace
#include "hostname.h" // hostname_cache_refresh
#include "sql_test.h" // mysql_print_status
#include "sql_select.h" // handle_select, mysql_select,
@@ -878,7 +877,6 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_ALTER_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_TRUNCATE]|= CF_DISALLOW_IN_RO_TRANS;
- sql_command_flags[SQLCOM_ALTER_TABLESPACE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_REPAIR]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_OPTIMIZE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_GRANT]|= CF_DISALLOW_IN_RO_TRANS;
@@ -4136,7 +4134,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
If new master was not added, we still need to free mi.
*/
if (master_info_added)
- master_info_index->remove_master_info(mi);
+ master_info_index->remove_master_info(mi, 1);
else
delete mi;
}
@@ -5888,12 +5886,6 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
case SQLCOM_XA_RECOVER:
res= mysql_xa_recover(thd);
break;
- case SQLCOM_ALTER_TABLESPACE:
- if (check_global_access(thd, CREATE_TABLESPACE_ACL))
- break;
- if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info)))
- my_ok(thd);
- break;
case SQLCOM_INSTALL_PLUGIN:
if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
&thd->lex->ident)))
@@ -6125,7 +6117,12 @@ finish:
thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
if (wsrep_thd_is_toi(thd) || wsrep_thd_is_in_rsu(thd))
+ {
+ WSREP_DEBUG("mysql_execute_command for %s", wsrep_thd_query(thd));
+ THD_STAGE_INFO(thd, stage_waiting_isolation);
wsrep_to_isolation_end(thd);
+ }
+
/*
Force release of transactional locks if not in active MST and wsrep is on.
*/
@@ -7889,7 +7886,8 @@ static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
});
WSREP_DEBUG("wsrep retrying AC query: %lu %s",
- thd->wsrep_retry_counter, wsrep_thd_query(thd));
+ thd->wsrep_retry_counter,
+ wsrep_thd_query(thd));
wsrep_prepare_for_autocommit_retry(thd, rawbuf, length, parser_state);
if (thd->lex->explain)
delete_explain_query(thd->lex);
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 0547331e7cd..b75a318ab65 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -67,7 +67,6 @@
#include "opt_range.h" // store_key_image_to_rec
#include "sql_alter.h" // Alter_table_ctx
#include "sql_select.h"
-#include "sql_tablespace.h" // check_tablespace_name
#include "ddl_log.h"
#include "tztime.h" // my_tz_OFFSET0
@@ -78,11 +77,6 @@ using std::min;
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
-#define ERROR_INJECT_CRASH(code) \
- DBUG_EVALUATE_IF(code, (DBUG_SUICIDE(), 0), 0)
-#define ERROR_INJECT_ERROR(code) \
- DBUG_EVALUATE_IF(code, (my_error(ER_UNKNOWN_ERROR, MYF(0)), TRUE), 0)
-
/*
Partition related functions declarations and some static constants;
*/
@@ -525,7 +519,7 @@ static bool create_full_part_field_array(THD *thd, TABLE *table,
goto end;
}
if (unlikely(my_bitmap_init(&part_info->full_part_field_set, bitmap_buf,
- table->s->fields, FALSE)))
+ table->s->fields)))
{
result= TRUE;
goto end;
@@ -1100,10 +1094,10 @@ static bool set_up_partition_bitmaps(THD *thd, partition_info *part_info)
bitmap_bytes * 2))))
DBUG_RETURN(TRUE);
- my_bitmap_init(&part_info->read_partitions, bitmap_buf, bitmap_bits, FALSE);
+ my_bitmap_init(&part_info->read_partitions, bitmap_buf, bitmap_bits);
/* Use the second half of the allocated buffer for lock_partitions */
my_bitmap_init(&part_info->lock_partitions, bitmap_buf + (bitmap_bytes / 4),
- bitmap_bits, FALSE);
+ bitmap_bits);
part_info->bitmaps_are_initialized= TRUE;
part_info->set_partition_bitmaps(NULL);
DBUG_RETURN(FALSE);
@@ -2215,8 +2209,6 @@ static int add_partition_options(String *str, partition_element *p_elem)
{
int err= 0;
- if (p_elem->tablespace_name)
- err+= add_keyword_string(str,"TABLESPACE", false, p_elem->tablespace_name);
if (p_elem->nodegroup_id != UNDEF_NODEGROUP)
err+= add_keyword_int(str,"NODEGROUP",(longlong)p_elem->nodegroup_id);
if (p_elem->part_max_rows)
@@ -4714,8 +4706,6 @@ bool compare_partition_options(HA_CREATE_INFO *table_create_info,
Note that there are not yet any engine supporting tablespace together
with partitioning. TODO: when there are, add compare.
*/
- if (part_elem->tablespace_name || table_create_info->tablespace)
- option_diffs[errors++]= "TABLESPACE";
if (part_elem->part_max_rows != table_create_info->max_rows)
option_diffs[errors++]= "MAX_ROWS";
if (part_elem->part_min_rows != table_create_info->min_rows)
@@ -4876,10 +4866,12 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
if (alter_info->partition_flags &
(ALTER_PARTITION_ADD |
ALTER_PARTITION_DROP |
+ ALTER_PARTITION_CONVERT_OUT |
ALTER_PARTITION_COALESCE |
ALTER_PARTITION_REORGANIZE |
ALTER_PARTITION_TABLE_REORG |
- ALTER_PARTITION_REBUILD))
+ ALTER_PARTITION_REBUILD |
+ ALTER_PARTITION_CONVERT_IN))
{
/*
You can't add column when we are doing alter related to partition
@@ -5085,6 +5077,13 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
}
if (alter_info->partition_flags & ALTER_PARTITION_ADD)
{
+ if ((alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN) &&
+ !(tab_part_info->part_type == RANGE_PARTITION ||
+ tab_part_info->part_type == LIST_PARTITION))
+ {
+ my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "CONVERT TABLE TO");
+ goto err;
+ }
if (*fast_alter_table && thd->locked_tables_mode)
{
MEM_ROOT *old_root= thd->mem_root;
@@ -5371,8 +5370,12 @@ that are reorganised.
tab_part_info->is_auto_partitioned= FALSE;
}
}
- else if (alter_info->partition_flags & ALTER_PARTITION_DROP)
+ else if ((alter_info->partition_flags & ALTER_PARTITION_DROP) |
+ (alter_info->partition_flags & ALTER_PARTITION_CONVERT_OUT))
{
+ const char * const cmd=
+ (alter_info->partition_flags & ALTER_PARTITION_CONVERT_OUT) ?
+ "CONVERT" : "DROP";
/*
Drop a partition from a range partition and list partitioning is
always safe and can be made more or less immediate. It is necessary
@@ -5401,7 +5404,7 @@ that are reorganised.
if (!(tab_part_info->part_type == RANGE_PARTITION ||
tab_part_info->part_type == LIST_PARTITION))
{
- my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
+ my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), cmd);
goto err;
}
if (num_parts_dropped >= tab_part_info->num_parts)
@@ -5443,7 +5446,7 @@ that are reorganised.
} while (++part_count < tab_part_info->num_parts);
if (num_parts_found != num_parts_dropped)
{
- my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
+ my_error(ER_PARTITION_DOES_NOT_EXIST, MYF(0));
goto err;
}
if (table->file->is_fk_defined_on_table_or_index(MAX_KEY))
@@ -5451,7 +5454,17 @@ that are reorganised.
my_error(ER_ROW_IS_REFERENCED, MYF(0));
goto err;
}
+ DBUG_ASSERT(!(alter_info->partition_flags & ALTER_PARTITION_CONVERT_OUT) ||
+ num_parts_dropped == 1);
+ /* NOTE: num_parts is used in generate_partition_syntax() */
tab_part_info->num_parts-= num_parts_dropped;
+ if ((alter_info->partition_flags & ALTER_PARTITION_CONVERT_OUT) &&
+ tab_part_info->is_sub_partitioned())
+ {
+ // TODO technically this can be converted to a *partitioned* table
+ my_error(ER_PARTITION_CONVERT_SUBPARTITIONED, MYF(0));
+ goto err;
+ }
}
else if (alter_info->partition_flags & ALTER_PARTITION_REBUILD)
{
@@ -5459,7 +5472,7 @@ that are reorganised.
tab_part_info->default_engine_type);
if (set_part_state(alter_info, tab_part_info, PART_CHANGED))
{
- my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
+ my_error(ER_PARTITION_DOES_NOT_EXIST, MYF(0));
goto err;
}
if (!(*fast_alter_table))
@@ -5735,7 +5748,7 @@ the generated partition syntax in a correct manner.
} while (++part_count < tab_part_info->num_parts);
if (drop_count != num_parts_reorged)
{
- my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
+ my_error(ER_PARTITION_DOES_NOT_EXIST, MYF(0));
goto err;
}
tab_part_info->num_parts= check_total_partitions;
@@ -5795,7 +5808,7 @@ the generated partition syntax in a correct manner.
goto err;
}
}
- } // ADD, DROP, COALESCE, REORGANIZE, TABLE_REORG, REBUILD
+ } // ADD, DROP, COALESCE, REORGANIZE, TABLE_REORG, REBUILD, CONVERT
else
{
/*
@@ -6117,8 +6130,6 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
char path[FN_REFLEN+1];
partition_info *part_info= lpt->table->part_info;
List_iterator<partition_element> part_it(part_info->partitions);
- uint i= 0;
- uint remove_count= 0;
int error;
DBUG_ENTER("mysql_drop_partitions");
@@ -6133,34 +6144,69 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
lpt->table->file->print_error(error, MYF(0));
DBUG_RETURN(TRUE);
}
- do
- {
- partition_element *part_elem= part_it++;
- if (part_elem->part_state == PART_IS_DROPPED)
- {
- part_it.remove();
- remove_count++;
- }
- } while (++i < part_info->num_parts);
- part_info->num_parts-= remove_count;
DBUG_RETURN(FALSE);
}
/*
- Insert log entry into list
+ Convert partition to a table in an ALTER TABLE of partitions
+
SYNOPSIS
- insert_part_info_log_entry_list()
- log_entry
+ alter_partition_convert_out()
+ lpt Struct containing parameters
+
RETURN VALUES
- NONE
+ TRUE Failure
+ FALSE Success
+
+ DESCRIPTION
+ Rename partition table marked with PART_TO_BE_DROPPED into a separate table
+ under the name lpt->alter_ctx->(new_db, new_name).
+
+ This is ddl-logged by write_log_convert_out_partition().
*/
-static void insert_part_info_log_entry_list(partition_info *part_info,
- DDL_LOG_MEMORY_ENTRY *log_entry)
+static bool alter_partition_convert_out(ALTER_PARTITION_PARAM_TYPE *lpt)
{
- log_entry->next_active_log_entry= part_info->first_log_entry;
- part_info->first_log_entry= log_entry;
+ partition_info *part_info= lpt->table->part_info;
+ THD *thd= lpt->thd;
+ int error;
+ handler *file= get_new_handler(NULL, thd->mem_root, part_info->default_engine_type);
+
+ DBUG_ASSERT(lpt->thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ lpt->table->s->db.str,
+ lpt->table->s->table_name.str,
+ MDL_EXCLUSIVE));
+
+ char from_name[FN_REFLEN + 1], to_name[FN_REFLEN + 1];
+ const char *path= lpt->table->s->path.str;
+
+ build_table_filename(to_name, sizeof(to_name) - 1, lpt->alter_ctx->new_db.str,
+ lpt->alter_ctx->new_name.str, "", 0);
+
+ for (const partition_element &e: part_info->partitions)
+ {
+ if (e.part_state != PART_TO_BE_DROPPED)
+ continue;
+
+ if (unlikely((error= create_partition_name(from_name, sizeof(from_name),
+ path, e.partition_name,
+ NORMAL_PART_NAME, FALSE))))
+ {
+ DBUG_ASSERT(thd->is_error());
+ return true;
+ }
+ if (DBUG_IF("error_convert_partition_00") ||
+ unlikely(error= file->ha_rename_table(from_name, to_name)))
+ {
+ my_error(ER_ERROR_ON_RENAME, MYF(0), from_name, to_name, my_errno);
+ lpt->table->file->print_error(error, MYF(0));
+ return true;
+ }
+ break;
+ }
+
+ return false;
}
@@ -6188,50 +6234,44 @@ static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry)
/*
- Log an delete/rename frm file
+ Log an rename frm file
SYNOPSIS
- write_log_replace_delete_frm()
+ write_log_replace_frm()
lpt Struct for parameters
next_entry Next reference to use in log record
from_path Name to rename from
to_path Name to rename to
- replace_flag TRUE if replace, else delete
RETURN VALUES
TRUE Error
FALSE Success
DESCRIPTION
- Support routine that writes a replace or delete of an frm file into the
+ Support routine that writes a replace of an frm file into the
ddl log. It also inserts an entry that keeps track of used space into
the partition info object
*/
-static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint next_entry,
- const char *from_path,
- const char *to_path,
- bool replace_flag)
+bool write_log_replace_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
+ uint next_entry,
+ const char *from_path,
+ const char *to_path)
{
DDL_LOG_ENTRY ddl_log_entry;
DDL_LOG_MEMORY_ENTRY *log_entry;
- DBUG_ENTER("write_log_replace_delete_frm");
+ DBUG_ENTER("write_log_replace_frm");
bzero(&ddl_log_entry, sizeof(ddl_log_entry));
- if (replace_flag)
- ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
- else
- ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
+ ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
ddl_log_entry.next_entry= next_entry;
lex_string_set(&ddl_log_entry.handler_name, reg_ext);
lex_string_set(&ddl_log_entry.name, to_path);
+ lex_string_set(&ddl_log_entry.from_name, from_path);
- if (replace_flag)
- lex_string_set(&ddl_log_entry.from_name, from_path);
if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
{
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(true);
}
- insert_part_info_log_entry_list(lpt->part_info, log_entry);
- DBUG_RETURN(FALSE);
+ ddl_log_add_entry(lpt->part_info, log_entry);
+ DBUG_RETURN(false);
}
@@ -6310,7 +6350,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
*next_entry= log_entry->entry_pos;
sub_elem->log_entry= log_entry;
- insert_part_info_log_entry_list(part_info, log_entry);
+ ddl_log_add_entry(part_info, log_entry);
} while (++j < num_subparts);
}
else
@@ -6337,7 +6377,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
}
*next_entry= log_entry->entry_pos;
part_elem->log_entry= log_entry;
- insert_part_info_log_entry_list(part_info, log_entry);
+ ddl_log_add_entry(part_info, log_entry);
}
}
} while (++i < num_elements);
@@ -6346,21 +6386,29 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
/*
- Log dropped partitions
+ Log dropped or converted partitions
SYNOPSIS
- write_log_dropped_partitions()
+ log_drop_or_convert_action()
lpt Struct containing parameters
RETURN VALUES
TRUE Error
FALSE Success
*/
-static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint *next_entry,
- const char *path,
- bool temp_list)
+enum log_action_enum
+{
+ ACT_DROP = 0,
+ ACT_CONVERT_IN,
+ ACT_CONVERT_OUT
+};
+
+static bool log_drop_or_convert_action(ALTER_PARTITION_PARAM_TYPE *lpt,
+ uint *next_entry, const char *path,
+ const char *from_name, bool temp_list,
+ const log_action_enum convert_action)
{
DDL_LOG_ENTRY ddl_log_entry;
+ DBUG_ASSERT(convert_action == ACT_DROP || (from_name != NULL));
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
char tmp_path[FN_REFLEN + 1];
@@ -6368,10 +6416,13 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
List_iterator<partition_element> temp_it(part_info->temp_partitions);
uint num_temp_partitions= part_info->temp_partitions.elements;
uint num_elements= part_info->partitions.elements;
- DBUG_ENTER("write_log_dropped_partitions");
+ DBUG_ENTER("log_drop_or_convert_action");
bzero(&ddl_log_entry, sizeof(ddl_log_entry));
- ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
+
+ ddl_log_entry.action_type= convert_action ?
+ DDL_LOG_RENAME_ACTION :
+ DDL_LOG_DELETE_ACTION;
if (temp_list)
num_elements= num_temp_partitions;
while (num_elements--)
@@ -6392,8 +6443,13 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
name_variant= TEMP_PART_NAME;
else
name_variant= NORMAL_PART_NAME;
+ DBUG_ASSERT(convert_action != ACT_CONVERT_IN ||
+ part_elem->part_state == PART_TO_BE_ADDED);
+ DBUG_ASSERT(convert_action != ACT_CONVERT_OUT ||
+ part_elem->part_state == PART_TO_BE_DROPPED);
if (part_info->is_sub_partitioned())
{
+ DBUG_ASSERT(!convert_action);
List_iterator<partition_element> sub_it(part_elem->subpartitions);
uint num_subparts= part_info->num_subparts;
uint j= 0;
@@ -6415,7 +6471,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
}
*next_entry= log_entry->entry_pos;
sub_elem->log_entry= log_entry;
- insert_part_info_log_entry_list(part_info, log_entry);
+ ddl_log_add_entry(part_info, log_entry);
} while (++j < num_subparts);
}
else
@@ -6427,14 +6483,25 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
part_elem->partition_name, name_variant,
TRUE))
DBUG_RETURN(TRUE);
- lex_string_set(&ddl_log_entry.name, tmp_path);
+ switch (convert_action)
+ {
+ case ACT_CONVERT_OUT:
+ ddl_log_entry.from_name= { from_name, strlen(from_name) };
+ /* fall through */
+ case ACT_DROP:
+ ddl_log_entry.name= { tmp_path, strlen(tmp_path) };
+ break;
+ case ACT_CONVERT_IN:
+ ddl_log_entry.name= { from_name, strlen(from_name) };
+ ddl_log_entry.from_name= { tmp_path, strlen(tmp_path) };
+ }
if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
{
DBUG_RETURN(TRUE);
}
*next_entry= log_entry->entry_pos;
part_elem->log_entry= log_entry;
- insert_part_info_log_entry_list(part_info, log_entry);
+ ddl_log_add_entry(part_info, log_entry);
}
}
}
@@ -6442,21 +6509,37 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
}
-/*
- Set execute log entry in ddl log for this partitioned table
- SYNOPSIS
- set_part_info_exec_log_entry()
- part_info Partition info object
- exec_log_entry Log entry
- RETURN VALUES
- NONE
-*/
-
-static void set_part_info_exec_log_entry(partition_info *part_info,
- DDL_LOG_MEMORY_ENTRY *exec_log_entry)
+inline
+static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
+ uint *next_entry, const char *path,
+ bool temp_list)
{
- part_info->exec_log_entry= exec_log_entry;
- exec_log_entry->next_active_log_entry= NULL;
+ return log_drop_or_convert_action(lpt, next_entry, path, NULL, temp_list,
+ ACT_DROP);
+}
+
+inline
+static bool write_log_convert_partition(ALTER_PARTITION_PARAM_TYPE *lpt,
+ uint *next_entry, const char *path)
+{
+ char other_table[FN_REFLEN + 1];
+ const ulong f= lpt->alter_info->partition_flags;
+ DBUG_ASSERT((f & ALTER_PARTITION_CONVERT_IN) || (f & ALTER_PARTITION_CONVERT_OUT));
+ const log_action_enum convert_action= (f & ALTER_PARTITION_CONVERT_IN)
+ ? ACT_CONVERT_IN : ACT_CONVERT_OUT;
+ build_table_filename(other_table, sizeof(other_table) - 1, lpt->alter_ctx->new_db.str,
+ lpt->alter_ctx->new_name.str, "", 0);
+ DDL_LOG_MEMORY_ENTRY *main_entry= lpt->part_info->main_entry;
+ bool res= log_drop_or_convert_action(lpt, next_entry, path, other_table,
+ false, convert_action);
+ /*
+ NOTE: main_entry is "drop shadow frm", we have to keep it like this
+ because partitioning crash-safety disables it at install shadow FRM phase.
+ This is needed to avoid spurious drop action when the shadow frm is replaced
+ by the backup frm and there is nothing to drop.
+ */
+ lpt->part_info->main_entry= main_entry;
+ return res;
}
@@ -6464,10 +6547,9 @@ static void set_part_info_exec_log_entry(partition_info *part_info,
Write the log entry to ensure that the shadow frm file is removed at
crash.
SYNOPSIS
- write_log_drop_shadow_frm()
+ write_log_drop_frm()
lpt Struct containing parameters
- install_frm Should we log action to install shadow frm or should
- the action be to remove the shadow frm file.
+
RETURN VALUES
TRUE Error
FALSE Success
@@ -6476,36 +6558,53 @@ static void set_part_info_exec_log_entry(partition_info *part_info,
file and its corresponding handler file.
*/
-static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
+static bool write_log_drop_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
+ DDL_LOG_STATE *drop_chain)
{
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
- char shadow_path[FN_REFLEN + 1];
- DBUG_ENTER("write_log_drop_shadow_frm");
+ char path[FN_REFLEN + 1];
+ DBUG_ENTER("write_log_drop_frm");
+ const DDL_LOG_STATE *main_chain= lpt->part_info;
+ const bool drop_backup= (drop_chain != main_chain);
- build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
+ build_table_shadow_filename(path, sizeof(path) - 1, lpt, drop_backup);
mysql_mutex_lock(&LOCK_gdl);
- if (write_log_replace_delete_frm(lpt, 0UL, NULL,
- (const char*)shadow_path, FALSE))
+ if (ddl_log_delete_frm(drop_chain, (const char*)path))
goto error;
- log_entry= part_info->first_log_entry;
- if (ddl_log_write_execute_entry(log_entry->entry_pos,
- &exec_log_entry))
+
+ if (drop_backup && (lpt->alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN))
+ {
+ TABLE_LIST *table_from= lpt->table_list->next_local;
+ build_table_filename(path, sizeof(path) - 1, table_from->db.str,
+ table_from->table_name.str, "", 0);
+
+ if (ddl_log_delete_frm(drop_chain, (const char*) path))
+ goto error;
+ }
+
+ if (ddl_log_write_execute_entry(drop_chain->list->entry_pos,
+ drop_backup ?
+ main_chain->execute_entry->entry_pos : 0,
+ &drop_chain->execute_entry))
goto error;
mysql_mutex_unlock(&LOCK_gdl);
- set_part_info_exec_log_entry(part_info, exec_log_entry);
DBUG_RETURN(FALSE);
error:
- release_part_info_log_entries(part_info->first_log_entry);
+ release_part_info_log_entries(drop_chain->list);
mysql_mutex_unlock(&LOCK_gdl);
- part_info->first_log_entry= NULL;
+ drop_chain->list= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
+static inline
+bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ return write_log_drop_frm(lpt, lpt->part_info);
+}
+
+
/*
Log renaming of shadow frm to real frm name and dropping of old frm
SYNOPSIS
@@ -6523,20 +6622,20 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
{
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
+ DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->execute_entry;
char path[FN_REFLEN + 1];
char shadow_path[FN_REFLEN + 1];
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
+ DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
DBUG_ENTER("write_log_rename_frm");
- part_info->first_log_entry= NULL;
+ part_info->list= NULL;
build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
mysql_mutex_lock(&LOCK_gdl);
- if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
+ if (write_log_replace_frm(lpt, 0UL, shadow_path, path))
goto error;
- log_entry= part_info->first_log_entry;
- part_info->frm_log_entry= log_entry;
+ log_entry= part_info->list;
+ part_info->main_entry= log_entry;
if (ddl_log_write_execute_entry(log_entry->entry_pos,
&exec_log_entry))
goto error;
@@ -6545,10 +6644,10 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
DBUG_RETURN(FALSE);
error:
- release_part_info_log_entries(part_info->first_log_entry);
+ release_part_info_log_entries(part_info->list);
mysql_mutex_unlock(&LOCK_gdl);
- part_info->first_log_entry= old_first_log_entry;
- part_info->frm_log_entry= NULL;
+ part_info->list= old_first_log_entry;
+ part_info->main_entry= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
@@ -6573,25 +6672,25 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
{
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
+ DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->execute_entry;
char tmp_path[FN_REFLEN + 1];
char path[FN_REFLEN + 1];
uint next_entry= 0;
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
+ DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
DBUG_ENTER("write_log_drop_partition");
- part_info->first_log_entry= NULL;
+ part_info->list= NULL;
build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
mysql_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
goto error;
- if (write_log_replace_delete_frm(lpt, next_entry, (const char*)tmp_path,
- (const char*)path, TRUE))
+ if (write_log_replace_frm(lpt, next_entry, (const char*)tmp_path,
+ (const char*)path))
goto error;
- log_entry= part_info->first_log_entry;
- part_info->frm_log_entry= log_entry;
+ log_entry= part_info->list;
+ part_info->main_entry= log_entry;
if (ddl_log_write_execute_entry(log_entry->entry_pos,
&exec_log_entry))
goto error;
@@ -6600,15 +6699,44 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
DBUG_RETURN(FALSE);
error:
- release_part_info_log_entries(part_info->first_log_entry);
+ release_part_info_log_entries(part_info->list);
mysql_mutex_unlock(&LOCK_gdl);
- part_info->first_log_entry= old_first_log_entry;
- part_info->frm_log_entry= NULL;
+ part_info->list= old_first_log_entry;
+ part_info->main_entry= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
+static bool write_log_convert_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ partition_info *part_info= lpt->part_info;
+ char tmp_path[FN_REFLEN + 1];
+ char path[FN_REFLEN + 1];
+ uint next_entry= part_info->list ? part_info->list->entry_pos : 0;
+
+ build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
+ build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
+
+ mysql_mutex_lock(&LOCK_gdl);
+
+ if (write_log_convert_partition(lpt, &next_entry, (const char*)path))
+ goto error;
+ DBUG_ASSERT(next_entry == part_info->list->entry_pos);
+ if (ddl_log_write_execute_entry(part_info->list->entry_pos,
+ &part_info->execute_entry))
+ goto error;
+ mysql_mutex_unlock(&LOCK_gdl);
+ return false;
+
+error:
+ mysql_mutex_unlock(&LOCK_gdl);
+ part_info->main_entry= NULL;
+ my_error(ER_DDL_LOG_ERROR, MYF(0));
+ return true;
+}
+
+
/*
Write the log entries to ensure that the add partition command is not
executed at all if a crash before it has completed
@@ -6630,11 +6758,10 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
{
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
char tmp_path[FN_REFLEN + 1];
char path[FN_REFLEN + 1];
uint next_entry= 0;
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
+ DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
/* write_log_drop_shadow_frm(lpt) must have been run first */
DBUG_ASSERT(old_first_log_entry);
DBUG_ENTER("write_log_add_change_partition");
@@ -6649,20 +6776,18 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
goto error;
- log_entry= part_info->first_log_entry;
+ log_entry= part_info->list;
if (ddl_log_write_execute_entry(log_entry->entry_pos,
- /* Reuse the old execute ddl_log_entry */
- &exec_log_entry))
+ &part_info->execute_entry))
goto error;
mysql_mutex_unlock(&LOCK_gdl);
- set_part_info_exec_log_entry(part_info, exec_log_entry);
DBUG_RETURN(FALSE);
error:
- release_part_info_log_entries(part_info->first_log_entry);
+ release_part_info_log_entries(part_info->list);
mysql_mutex_unlock(&LOCK_gdl);
- part_info->first_log_entry= old_first_log_entry;
+ part_info->list= old_first_log_entry;
my_error(ER_DDL_LOG_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
@@ -6694,10 +6819,10 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
{
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
+ DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->execute_entry;
char path[FN_REFLEN + 1];
char shadow_path[FN_REFLEN + 1];
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
+ DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
uint next_entry= 0;
DBUG_ENTER("write_log_final_change_partition");
@@ -6705,7 +6830,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
Do not link any previous log entry.
Replace the revert operations with forced retry operations.
*/
- part_info->first_log_entry= NULL;
+ part_info->list= NULL;
build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
mysql_mutex_lock(&LOCK_gdl);
@@ -6715,10 +6840,10 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
lpt->alter_info->partition_flags &
ALTER_PARTITION_REORGANIZE))
goto error;
- if (write_log_replace_delete_frm(lpt, next_entry, shadow_path, path, TRUE))
+ if (write_log_replace_frm(lpt, next_entry, shadow_path, path))
goto error;
- log_entry= part_info->first_log_entry;
- part_info->frm_log_entry= log_entry;
+ log_entry= part_info->list;
+ part_info->main_entry= log_entry;
/* Overwrite the revert execute log entry with this retry execute entry */
if (ddl_log_write_execute_entry(log_entry->entry_pos,
&exec_log_entry))
@@ -6728,10 +6853,10 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
DBUG_RETURN(FALSE);
error:
- release_part_info_log_entries(part_info->first_log_entry);
+ release_part_info_log_entries(part_info->list);
mysql_mutex_unlock(&LOCK_gdl);
- part_info->first_log_entry= old_first_log_entry;
- part_info->frm_log_entry= NULL;
+ part_info->list= old_first_log_entry;
+ part_info->main_entry= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
@@ -6748,11 +6873,15 @@ error:
FALSE Success
*/
+/*
+ TODO: Partitioning atomic DDL refactoring: this should be replaced with
+ ddl_log_complete().
+*/
static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
bool dont_crash)
{
partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry;
+ DDL_LOG_MEMORY_ENTRY *log_entry= part_info->execute_entry;
DBUG_ENTER("write_log_completed");
DBUG_ASSERT(log_entry);
@@ -6768,11 +6897,11 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
*/
;
}
- release_part_info_log_entries(part_info->first_log_entry);
- release_part_info_log_entries(part_info->exec_log_entry);
+ release_part_info_log_entries(part_info->list);
+ release_part_info_log_entries(part_info->execute_entry);
mysql_mutex_unlock(&LOCK_gdl);
- part_info->exec_log_entry= NULL;
- part_info->first_log_entry= NULL;
+ part_info->execute_entry= NULL;
+ part_info->list= NULL;
DBUG_VOID_RETURN;
}
@@ -6786,14 +6915,18 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
NONE
*/
+/*
+ TODO: Partitioning atomic DDL refactoring: this should be replaced with
+ ddl_log_release_entries().
+*/
static void release_log_entries(partition_info *part_info)
{
mysql_mutex_lock(&LOCK_gdl);
- release_part_info_log_entries(part_info->first_log_entry);
- release_part_info_log_entries(part_info->exec_log_entry);
+ release_part_info_log_entries(part_info->list);
+ release_part_info_log_entries(part_info->execute_entry);
mysql_mutex_unlock(&LOCK_gdl);
- part_info->first_log_entry= NULL;
- part_info->exec_log_entry= NULL;
+ part_info->list= NULL;
+ part_info->execute_entry= NULL;
}
@@ -6859,6 +6992,10 @@ static int alter_close_table(ALTER_PARTITION_PARAM_TYPE *lpt)
@param close_table Table is still open, close it before reverting
*/
+/*
+ TODO: Partitioning atomic DDL refactoring: this should be replaced with
+ correct combination of ddl_log_revert() / ddl_log_complete()
+*/
static void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
bool action_completed,
bool drop_partition,
@@ -6906,8 +7043,8 @@ static void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
}
- if (part_info->first_log_entry &&
- ddl_log_execute_entry(thd, part_info->first_log_entry->entry_pos))
+ if (part_info->list &&
+ ddl_log_execute_entry(thd, part_info->list->entry_pos))
{
/*
We couldn't recover from error, most likely manual interaction
@@ -7069,6 +7206,64 @@ bool log_partition_alter_to_ddl_log(ALTER_PARTITION_PARAM_TYPE *lpt)
}
+extern bool alter_partition_convert_in(ALTER_PARTITION_PARAM_TYPE *lpt);
+
+/**
+ Check that definition of source table fits definition of partition being
+ added and every row stored in the table conforms partition's expression.
+
+ @param lpt Structure containing parameters required for checking
+ @param[in,out] part_file_name_buf Buffer for storing a partition name
+ @param part_file_name_buf_sz Size of buffer for storing a partition name
+ @param part_file_name_len Length of partition prefix stored in the buffer
+ on invocation of function
+
+ @return false on success, true on error
+*/
+
+static bool check_table_data(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ /*
+ TODO: if destination is partitioned by range(X) and source is indexed by X
+ then just get min(X) and max(X) from index.
+ */
+ THD *thd= lpt->thd;
+ TABLE *table_to= lpt->table_list->table;
+ TABLE *table_from= lpt->table_list->next_local->table;
+
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ table_to->s->db.str,
+ table_to->s->table_name.str,
+ MDL_EXCLUSIVE));
+
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ table_from->s->db.str,
+ table_from->s->table_name.str,
+ MDL_EXCLUSIVE));
+
+ uint32 new_part_id;
+ partition_element *part_elem;
+ const char* partition_name= thd->lex->part_info->curr_part_elem->partition_name;
+ part_elem= table_to->part_info->get_part_elem(partition_name,
+ nullptr, 0, &new_part_id);
+ if (unlikely(!part_elem))
+ return true;
+
+ if (unlikely(new_part_id == NOT_A_PARTITION_ID))
+ {
+ DBUG_ASSERT(table_to->part_info->is_sub_partitioned());
+ my_error(ER_PARTITION_INSTEAD_OF_SUBPARTITION, MYF(0));
+ return true;
+ }
+
+ if (verify_data_with_partition(table_from, table_to, new_part_id))
+ {
+ return true;
+ }
+
+ return false;
+}
+
/**
Actually perform the change requested by ALTER TABLE of partitions
@@ -7093,11 +7288,23 @@ bool log_partition_alter_to_ddl_log(ALTER_PARTITION_PARAM_TYPE *lpt)
uint fast_alter_partition_table(THD *thd, TABLE *table,
Alter_info *alter_info,
+ Alter_table_ctx *alter_ctx,
HA_CREATE_INFO *create_info,
- TABLE_LIST *table_list,
- const LEX_CSTRING *db,
- const LEX_CSTRING *table_name)
+ TABLE_LIST *table_list)
{
+ /*
+ TODO: Partitioning atomic DDL refactoring.
+
+ DDL log chain state is stored in partition_info:
+
+ struct st_ddl_log_memory_entry *first_log_entry;
+ struct st_ddl_log_memory_entry *exec_log_entry;
+ struct st_ddl_log_memory_entry *frm_log_entry;
+
+ Make it stored and used in DDL_LOG_STATE like it was done in MDEV-17567.
+ This requires mysql_write_frm() refactoring (see comment there).
+ */
+
/* Set-up struct used to write frm files */
partition_info *part_info;
ALTER_PARTITION_PARAM_TYPE lpt_obj;
@@ -7115,13 +7322,14 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
lpt->table_list= table_list;
lpt->part_info= part_info;
lpt->alter_info= alter_info;
+ lpt->alter_ctx= alter_ctx;
lpt->create_info= create_info;
lpt->db_options= create_info->table_options_with_row_type();
lpt->table= table;
lpt->key_info_buffer= 0;
lpt->key_count= 0;
- lpt->db= *db;
- lpt->table_name= *table_name;
+ lpt->db= alter_ctx->db;
+ lpt->table_name= alter_ctx->table_name;
lpt->org_tabledef_version= table->s->tabledef_version;
lpt->copied= 0;
lpt->deleted= 0;
@@ -7241,38 +7449,29 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
to test if recovery is properly done.
*/
if (write_log_drop_shadow_frm(lpt) ||
- ERROR_INJECT_CRASH("crash_drop_partition_1") ||
- ERROR_INJECT_ERROR("fail_drop_partition_1") ||
+ ERROR_INJECT("drop_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
- ERROR_INJECT_CRASH("crash_drop_partition_2") ||
- ERROR_INJECT_ERROR("fail_drop_partition_2") ||
+ ERROR_INJECT("drop_partition_2") ||
wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
- ERROR_INJECT_CRASH("crash_drop_partition_3") ||
- ERROR_INJECT_ERROR("fail_drop_partition_3") ||
+ ERROR_INJECT("drop_partition_3") ||
write_log_drop_partition(lpt) ||
(action_completed= TRUE, FALSE) ||
- ERROR_INJECT_CRASH("crash_drop_partition_4") ||
- ERROR_INJECT_ERROR("fail_drop_partition_4") ||
+ ERROR_INJECT("drop_partition_4") ||
alter_close_table(lpt) ||
- ERROR_INJECT_CRASH("crash_drop_partition_5") ||
- ERROR_INJECT_ERROR("fail_drop_partition_5") ||
- ERROR_INJECT_CRASH("crash_drop_partition_6") ||
- ERROR_INJECT_ERROR("fail_drop_partition_6") ||
+ ERROR_INJECT("drop_partition_5") ||
+ ERROR_INJECT("drop_partition_6") ||
(frm_install= TRUE, FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
log_partition_alter_to_ddl_log(lpt) ||
(frm_install= FALSE, FALSE) ||
- ERROR_INJECT_CRASH("crash_drop_partition_7") ||
- ERROR_INJECT_ERROR("fail_drop_partition_7") ||
+ ERROR_INJECT("drop_partition_7") ||
mysql_drop_partitions(lpt) ||
- ERROR_INJECT_CRASH("crash_drop_partition_8") ||
- ERROR_INJECT_ERROR("fail_drop_partition_8") ||
+ ERROR_INJECT("drop_partition_8") ||
(write_log_completed(lpt, FALSE), FALSE) ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query(), thd->query_length()), FALSE)) ||
- ERROR_INJECT_CRASH("crash_drop_partition_9") ||
- ERROR_INJECT_ERROR("fail_drop_partition_9"))
+ ERROR_INJECT("drop_partition_9"))
{
handle_alter_part_error(lpt, action_completed, TRUE, frm_install);
goto err;
@@ -7280,10 +7479,102 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
if (alter_partition_lock_handling(lpt))
goto err;
}
+ else if (alter_info->partition_flags & ALTER_PARTITION_CONVERT_OUT)
+ {
+ DDL_LOG_STATE chain_drop_backup;
+ bzero(&chain_drop_backup, sizeof(chain_drop_backup));
+
+ if (mysql_write_frm(lpt, WFRM_WRITE_CONVERTED_TO) ||
+ ERROR_INJECT("convert_partition_1") ||
+ write_log_drop_shadow_frm(lpt) ||
+ ERROR_INJECT("convert_partition_2") ||
+ mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
+ ERROR_INJECT("convert_partition_3") ||
+ wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
+ ERROR_INJECT("convert_partition_4") ||
+ write_log_convert_partition(lpt) ||
+ ERROR_INJECT("convert_partition_5") ||
+ alter_close_table(lpt) ||
+ ERROR_INJECT("convert_partition_6") ||
+ alter_partition_convert_out(lpt) ||
+ ERROR_INJECT("convert_partition_7") ||
+ write_log_drop_frm(lpt, &chain_drop_backup) ||
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
+ log_partition_alter_to_ddl_log(lpt) ||
+ ERROR_INJECT("convert_partition_8") ||
+ ((!thd->lex->no_write_to_binlog) &&
+ ((thd->binlog_xid= thd->query_id),
+ ddl_log_update_xid(lpt->part_info, thd->binlog_xid),
+ write_bin_log(thd, false, thd->query(), thd->query_length()),
+ (thd->binlog_xid= 0))) ||
+ ERROR_INJECT("convert_partition_9"))
+ {
+ ddl_log_complete(&chain_drop_backup);
+ (void) ddl_log_revert(thd, lpt->part_info);
+ handle_alter_part_error(lpt, true, true, false);
+ goto err;
+ }
+ ddl_log_complete(lpt->part_info);
+ ERROR_INJECT("convert_partition_10");
+ (void) ddl_log_revert(thd, &chain_drop_backup);
+ if (alter_partition_lock_handling(lpt) ||
+ ERROR_INJECT("convert_partition_11"))
+ goto err;
+ }
+ else if ((alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN))
+ {
+ DDL_LOG_STATE chain_drop_backup;
+ bzero(&chain_drop_backup, sizeof(chain_drop_backup));
+ TABLE *table_from= table_list->next_local->table;
+
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
+ wait_while_table_is_used(thd, table_from, HA_EXTRA_PREPARE_FOR_RENAME) ||
+ ERROR_INJECT("convert_partition_1") ||
+ compare_table_with_partition(thd, table_from, table, NULL, 0) ||
+ ERROR_INJECT("convert_partition_2") ||
+ check_table_data(lpt))
+ goto err;
+
+ if (write_log_drop_shadow_frm(lpt) ||
+ ERROR_INJECT("convert_partition_3") ||
+ mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
+ ERROR_INJECT("convert_partition_4") ||
+ alter_close_table(lpt) ||
+ ERROR_INJECT("convert_partition_5") ||
+ write_log_convert_partition(lpt) ||
+ ERROR_INJECT("convert_partition_6") ||
+ alter_partition_convert_in(lpt) ||
+ ERROR_INJECT("convert_partition_7") ||
+ (frm_install= true, false) ||
+ write_log_drop_frm(lpt, &chain_drop_backup) ||
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
+ log_partition_alter_to_ddl_log(lpt) ||
+ (frm_install= false, false) ||
+ ERROR_INJECT("convert_partition_8") ||
+ ((!thd->lex->no_write_to_binlog) &&
+ ((thd->binlog_xid= thd->query_id),
+ ddl_log_update_xid(lpt->part_info, thd->binlog_xid),
+ write_bin_log(thd, false, thd->query(), thd->query_length()),
+ (thd->binlog_xid= 0))) ||
+ ERROR_INJECT("convert_partition_9"))
+ {
+ ddl_log_complete(&chain_drop_backup);
+ (void) ddl_log_revert(thd, lpt->part_info);
+ handle_alter_part_error(lpt, true, true, false);
+ goto err;
+ }
+ ddl_log_complete(lpt->part_info);
+ ERROR_INJECT("convert_partition_10");
+ (void) ddl_log_revert(thd, &chain_drop_backup);
+ if (alter_partition_lock_handling(lpt) ||
+ ERROR_INJECT("convert_partition_11"))
+ goto err;
+ }
else if ((alter_info->partition_flags & ALTER_PARTITION_ADD) &&
(part_info->part_type == RANGE_PARTITION ||
part_info->part_type == LIST_PARTITION))
{
+ DBUG_ASSERT(!(alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN));
/*
ADD RANGE/LIST PARTITIONS
In this case there are no tuples removed and no tuples are added.
@@ -7315,41 +7606,31 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
12)Complete query
*/
if (write_log_drop_shadow_frm(lpt) ||
- ERROR_INJECT_CRASH("crash_add_partition_1") ||
- ERROR_INJECT_ERROR("fail_add_partition_1") ||
+ ERROR_INJECT("add_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
- ERROR_INJECT_CRASH("crash_add_partition_2") ||
- ERROR_INJECT_ERROR("fail_add_partition_2") ||
+ ERROR_INJECT("add_partition_2") ||
wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
- ERROR_INJECT_CRASH("crash_add_partition_3") ||
- ERROR_INJECT_ERROR("fail_add_partition_3") ||
+ ERROR_INJECT("add_partition_3") ||
write_log_add_change_partition(lpt) ||
- ERROR_INJECT_CRASH("crash_add_partition_4") ||
- ERROR_INJECT_ERROR("fail_add_partition_4") ||
+ ERROR_INJECT("add_partition_4") ||
mysql_change_partitions(lpt) ||
- ERROR_INJECT_CRASH("crash_add_partition_5") ||
- ERROR_INJECT_ERROR("fail_add_partition_5") ||
+ ERROR_INJECT("add_partition_5") ||
alter_close_table(lpt) ||
- ERROR_INJECT_CRASH("crash_add_partition_6") ||
- ERROR_INJECT_ERROR("fail_add_partition_6") ||
- ERROR_INJECT_CRASH("crash_add_partition_7") ||
- ERROR_INJECT_ERROR("fail_add_partition_7") ||
+ ERROR_INJECT("add_partition_6") ||
+ ERROR_INJECT("add_partition_7") ||
write_log_rename_frm(lpt) ||
(action_completed= TRUE, FALSE) ||
- ERROR_INJECT_CRASH("crash_add_partition_8") ||
- ERROR_INJECT_ERROR("fail_add_partition_8") ||
+ ERROR_INJECT("add_partition_8") ||
(frm_install= TRUE, FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
log_partition_alter_to_ddl_log(lpt) ||
(frm_install= FALSE, FALSE) ||
- ERROR_INJECT_CRASH("crash_add_partition_9") ||
- ERROR_INJECT_ERROR("fail_add_partition_9") ||
+ ERROR_INJECT("add_partition_9") ||
(write_log_completed(lpt, FALSE), FALSE) ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query(), thd->query_length()), FALSE)) ||
- ERROR_INJECT_CRASH("crash_add_partition_10") ||
- ERROR_INJECT_ERROR("fail_add_partition_10"))
+ ERROR_INJECT("add_partition_10"))
{
handle_alter_part_error(lpt, action_completed, FALSE, frm_install);
goto err;
@@ -7414,47 +7695,35 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
13) Complete query.
*/
if (write_log_drop_shadow_frm(lpt) ||
- ERROR_INJECT_CRASH("crash_change_partition_1") ||
- ERROR_INJECT_ERROR("fail_change_partition_1") ||
+ ERROR_INJECT("change_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
- ERROR_INJECT_CRASH("crash_change_partition_2") ||
- ERROR_INJECT_ERROR("fail_change_partition_2") ||
+ ERROR_INJECT("change_partition_2") ||
write_log_add_change_partition(lpt) ||
- ERROR_INJECT_CRASH("crash_change_partition_3") ||
- ERROR_INJECT_ERROR("fail_change_partition_3") ||
+ ERROR_INJECT("change_partition_3") ||
mysql_change_partitions(lpt) ||
- ERROR_INJECT_CRASH("crash_change_partition_4") ||
- ERROR_INJECT_ERROR("fail_change_partition_4") ||
+ ERROR_INJECT("change_partition_4") ||
wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
- ERROR_INJECT_CRASH("crash_change_partition_5") ||
- ERROR_INJECT_ERROR("fail_change_partition_5") ||
+ ERROR_INJECT("change_partition_5") ||
alter_close_table(lpt) ||
- ERROR_INJECT_CRASH("crash_change_partition_6") ||
- ERROR_INJECT_ERROR("fail_change_partition_6") ||
+ ERROR_INJECT("change_partition_6") ||
write_log_final_change_partition(lpt) ||
(action_completed= TRUE, FALSE) ||
- ERROR_INJECT_CRASH("crash_change_partition_7") ||
- ERROR_INJECT_ERROR("fail_change_partition_7") ||
- ERROR_INJECT_CRASH("crash_change_partition_8") ||
- ERROR_INJECT_ERROR("fail_change_partition_8") ||
+ ERROR_INJECT("change_partition_7") ||
+ ERROR_INJECT("change_partition_8") ||
((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
log_partition_alter_to_ddl_log(lpt) ||
(frm_install= FALSE, FALSE) ||
- ERROR_INJECT_CRASH("crash_change_partition_9") ||
- ERROR_INJECT_ERROR("fail_change_partition_9") ||
+ ERROR_INJECT("change_partition_9") ||
mysql_drop_partitions(lpt) ||
- ERROR_INJECT_CRASH("crash_change_partition_10") ||
- ERROR_INJECT_ERROR("fail_change_partition_10") ||
+ ERROR_INJECT("change_partition_10") ||
mysql_rename_partitions(lpt) ||
- ERROR_INJECT_CRASH("crash_change_partition_11") ||
- ERROR_INJECT_ERROR("fail_change_partition_11") ||
+ ERROR_INJECT("change_partition_11") ||
(write_log_completed(lpt, FALSE), FALSE) ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query(), thd->query_length()), FALSE)) ||
- ERROR_INJECT_CRASH("crash_change_partition_12") ||
- ERROR_INJECT_ERROR("fail_change_partition_12"))
+ ERROR_INJECT("change_partition_12"))
{
handle_alter_part_error(lpt, action_completed, FALSE, frm_install);
goto err;
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 57e6d0600ed..a90eaae0bae 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -55,6 +55,7 @@ typedef struct st_lock_param_type
THD *thd;
HA_CREATE_INFO *create_info;
Alter_info *alter_info;
+ Alter_table_ctx *alter_ctx;
TABLE *table;
KEY *key_info_buffer;
LEX_CSTRING db;
@@ -64,6 +65,7 @@ typedef struct st_lock_param_type
uint key_count;
uint db_options;
size_t pack_frm_len;
+ // TODO: remove duplicate data: part_info can be accessed via table->part_info
partition_info *part_info;
} ALTER_PARTITION_PARAM_TYPE;
@@ -255,10 +257,9 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
#ifdef WITH_PARTITION_STORAGE_ENGINE
uint fast_alter_partition_table(THD *thd, TABLE *table,
Alter_info *alter_info,
+ Alter_table_ctx *alter_ctx,
HA_CREATE_INFO *create_info,
- TABLE_LIST *table_list,
- const LEX_CSTRING *db,
- const LEX_CSTRING *table_name);
+ TABLE_LIST *table_list);
bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
enum partition_state part_state);
uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
@@ -278,7 +279,16 @@ bool verify_data_with_partition(TABLE *table, TABLE *part_table,
uint32 part_id);
bool compare_partition_options(HA_CREATE_INFO *table_create_info,
partition_element *part_elem);
+bool compare_table_with_partition(THD *thd, TABLE *table,
+ TABLE *part_table,
+ partition_element *part_elem,
+ uint part_id);
bool partition_key_modified(TABLE *table, const MY_BITMAP *fields);
+bool write_log_replace_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
+ uint next_entry,
+ const char *from_path,
+ const char *to_path);
+
#else
#define partition_key_modified(X,Y) 0
#endif
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 1056998ef08..fb1ae0d5fc7 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -192,10 +192,8 @@ static bool check_exchange_partition(TABLE *table, TABLE *part_table)
@param part_table Partitioned table.
@param part_elem Partition element to use for partition specific compare.
*/
-static bool compare_table_with_partition(THD *thd, TABLE *table,
- TABLE *part_table,
- partition_element *part_elem,
- uint part_id)
+bool compare_table_with_partition(THD *thd, TABLE *table, TABLE *part_table,
+ partition_element *part_elem, uint part_id)
{
HA_CREATE_INFO table_create_info, part_create_info;
Alter_info part_alter_info;
@@ -292,7 +290,7 @@ static bool compare_table_with_partition(THD *thd, TABLE *table,
The workaround is to use REORGANIZE PARTITION to rewrite
the frm file and then use EXCHANGE PARTITION when they are the same.
*/
- if (compare_partition_options(&table_create_info, part_elem))
+ if (part_elem && compare_partition_options(&table_create_info, part_elem))
DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE);
@@ -988,4 +986,53 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
DBUG_RETURN(error);
}
+
+/**
+ Move a table specified in the CONVERT TABLE <table_name> TO PARTITION ...
+ to the new partition.
+
+ @param lpt A structure containing parameters regarding to the statement
+ ALTER TABLE ... TO PARTITION ...
+ @param part_file_name a file name of the partition being added
+
+ @return false on success, true on error
+*/
+
+bool alter_partition_convert_in(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ char part_file_name[2*FN_REFLEN+1];
+ THD *thd= lpt->thd;
+ const char *path= lpt->table_list->table->s->path.str;
+ TABLE_LIST *table_from= lpt->table_list->next_local;
+
+ const char *partition_name=
+ thd->lex->part_info->curr_part_elem->partition_name;
+
+ if (create_partition_name(part_file_name, sizeof(part_file_name), path,
+ partition_name, NORMAL_PART_NAME, false))
+ return true;
+
+ char from_file_name[FN_REFLEN+1];
+
+ build_table_filename(from_file_name, sizeof(from_file_name),
+ table_from->db.str, table_from->table_name.str, "", 0);
+
+ handler *file= get_new_handler(nullptr, thd->mem_root,
+ table_from->table->file->ht);
+ if (unlikely(!file))
+ return true;
+
+ close_all_tables_for_name(thd, table_from->table->s,
+ HA_EXTRA_PREPARE_FOR_RENAME, nullptr);
+
+ bool res= file->ha_rename_table(from_file_name, part_file_name);
+
+ if (res)
+ my_error(ER_ERROR_ON_RENAME, MYF(0), from_file_name,
+ part_file_name, my_errno);
+
+ delete file;
+ return res;
+}
+
#endif /* WITH_PARTITION_STORAGE_ENGINE */
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index ab13e8cc569..e3ddd14fe6a 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -456,7 +456,7 @@ static int item_val_real(struct st_mysql_value *value, double *buf)
static struct st_plugin_dl *plugin_dl_find(const LEX_CSTRING *dl)
{
- uint i;
+ size_t i;
struct st_plugin_dl *tmp;
DBUG_ENTER("plugin_dl_find");
for (i= 0; i < plugin_dl_array.elements; i++)
@@ -473,7 +473,7 @@ static struct st_plugin_dl *plugin_dl_find(const LEX_CSTRING *dl)
static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
{
- uint i;
+ size_t i;
struct st_plugin_dl *tmp;
DBUG_ENTER("plugin_dl_insert_or_reuse");
for (i= 0; i < plugin_dl_array.elements; i++)
@@ -1068,6 +1068,8 @@ plugin_ref plugin_lock_by_name(THD *thd, const LEX_CSTRING *name, int type)
plugin_ref rc= NULL;
st_plugin_int *plugin;
DBUG_ENTER("plugin_lock_by_name");
+ if (!name->length)
+ DBUG_RETURN(NULL);
mysql_mutex_lock(&LOCK_plugin);
if ((plugin= plugin_find_internal(name, type)))
rc= intern_plugin_lock(lex, plugin_int_to_ref(plugin));
@@ -1078,7 +1080,7 @@ plugin_ref plugin_lock_by_name(THD *thd, const LEX_CSTRING *name, int type)
static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
{
- uint i;
+ size_t i;
struct st_plugin_int *tmp;
DBUG_ENTER("plugin_insert_or_reuse");
for (i= 0; i < plugin_array.elements; i++)
@@ -1261,24 +1263,18 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
remove_status_vars(show_vars);
}
- if (plugin_type_deinitialize[plugin->plugin->type])
- {
- if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin))
- {
- sql_print_error("Plugin '%s' of type %s failed deinitialization",
- plugin->name.str, plugin_type_names[plugin->plugin->type].str);
- }
- }
- else if (plugin->plugin->deinit)
+ plugin_type_init deinit= plugin_type_deinitialize[plugin->plugin->type];
+ if (!deinit)
+ deinit= (plugin_type_init)(plugin->plugin->deinit);
+
+ if (deinit && deinit(plugin))
{
- DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
- if (plugin->plugin->deinit(plugin))
- {
- DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
- plugin->name.str));
- }
+ if (THD *thd= current_thd)
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ WARN_PLUGIN_BUSY, ER_THD(thd, WARN_PLUGIN_BUSY));
}
- plugin->state= PLUGIN_IS_UNINITIALIZED;
+ else
+ plugin->state= PLUGIN_IS_UNINITIALIZED; // free to unload
if (ref_check && plugin->ref_count)
sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
@@ -1286,10 +1282,13 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
plugin_variables_deinit(plugin);
}
-static void plugin_del(struct st_plugin_int *plugin)
+static void plugin_del(struct st_plugin_int *plugin, uint del_mask)
{
DBUG_ENTER("plugin_del");
mysql_mutex_assert_owner(&LOCK_plugin);
+ del_mask|= PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_DISABLED; // always use these
+ if (!(plugin->state & del_mask))
+ DBUG_VOID_RETURN;
/* Free allocated strings before deleting the plugin. */
plugin_vars_free_values(plugin->system_vars);
restore_ptr_backup(plugin->nbackups, plugin->ptr_backup);
@@ -1307,7 +1306,7 @@ static void plugin_del(struct st_plugin_int *plugin)
static void reap_plugins(void)
{
- uint count;
+ size_t count;
struct st_plugin_int *plugin, **reap, **list;
mysql_mutex_assert_owner(&LOCK_plugin);
@@ -1339,19 +1338,19 @@ static void reap_plugins(void)
list= reap;
while ((plugin= *(--list)))
- plugin_deinitialize(plugin, true);
+ plugin_deinitialize(plugin, true);
mysql_mutex_lock(&LOCK_plugin);
while ((plugin= *(--reap)))
- plugin_del(plugin);
+ plugin_del(plugin, 0);
my_afree(reap);
}
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
{
- int i;
+ ssize_t i;
st_plugin_int *pi;
DBUG_ENTER("intern_plugin_unlock");
@@ -1417,7 +1416,7 @@ void plugin_unlock(THD *thd, plugin_ref plugin)
}
-void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
+void plugin_unlock_list(THD *thd, plugin_ref *list, size_t count)
{
LEX *lex= thd ? thd->lex : 0;
DBUG_ENTER("plugin_unlock_list");
@@ -1590,7 +1589,7 @@ static void init_plugin_psi_keys(void) {}
*/
int plugin_init(int *argc, char **argv, int flags)
{
- uint i;
+ size_t i;
struct st_maria_plugin **builtins;
struct st_maria_plugin *plugin;
struct st_plugin_int tmp, *plugin_ptr, **reap;
@@ -1782,7 +1781,7 @@ int plugin_init(int *argc, char **argv, int flags)
reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true);
mysql_mutex_lock(&LOCK_plugin);
- plugin_del(plugin_ptr);
+ plugin_del(plugin_ptr, 0);
}
mysql_mutex_unlock(&LOCK_plugin);
@@ -2021,7 +2020,7 @@ error:
void plugin_shutdown(void)
{
- uint i, count= plugin_array.elements;
+ size_t i, count= plugin_array.elements;
struct st_plugin_int **plugins, *plugin;
struct st_plugin_dl **dl;
DBUG_ENTER("plugin_shutdown");
@@ -2070,12 +2069,14 @@ void plugin_shutdown(void)
plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1));
/*
- If we have any plugins which did not die cleanly, we force shutdown
+ If we have any plugins which did not die cleanly, we force shutdown.
+ Don't re-deinit() plugins that failed deinit() earlier (already dying)
*/
for (i= 0; i < count; i++)
{
plugins[i]= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
- /* change the state to ensure no reaping races */
+ if (plugins[i]->state == PLUGIN_IS_DYING)
+ plugins[i]->state= PLUGIN_IS_UNINITIALIZED;
if (plugins[i]->state == PLUGIN_IS_DELETED)
plugins[i]->state= PLUGIN_IS_DYING;
}
@@ -2111,9 +2112,7 @@ void plugin_shutdown(void)
if (plugins[i]->ref_count)
sql_print_error("Plugin '%s' has ref_count=%d after shutdown.",
plugins[i]->name.str, plugins[i]->ref_count);
- if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED ||
- plugins[i]->state & PLUGIN_IS_DISABLED)
- plugin_del(plugins[i]);
+ plugin_del(plugins[i], PLUGIN_IS_DYING);
}
/*
@@ -2352,7 +2351,7 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name)
of the delete from the plugin table, so that it is not replicated in
row based mode.
*/
- table->file->row_logging= 0; // No logging
+ table->file->row_logging= 0; // No logging
error= table->file->ha_delete_row(table->record[0]);
if (unlikely(error))
{
@@ -2465,7 +2464,7 @@ wsrep_error_label:
bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
int type, uint state_mask, void *arg)
{
- uint idx, total= 0;
+ size_t idx, total= 0;
struct st_plugin_int *plugin;
plugin_ref *plugins;
my_bool res= FALSE;
@@ -3316,7 +3315,7 @@ static void cleanup_variables(struct system_variables *vars)
void plugin_thdvar_cleanup(THD *thd)
{
- uint idx;
+ size_t idx;
plugin_ref *list;
DBUG_ENTER("plugin_thdvar_cleanup");
@@ -4300,7 +4299,7 @@ void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root)
if (!initialized)
return;
- for (uint idx= 0; idx < plugin_array.elements; idx++)
+ for (size_t idx= 0; idx < plugin_array.elements; idx++)
{
p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
@@ -4407,7 +4406,7 @@ int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value)
DBUG_ASSERT(key != INVALID_THD_KEY);
if (key == INVALID_THD_KEY || (!thd && !(thd= current_thd)))
return EINVAL;
-
+
memcpy(intern_sys_var_ptr(thd, key, true), &value, sizeof(void*));
return 0;
}
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index eaf0b40f34a..d4df8c6468f 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -172,7 +172,7 @@ extern plugin_ref plugin_lock(THD *thd, plugin_ref ptr);
extern plugin_ref plugin_lock_by_name(THD *thd, const LEX_CSTRING *name,
int type);
extern void plugin_unlock(THD *thd, plugin_ref plugin);
-extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count);
+extern void plugin_unlock_list(THD *thd, plugin_ref *list, size_t count);
extern bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
const LEX_CSTRING *dl);
extern bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index c6f07158003..3dd41ffbed9 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -216,7 +216,7 @@ static struct my_print_error_service_st my_print_error_handler=
my_printv_error
};
-struct json_service_st json_handler=
+static struct json_service_st json_handler=
{
json_type,
json_get_array_item,
@@ -231,6 +231,92 @@ static struct thd_mdl_service_st thd_mdl_handler=
thd_mdl_context
};
+struct sql_service_st sql_service_handler=
+{
+ mysql_init,
+ mysql_real_connect_local,
+ mysql_real_connect,
+ mysql_errno,
+ mysql_error,
+ mysql_real_query,
+ mysql_affected_rows,
+ mysql_num_rows,
+ mysql_store_result,
+ mysql_free_result,
+ mysql_fetch_row,
+ mysql_close,
+};
+
+#define DEFINE_warning_function(name, ret) { \
+ static query_id_t last_query_id= -1; \
+ THD *thd= current_thd; \
+ if((thd ? thd->query_id : 0) != last_query_id) \
+ { \
+ my_error(ER_PROVIDER_NOT_LOADED, MYF(ME_ERROR_LOG|ME_WARNING), name); \
+ last_query_id= thd ? thd->query_id : 0; \
+ } \
+ return ret; \
+}
+
+#include <providers/lzma.h>
+static struct provider_service_lzma_st provider_handler_lzma=
+{
+ DEFINE_lzma_stream_buffer_decode([]) DEFINE_warning_function("LZMA compression", LZMA_PROG_ERROR),
+ DEFINE_lzma_easy_buffer_encode([]) DEFINE_warning_function("LZMA compression", LZMA_PROG_ERROR),
+
+ false // .is_loaded
+};
+struct provider_service_lzma_st *provider_service_lzma= &provider_handler_lzma;
+
+#include <providers/lzo/lzo1x.h>
+static struct provider_service_lzo_st provider_handler_lzo=
+{
+ DEFINE_lzo1x_1_15_compress([]) DEFINE_warning_function("LZO compression", LZO_E_INTERNAL_ERROR),
+ DEFINE_lzo1x_decompress_safe([]) DEFINE_warning_function("LZO compression", LZO_E_INTERNAL_ERROR),
+
+ false // .is_loaded
+};
+struct provider_service_lzo_st *provider_service_lzo= &provider_handler_lzo;
+
+#include <providers/bzlib.h>
+static struct provider_service_bzip2_st provider_handler_bzip2=
+{
+ DEFINE_BZ2_bzBuffToBuffCompress([]) DEFINE_warning_function("BZip2 compression", -1),
+ DEFINE_BZ2_bzBuffToBuffDecompress([]) DEFINE_warning_function("BZip2 compression", -1),
+ DEFINE_BZ2_bzCompress([]) DEFINE_warning_function("BZip2 compression", -1),
+ DEFINE_BZ2_bzCompressEnd([]) DEFINE_warning_function("BZip2 compression", -1),
+ DEFINE_BZ2_bzCompressInit([]) DEFINE_warning_function("BZip2 compression", -1),
+ DEFINE_BZ2_bzDecompress([]) DEFINE_warning_function("BZip2 compression", -1),
+ DEFINE_BZ2_bzDecompressEnd([]) DEFINE_warning_function("BZip2 compression", -1),
+ DEFINE_BZ2_bzDecompressInit([]) DEFINE_warning_function("BZip2 compression", -1),
+
+ false // .is_loaded
+};
+struct provider_service_bzip2_st *provider_service_bzip2= &provider_handler_bzip2;
+
+#include <providers/snappy-c.h>
+static struct provider_service_snappy_st provider_handler_snappy=
+{
+ DEFINE_snappy_max_compressed_length([]) -> size_t DEFINE_warning_function("Snappy compression", 0),
+ DEFINE_snappy_compress([]) DEFINE_warning_function("Snappy compression", SNAPPY_INVALID_INPUT),
+ DEFINE_snappy_uncompressed_length([]) DEFINE_warning_function("Snappy compression", SNAPPY_INVALID_INPUT),
+ DEFINE_snappy_uncompress([]) DEFINE_warning_function("Snappy compression", SNAPPY_INVALID_INPUT),
+
+ false // .is_loaded
+};
+struct provider_service_snappy_st *provider_service_snappy= &provider_handler_snappy;
+
+#include <providers/lz4.h>
+static struct provider_service_lz4_st provider_handler_lz4=
+{
+ DEFINE_LZ4_compressBound([]) DEFINE_warning_function("LZ4 compression", 0),
+ DEFINE_LZ4_compress_default([]) DEFINE_warning_function("LZ4 compression", 0),
+ DEFINE_LZ4_decompress_safe([]) DEFINE_warning_function("LZ4 compression", -1),
+
+ false // .is_loaded
+};
+struct provider_service_lz4_st *provider_service_lz4= &provider_handler_lz4;
+
static struct st_service_ref list_of_services[]=
{
{ "base64_service", VERSION_base64, &base64_handler },
@@ -255,5 +341,11 @@ static struct st_service_ref list_of_services[]=
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "wsrep_service", VERSION_wsrep, &wsrep_handler },
{ "json_service", VERSION_json, &json_handler },
- { "thd_mdl_service", VERSION_thd_mdl, &thd_mdl_handler }
+ { "thd_mdl_service", VERSION_thd_mdl, &thd_mdl_handler },
+ { "sql_service", VERSION_sql_service, &sql_service_handler },
+ { "provider_service_bzip2", VERSION_provider_bzip2, &provider_handler_bzip2 },
+ { "provider_service_lz4", VERSION_provider_lz4, &provider_handler_lz4 },
+ { "provider_service_lzma", VERSION_provider_lzma, &provider_handler_lzma },
+ { "provider_service_lzo", VERSION_provider_lzo, &provider_handler_lzo },
+ { "provider_service_snappy", VERSION_provider_snappy, &provider_handler_snappy }
};
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 67032142591..68dd670787c 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -133,6 +133,7 @@ static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8;
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
#include "xa.h" // xa_recover_get_fields
+#include "sql_audit.h" // mysql_audit_release
/**
A result class used to send cursor rows using the binary protocol.
@@ -1314,7 +1315,6 @@ static bool mysql_test_insert_common(Prepared_statement *stmt,
if ((values= its++))
{
uint value_count;
- ulong counter= 0;
Item *unused_conds= 0;
if (table_list->table)
@@ -1340,16 +1340,18 @@ static bool mysql_test_insert_common(Prepared_statement *stmt,
}
while ((values= its++))
{
- counter++;
if (values->elements != value_count)
{
- my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0),
+ thd->get_stmt_da()->current_row_for_warning());
goto error;
}
if (setup_fields(thd, Ref_ptr_array(),
*values, COLUMNS_READ, 0, NULL, 0))
goto error;
+ thd->get_stmt_da()->inc_current_row_for_warning();
}
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
}
DBUG_RETURN(FALSE);
@@ -4048,19 +4050,22 @@ Execute_sql_statement(LEX_STRING sql_text)
executions without having to cleanup/reset THD in between.
*/
-bool
-Execute_sql_statement::execute_server_code(THD *thd)
+static bool execute_server_code(THD *thd,
+ const char *sql_text, size_t sql_len)
{
PSI_statement_locker *parent_locker;
bool error;
+ query_id_t save_query_id= thd->query_id;
+ query_id_t next_id= next_query_id();
- if (alloc_query(thd, m_sql_text.str, m_sql_text.length))
+ if (alloc_query(thd, sql_text, sql_len))
return TRUE;
Parser_state parser_state;
if (parser_state.init(thd, thd->query(), thd->query_length()))
return TRUE;
+ thd->query_id= next_id;
parser_state.m_lip.multi_statements= FALSE;
lex_start(thd);
@@ -4078,17 +4083,23 @@ Execute_sql_statement::execute_server_code(THD *thd)
/* report error issued during command execution */
if (likely(error == 0) && thd->spcont == NULL)
- general_log_write(thd, COM_STMT_EXECUTE,
+ general_log_write(thd, COM_QUERY,
thd->query(), thd->query_length());
end:
thd->lex->restore_set_statement_var();
+ thd->query_id= save_query_id;
delete_explain_query(thd->lex);
lex_end(thd->lex);
return error;
}
+bool Execute_sql_statement::execute_server_code(THD *thd)
+{
+ return ::execute_server_code(thd, m_sql_text.str, m_sql_text.length);
+}
+
/***************************************************************************
Prepared_statement
****************************************************************************/
@@ -4849,7 +4860,9 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
Statement stmt_backup;
bool error;
Query_arena *save_stmt_arena= thd->stmt_arena;
+ Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
Item_change_list save_change_list;
+
thd->Item_change_list::move_elements_to(&save_change_list);
state= STMT_CONVENTIONAL_EXECUTION;
@@ -4859,12 +4872,15 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
thd->set_n_backup_statement(this, &stmt_backup);
thd->set_n_backup_active_arena(this, &stmt_backup);
+
thd->stmt_arena= this;
+ thd->m_reprepare_observer= 0;
error= server_runnable->execute_server_code(thd);
thd->cleanup_after_query();
+ thd->m_reprepare_observer= save_reprepare_observer;
thd->restore_active_arena(this, &stmt_backup);
thd->restore_backup_statement(this, &stmt_backup);
thd->stmt_arena= save_stmt_arena;
@@ -5581,14 +5597,6 @@ Ed_connection::store_result_set()
return ed_result_set;
}
-/*
- MENT-56
- Protocol_local and service_sql for plugins to enable 'local' SQL query execution.
-*/
-
-#ifndef EMBEDDED_LIBRARY
-// This part is mostly copied from libmysqld/lib_sql.cc
-// TODO: get rid of code duplications
#include <mysql.h>
#include "../libmysqld/embedded_priv.h"
@@ -5604,11 +5612,14 @@ public:
char **next_field;
MYSQL_FIELD *next_mysql_field;
MEM_ROOT *alloc;
+ THD *new_thd;
+ Security_context empty_ctx;
- Protocol_local(THD *thd_arg, ulong prealloc= 0) :
+ Protocol_local(THD *thd_arg, THD *new_thd_arg, ulong prealloc) :
Protocol_text(thd_arg, prealloc),
- cur_data(0), first_data(0), data_tail(&first_data), alloc(0)
- {}
+ cur_data(0), first_data(0), data_tail(&first_data), alloc(0),
+ new_thd(new_thd_arg)
+ {}
protected:
bool net_store_data(const uchar *from, size_t length);
@@ -5680,6 +5691,20 @@ MYSQL_DATA *Protocol_local::alloc_new_dataset()
}
+void Protocol_local::clear_data_list()
+{
+ while (first_data)
+ {
+ MYSQL_DATA *data= first_data;
+ first_data= data->embedded_info->next;
+ free_rows(data);
+ }
+ data_tail= &first_data;
+ free_rows(cur_data);
+ cur_data= 0;
+}
+
+
static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
@@ -5973,7 +5998,6 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
{
List_iterator_fast<Item> it(*list);
Item *item;
-// Protocol_local prot(thd);
DBUG_ENTER("send_result_set_metadata");
// if (!thd->mysql) // bootstrap file handling
@@ -5984,7 +6008,7 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
for (uint pos= 0 ; (item= it++); pos++)
{
- if (/*prot.*/store_item_metadata(thd, item, pos))
+ if (store_item_metadata(thd, item, pos))
goto err;
}
@@ -5998,6 +6022,7 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
DBUG_RETURN(1); /* purecov: inspected */
}
+
static void
list_fields_send_default(THD *thd, Protocol_local *p, Field *fld, uint pos)
{
@@ -6085,19 +6110,6 @@ bool Protocol_local::store_null()
#include <sql_common.h>
#include <errmsg.h>
-struct local_results
-{
- struct st_mysql_data *cur_data;
- struct st_mysql_data *first_data;
- struct st_mysql_data **data_tail;
- void clear_data_list();
- struct st_mysql_data *alloc_new_dataset();
- char **next_field;
- MYSQL_FIELD *next_mysql_field;
- MEM_ROOT *alloc;
-};
-
-
static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
{
NET *net= &mysql->net;
@@ -6112,11 +6124,11 @@ static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
static my_bool loc_read_query_result(MYSQL *mysql)
{
- local_results *thd= (local_results *) mysql->thd;
+ Protocol_local *p= (Protocol_local *) mysql->thd;
- MYSQL_DATA *res= thd->first_data;
- DBUG_ASSERT(!thd->cur_data);
- thd->first_data= res->embedded_info->next;
+ MYSQL_DATA *res= p->first_data;
+ DBUG_ASSERT(!p->cur_data);
+ p->first_data= res->embedded_info->next;
if (res->embedded_info->last_errno &&
!res->embedded_info->fields_list)
{
@@ -6144,7 +6156,7 @@ static my_bool loc_read_query_result(MYSQL *mysql)
if (res->embedded_info->fields_list)
{
mysql->status=MYSQL_STATUS_GET_RESULT;
- thd->cur_data= res;
+ p->cur_data= res;
}
else
my_free(res);
@@ -6153,174 +6165,257 @@ static my_bool loc_read_query_result(MYSQL *mysql)
}
-static MYSQL_METHODS local_methods=
+static my_bool
+loc_advanced_command(MYSQL *mysql, enum enum_server_command command,
+ const uchar *header, ulong header_length,
+ const uchar *arg, ulong arg_length, my_bool skip_check,
+ MYSQL_STMT *stmt)
{
- loc_read_query_result, /* read_query_result */
- NULL/*loc_advanced_command*/, /* advanced_command */
- NULL/*loc_read_rows*/, /* read_rows */
- NULL/*loc_use_result*/, /* use_result */
- NULL/*loc_fetch_lengths*/, /* fetch_lengths */
- NULL/*loc_flush_use_result*/, /* flush_use_result */
- NULL/*loc_read_change_user_result*/ /* read_change_user_result */
-};
+ my_bool result= 1;
+ Protocol_local *p= (Protocol_local *) mysql->thd;
+ NET *net= &mysql->net;
+ if (p->thd && p->thd->killed != NOT_KILLED)
+ {
+ if (p->thd->killed < KILL_CONNECTION)
+ p->thd->killed= NOT_KILLED;
+ else
+ return 1;
+ }
-extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql,
- const char *host, const char *user, const char *passwd, const char *db)
-{
- //char name_buff[USERNAME_LENGTH];
+ p->clear_data_list();
+ /* Check that we are calling the client functions in right order */
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
+ goto end;
+ }
- DBUG_ENTER("mysql_real_connect_local");
+ /* Clear result variables */
+ p->thd->clear_error(1);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ mysql->field_count= 0;
+ net_clear_error(net);
- /* Test whether we're already connected */
- if (mysql->server_version)
+ /*
+ We have to call free_old_query before we start to fill mysql->fields
+ for new query. In the case of embedded server we collect field data
+ during query execution (not during data retrieval as it is in remote
+ client). So we have to call free_old_query here
+ */
+ free_old_query(mysql);
+
+ if (header)
{
- set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate);
- DBUG_RETURN(0);
+ arg= header;
+ arg_length= header_length;
}
- if (!host || !host[0])
- host= mysql->options.host;
+ if (p->new_thd)
+ {
+ THD *thd_orig= current_thd;
+ set_current_thd(p->thd);
+ p->thd->thread_stack= (char*) &result;
+ p->thd->set_time();
+ result= execute_server_code(p->thd, (const char *)arg, arg_length);
+ p->thd->cleanup_after_query();
+ mysql_audit_release(p->thd);
+ p->end_statement();
+ set_current_thd(thd_orig);
+ }
+ else
+ {
+ Ed_connection con(p->thd);
+ Security_context *ctx_orig= p->thd->security_ctx;
+ MYSQL_LEX_STRING sql_text;
+ DBUG_ASSERT(current_thd == p->thd);
+ sql_text.str= (char *) arg;
+ sql_text.length= arg_length;
+ p->thd->security_ctx= &p->empty_ctx;
+ result= con.execute_direct(p, sql_text);
+ p->thd->security_ctx= ctx_orig;
+ }
+ if (skip_check)
+ result= 0;
+ p->cur_data= 0;
- mysql->methods= &local_methods;
+end:
+ return result;
+}
- if (!db || !db[0])
- db=mysql->options.db;
- if (!user || !user[0])
- user=mysql->options.user;
+/*
+ reads dataset from the next query result
- mysql->user= my_strdup(PSI_INSTRUMENT_ME, user, MYF(0));
+ SYNOPSIS
+ loc_read_rows()
+ mysql connection handle
+ other parameters are not used
+ NOTES
+ It just gets next MYSQL_DATA from the result's queue
- mysql->info_buffer= (char *) my_malloc(PSI_INSTRUMENT_ME,
- MYSQL_ERRMSG_SIZE, MYF(0));
- //mysql->thd= create_embedded_thd(client_flag);
+ RETURN
+ pointer to MYSQL_DATA with the coming recordset
+*/
+
+static MYSQL_DATA *
+loc_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
+ unsigned int fields __attribute__((unused)))
+{
+ MYSQL_DATA *result= ((Protocol_local *)mysql->thd)->cur_data;
+ ((Protocol_local *)mysql->thd)->cur_data= 0;
+ if (result->embedded_info->last_errno)
+ {
+ embedded_get_error(mysql, result);
+ return NULL;
+ }
+ *result->embedded_info->prev_ptr= NULL;
+ return result;
+}
- //init_embedded_mysql(mysql, client_flag);
- //if (mysql_init_character_set(mysql))
- // goto error;
+/**************************************************************************
+ Get column lengths of the current row
+ If one uses mysql_use_result, res->lengths contains the length information,
+ else the lengths are calculated from the offset between pointers.
+**************************************************************************/
- //if (check_embedded_connection(mysql, db))
- // goto error;
+static void loc_fetch_lengths(ulong *to, MYSQL_ROW column,
+ unsigned int field_count)
+{
+ MYSQL_ROW end;
- mysql->server_status= SERVER_STATUS_AUTOCOMMIT;
+ for (end=column + field_count; column != end ; column++,to++)
+ *to= *column ? *(uint *)((*column) - sizeof(uint)) : 0;
+}
- //if (mysql->options.init_commands)
- //{
- // DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
- // char **ptr= (char**)init_commands->buffer;
- // char **end= ptr + init_commands->elements;
-//
- // for (; ptr<end; ptr++)
- // {
- // MYSQL_RES *res;
- // if (mysql_query(mysql,*ptr))
- // goto error;
- // if (mysql->fields)
- // {
- // if (!(res= (*mysql->methods->use_result)(mysql)))
- // goto error;
- // mysql_free_result(res);
- // }
- // }
- //}
- DBUG_PRINT("exit",("Mysql handler: %p", mysql));
- DBUG_RETURN(mysql);
+static void loc_flush_use_result(MYSQL *mysql, my_bool)
+{
+ Protocol_local *p= (Protocol_local *) mysql->thd;
+ if (p->cur_data)
+ {
+ free_rows(p->cur_data);
+ p->cur_data= 0;
+ }
+ else if (p->first_data)
+ {
+ MYSQL_DATA *data= p->first_data;
+ p->first_data= data->embedded_info->next;
+ free_rows(data);
+ }
+}
-//error:
- DBUG_PRINT("error",("message: %u (%s)",
- mysql->net.last_errno,
- mysql->net.last_error));
+
+static void loc_on_close_free(MYSQL *mysql)
+{
+ Protocol_local *p= (Protocol_local *) mysql->thd;
+ THD *thd= p->new_thd;
+ delete p;
+ if (thd)
{
- /* Free alloced memory */
- my_bool free_me=mysql->free_me;
- free_old_query(mysql);
- mysql->free_me=0;
- mysql_close(mysql);
- mysql->free_me=free_me;
+ delete thd;
+ local_connection_thread_count--;
}
- DBUG_RETURN(0);
+ my_free(mysql->info_buffer);
+ mysql->info_buffer= 0;
}
+static MYSQL_RES *loc_use_result(MYSQL *mysql)
+{
+ return mysql_store_result(mysql);
+}
-extern "C" int execute_sql_command(const char *command,
- char *hosts, char *names, char *filters)
+static MYSQL_METHODS local_methods=
{
- MYSQL_LEX_STRING sql_text;
- THD *thd= current_thd;
- THD *new_thd= 0;
- int result;
- my_bool qc_save= 0;
- Reprepare_observer *save_reprepare_observer= nullptr;
+ loc_read_query_result, /* read_query_result */
+ loc_advanced_command, /* advanced_command */
+ loc_read_rows, /* read_rows */
+ loc_use_result, /* use_result */
+ loc_fetch_lengths, /* fetch_lengths */
+ loc_flush_use_result, /* flush_use_result */
+ NULL, /* read_change_user_result */
+ loc_on_close_free /* on_close_free */
+#ifdef EMBEDDED_LIBRARY
+ ,NULL, /* list_fields */
+ NULL, /* read_prepare_result */
+ NULL, /* stmt_execute */
+ NULL, /* read_binary_rows */
+ NULL, /* unbuffered_fetch */
+ NULL, /* read_statistics */
+ NULL, /* next_result */
+ NULL /* read_rows_from_cursor */
+#endif
+};
+
- if (!thd)
+Atomic_counter<uint32_t> local_connection_thread_count;
+
+extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql)
+{
+ THD *thd_orig= current_thd;
+ THD *new_thd;
+ Protocol_local *p;
+ DBUG_ENTER("mysql_real_connect_local");
+
+ /* Test whether we're already connected */
+ if (mysql->server_version)
{
+ set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate);
+ DBUG_RETURN(0);
+ }
+
+ mysql->methods= &local_methods;
+ mysql->user= NULL;
+
+ mysql->info_buffer= (char *) my_malloc(PSI_INSTRUMENT_ME,
+ MYSQL_ERRMSG_SIZE, MYF(0));
+ if (!thd_orig || thd_orig->lock)
+ {
+ /*
+ When we start with the empty current_thd (that happens when plugins
+ are loaded during the server start) or when some tables are locked
+ with the current_thd already (that happens when INSTALL PLUGIN
+ calls the plugin_init or with queries), we create the new THD for
+ the local connection. So queries with this MYSQL will be run with
+ it rather than the current THD.
+ */
+
new_thd= new THD(0);
- new_thd->thread_stack= (char*) &sql_text;
+ local_connection_thread_count++;
+ new_thd->thread_stack= (char*) &thd_orig;
new_thd->store_globals();
new_thd->security_ctx->skip_grants();
new_thd->query_cache_is_applicable= 0;
new_thd->variables.wsrep_on= 0;
+ /*
+ TOSO: decide if we should turn the auditing off
+ for such threads.
+ We can do it like this:
+ new_thd->audit_class_mask[0]= ~0;
+ */
bzero((char*) &new_thd->net, sizeof(new_thd->net));
- thd= new_thd;
+ set_current_thd(thd_orig);
+ thd_orig= new_thd;
}
else
- {
- if (thd->lock)
- /* Doesn't work if the thread opened/locked tables already. */
- return 2;
-
- qc_save= thd->query_cache_is_applicable;
- thd->query_cache_is_applicable= 0;
- save_reprepare_observer= thd->m_reprepare_observer;
- thd->m_reprepare_observer= nullptr;
- }
- sql_text.str= (char *) command;
- sql_text.length= strlen(command);
- {
- Protocol_local p(thd);
- Ed_connection con(thd);
- result= con.execute_direct(&p, sql_text);
- if (!result && p.first_data)
- {
- int nr= (int) p.first_data->rows;
- MYSQL_ROWS *rows= p.first_data->data;
-
- while (nr--)
- {
- strcpy(hosts, rows->data[0]);
- hosts+= strlen(hosts) + 1;
- strcpy(names, rows->data[1]);
- names+= strlen(names) + 1;
- if (filters)
- {
- strcpy(filters, rows->data[2]);
- filters+= strlen(filters) + 1;
- }
- rows= rows->next;
- }
- }
- if (p.first_data)
- {
- if (p.alloc)
- free_root(p.alloc, MYF(0));
- my_free(p.first_data);
- }
- }
+ new_thd= NULL;
+ p= new Protocol_local(thd_orig, new_thd, 0);
if (new_thd)
- delete new_thd;
+ new_thd->protocol= p;
else
{
- thd->query_cache_is_applicable= qc_save;
- thd->m_reprepare_observer= save_reprepare_observer;
+ p->empty_ctx.init();
+ p->empty_ctx.skip_grants();
}
- *hosts= 0;
- return result;
+ mysql->thd= p;
+ mysql->server_status= SERVER_STATUS_AUTOCOMMIT;
+
+
+ DBUG_PRINT("exit",("Mysql handler: %p", mysql));
+ DBUG_RETURN(mysql);
}
-#endif /*!EMBEDDED_LIBRARY*/
diff --git a/sql/sql_prepare.h b/sql/sql_prepare.h
index 1e81b9f80e6..1a96df85a19 100644
--- a/sql/sql_prepare.h
+++ b/sql/sql_prepare.h
@@ -353,4 +353,6 @@ private:
size_t m_column_count; /* TODO: change to point to metadata */
};
+extern Atomic_counter<uint32_t> local_connection_thread_count;
+
#endif // SQL_PREPARE_H
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 2206f71c060..f7d8ef0da67 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -416,16 +416,6 @@ inline int hexchar_to_int(char c)
/* This must match the path length limit in the ER_NOT_RW_DIR error msg. */
#define ER_NOT_RW_DIR_PATHSIZE 200
-#define IS_TABLESPACES_TABLESPACE_NAME 0
-#define IS_TABLESPACES_ENGINE 1
-#define IS_TABLESPACES_TABLESPACE_TYPE 2
-#define IS_TABLESPACES_LOGFILE_GROUP_NAME 3
-#define IS_TABLESPACES_EXTENT_SIZE 4
-#define IS_TABLESPACES_AUTOEXTEND_SIZE 5
-#define IS_TABLESPACES_MAXIMUM_SIZE 6
-#define IS_TABLESPACES_NODEGROUP_ID 7
-#define IS_TABLESPACES_TABLESPACE_COMMENT 8
-
bool db_name_is_in_ignore_db_dirs_list(const char *dbase);
#endif /* MYSQL_SERVER */
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index ddada6ad892..1dfa238de50 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -403,7 +403,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
/* If not default connection and 'all' is used */
mi->release();
mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index->remove_master_info(mi))
+ if (master_info_index->remove_master_info(mi, 0))
result= 1;
mysql_mutex_unlock(&LOCK_active_mi);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 333e97d07ef..ae5cd82da4c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2561,7 +2561,7 @@ int JOIN::optimize_stage2()
if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
- conds= (Item*) &Item_true;
+ conds= (Item*) Item_true;
}
if (impossible_where)
@@ -2731,9 +2731,7 @@ int JOIN::optimize_stage2()
if (conds && const_table_map != found_const_table_map &&
(select_options & SELECT_DESCRIBE))
- {
- conds= (Item*) &Item_false;
- }
+ conds= (Item*) Item_false;
/* Cache constant expressions in WHERE, HAVING, ON clauses. */
cache_const_exprs();
@@ -3050,7 +3048,7 @@ int JOIN::optimize_stage2()
having= having->remove_eq_conds(thd, &select_lex->having_value, true);
if (select_lex->having_value == Item::COND_FALSE)
{
- having= (Item*) &Item_false;
+ having= (Item*) Item_false;
zero_result_cause= "Impossible HAVING noticed after reading const tables";
error= 0;
select_lex->mark_const_derived(zero_result_cause);
@@ -4974,6 +4972,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
}
}
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
/* Look for a table owned by an engine with the select_handler interface */
select_lex->pushdown_select= find_select_handler(thd, select_lex);
@@ -5636,7 +5635,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (join->cond_value == Item::COND_FALSE)
{
join->impossible_where= true;
- conds= (Item*) &Item_false;
+ conds= (Item*) Item_false;
}
join->cond_equal= NULL;
@@ -7117,7 +7116,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* set a barrier for the array of SARGABLE_PARAM */
(*sargables)[0].field= 0;
- if (my_init_dynamic_array2(thd->mem_root->m_psi_key, keyuse, sizeof(KEYUSE),
+ if (my_init_dynamic_array2(thd->mem_root->psi_key, keyuse, sizeof(KEYUSE),
thd->alloc(sizeof(KEYUSE) * 20), 20, 64,
MYF(MY_THREAD_SPECIFIC)))
DBUG_RETURN(TRUE);
@@ -11922,7 +11921,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
below to check if we should use 'quick' instead.
*/
DBUG_PRINT("info", ("Item_int"));
- tmp= (Item*) &Item_true;
+ tmp= (Item*) Item_true;
}
}
@@ -12466,9 +12465,9 @@ static
bool generate_derived_keys(DYNAMIC_ARRAY *keyuse_array)
{
KEYUSE *keyuse= dynamic_element(keyuse_array, 0, KEYUSE*);
- uint elements= keyuse_array->elements;
+ size_t elements= keyuse_array->elements;
TABLE *prev_table= 0;
- for (uint i= 0; i < elements; i++, keyuse++)
+ for (size_t i= 0; i < elements; i++, keyuse++)
{
if (!keyuse->table)
break;
@@ -15505,7 +15504,7 @@ COND *Item_cond_and::build_equal_items(THD *thd,
if (!cond_args->elements &&
!cond_equal.current_level.elements &&
!eq_list.elements)
- return (Item*) &Item_true;
+ return (Item*) Item_true;
List_iterator_fast<Item_equal> it(cond_equal.current_level);
while ((item_equal= it++))
@@ -15612,7 +15611,7 @@ COND *Item_func_eq::build_equal_items(THD *thd,
Item_equal *item_equal;
int n= cond_equal.current_level.elements + eq_list.elements;
if (n == 0)
- return (Item*) &Item_true;
+ return (Item*) Item_true;
else if (n == 1)
{
if ((item_equal= cond_equal.current_level.pop()))
@@ -16016,7 +16015,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
List<Item> eq_list;
Item_func_eq *eq_item= 0;
if (((Item *) item_equal)->const_item() && !item_equal->val_int())
- return (Item*) &Item_false;
+ return (Item*) Item_false;
Item *item_const= item_equal->get_const();
Item_equal_fields_iterator it(*item_equal);
Item *head;
@@ -16161,7 +16160,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
switch (eq_list.elements)
{
case 0:
- res= cond ? cond : (Item*) &Item_true;
+ res= cond ? cond : (Item*) Item_true;
break;
case 1:
if (!cond || cond->is_bool_literal())
@@ -16414,9 +16413,9 @@ static void update_const_equal_items(THD *thd, COND *cond, JOIN_TAB *tab,
Item *item;
while ((item= li++))
update_const_equal_items(thd, item, tab,
- (((Item_cond*) cond)->top_level() &&
- ((Item_cond*) cond)->functype() ==
- Item_func::COND_AND_FUNC));
+ cond->is_top_level_item() &&
+ ((Item_cond*) cond)->functype() ==
+ Item_func::COND_AND_FUNC);
}
else if (cond->type() == Item::FUNC_ITEM &&
((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
@@ -17999,7 +17998,7 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
*/
- Item *item0= (Item*) &Item_false;
+ Item *item0= (Item*) Item_false;
Item *eq_cond= new(thd->mem_root) Item_func_eq(thd, args[0], item0);
if (!eq_cond)
return this;
@@ -18566,20 +18565,19 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, uint field_count)
DBUG_ASSERT(table->s->virtual_fields == 0);
- my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
- FALSE);
+ my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count);
bitmaps+= bitmap_size;
my_bitmap_init(&table->tmp_set,
- (my_bitmap_map*) bitmaps, field_count, FALSE);
+ (my_bitmap_map*) bitmaps, field_count);
bitmaps+= bitmap_size;
my_bitmap_init(&table->eq_join_set,
- (my_bitmap_map*) bitmaps, field_count, FALSE);
+ (my_bitmap_map*) bitmaps, field_count);
bitmaps+= bitmap_size;
my_bitmap_init(&table->cond_set,
- (my_bitmap_map*) bitmaps, field_count, FALSE);
+ (my_bitmap_map*) bitmaps, field_count);
bitmaps+= bitmap_size;
my_bitmap_init(&table->has_value_set,
- (my_bitmap_map*) bitmaps, field_count, FALSE);
+ (my_bitmap_map*) bitmaps, field_count);
/* write_set and all_set are copies of read_set */
table->def_write_set= table->def_read_set;
table->s->all_set= table->def_read_set;
@@ -18702,7 +18700,7 @@ TABLE *Create_tmp_table::start(THD *thd,
(ulong) m_rows_limit, MY_TEST(m_group)));
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
- m_temp_pool_slot = bitmap_lock_set_next(&temp_pool);
+ m_temp_pool_slot = temp_pool_set_next();
if (m_temp_pool_slot != MY_BIT_NONE) // we got a slot
sprintf(path, "%s-%s-%lx-%i", tmp_file_prefix, param->tmp_name,
@@ -19614,7 +19612,7 @@ void Create_tmp_table::cleanup_on_failure(THD *thd, TABLE *table)
if (table)
free_tmp_table(thd, table);
if (m_temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, m_temp_pool_slot);
+ temp_pool_clear_bit(m_temp_pool_slot);
}
@@ -20379,7 +20377,7 @@ free_tmp_table(THD *thd, TABLE *entry)
(*ptr)->free();
if (entry->temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot);
+ temp_pool_clear_bit(entry->temp_pool_slot);
plugin_unlock(0, entry->s->db_plugin);
entry->alias.free();
@@ -21061,7 +21059,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
if (join_tab->on_precond && !join_tab->on_precond->val_int())
rc= NESTED_LOOP_NO_MORE_ROWS;
}
- join->thd->get_stmt_da()->reset_current_row_for_warning();
+ join->thd->get_stmt_da()->reset_current_row_for_warning(1);
if (rc != NESTED_LOOP_NO_MORE_ROWS &&
(rc= join_tab_execution_startup(join_tab)) < 0)
@@ -28574,7 +28572,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
{
DYNAMIC_ARRAY added_keyuse;
SARGABLE_PARAM *sargables= 0; /* Used only as a dummy parameter. */
- uint org_keyuse_elements;
+ size_t org_keyuse_elements;
/* Re-run the REF optimizer to take into account the new conditions. */
if (update_ref_and_keys(thd, &added_keyuse, join_tab, table_count, added_where,
@@ -28596,7 +28594,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
reset_query_plan();
if (!keyuse.buffer &&
- my_init_dynamic_array(thd->mem_root->m_psi_key, &keyuse, sizeof(KEYUSE),
+ my_init_dynamic_array(thd->mem_root->psi_key, &keyuse, sizeof(KEYUSE),
20, 64, MYF(MY_THREAD_SPECIFIC)))
{
delete_dynamic(&added_keyuse);
@@ -29739,7 +29737,7 @@ void JOIN::make_notnull_conds_for_range_scans()
Found a IS NULL conjunctive predicate for a null-rejected field
in the WHERE clause
*/
- conds= (Item*) &Item_false;
+ conds= (Item*) Item_false;
cond_equal= 0;
impossible_where= true;
DBUG_VOID_RETURN;
@@ -29762,7 +29760,7 @@ void JOIN::make_notnull_conds_for_range_scans()
Found a IS NULL conjunctive predicate for a null-rejected field
of the inner table of an outer join with ON expression tbl->on_expr
*/
- tbl->on_expr= (Item*) &Item_false;
+ tbl->on_expr= (Item*) Item_false;
}
}
}
@@ -29913,7 +29911,7 @@ void build_notnull_conds_for_inner_nest_of_outer_join(JOIN *join,
if (used_tables &&
build_notnull_conds_for_range_scans(join, nest_tbl->on_expr, used_tables))
{
- nest_tbl->on_expr= (Item*) &Item_false;
+ nest_tbl->on_expr= (Item*) Item_false;
}
li.rewind();
@@ -29927,7 +29925,7 @@ void build_notnull_conds_for_inner_nest_of_outer_join(JOIN *join,
}
else if (build_notnull_conds_for_range_scans(join, tbl->on_expr,
tbl->table->map))
- tbl->on_expr= (Item*) &Item_false;
+ tbl->on_expr= (Item*) Item_false;
}
}
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index b706829451d..d01f84fe7d1 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -231,6 +231,9 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin,
case PLUGIN_IS_DISABLED:
table->field[2]->store(STRING_WITH_LEN("DISABLED"), cs);
break;
+ case PLUGIN_IS_DYING:
+ table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs);
+ break;
case PLUGIN_IS_FREED: // filtered in fill_plugins, used in fill_all_plugins
table->field[2]->store(STRING_WITH_LEN("NOT INSTALLED"), cs);
break;
@@ -324,7 +327,7 @@ int fill_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE *table= tables->table;
if (plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
- ~(PLUGIN_IS_FREED | PLUGIN_IS_DYING), table))
+ ~PLUGIN_IS_FREED, table))
DBUG_RETURN(1);
DBUG_RETURN(0);
@@ -354,7 +357,7 @@ int fill_all_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
plugin_dl_foreach(thd, 0, show_plugins, table);
const char *wstr= lookup.db_value.str, *wend= wstr + lookup.db_value.length;
- for (uint i=0; i < (uint) dirp->number_of_files; i++)
+ for (size_t i=0; i < dirp->number_of_files; i++)
{
FILEINFO *file= dirp->dir_entry+i;
LEX_CSTRING dl= { file->name, strlen(file->name) };
@@ -952,7 +955,7 @@ find_files(THD *thd, Dynamic_array<LEX_CSTRING*> *files, LEX_CSTRING *db,
if (!db) /* Return databases */
{
- for (uint i=0; i < (uint) dirp->number_of_files; i++)
+ for (size_t i=0; i < dirp->number_of_files; i++)
{
FILEINFO *file= dirp->dir_entry+i;
#ifdef USE_SYMDIR
@@ -6717,7 +6720,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
{
if ((key_info->flags & HA_INVISIBLE_KEY) &&
- DBUG_EVALUATE_IF("test_invisible_index", 0, 1))
+ !DBUG_IF("test_invisible_index"))
continue;
KEY_PART_INFO *key_part= key_info->key_part;
LEX_CSTRING *str;
@@ -6725,7 +6728,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
{
if (key_part->field->invisible >= INVISIBLE_SYSTEM &&
- DBUG_EVALUATE_IF("test_completely_invisible", 0, 1))
+ !DBUG_IF("test_completely_invisible"))
{
/*
NOTE: we will get SEQ_IN_INDEX gap inside the result if this key_part
@@ -7385,13 +7388,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
table->field[23]->store(STRING_WITH_LEN("default"), cs);
table->field[24]->set_notnull();
- if (part_elem->tablespace_name)
- table->field[24]->store(part_elem->tablespace_name,
- strlen(part_elem->tablespace_name), cs);
- else
- {
- table->field[24]->set_null();
- }
+ table->field[24]->set_null(); // Tablespace
}
return;
}
@@ -8222,8 +8219,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(0);
my_bitmap_map* bitmaps=
(my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
- my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
- FALSE);
+ my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count);
table->read_set= &table->def_read_set;
bitmap_clear_all(table->read_set);
table_list->schema_table_param= tmp_table_param;
@@ -9814,23 +9810,17 @@ int initialize_schema_table(st_plugin_int *plugin)
int finalize_schema_table(st_plugin_int *plugin)
{
+ int deinit_status= 0;
ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
DBUG_ENTER("finalize_schema_table");
if (schema_table)
{
if (plugin->plugin->deinit)
- {
- DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
- if (plugin->plugin->deinit(NULL))
- {
- DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
- plugin->name.str));
- }
- }
+ deinit_status= plugin->plugin->deinit(NULL);
my_free(schema_table);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(deinit_status);
}
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index 8e973f9b0b3..4e86cc4d782 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -44,6 +44,7 @@ const LEX_CSTRING Diag_condition_item_names[]=
{ STRING_WITH_LEN("CURSOR_NAME") },
{ STRING_WITH_LEN("MESSAGE_TEXT") },
{ STRING_WITH_LEN("MYSQL_ERRNO") },
+ { STRING_WITH_LEN("ROW_NUMBER") },
{ STRING_WITH_LEN("CONDITION_IDENTIFIER") },
{ STRING_WITH_LEN("CONDITION_NUMBER") },
@@ -309,6 +310,26 @@ int Sql_cmd_common_signal::eval_signal_informations(THD *thd, Sql_condition *con
cond->m_sql_errno= (int) code;
}
+ set= m_set_signal_information.m_item[DIAG_ROW_NUMBER];
+ if (set != NULL)
+ {
+ if (set->is_null())
+ {
+ thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
+ "ROW_NUMBER", "NULL");
+ goto end;
+ }
+ longlong row_number_value= set->val_int();
+ if (row_number_value < 0)
+ {
+ str= set->val_str(& str_value);
+ thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
+ "ROW_NUMBER", str->c_ptr_safe());
+ goto end;
+ }
+ cond->m_row_number= (ulong) row_number_value;
+ }
+
/*
The various item->val_xxx() methods don't return an error code,
but flag thd in case of failure.
@@ -419,7 +440,8 @@ bool Sql_cmd_resignal::execute(THD *thd)
DBUG_RETURN(result);
}
- Sql_condition signaled_err(thd->mem_root, *signaled, signaled->message);
+ Sql_condition signaled_err(thd->mem_root, *signaled, signaled->message,
+ signaled->m_row_number);
if (m_cond)
{
diff --git a/sql/sql_string.h b/sql/sql_string.h
index fe57c8153bb..795f80c3e08 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -484,6 +484,11 @@ public:
if (str.Alloced_length)
Alloced_length= (uint32) (str.Alloced_length - offset);
}
+ LEX_CSTRING to_lex_cstring() const
+ {
+ LEX_CSTRING tmp= {Ptr, str_length};
+ return tmp;
+ }
inline LEX_CSTRING *get_value(LEX_CSTRING *res)
{
res->str= Ptr;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9b3c3f5a26c..7d9fd0c516d 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -667,10 +667,12 @@ void build_lower_case_table_filename(char *buff, size_t bufflen,
*/
uint build_table_shadow_filename(char *buff, size_t bufflen,
- ALTER_PARTITION_PARAM_TYPE *lpt)
+ ALTER_PARTITION_PARAM_TYPE *lpt,
+ bool backup)
{
char tmp_name[FN_REFLEN];
- my_snprintf(tmp_name, sizeof (tmp_name), "%s-shadow-%lx-%s", tmp_file_prefix,
+ my_snprintf(tmp_name, sizeof (tmp_name), "%s-%s-%lx-%s", tmp_file_prefix,
+ backup ? "backup" : "shadow",
(ulong) current_thd->thread_id, lpt->table_name.str);
return build_table_filename(buff, bufflen, lpt->db.str, tmp_name, "",
FN_IS_TMP);
@@ -704,6 +706,11 @@ uint build_table_shadow_filename(char *buff, size_t bufflen,
tables since it only handles partitioned data if it exists.
*/
+
+/*
+ TODO: Partitioning atomic DDL refactoring: WFRM_WRITE_SHADOW
+ should be merged with create_table_impl(frm_only == true).
+*/
bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
{
/*
@@ -717,8 +724,11 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
char shadow_frm_name[FN_REFLEN+1];
char frm_name[FN_REFLEN+1];
#ifdef WITH_PARTITION_STORAGE_ENGINE
+ char bak_path[FN_REFLEN+1];
+ char bak_frm_name[FN_REFLEN+1];
char *part_syntax_buf;
uint syntax_len;
+ partition_info *part_info= lpt->part_info;
#endif
DBUG_ENTER("mysql_write_frm");
@@ -777,6 +787,94 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
goto end;
}
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (flags & WFRM_WRITE_CONVERTED_TO)
+ {
+ THD *thd= lpt->thd;
+ Alter_table_ctx *alter_ctx= lpt->alter_ctx;
+ HA_CREATE_INFO *create_info= lpt->create_info;
+
+ LEX_CSTRING new_path= { alter_ctx->get_new_path(), 0 };
+ partition_info *work_part_info= thd->work_part_info;
+ handlerton *db_type= create_info->db_type;
+ DBUG_ASSERT(lpt->table->part_info);
+ DBUG_ASSERT(lpt->table->part_info == part_info);
+ handler *file= ((ha_partition *)(lpt->table->file))->get_child_handlers()[0];
+ DBUG_ASSERT(file);
+ new_path.length= strlen(new_path.str);
+ strxnmov(frm_name, sizeof(frm_name) - 1, new_path.str, reg_ext, NullS);
+ create_info->alias= alter_ctx->table_name;
+ thd->work_part_info= NULL;
+ create_info->db_type= work_part_info->default_engine_type;
+ /* NOTE: partitioned temporary tables are not supported. */
+ DBUG_ASSERT(!create_info->tmp_table());
+ if (ddl_log_create_table(thd, part_info, create_info->db_type, &new_path,
+ &alter_ctx->new_db, &alter_ctx->new_name, true) ||
+ ERROR_INJECT("create_before_create_frm"))
+ DBUG_RETURN(TRUE);
+
+ if (mysql_prepare_create_table(thd, create_info, lpt->alter_info,
+ &lpt->db_options, file,
+ &lpt->key_info_buffer, &lpt->key_count,
+ C_ALTER_TABLE, alter_ctx->new_db,
+ alter_ctx->new_name))
+ DBUG_RETURN(TRUE);
+
+ lpt->create_info->table_options= lpt->db_options;
+ LEX_CUSTRING frm= build_frm_image(thd, alter_ctx->new_name, create_info,
+ lpt->alter_info->create_list,
+ lpt->key_count, lpt->key_info_buffer,
+ file);
+ if (unlikely(!frm.str))
+ DBUG_RETURN(TRUE);
+
+ thd->work_part_info= work_part_info;
+ create_info->db_type= db_type;
+
+ ERROR_INJECT("alter_partition_after_create_frm");
+
+ error= writefile(frm_name, alter_ctx->new_db.str, alter_ctx->new_name.str,
+ create_info->tmp_table(), frm.str, frm.length);
+ my_free((void *) frm.str);
+ if (unlikely(error) || ERROR_INJECT("alter_partition_after_write_frm"))
+ {
+ mysql_file_delete(key_file_frm, frm_name, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ DBUG_RETURN(false);
+ }
+ if (flags & WFRM_BACKUP_ORIGINAL)
+ {
+ build_table_filename(path, sizeof(path) - 1, lpt->db.str,
+ lpt->table_name.str, "", 0);
+ strxnmov(frm_name, sizeof(frm_name), path, reg_ext, NullS);
+
+ build_table_shadow_filename(bak_path, sizeof(bak_path) - 1, lpt, true);
+ strxmov(bak_frm_name, bak_path, reg_ext, NullS);
+
+ DDL_LOG_MEMORY_ENTRY *main_entry= part_info->main_entry;
+ mysql_mutex_lock(&LOCK_gdl);
+ if (write_log_replace_frm(lpt, part_info->list->entry_pos,
+ (const char*) bak_path,
+ (const char*) path) ||
+ ddl_log_write_execute_entry(part_info->list->entry_pos,
+ &part_info->execute_entry))
+ {
+ mysql_mutex_unlock(&LOCK_gdl);
+ DBUG_RETURN(TRUE);
+ }
+ mysql_mutex_unlock(&LOCK_gdl);
+ part_info->main_entry= main_entry;
+ if (mysql_file_rename(key_file_frm, frm_name, bak_frm_name, MYF(MY_WME)))
+ DBUG_RETURN(TRUE);
+ if (lpt->table->file->ha_create_partitioning_metadata(bak_path, path,
+ CHF_RENAME_FLAG))
+ DBUG_RETURN(TRUE);
+ }
+#else /* !WITH_PARTITION_STORAGE_ENGINE */
+ DBUG_ASSERT(!(flags & WFRM_BACKUP_ORIGINAL));
+#endif /* !WITH_PARTITION_STORAGE_ENGINE */
if (flags & WFRM_INSTALL_SHADOW)
{
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -798,20 +896,25 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
completing this we write a new phase to the log entry that will
deactivate it.
*/
- if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
+ if (!(flags & WFRM_BACKUP_ORIGINAL) && (
+ mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME))
#ifdef WITH_PARTITION_STORAGE_ENGINE
- lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
+ || lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
CHF_DELETE_FLAG) ||
- ddl_log_increment_phase(part_info->frm_log_entry->entry_pos) ||
- (ddl_log_sync(), FALSE) ||
- mysql_file_rename(key_file_frm,
- shadow_frm_name, frm_name, MYF(MY_WME)) ||
- lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
- CHF_RENAME_FLAG))
-#else
- mysql_file_rename(key_file_frm,
- shadow_frm_name, frm_name, MYF(MY_WME)))
+ ddl_log_increment_phase(part_info->main_entry->entry_pos) ||
+ (ddl_log_sync(), FALSE)
#endif
+ ))
+ {
+ error= 1;
+ goto err;
+ }
+ if (mysql_file_rename(key_file_frm, shadow_frm_name, frm_name, MYF(MY_WME))
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ || lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
+ CHF_RENAME_FLAG)
+#endif
+ )
{
error= 1;
goto err;
@@ -850,8 +953,8 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
err:
#ifdef WITH_PARTITION_STORAGE_ENGINE
- ddl_log_increment_phase(part_info->frm_log_entry->entry_pos);
- part_info->frm_log_entry= NULL;
+ ddl_log_increment_phase(part_info->main_entry->entry_pos);
+ part_info->main_entry= NULL;
(void) ddl_log_sync();
#endif
;
@@ -2758,8 +2861,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
*/
if (sql_field->stored_in_db())
record_offset+= sql_field->pack_length;
- if (sql_field->flags & VERS_SYSTEM_FIELD)
- continue;
}
/* Update virtual fields' offset and give error if
All fields are invisible */
@@ -3114,14 +3215,14 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (!sql_field || (sql_field->invisible > INVISIBLE_USER &&
!column->generated))
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXIST, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
if (sql_field->invisible > INVISIBLE_USER &&
!(sql_field->flags & VERS_SYSTEM_FIELD) &&
- !key->invisible && DBUG_EVALUATE_IF("test_invisible_index", 0, 1))
+ !key->invisible && !DBUG_IF("test_invisible_index"))
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXIST, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
while ((dup_column= cols2++) != column)
@@ -4188,7 +4289,6 @@ err:
@retval -1 table existed but IF NOT EXISTS was used
*/
-static
int create_table_impl(THD *thd,
DDL_LOG_STATE *ddl_log_state_create,
DDL_LOG_STATE *ddl_log_state_rm,
@@ -6042,9 +6142,8 @@ remove_key:
if (!part_elem)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_DROP_PARTITION_NON_EXISTENT,
- ER_THD(thd, ER_DROP_PARTITION_NON_EXISTENT),
- "DROP");
+ ER_PARTITION_DOES_NOT_EXIST,
+ ER_THD(thd, ER_PARTITION_DOES_NOT_EXIST));
names_it.remove();
}
}
@@ -8347,7 +8446,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
key_type= Key::UNIQUE;
if (dropped_key_part)
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), dropped_key_part);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXIST, MYF(0), dropped_key_part);
if (long_hash_key)
{
key_info->algorithm= HA_KEY_ALG_LONG_HASH;
@@ -9624,7 +9723,8 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
Table maybe does not exist, but we got an exclusive lock
on the name, now we can safely try to find out for sure.
*/
- if (ha_table_exists(thd, &alter_ctx.new_db, &alter_ctx.new_name))
+ if (!(alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN) &&
+ ha_table_exists(thd, &alter_ctx.new_db, &alter_ctx.new_name))
{
/* Table will be closed in do_command() */
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias.str);
@@ -9932,10 +10032,8 @@ do_continue:;
}
// In-place execution of ALTER TABLE for partitioning.
- DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
- create_info, table_list,
- &alter_ctx.db,
- &alter_ctx.table_name));
+ DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info, &alter_ctx,
+ create_info, table_list));
}
#endif
@@ -11047,7 +11145,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
if (ignore && !alter_ctx->fk_error_if_delete_row)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- thd->get_stmt_da()->reset_current_row_for_warning();
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
restore_record(to, s->default_values); // Create empty record
to->reset_default_fields();
@@ -11511,16 +11609,11 @@ bool check_engine(THD *thd, const char *db_name,
if (create_info->tmp_table() &&
ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
{
- if (create_info->used_fields & HA_CREATE_USED_ENGINE)
- {
- my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
- hton_name(*new_engine)->str, "TEMPORARY");
- *new_engine= 0;
- DBUG_RETURN(true);
- }
- *new_engine= myisam_hton;
+ my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
+ hton_name(*new_engine)->str, "TEMPORARY");
+ *new_engine= 0;
+ DBUG_RETURN(true);
}
-
lex_string_set(&create_info->new_storage_engine_name,
ha_resolve_storage_engine_name(*new_engine));
DBUG_RETURN(false);
diff --git a/sql/sql_table.h b/sql/sql_table.h
index aacb6c99f15..eaa03bfaf8c 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -20,6 +20,10 @@
#include <my_sys.h> // pthread_mutex_t
#include "m_string.h" // LEX_CUSTRING
+#define ERROR_INJECT(code) \
+ ((DBUG_IF("crash_" code) && (DBUG_SUICIDE(), 0)) || \
+ (DBUG_IF("fail_" code) && (my_error(ER_UNKNOWN_ERROR, MYF(0)), 1)))
+
class Alter_info;
class Alter_table_ctx;
class Column_definition;
@@ -53,6 +57,8 @@ enum enum_explain_filename_mode
#define WFRM_WRITE_SHADOW 1
#define WFRM_INSTALL_SHADOW 2
#define WFRM_KEEP_SHARE 4
+#define WFRM_WRITE_CONVERTED_TO 8
+#define WFRM_BACKUP_ORIGINAL 16
/* Flags for conversion functions. */
static const uint FN_FROM_IS_TMP= 1 << 0;
@@ -77,7 +83,8 @@ bool check_mysql50_prefix(const char *name);
uint build_table_filename(char *buff, size_t bufflen, const char *db,
const char *table, const char *ext, uint flags);
uint build_table_shadow_filename(char *buff, size_t bufflen,
- ALTER_PARTITION_PARAM_TYPE *lpt);
+ ALTER_PARTITION_PARAM_TYPE *lpt,
+ bool backup= false);
void build_lower_case_table_filename(char *buff, size_t bufflen,
const LEX_CSTRING *db,
const LEX_CSTRING *table,
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
deleted file mode 100644
index bfbaf185243..00000000000
--- a/sql/sql_tablespace.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
-
- 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
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
-
-/* drop and alter of tablespaces */
-
-#include "mariadb.h"
-#include "sql_priv.h"
-#include "unireg.h"
-#include "sql_tablespace.h"
-#include "sql_table.h" // write_bin_log
-#include "sql_class.h" // THD
-
-int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
-{
- int error= HA_ADMIN_NOT_IMPLEMENTED;
- handlerton *hton= ts_info->storage_engine;
-
- DBUG_ENTER("mysql_alter_tablespace");
- /*
- If the user haven't defined an engine, this will fallback to using the
- default storage engine.
- */
- if (hton == NULL)
- {
- hton= ha_default_handlerton(thd);
- if (ts_info->storage_engine != 0)
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
- hton_name(hton)->str,
- ts_info->tablespace_name ? ts_info->tablespace_name
- : ts_info->logfile_group_name);
- }
-
- if (hton->alter_tablespace)
- {
- if (unlikely((error= hton->alter_tablespace(hton, thd, ts_info))))
- {
- if (error == 1)
- DBUG_RETURN(1);
-
- if (error == HA_ADMIN_NOT_IMPLEMENTED)
- my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "");
- else
- my_error(error, MYF(0));
-
- DBUG_RETURN(error);
- }
- }
- else
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_ILLEGAL_HA_CREATE_OPTION,
- ER_THD(thd, ER_ILLEGAL_HA_CREATE_OPTION),
- hton_name(hton)->str,
- "TABLESPACE or LOGFILE GROUP");
- }
- error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
- DBUG_RETURN(error);
-}
diff --git a/sql/sql_tablespace.h b/sql/sql_tablespace.h
deleted file mode 100644
index 0760935edfc..00000000000
--- a/sql/sql_tablespace.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
-
- 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
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
-
-#ifndef SQL_TABLESPACE_INCLUDED
-#define SQL_TABLESPACE_INCLUDED
-
-class THD;
-class st_alter_tablespace;
-
-int mysql_alter_tablespace(THD* thd, st_alter_tablespace *ts_info);
-
-#endif /* SQL_TABLESPACE_INCLUDED */
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index e06600700bb..0d1a8313564 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -264,7 +264,7 @@ static void print_keyuse(KEYUSE *keyuse)
void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array)
{
DBUG_LOCK_FILE;
- fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements);
+ fprintf(DBUG_FILE, "KEYUSE array (%zu elements)\n", keyuse_array->elements);
for(uint i=0; i < keyuse_array->elements; i++)
print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i));
DBUG_UNLOCK_FILE;
diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h
new file mode 100644
index 00000000000..332b712db31
--- /dev/null
+++ b/sql/sql_type_fixedbin.h
@@ -0,0 +1,1912 @@
+#ifndef SQL_TYPE_FIXEDBIN_H
+#define SQL_TYPE_FIXEDBIN_H
+/* Copyright (c) 2019,2021 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ This is a common code for plugin (?) types that are generally
+ handled like strings, but have their own fixed size on-disk binary storage
+ format and their own (variable size) canonical string representation.
+
+ Examples are INET6 and UUID types.
+*/
+
+#define MYSQL_SERVER
+#include "sql_class.h" // THD, SORT_FIELD_ATTR
+#include "opt_range.h" // SEL_ARG, null_element
+#include "sql_type_fixedbin_storage.h"
+
+/***********************************************************************/
+
+
+template<class FbtImpl>
+class FixedBinTypeBundle
+{
+public:
+ class Fbt: public FbtImpl
+ {
+ protected:
+ using FbtImpl::m_buffer;
+ bool make_from_item(Item *item, bool warn)
+ {
+ if (item->type_handler() == type_handler_fbt())
+ {
+ Native tmp(m_buffer, sizeof(m_buffer));
+ bool rc= item->val_native(current_thd, &tmp);
+ if (rc)
+ return true;
+ DBUG_ASSERT(tmp.length() == sizeof(m_buffer));
+ if (tmp.ptr() != m_buffer)
+ memcpy(m_buffer, tmp.ptr(), sizeof(m_buffer));
+ return false;
+ }
+ StringBuffer<FbtImpl::max_char_length()+1> tmp;
+ String *str= item->val_str(&tmp);
+ return str ? make_from_character_or_binary_string(str, warn) : true;
+ }
+
+ bool character_string_to_fbt(const char *str, size_t str_length,
+ CHARSET_INFO *cs)
+ {
+ if (cs->state & MY_CS_NONASCII)
+ {
+ char tmp[FbtImpl::max_char_length()+1];
+ String_copier copier;
+ uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp),
+ cs, str, str_length);
+ return FbtImpl::ascii_to_fbt(tmp, length);
+ }
+ return FbtImpl::ascii_to_fbt(str, str_length);
+ }
+ bool make_from_character_or_binary_string(const String *str, bool warn)
+ {
+ if (str->charset() != &my_charset_bin)
+ {
+ bool rc= character_string_to_fbt(str->ptr(), str->length(),
+ str->charset());
+ if (rc && warn)
+ current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ type_handler_fbt()->name().ptr(), ErrConvString(str).ptr());
+ return rc;
+ }
+ if (str->length() != sizeof(m_buffer))
+ {
+ if (warn)
+ current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ type_handler_fbt()->name().ptr(), ErrConvString(str).ptr());
+ return true;
+ }
+ DBUG_ASSERT(str->ptr() != m_buffer);
+ memcpy(m_buffer, str->ptr(), sizeof(m_buffer));
+ return false;
+ }
+ bool binary_to_fbt(const char *str, size_t length)
+ {
+ if (length != sizeof(m_buffer))
+ return true;
+ memcpy(m_buffer, str, length);
+ return false;
+ }
+
+ Fbt() { }
+
+ public:
+
+ static Fbt zero()
+ {
+ Fbt fbt;
+ fbt.set_zero();
+ return fbt;
+ }
+
+ static Fbt record_to_memory(const char *ptr)
+ {
+ Fbt fbt;
+ FbtImpl::record_to_memory(fbt.m_buffer, ptr);
+ return fbt;
+ }
+ /*
+ Check at Item's fix_fields() time if "item" can return a nullable value
+ on conversion to Fbt, or conversion produces a NOT NULL Fbt value.
+ */
+ static bool fix_fields_maybe_null_on_conversion_to_fbt(Item *item)
+ {
+ if (item->maybe_null())
+ return true;
+ if (item->type_handler() == type_handler_fbt())
+ return false;
+ if (!item->const_item() || item->is_expensive())
+ return true;
+ return Fbt_null(item, false).is_null();
+ }
+
+ public:
+
+ Fbt(Item *item, bool *error, bool warn= true)
+ {
+ *error= make_from_item(item, warn);
+ }
+ void to_record(char *str, size_t str_size) const
+ {
+ DBUG_ASSERT(str_size >= sizeof(m_buffer));
+ FbtImpl::memory_to_record(str, m_buffer);
+ }
+ bool to_binary(String *to) const
+ {
+ return to->copy(m_buffer, sizeof(m_buffer), &my_charset_bin);
+ }
+ bool to_native(Native *to) const
+ {
+ return to->copy(m_buffer, sizeof(m_buffer));
+ }
+ bool to_string(String *to) const
+ {
+ to->set_charset(&my_charset_latin1);
+ if (to->alloc(FbtImpl::max_char_length()+1))
+ return true;
+ to->length((uint32) FbtImpl::to_string(const_cast<char*>(to->ptr()),
+ FbtImpl::max_char_length()+1));
+ return false;
+ }
+ int cmp(const Binary_string &other) const
+ {
+ return FbtImpl::cmp(FbtImpl::to_lex_cstring(), other.to_lex_cstring());
+ }
+ int cmp(const Fbt &other) const
+ {
+ return FbtImpl::cmp(FbtImpl::to_lex_cstring(), other.to_lex_cstring());
+ }
+ };
+
+ class Fbt_null: public Fbt, public Null_flag
+ {
+ public:
+ // Initialize from a text representation
+ Fbt_null(const char *str, size_t length, CHARSET_INFO *cs)
+ :Null_flag(Fbt::character_string_to_fbt(str, length, cs)) { }
+ Fbt_null(const String &str)
+ :Fbt_null(str.ptr(), str.length(), str.charset()) { }
+ // Initialize from a binary representation
+ Fbt_null(const char *str, size_t length)
+ :Null_flag(Fbt::binary_to_fbt(str, length)) { }
+ Fbt_null(const Binary_string &str)
+ :Fbt_null(str.ptr(), str.length()) { }
+ // Initialize from an Item
+ Fbt_null(Item *item, bool warn= true)
+ :Null_flag(Fbt::make_from_item(item, warn)) { }
+ public:
+ const Fbt& to_fbt() const
+ {
+ DBUG_ASSERT(!is_null());
+ return *this;
+ }
+ void to_record(char *str, size_t str_size) const
+ {
+ to_fbt().to_record(str, str_size);
+ }
+ bool to_binary(String *to) const
+ {
+ return to_fbt().to_binary(to);
+ }
+ size_t to_string(char *dst, size_t dstsize) const
+ {
+ return to_fbt().to_string(dst, dstsize);
+ }
+ bool to_string(String *to) const
+ {
+ return to_fbt().to_string(to);
+ }
+ };
+
+ class Type_std_attributes_fbt: public Type_std_attributes
+ {
+ public:
+ Type_std_attributes_fbt()
+ :Type_std_attributes(
+ Type_numeric_attributes(FbtImpl::max_char_length(), 0, true),
+ DTCollation_numeric())
+ { }
+ };
+
+ class Type_handler_fbt: public Type_handler
+ {
+ bool character_or_binary_string_to_native(THD *thd, const String *str,
+ Native *to) const
+ {
+ if (str->charset() == &my_charset_bin)
+ {
+ // Convert from a binary string
+ if (str->length() != FbtImpl::binary_length() ||
+ to->copy(str->ptr(), str->length()))
+ {
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name().ptr(), ErrConvString(str).ptr());
+ return true;
+ }
+ return false;
+ }
+ // Convert from a character string
+ Fbt_null tmp(*str);
+ if (tmp.is_null())
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name().ptr(), ErrConvString(str).ptr());
+ return tmp.is_null() || tmp.to_native(to);
+ }
+
+ public:
+ ~Type_handler_fbt() override {}
+
+ const Type_collection *type_collection() const override
+ {
+ static Type_collection_fbt type_collection_fbt;
+ return &type_collection_fbt;
+ }
+
+ const Name &default_value() const override
+ {
+ return FbtImpl::default_value();
+ }
+ ulong KEY_pack_flags(uint column_nr) const override
+ {
+ return FbtImpl::KEY_pack_flags(column_nr);
+ }
+ protocol_send_type_t protocol_send_type() const override
+ {
+ return PROTOCOL_SEND_STRING;
+ }
+ bool Item_append_extended_type_info(Send_field_extended_metadata *to,
+ const Item *item) const override
+ {
+ return to->set_data_type_name(name().lex_cstring());
+ }
+
+ enum_field_types field_type() const override
+ {
+ return MYSQL_TYPE_STRING;
+ }
+
+ Item_result result_type() const override
+ {
+ return STRING_RESULT;
+ }
+
+ Item_result cmp_type() const override
+ {
+ return STRING_RESULT;
+ }
+
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_STRING;
+ }
+
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ {
+ return FbtImpl::max_char_length();
+ }
+
+ const Type_handler *type_handler_for_comparison() const override
+ {
+ return this;
+ }
+
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override
+ {
+ DBUG_ASSERT(field->type_handler() == this);
+ Fbt_null ni(item); // Convert Item to Fbt
+ if (ni.is_null())
+ return 0;
+ NativeBuffer<FbtImpl::binary_length()+1> tmp;
+ if (field->val_native(&tmp))
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ return -ni.cmp(tmp);
+ }
+ CHARSET_INFO *charset_for_protocol(const Item *item) const override
+ {
+ return item->collation.collation;
+ }
+
+ bool is_scalar_type() const override { return true; }
+ bool is_val_native_ready() const override { return true; }
+ bool can_return_int() const override { return false; }
+ bool can_return_decimal() const override { return false; }
+ bool can_return_real() const override { return false; }
+ bool can_return_str() const override { return true; }
+ bool can_return_text() const override { return true; }
+ bool can_return_date() const override { return false; }
+ bool can_return_time() const override { return false; }
+ bool convert_to_binary_using_val_native() const override { return true; }
+
+ decimal_digits_t Item_time_precision(THD *thd, Item *item) const override
+ {
+ return 0;
+ }
+ decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const override
+ {
+ return 0;
+ }
+ decimal_digits_t Item_decimal_scale(const Item *item) const override
+ {
+ return 0;
+ }
+ decimal_digits_t Item_decimal_precision(const Item *item) const override
+ {
+ /* This will be needed if we ever allow cast from Fbt to DECIMAL. */
+ return (FbtImpl::binary_length()*8+7)/10*3; // = bytes to decimal digits
+ }
+
+ /*
+ Returns how many digits a divisor adds into a division result.
+ See Item::divisor_precision_increment() in item.h for more comments.
+ */
+ decimal_digits_t Item_divisor_precision_increment(const Item *) const override
+ {
+ return 0;
+ }
+ /**
+ Makes a temporary table Field to handle numeric aggregate functions,
+ e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc.
+ */
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata,
+ const Field *target) const override
+ {
+ const Record_addr tmp(NULL, Bit_addr(true));
+ return new (table->in_use->mem_root) Field_fbt(&empty_clex_str, tmp);
+ }
+ // Fix attributes after the parser
+ bool Column_definition_fix_attributes(Column_definition *c) const override
+ {
+ c->length= FbtImpl::max_char_length();
+ return false;
+ }
+
+ bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root,
+ Column_definition *def, handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes *derived_attr)
+ const override
+ {
+ def->prepare_stage1_simple(&my_charset_numeric);
+ return false;
+ }
+
+ bool Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file) const override
+ {
+ def->redefine_stage1_common(dup, file);
+ def->set_compression_method(dup->compression_method());
+ def->create_length_to_internal_length_string();
+ return false;
+ }
+
+ bool Column_definition_prepare_stage2(Column_definition *def, handler *file,
+ ulonglong table_flags) const override
+ {
+ def->pack_flag= FIELDFLAG_BINARY;
+ return false;
+ }
+
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ if (item_expr->cmp_type() != STRING_RESULT)
+ {
+ my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+ return true;
+ }
+ return false;
+ }
+
+ bool partition_field_append_value(String *to, Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const override
+ {
+ StringBuffer<FbtImpl::max_char_length()+64> fbtstr;
+ Fbt_null fbt(item_expr);
+ if (fbt.is_null())
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ return true;
+ }
+ return fbt.to_string(&fbtstr) ||
+ to->append('\'') ||
+ to->append(fbtstr) ||
+ to->append('\'');
+ }
+
+ Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *table) const override
+ {
+ return new (root) Field_fbt(name, addr);
+ }
+
+ Field * make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name, const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const override
+ {
+ return new (mem_root) Field_fbt(name, addr);
+ }
+ void Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const override
+ {
+ def->frm_pack_basic(buff);
+ def->frm_pack_charset(buff);
+ }
+ bool Column_definition_attributes_frm_unpack(Column_definition_attributes *def,
+ TABLE_SHARE *share, const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const override
+ {
+ def->frm_unpack_basic(buffer);
+ return def->frm_unpack_charset(share, buffer);
+ }
+ void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override
+ {
+ DBUG_ASSERT(item->type_handler() == this);
+ NativeBuffer<FbtImpl::binary_length()+1> tmp;
+ item->val_native_result(current_thd, &tmp);
+ if (item->maybe_null())
+ {
+ if (item->null_value)
+ {
+ memset(to, 0, FbtImpl::binary_length() + 1);
+ return;
+ }
+ *to++= 1;
+ }
+ DBUG_ASSERT(!item->null_value);
+ DBUG_ASSERT(FbtImpl::binary_length() == tmp.length());
+ DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length);
+ FbtImpl::memory_to_record((char*) to, tmp.ptr());
+ }
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override
+ {
+ DBUG_ASSERT(item->type_handler() == this);
+ NativeBuffer<FbtImpl::binary_length()+1> tmp;
+ item->val_native_result(current_thd, &tmp);
+ if (item->maybe_null())
+ {
+ if (item->null_value)
+ {
+ *to++=0;
+ return 0;
+ }
+ *to++= 1;
+ }
+ DBUG_ASSERT(!item->null_value);
+ DBUG_ASSERT(FbtImpl::binary_length() == tmp.length());
+ DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length);
+ FbtImpl::memory_to_record((char*) to, tmp.ptr());
+ return tmp.length();
+ }
+ void sort_length(THD *thd, const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override
+ {
+ attr->original_length= attr->length= FbtImpl::binary_length();
+ attr->suffix_length= 0;
+ }
+ uint32 max_display_length(const Item *item) const override
+ {
+ return FbtImpl::max_char_length();
+ }
+ uint32 calc_pack_length(uint32 length) const override
+ {
+ return FbtImpl::binary_length();
+ }
+ void Item_update_null_value(Item *item) const override
+ {
+ NativeBuffer<FbtImpl::binary_length()+1> tmp;
+ item->val_native(current_thd, &tmp);
+ }
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override
+ {
+ value->m_type= DYN_COL_STRING;
+ String *str= item->val_str(&value->m_string);
+ if (str != &value->m_string && !item->null_value)
+ {
+ // "item" returned a non-NULL value
+ if (Fbt_null(*str).is_null())
+ {
+ /*
+ The value was not-null, but conversion to FBT failed:
+ SELECT a, DECODE_ORACLE(fbtcol, 'garbage', '<NULL>', '::01', '01')
+ FROM t1;
+ */
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name().ptr(), ErrConvString(str).ptr());
+ value->m_type= DYN_COL_NULL;
+ return true;
+ }
+ // "item" returned a non-NULL value, and it was a valid FBT
+ value->m_string.set(str->ptr(), str->length(), str->charset());
+ }
+ return check_null(item, value);
+ }
+ void Item_param_setup_conversion(THD *thd, Item_param *param) const override
+ {
+ param->setup_conversion_string(thd, thd->variables.character_set_client);
+ }
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const override
+ {
+ param->set_param_str(pos, len);
+ }
+ bool Item_param_set_from_value(THD *thd, Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const override
+ {
+ param->unsigned_flag= false;
+ param->setup_conversion_string(thd, attr->collation.collation);
+ /*
+ Exact value of max_length is not known unless fbt is converted to
+ charset of connection, so we have to set it later.
+ */
+ return param->set_str(val->m_string.ptr(), val->m_string.length(),
+ attr->collation.collation,
+ attr->collation.collation);
+ }
+ bool Item_param_val_native(THD *thd, Item_param *item, Native *to)
+ const override
+ {
+ StringBuffer<FbtImpl::max_char_length()+1> buffer;
+ String *str= item->val_str(&buffer);
+ if (!str)
+ return true;
+ Fbt_null tmp(*str);
+ return tmp.is_null() || tmp.to_native(to);
+ }
+ bool Item_send(Item *item, Protocol *p, st_value *buf) const override
+ {
+ return Item_send_str(item, p, buf);
+ }
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override
+ {
+ if (field->type_handler() == this)
+ {
+ NativeBuffer<MAX_FIELD_WIDTH> tmp;
+ bool rc= item->val_native(current_thd, &tmp);
+ if (rc || item->null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+ field->set_notnull();
+ return field->store_native(tmp);
+ }
+ return item->save_str_in_field(field, no_conversions);
+ }
+
+ String *print_item_value(THD *thd, Item *item, String *str) const override
+ {
+ StringBuffer<FbtImpl::max_char_length()+64> buf;
+ String *result= item->val_str(&buf);
+ /*
+ TODO: This should eventually use one of these notations:
+ 1. CAST('xxx' AS Fbt)
+ Problem: CAST is not supported as a NAME_CONST() argument.
+ 2. Fbt'xxx'
+ Problem: This syntax is not supported by the parser yet.
+ */
+ return !result || str->realloc(result->length() + 2) ||
+ str->append(STRING_WITH_LEN("'")) ||
+ str->append(result->ptr(), result->length()) ||
+ str->append(STRING_WITH_LEN("'")) ? nullptr : str;
+ }
+
+ /**
+ Check if
+ WHERE expr=value AND expr=const
+ can be rewritten as:
+ WHERE const=value AND expr=const
+
+ "this" is the comparison handler that is used by "target".
+
+ @param target - the predicate expr=value,
+ whose "expr" argument will be replaced to "const".
+ @param target_expr - the target's "expr" which will be replaced to "const".
+ @param target_value - the target's second argument, it will remain unchanged.
+ @param source - the equality predicate expr=const (or expr<=>const)
+ that can be used to rewrite the "target" part
+ (under certain conditions, see the code).
+ @param source_expr - the source's "expr". It should be exactly equal to
+ the target's "expr" to make condition rewrite possible.
+ @param source_const - the source's "const" argument, it will be inserted
+ into "target" instead of "expr".
+ */
+ bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr,
+ Item *target_value, Item_bool_func2 *source,
+ Item *source_expr, Item *source_const)
+ const override
+ {
+ /*
+ WHERE COALESCE(col)='xxx' AND COALESCE(col)=CONCAT(a); -->
+ WHERE COALESCE(col)='xxx' AND 'xxx'=CONCAT(a);
+ */
+ return target->compare_type_handler() == source->compare_type_handler();
+ }
+ bool subquery_type_allows_materialization(const Item *inner,
+ const Item *outer, bool) const override
+ {
+ /*
+ Example:
+ SELECT * FROM t1 WHERE a IN (SELECT col FROM t1 GROUP BY col);
+ Allow materialization only if the outer column is also FBT.
+ This can be changed for more relaxed rules in the future.
+ */
+ DBUG_ASSERT(inner->type_handler() == this);
+ return outer->type_handler() == this;
+ }
+ /**
+ Make a simple constant replacement item for a constant "src",
+ so the new item can futher be used for comparison with "cmp", e.g.:
+ src = cmp -> replacement = cmp
+
+ "this" is the type handler that is used to compare "src" and "cmp".
+
+ @param thd - current thread, for mem_root
+ @param src - The item that we want to replace. It's a const item,
+ but it can be complex enough to calculate on every row.
+ @param cmp - The src's comparand.
+ @retval - a pointer to the created replacement Item
+ @retval - NULL, if could not create a replacement (e.g. on EOM).
+ NULL is also returned for ROWs, because instead of replacing
+ a Item_row to a new Item_row, Type_handler_row just replaces
+ its elements.
+ */
+ Item *make_const_item_for_comparison(THD *thd, Item *src,
+ const Item *cmp) const override
+ {
+ Fbt_null tmp(src);
+ if (tmp.is_null())
+ return new (thd->mem_root) Item_null(thd, src->name.str);
+ return new (thd->mem_root) Item_literal_fbt(thd, tmp);
+ }
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override
+ {
+ return new (thd->mem_root) Item_cache_fbt(thd);
+ }
+
+ Item *create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const override
+ {
+ return new (thd->mem_root) Item_typecast_fbt(thd, item);
+ }
+ Item_copy *create_item_copy(THD *thd, Item *item) const override
+ {
+ return new (thd->mem_root) Item_copy_fbt(thd, item);
+ }
+ int cmp_native(const Native &a, const Native &b) const override
+ {
+ return FbtImpl::cmp(a.to_lex_cstring(), b.to_lex_cstring());
+ }
+ bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override
+ {
+ return cmp->set_cmp_func_native(thd);
+ }
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const override
+ {
+ return false;
+ }
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const override
+ {
+ Fbt_null na(a), nb(b);
+ return !na.is_null() && !nb.is_null() && !na.cmp(nb);
+ }
+ bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name,
+ Type_handler_hybrid_field_type *h,
+ Type_all_attributes *attr,
+ Item **items, uint nitems) const override
+ {
+ attr->Type_std_attributes::operator=(Type_std_attributes_fbt());
+ h->set_handler(this);
+ /*
+ If some of the arguments cannot be safely converted to "FBT NOT NULL",
+ then mark the entire function nullability as NULL-able.
+ Otherwise, keep the generic nullability calculated by earlier stages:
+ - either by the most generic way in Item_func::fix_fields()
+ - or by Item_func_xxx::fix_length_and_dec() before the call of
+ Item_hybrid_func_fix_attributes()
+ IFNULL() is special. It does not need to test args[0].
+ */
+ uint first= dynamic_cast<Item_func_ifnull*>(attr) ? 1 : 0;
+ for (uint i= first; i < nitems; i++)
+ {
+ if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(items[i]))
+ {
+ attr->set_type_maybe_null(true);
+ break;
+ }
+ }
+ return false;
+ }
+ bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const override
+ {
+ return Item_hybrid_func_fix_attributes(thd, func->func_name_cstring(),
+ func, func, items, nitems);
+
+ }
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override
+ {
+ func->Type_std_attributes::operator=(Type_std_attributes_fbt());
+ func->set_handler(this);
+ return false;
+ }
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool Item_val_native_with_conversion(THD *thd, Item *item,
+ Native *to) const override
+ {
+ if (item->type_handler() == this)
+ return item->val_native(thd, to); // No conversion needed
+ StringBuffer<FbtImpl::max_char_length()+1> buffer;
+ String *str= item->val_str(&buffer);
+ return str ? character_or_binary_string_to_native(thd, str, to) : true;
+ }
+ bool Item_val_native_with_conversion_result(THD *thd, Item *item,
+ Native *to) const override
+ {
+ if (item->type_handler() == this)
+ return item->val_native_result(thd, to); // No conversion needed
+ StringBuffer<FbtImpl::max_char_length()+1> buffer;
+ String *str= item->str_result(&buffer);
+ return str ? character_or_binary_string_to_native(thd, str, to) : true;
+ }
+
+ bool Item_val_bool(Item *item) const override
+ {
+ NativeBuffer<FbtImpl::binary_length()+1> tmp;
+ if (item->val_native(current_thd, &tmp))
+ return false;
+ return !Fbt::only_zero_bytes(tmp.ptr(), tmp.length());
+ }
+ void Item_get_date(THD *thd, Item *item, Temporal::Warn *buff,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ }
+
+ longlong Item_val_int_signed_typecast(Item *item) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+
+ longlong Item_val_int_unsigned_typecast(Item *item) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str)
+ const override
+ {
+ NativeBuffer<FbtImpl::binary_length()+1> tmp;
+ if ((item->null_value= item->arguments()[0]->val_native(current_thd, &tmp)))
+ return nullptr;
+ DBUG_ASSERT(tmp.length() == FbtImpl::binary_length());
+ if (str->set_hex(tmp.ptr(), tmp.length()))
+ {
+ str->length(0);
+ str->set_charset(item->collation.collation);
+ }
+ return str;
+ }
+
+ String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *item,
+ String *str) const override
+ {
+ NativeBuffer<FbtImpl::binary_length()+1> native;
+ if (item->val_native(current_thd, &native))
+ {
+ DBUG_ASSERT(item->null_value);
+ return nullptr;
+ }
+ DBUG_ASSERT(native.length() == FbtImpl::binary_length());
+ Fbt_null tmp(native.ptr(), native.length());
+ return tmp.is_null() || tmp.to_string(str) ? nullptr : str;
+ }
+ double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+ const override
+ {
+ return 0;
+ }
+ longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+ const override
+ {
+ return 0;
+ }
+ my_decimal *
+ Item_func_hybrid_field_type_val_decimal(Item_func_hybrid_field_type *,
+ my_decimal *to) const override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
+ MYSQL_TIME *to,
+ date_mode_t fuzzydate)
+ const override
+ {
+ set_zero_time(to, MYSQL_TIMESTAMP_TIME);
+ }
+ // WHERE is Item_func_min_max_val_native???
+ String *Item_func_min_max_val_str(Item_func_min_max *func, String *str)
+ const override
+ {
+ Fbt_null tmp(func);
+ return tmp.is_null() || tmp.to_string(str) ? nullptr : str;
+ }
+ double Item_func_min_max_val_real(Item_func_min_max *) const override
+ {
+ return 0;
+ }
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override
+ {
+ return 0;
+ }
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
+ my_decimal *to) const override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *to,
+ date_mode_t fuzzydate) const override
+ {
+ set_zero_time(to, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+
+ bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override
+ {
+ return false;
+ }
+ longlong Item_func_between_val_int(Item_func_between *func) const override
+ {
+ return func->val_int_cmp_native();
+ }
+
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override
+ {
+ return new (thd->mem_root) cmp_item_fbt;
+ }
+
+ in_vector *make_in_vector(THD *thd, const Item_func_in *func,
+ uint nargs) const override
+ {
+ return new (thd->mem_root) in_fbt(thd, nargs);
+ }
+
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func)
+ const override
+ {
+ if (func->compatible_types_scalar_bisection_possible())
+ {
+ return func->value_list_convert_const_to_int(thd) ||
+ func->fix_for_scalar_comparison_using_bisection(thd);
+ }
+ return
+ func->fix_for_scalar_comparison_using_cmp_items(thd,
+ 1U << (uint) STRING_RESULT);
+ }
+ bool Item_func_round_fix_length_and_dec(Item_func_round *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *item)
+ const override
+ {
+ if (item->cast_charset() == &my_charset_bin)
+ {
+ static Item_char_typecast_func_handler_fbt_to_binary
+ item_char_typecast_func_handler_fbt_to_binary;
+ item->fix_length_and_dec_native_to_binary(FbtImpl::binary_length());
+ item->set_func_handler(&item_char_typecast_func_handler_fbt_to_binary);
+ return false;
+ }
+ item->fix_length_and_dec_str();
+ return false;
+ }
+
+ bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_func_div_fix_length_and_dec(Item_func_div *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ };
+
+ class cmp_item_fbt: public cmp_item_scalar
+ {
+ Fbt m_native;
+ public:
+ cmp_item_fbt()
+ :cmp_item_scalar(),
+ m_native(Fbt::zero())
+ { }
+ void store_value(Item *item) override
+ {
+ m_native= Fbt(item, &m_null_value);
+ }
+ int cmp_not_null(const Value *val) override
+ {
+ DBUG_ASSERT(!val->is_null());
+ DBUG_ASSERT(val->is_string());
+ Fbt_null tmp(val->m_string);
+ DBUG_ASSERT(!tmp.is_null());
+ return m_native.cmp(tmp);
+ }
+ int cmp(Item *arg) override
+ {
+ Fbt_null tmp(arg);
+ return m_null_value || tmp.is_null() ? UNKNOWN : m_native.cmp(tmp) != 0;
+ }
+ int compare(cmp_item *ci) override
+ {
+ cmp_item_fbt *tmp= static_cast<cmp_item_fbt*>(ci);
+ DBUG_ASSERT(!m_null_value);
+ DBUG_ASSERT(!tmp->m_null_value);
+ return m_native.cmp(tmp->m_native);
+ }
+ cmp_item *make_same(THD *thd) override
+ {
+ return new (thd->mem_root) cmp_item_fbt();
+ }
+ };
+
+ class Field_fbt: public Field
+ {
+ static void set_min_value(char *ptr)
+ {
+ memset(ptr, 0, FbtImpl::binary_length());
+ }
+ static void set_max_value(char *ptr)
+ {
+ memset(ptr, 0xFF, FbtImpl::binary_length());
+ }
+ void store_warning(const ErrConv &str,
+ Sql_condition::enum_warning_level level)
+ {
+ if (get_thd()->count_cuted_fields <= CHECK_FIELD_EXPRESSION)
+ return;
+ const TABLE_SHARE *s= table->s;
+ static const Name type_name= type_handler_fbt()->name();
+ get_thd()->push_warning_truncated_value_for_field(level, type_name.ptr(),
+ str.ptr(), s ? s->db.str : nullptr, s ? s->table_name.str : nullptr,
+ field_name.str);
+ }
+ int set_null_with_warn(const ErrConv &str)
+ {
+ store_warning(str, Sql_condition::WARN_LEVEL_WARN);
+ set_null();
+ return 1;
+ }
+ int set_min_value_with_warn(const ErrConv &str)
+ {
+ store_warning(str, Sql_condition::WARN_LEVEL_WARN);
+ set_min_value((char*) ptr);
+ return 1;
+ }
+ int set_max_value_with_warn(const ErrConv &str)
+ {
+ store_warning(str, Sql_condition::WARN_LEVEL_WARN);
+ set_max_value((char*) ptr);
+ return 1;
+ }
+ int store_fbt_null_with_warn(const Fbt_null &fbt,
+ const ErrConvString &err)
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ if (fbt.is_null())
+ return maybe_null() ? set_null_with_warn(err)
+ : set_min_value_with_warn(err);
+ fbt.to_record((char *) ptr, FbtImpl::binary_length());
+ return 0;
+ }
+
+ public:
+ Field_fbt(const LEX_CSTRING *field_name_arg, const Record_addr &rec)
+ :Field(rec.ptr(), FbtImpl::max_char_length(),
+ rec.null_ptr(), rec.null_bit(), Field::NONE, field_name_arg)
+ {
+ flags|= BINARY_FLAG | UNSIGNED_FLAG;
+ }
+ const Type_handler *type_handler() const override
+ {
+ return type_handler_fbt();
+ }
+ uint32 max_display_length() const override { return field_length; }
+ bool str_needs_quotes() const override { return true; }
+ const DTCollation &dtcollation() const override
+ {
+ static DTCollation_numeric c;
+ return c;
+ }
+ CHARSET_INFO *charset(void) const override { return &my_charset_numeric; }
+ const CHARSET_INFO *sort_charset(void) const override { return &my_charset_bin; }
+ /**
+ This makes client-server protocol convert the value according
+ to @@character_set_client.
+ */
+ bool binary() const override { return false; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
+
+ bool is_equal(const Column_definition &new_field) const override
+ {
+ return new_field.type_handler() == type_handler();
+ }
+ bool eq_def(const Field *field) const override
+ {
+ return Field::eq_def(field);
+ }
+ double pos_in_interval(Field *min, Field *max) override
+ {
+ return pos_in_interval_val_str(min, max, 0);
+ }
+ int cmp(const uchar *a, const uchar *b) const override
+ { return memcmp(a, b, pack_length()); }
+
+ void sort_string(uchar *to, uint length) override
+ {
+ DBUG_ASSERT(length == pack_length());
+ memcpy(to, ptr, length);
+ }
+ uint32 pack_length() const override
+ {
+ return FbtImpl::binary_length();
+ }
+ uint pack_length_from_metadata(uint field_metadata) const override
+ {
+ return FbtImpl::binary_length();
+ }
+
+ void sql_type(String &str) const override
+ {
+ static Name name= type_handler_fbt()->name();
+ str.set_ascii(name.ptr(), name.length());
+ }
+
+ void make_send_field(Send_field *to) override
+ {
+ Field::make_send_field(to);
+ to->set_data_type_name(type_handler_fbt()->name().lex_cstring());
+ }
+
+ bool validate_value_in_record(THD *thd, const uchar *record) const override
+ {
+ return false;
+ }
+
+ bool val_native(Native *to) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ DBUG_ASSERT(!is_null());
+ if (to->alloc(FbtImpl::binary_length()))
+ return true;
+ to->length(FbtImpl::binary_length());
+ FbtImpl::record_to_memory((char*) to->ptr(), (const char*) ptr);
+ return false;
+ }
+
+ Fbt to_fbt() const
+ {
+ DBUG_ASSERT(marked_for_read());
+ DBUG_ASSERT(!is_null());
+ return Fbt::record_to_memory((const char*) ptr);
+ }
+
+ String *val_str(String *val_buffer, String *) override
+ {
+ return to_fbt().to_string(val_buffer) ? NULL : val_buffer;
+ }
+
+ my_decimal *val_decimal(my_decimal *to) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ my_decimal_set_zero(to);
+ return to;
+ }
+
+ longlong val_int() override
+ {
+ DBUG_ASSERT(marked_for_read());
+ return 0;
+ }
+
+ double val_real() override
+ {
+ DBUG_ASSERT(marked_for_read());
+ return 0;
+ }
+
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+
+ bool val_bool(void) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ return !Fbt::only_zero_bytes((const char *) ptr, FbtImpl::binary_length());
+ }
+
+ int store_native(const Native &value) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ DBUG_ASSERT(value.length() == FbtImpl::binary_length());
+ FbtImpl::memory_to_record((char*) ptr, value.ptr());
+ return 0;
+ }
+
+ int store(const char *str, size_t length, CHARSET_INFO *cs) override
+ {
+ return cs == &my_charset_bin ? store_binary(str, length)
+ : store_text(str, length, cs);
+ }
+
+ int store_text(const char *str, size_t length, CHARSET_INFO *cs) override
+ {
+ return store_fbt_null_with_warn(Fbt_null(str, length, cs),
+ ErrConvString(str, length, cs));
+ }
+
+ int store_binary(const char *str, size_t length) override
+ {
+ return store_fbt_null_with_warn(Fbt_null(str, length),
+ ErrConvString(str, length,
+ &my_charset_bin));
+ }
+
+ int store_hex_hybrid(const char *str, size_t length) override
+ {
+ return Field_fbt::store_binary(str, length);
+ }
+
+ int store_decimal(const my_decimal *num) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(ErrConvDecimal(num));
+ }
+
+ int store(longlong nr, bool unsigned_flag) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(
+ ErrConvInteger(Longlong_hybrid(nr, unsigned_flag)));
+ }
+
+ int store(double nr) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(ErrConvDouble(nr));
+ }
+
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(ErrConvTime(ltime));
+ }
+
+ /*** Field conversion routines ***/
+ int store_field(Field *from) override
+ {
+ // INSERT INTO t1 (fbt_field) SELECT different_field_type FROM t2;
+ return from->save_in_field(this);
+ }
+ int save_in_field(Field *to) override
+ {
+ // INSERT INTO t2 (different_field_type) SELECT fbt_field FROM t1;
+ if (to->charset() == &my_charset_bin &&
+ dynamic_cast<const Type_handler_general_purpose_string*>
+ (to->type_handler()))
+ {
+ NativeBuffer<FbtImpl::binary_length()+1> res;
+ val_native(&res);
+ return to->store(res.ptr(), res.length(), &my_charset_bin);
+ }
+ return save_in_field_str(to);
+ }
+ Copy_func *get_copy_func(const Field *from) const override
+ {
+ // ALTER to FBT from another field
+ return do_field_string;
+ }
+
+ Copy_func *get_copy_func_to(const Field *to) const override
+ {
+ if (type_handler() == to->type_handler())
+ {
+ // ALTER from FBT to FBT
+ DBUG_ASSERT(pack_length() == to->pack_length());
+ DBUG_ASSERT(charset() == to->charset());
+ DBUG_ASSERT(sort_charset() == to->sort_charset());
+ return Field::do_field_eq;
+ }
+ // ALTER from FBT to another fbt type
+ if (to->charset() == &my_charset_bin &&
+ dynamic_cast<const Type_handler_general_purpose_string*>
+ (to->type_handler()))
+ {
+ /*
+ ALTER from FBT to a binary string type, e.g.:
+ BINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
+ */
+ return do_field_fbt_native_to_binary;
+ }
+ return do_field_string;
+ }
+
+ static void do_field_fbt_native_to_binary(Copy_field *copy)
+ {
+ NativeBuffer<FbtImpl::binary_length()+1> res;
+ copy->from_field->val_native(&res);
+ copy->to_field->store(res.ptr(), res.length(), &my_charset_bin);
+ }
+
+ bool memcpy_field_possible(const Field *from) const override
+ {
+ // INSERT INTO t1 (fbt_field) SELECT field2 FROM t2;
+ return type_handler() == from->type_handler();
+ }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override
+ {
+ if (type_handler() == source.type_handler() ||
+ (source.type_handler() == &type_handler_string &&
+ source.type_handler()->max_display_length_for_field(source) ==
+ FbtImpl::binary_length()))
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ return CONV_TYPE_IMPOSSIBLE;
+ }
+
+ /*** Optimizer routines ***/
+ bool test_if_equality_guarantees_uniqueness(const Item *const_item) const override
+ {
+ /*
+ This condition:
+ WHERE fbt_field=const
+ should return a single distinct value only,
+ as comparison is done according to FBT.
+ */
+ return true;
+ }
+ bool can_be_substituted_to_equal_item(const Context &ctx,
+ const Item_equal *item_equal)
+ override
+ {
+ switch (ctx.subst_constraint()) {
+ case ANY_SUBST:
+ return ctx.compare_type_handler() == item_equal->compare_type_handler();
+ case IDENTITY_SUBST:
+ return true;
+ }
+ return false;
+ }
+ Item *get_equal_const_item(THD *thd, const Context &ctx,
+ Item *const_item) override
+ {
+ Fbt_null tmp(const_item);
+ if (tmp.is_null())
+ return NULL;
+ return new (thd->mem_root) Item_literal_fbt(thd, tmp);
+ }
+ bool can_optimize_keypart_ref(const Item_bool_func *cond,
+ const Item *item) const override
+ {
+ /*
+ Mixing of two different non-traditional types is currently prevented.
+ This may change in the future.
+ */
+ DBUG_ASSERT(item->type_handler()->is_traditional_scalar_type() ||
+ item->type_handler() == type_handler());
+ return true;
+ }
+ /**
+ Test if Field can use range optimizer for a standard comparison operation:
+ <=, <, =, <=>, >, >=
+ Note, this method does not cover spatial operations.
+ */
+ bool can_optimize_range(const Item_bool_func *cond,
+ const Item *item,
+ bool is_eq_func) const override
+ {
+ // See the DBUG_ASSERT comment in can_optimize_keypart_ref()
+ DBUG_ASSERT(item->type_handler()->is_traditional_scalar_type() ||
+ item->type_handler() == type_handler());
+ return true;
+ }
+ void hash(ulong *nr, ulong *nr2) override
+ {
+ if (is_null())
+ *nr^= (*nr << 1) | 1;
+ else
+ FbtImpl::hash_record(ptr, nr, nr2);
+ }
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value) override
+ {
+ DBUG_ENTER("Field_fbt::get_mm_leaf");
+ if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
+ DBUG_RETURN(0);
+ int err= value->save_in_field_no_warnings(this, 1);
+ if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
+ DBUG_RETURN(&null_element);
+ if (err > 0)
+ {
+ if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL)
+ DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this));
+ DBUG_RETURN(NULL); /* Cannot infer anything */
+ }
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
+ }
+ bool can_optimize_hash_join(const Item_bool_func *cond,
+ const Item *item) const override
+ {
+ return can_optimize_keypart_ref(cond, item);
+ }
+ bool can_optimize_group_min_max(const Item_bool_func *cond,
+ const Item *const_item) const override
+ {
+ return true;
+ }
+
+ uint row_pack_length() const override { return pack_length(); }
+
+ Binlog_type_info binlog_type_info() const override
+ {
+ DBUG_ASSERT(type() == binlog_type());
+ return Binlog_type_info_fixed_string(Field_fbt::binlog_type(),
+ FbtImpl::binary_length(), &my_charset_bin);
+ }
+
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override
+ {
+ DBUG_PRINT("debug", ("Packing field '%s'", field_name.str));
+ return FbtImpl::pack(to, from, max_length);
+ }
+
+ const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data) override
+ {
+ return FbtImpl::unpack(to, from, from_end, param_data);
+ }
+
+ uint max_packed_col_length(uint max_length) override
+ {
+ return StringPack::max_packed_col_length(max_length);
+ }
+
+ uint packed_col_length(const uchar *fbt_ptr, uint length) override
+ {
+ return StringPack::packed_col_length(fbt_ptr, length);
+ }
+
+ uint size_of() const override { return sizeof(*this); }
+ };
+
+ class Item_typecast_fbt: public Item_func
+ {
+ public:
+ Item_typecast_fbt(THD *thd, Item *a) :Item_func(thd, a) {}
+
+ const Type_handler *type_handler() const override
+ { return type_handler_fbt(); }
+
+ enum Functype functype() const override { return CHAR_TYPECAST_FUNC; }
+ bool eq(const Item *item, bool binary_cmp) const override
+ {
+ if (this == item)
+ return true;
+ if (item->type() != FUNC_ITEM ||
+ functype() != ((Item_func*)item)->functype())
+ return false;
+ if (type_handler() != item->type_handler())
+ return false;
+ Item_typecast_fbt *cast= (Item_typecast_fbt*) item;
+ return args[0]->eq(cast->args[0], binary_cmp);
+ }
+ LEX_CSTRING func_name_cstring() const override
+ {
+ static Name name= type_handler_fbt()->name();
+ size_t len= 9+name.length()+1;
+ char *buf= (char*)current_thd->alloc(len);
+ strmov(strmov(buf, "cast_as_"), name.ptr());
+ return { buf, len };
+ }
+ void print(String *str, enum_query_type query_type) override
+ {
+ str->append(STRING_WITH_LEN("cast("));
+ args[0]->print(str, query_type);
+ str->append(STRING_WITH_LEN(" as "));
+ str->append(type_handler_fbt()->name().lex_cstring());
+ str->append(')');
+ }
+ bool fix_length_and_dec() override
+ {
+ Type_std_attributes::operator=(Type_std_attributes_fbt());
+ if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(args[0]))
+ set_maybe_null();
+ return false;
+ }
+ String *val_str(String *to) override
+ {
+ Fbt_null tmp(args[0]);
+ return (null_value= tmp.is_null() || tmp.to_string(to)) ? NULL : to;
+ }
+ longlong val_int() override
+ {
+ return 0;
+ }
+ double val_real() override
+ {
+ return 0;
+ }
+ my_decimal *val_decimal(my_decimal *to) override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+ bool val_native(THD *thd, Native *to) override
+ {
+ Fbt_null tmp(args[0]);
+ return null_value= tmp.is_null() || tmp.to_native(to);
+ }
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_typecast_fbt>(thd, this); }
+ };
+
+ class Item_cache_fbt: public Item_cache
+ {
+ NativeBuffer<FbtImpl::binary_length()+1> m_value;
+ public:
+ Item_cache_fbt(THD *thd)
+ :Item_cache(thd, type_handler_fbt()) { }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_cache_fbt>(thd, this); }
+ bool cache_value()
+ {
+ if (!example)
+ return false;
+ value_cached= true;
+ null_value= example->val_native_with_conversion_result(current_thd,
+ &m_value, type_handler());
+ return true;
+ }
+ String* val_str(String *to)
+ {
+ if (!has_value())
+ return NULL;
+ Fbt_null tmp(m_value.ptr(), m_value.length());
+ return tmp.is_null() || tmp.to_string(to) ? NULL : to;
+ }
+ my_decimal *val_decimal(my_decimal *to)
+ {
+ if (!has_value())
+ return NULL;
+ my_decimal_set_zero(to);
+ return to;
+ }
+ longlong val_int()
+ {
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ double val_real()
+ {
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ longlong val_datetime_packed(THD *thd)
+ {
+ DBUG_ASSERT(0);
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ longlong val_time_packed(THD *thd)
+ {
+ DBUG_ASSERT(0);
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ {
+ if (!has_value())
+ return true;
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+ bool val_native(THD *thd, Native *to)
+ {
+ if (!has_value())
+ return true;
+ return to->copy(m_value.ptr(), m_value.length());
+ }
+ };
+
+ class Item_literal_fbt: public Item_literal
+ {
+ Fbt m_value;
+ public:
+ Item_literal_fbt(THD *thd)
+ :Item_literal(thd),
+ m_value(Fbt::zero())
+ { }
+ Item_literal_fbt(THD *thd, const Fbt &value)
+ :Item_literal(thd),
+ m_value(value)
+ { }
+ const Type_handler *type_handler() const override
+ {
+ return type_handler_fbt();
+ }
+ longlong val_int() override
+ {
+ return 0;
+ }
+ double val_real() override
+ {
+ return 0;
+ }
+ String *val_str(String *to) override
+ {
+ return m_value.to_string(to) ? NULL : to;
+ }
+ my_decimal *val_decimal(my_decimal *to) override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+ bool val_native(THD *thd, Native *to) override
+ {
+ return m_value.to_native(to);
+ }
+ void print(String *str, enum_query_type query_type) override
+ {
+ StringBuffer<FbtImpl::max_char_length()+64> tmp;
+ tmp.append(type_handler_fbt()->name().lex_cstring());
+ my_caseup_str(&my_charset_latin1, tmp.c_ptr());
+ str->append(tmp);
+ str->append('\'');
+ m_value.to_string(&tmp);
+ str->append(tmp);
+ str->append('\'');
+ }
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_literal_fbt>(thd, this); }
+
+ // Non-overriding methods
+ void set_value(const Fbt &value)
+ {
+ m_value= value;
+ }
+ };
+
+ class Item_copy_fbt: public Item_copy
+ {
+ NativeBuffer<Fbt::binary_length()+1> m_value;
+ public:
+ Item_copy_fbt(THD *thd, Item *item_arg): Item_copy(thd, item_arg) {}
+
+ bool val_native(THD *thd, Native *to) override
+ {
+ if (null_value)
+ return true;
+ return to->copy(m_value.ptr(), m_value.length());
+ }
+ String *val_str(String *to) override
+ {
+ if (null_value)
+ return NULL;
+ Fbt_null tmp(m_value.ptr(), m_value.length());
+ return tmp.is_null() || tmp.to_string(to) ? NULL : to;
+ }
+ my_decimal *val_decimal(my_decimal *to) override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ double val_real() override
+ {
+ return 0;
+ }
+ longlong val_int() override
+ {
+ return 0;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return null_value;
+ }
+ void copy() override
+ {
+ null_value= item->val_native(current_thd, &m_value);
+ DBUG_ASSERT(null_value == item->null_value);
+ }
+ int save_in_field(Field *field, bool no_conversions) override
+ {
+ return Item::save_in_field(field, no_conversions);
+ }
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_copy_fbt>(thd, this); }
+ };
+
+ class in_fbt :public in_vector
+ {
+ Fbt m_value;
+ static int cmp_fbt(void *cmp_arg, Fbt *a, Fbt *b)
+ {
+ return a->cmp(*b);
+ }
+ public:
+ in_fbt(THD *thd, uint elements)
+ :in_vector(thd, elements, sizeof(Fbt), (qsort2_cmp) cmp_fbt, 0),
+ m_value(Fbt::zero())
+ { }
+ const Type_handler *type_handler() const override
+ {
+ return type_handler_fbt();
+ }
+ void set(uint pos, Item *item) override
+ {
+ Fbt *buff= &((Fbt *) base)[pos];
+ Fbt_null value(item);
+ if (value.is_null())
+ *buff= Fbt::zero();
+ else
+ *buff= value;
+ }
+ uchar *get_value(Item *item) override
+ {
+ Fbt_null value(item);
+ if (value.is_null())
+ return 0;
+ m_value= value;
+ return (uchar *) &m_value;
+ }
+ Item* create_item(THD *thd) override
+ {
+ return new (thd->mem_root) Item_literal_fbt(thd);
+ }
+ void value_to_item(uint pos, Item *item) override
+ {
+ const Fbt &buff= (((Fbt*) base)[pos]);
+ static_cast<Item_literal_fbt*>(item)->set_value(buff);
+ }
+ };
+
+ class Item_char_typecast_func_handler_fbt_to_binary:
+ public Item_handled_func::Handler_str
+ {
+ public:
+ const Type_handler *return_type_handler(const Item_handled_func *item)
+ const override
+ {
+ if (item->max_length > MAX_FIELD_VARCHARLENGTH)
+ return Type_handler::blob_type_handler(item->max_length);
+ if (item->max_length > 255)
+ return &type_handler_varchar;
+ return &type_handler_string;
+ }
+ bool fix_length_and_dec(Item_handled_func *xitem) const override
+ {
+ return false;
+ }
+ String *val_str(Item_handled_func *item, String *to) const override
+ {
+ DBUG_ASSERT(dynamic_cast<const Item_char_typecast*>(item));
+ return static_cast<Item_char_typecast*>(item)->
+ val_str_binary_from_native(to);
+ }
+ };
+
+ class Type_collection_fbt: public Type_collection
+ {
+ const Type_handler *aggregate_common(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ if (a == b)
+ return a;
+ return NULL;
+ }
+ const Type_handler *aggregate_if_string(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ static const Type_aggregator::Pair agg[]=
+ {
+ {type_handler_fbt(), &type_handler_null, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_varchar, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_string, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_tiny_blob, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_blob, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_medium_blob, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_long_blob, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_hex_hybrid, type_handler_fbt()},
+ {NULL,NULL,NULL}
+ };
+ return Type_aggregator::find_handler_in_array(agg, a, b, true);
+ }
+ public:
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ const Type_handler *h;
+ if ((h= aggregate_common(a, b)) ||
+ (h= aggregate_if_string(a, b)))
+ return h;
+ return NULL;
+ }
+
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return aggregate_for_result(a, b);
+ }
+
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ if (const Type_handler *h= aggregate_common(a, b))
+ return h;
+ static const Type_aggregator::Pair agg[]=
+ {
+ {type_handler_fbt(), &type_handler_null, type_handler_fbt()},
+ {type_handler_fbt(), &type_handler_long_blob, type_handler_fbt()},
+ {NULL,NULL,NULL}
+ };
+ return Type_aggregator::find_handler_in_array(agg, a, b, true);
+ }
+
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ if (type_handler_fbt()->name().eq(name))
+ return type_handler_fbt();
+ return NULL;
+ }
+ };
+ static Type_handler_fbt *type_handler_fbt()
+ {
+ static Type_handler_fbt th;
+ return &th;
+ }
+};
+
+#endif /* SQL_TYPE_FIXEDBIN_H */
diff --git a/sql/sql_type_fixedbin_storage.h b/sql/sql_type_fixedbin_storage.h
new file mode 100644
index 00000000000..6e18335bd4c
--- /dev/null
+++ b/sql/sql_type_fixedbin_storage.h
@@ -0,0 +1,173 @@
+#ifndef SQL_TYPE_FIXEDBIN_STORAGE
+#define SQL_TYPE_FIXEDBIN_STORAGE
+/* Copyright (c) 2019,2021 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ This is a common code for plugin (?) types that are generally
+ handled like strings, but have their own fixed size on-disk binary storage
+ format and their own (variable size) canonical string representation.
+
+ Examples are INET6 and UUID types.
+
+ The MariaDB server uses three binary representations of a data type:
+
+ 1. In-memory binary representation (user visible)
+ This representation:
+ - can be used in INSERT..VALUES (X'AABBCC')
+ - can be used in WHERE conditions: WHERE c1=X'AABBCC'
+ - is returned by CAST(x AS BINARY(N))
+ - is returned by Field::val_native() and Item::val_native()
+
+ 2. In-record binary representation (user invisible)
+ This representation:
+ - is used in records (is pointed by Field::ptr)
+ - must be comparable by memcmp()
+
+ 3. Binlog binary (row) representation
+ Usually, for string data types the binlog representation
+ is based on the in-record representation with trailing byte compression:
+ - trailing space compression for text string data types
+ - trailing zero compression for binary string data types
+
+ We have to have separate in-memory and in-record representations
+ because we use HA_KEYTYPE_BINARY for indexing. The engine API
+ does not have a way to pass a comparison function as a parameter.
+
+ The default implementation below assumes that:
+ - the in-memory and in-record representations are equal
+ - the binlog representation is compatible with BINARY(N)
+ This is OK for simple data types, like INET6.
+
+ Data type implementations that need different representations
+ can override the default implementation (like e.g. UUID does).
+*/
+
+/***********************************************************************/
+
+template<size_t NATIVE_LEN, size_t MAX_CHAR_LEN>
+class FixedBinTypeStorage
+{
+protected:
+ // The buffer that stores the in-memory binary representation
+ char m_buffer[NATIVE_LEN];
+
+ // Non-initializing constructor
+ FixedBinTypeStorage()
+ { }
+
+ FixedBinTypeStorage & set_zero()
+ {
+ bzero(&m_buffer, sizeof(m_buffer));
+ return *this;
+ }
+public:
+
+ // Initialize from the in-memory binary representation
+ FixedBinTypeStorage(const char *str, size_t length)
+ {
+ if (length != binary_length())
+ set_zero();
+ else
+ memcpy(&m_buffer, str, sizeof(m_buffer));
+ }
+
+ // Return the buffer with the in-memory representation
+ Lex_cstring to_lex_cstring() const
+ {
+ return Lex_cstring(m_buffer, sizeof(m_buffer));
+ }
+
+ static constexpr uint binary_length() { return NATIVE_LEN; }
+ static constexpr uint max_char_length() { return MAX_CHAR_LEN; }
+
+ // Compare the in-memory binary representations of two values
+ static int cmp(const LEX_CSTRING &a, const LEX_CSTRING &b)
+ {
+ DBUG_ASSERT(a.length == binary_length());
+ DBUG_ASSERT(b.length == binary_length());
+ return memcmp(a.str, b.str, b.length);
+ }
+
+ /*
+ Convert from the in-memory to the in-record representation.
+ Used in Field::store_native().
+ */
+ static void memory_to_record(char *to, const char *from)
+ {
+ memcpy(to, from, NATIVE_LEN);
+ }
+ /*
+ Convert from the in-record to the in-memory representation
+ Used in Field::val_native().
+ */
+ static void record_to_memory(char *to, const char *from)
+ {
+ memcpy(to, from, NATIVE_LEN);
+ }
+
+ /*
+ Hash the in-record representation
+ Used in Field::hash().
+ */
+ static void hash_record(const uchar *ptr, ulong *nr, ulong *nr2)
+ {
+ my_charset_bin.hash_sort(ptr, binary_length(), nr, nr2);
+ }
+
+ static bool only_zero_bytes(const char *ptr, size_t length)
+ {
+ for (uint i= 0 ; i < length; i++)
+ {
+ if (ptr[i] != 0)
+ return false;
+ }
+ return true;
+ }
+
+ static ulong KEY_pack_flags(uint column_nr)
+ {
+ /*
+ Return zero by default. A particular data type can override
+ this method return some flags, e.g. HA_PACK_KEY to enable
+ key prefix compression.
+ */
+ return 0;
+ }
+
+ /*
+ Convert from the in-record to the binlog representation.
+ Used in Field::pack(), and in filesort to store the addon fields.
+ By default, do what BINARY(N) does.
+ */
+ static uchar *pack(uchar *to, const uchar *from, uint max_length)
+ {
+ return StringPack(&my_charset_bin, binary_length()).pack(to, from, max_length);
+ }
+
+ /*
+ Convert from the in-binary-log to the in-record representation.
+ Used in Field::unpack().
+ By default, do what BINARY(N) does.
+ */
+ static const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data)
+ {
+ return StringPack(&my_charset_bin, binary_length()).unpack(to, from, from_end,
+ param_data);
+ }
+
+};
+#endif /* SQL_TYPE_FIXEDBIN_STORAGE */
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f5aec151686..539bea958e8 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -271,7 +271,7 @@ static void prepare_record_for_error_message(int error, TABLE *table)
DBUG_VOID_RETURN;
/* Create unique_map with all fields used by that index. */
- my_bitmap_init(&unique_map, unique_map_buf, table->s->fields, FALSE);
+ my_bitmap_init(&unique_map, unique_map_buf, table->s->fields);
table->mark_index_columns(keynr, &unique_map);
/* Subtract read_set and write_set. */
@@ -1002,6 +1002,7 @@ update_begin:
THD_STAGE_INFO(thd, stage_updating);
fix_rownum_pointers(thd, thd->lex->current_select, &updated_or_same);
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
while (!(error=info.read_record()) && !thd->killed)
{
explain->tracker.on_record_read();
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 34814d4afae..8ebefbb3d82 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -782,6 +782,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> CATALOG_NAME_SYM /* SQL-2003-N */
%token <kwd> CHAIN_SYM /* SQL-2003-N */
%token <kwd> CHANGED
+%token <kwd> CHANNEL_SYM
%token <kwd> CHARSET
%token <kwd> CHECKPOINT_SYM
%token <kwd> CHECKSUM_SYM
@@ -1463,7 +1464,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
field_options last_field_options
%type <ulonglong_number>
- ulonglong_num real_ulonglong_num size_number
+ ulonglong_num real_ulonglong_num
%type <longlong_number>
longlong_num
@@ -2080,6 +2081,7 @@ change:
Lex->sql_command = SQLCOM_CHANGE_MASTER;
}
master_defs
+ optional_for_channel
{}
;
@@ -2311,6 +2313,34 @@ connection_name:
}
;
+optional_for_channel:
+ /* empty */
+ {
+ /*do nothing */
+ }
+ | for_channel
+
+ ;
+
+for_channel:
+ FOR_SYM CHANNEL_SYM TEXT_STRING_sys
+ {
+ if (Lex->mi.connection_name.str != NULL)
+ {
+ my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "CONNECTION_NAME AND FOR CHANNEL CAN NOT BE SPECIFIED AT THE SAME TIME)"));
+ }
+ else
+ {
+ Lex->mi.connection_name= $3;
+#ifdef HAVE_REPLICATION
+ if (unlikely(check_master_connection_name(&$3)))
+ my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME"));
+#endif
+ }
+
+ }
+ ;
+
/* create a table */
create:
@@ -2552,14 +2582,6 @@ create:
$1 | $3)))
MYSQL_YYABORT;
}
- | CREATE LOGFILE_SYM GROUP_SYM logfile_group_info
- {
- Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
- }
- | CREATE TABLESPACE tablespace_info
- {
- Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
- }
| create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); }
server_def
{ }
@@ -3453,6 +3475,8 @@ signal_condition_information_item_name:
{ $$= DIAG_MESSAGE_TEXT; }
| MYSQL_ERRNO_SYM
{ $$= DIAG_MYSQL_ERRNO; }
+ | ROW_NUMBER_SYM
+ { $$= DIAG_ROW_NUMBER; }
;
resignal_stmt:
@@ -3533,6 +3557,11 @@ simple_target_specification:
}
| '@' ident_or_text
{
+ if (!$2.length)
+ {
+ thd->parse_error();
+ YYABORT;
+ }
$$= new (thd->mem_root) Item_func_get_user_var(thd, &$2);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
@@ -3609,6 +3638,8 @@ condition_information_item_name:
{ $$= Condition_information_item::MYSQL_ERRNO; }
| RETURNED_SQLSTATE_SYM
{ $$= Condition_information_item::RETURNED_SQLSTATE; }
+ | ROW_NUMBER_SYM
+ { $$= Condition_information_item::ROW_NUMBER; }
;
sp_decl_ident:
@@ -4308,350 +4339,6 @@ trg_event:
| DELETE_SYM
{ Lex->trg_chistics.event= TRG_EVENT_DELETE; }
;
-/*
- This part of the parser contains common code for all TABLESPACE
- commands.
- CREATE TABLESPACE name ...
- ALTER TABLESPACE name CHANGE DATAFILE ...
- ALTER TABLESPACE name ADD DATAFILE ...
- ALTER TABLESPACE name access_mode
- CREATE LOGFILE GROUP_SYM name ...
- ALTER LOGFILE GROUP_SYM name ADD UNDOFILE ..
- ALTER LOGFILE GROUP_SYM name ADD REDOFILE ..
- DROP TABLESPACE name
- DROP LOGFILE GROUP_SYM name
-*/
-change_tablespace_access:
- tablespace_name
- ts_access_mode
- ;
-
-change_tablespace_info:
- tablespace_name
- CHANGE ts_datafile
- change_ts_option_list
- ;
-
-tablespace_info:
- tablespace_name
- ADD ts_datafile
- opt_logfile_group_name
- tablespace_option_list
- ;
-
-opt_logfile_group_name:
- /* empty */ {}
- | USE_SYM LOGFILE_SYM GROUP_SYM ident
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->logfile_group_name= $4.str;
- }
- ;
-
-alter_tablespace_info:
- tablespace_name
- ADD ts_datafile
- alter_tablespace_option_list
- {
- Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_ADD_FILE;
- }
- | tablespace_name
- DROP ts_datafile
- alter_tablespace_option_list
- {
- Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_DROP_FILE;
- }
- ;
-
-logfile_group_info:
- logfile_group_name
- add_log_file
- logfile_group_option_list
- ;
-
-alter_logfile_group_info:
- logfile_group_name
- add_log_file
- alter_logfile_group_option_list
- ;
-
-add_log_file:
- ADD lg_undofile
- | ADD lg_redofile
- ;
-
-change_ts_option_list:
- /* empty */ {}
- change_ts_options
- ;
-
-change_ts_options:
- change_ts_option
- | change_ts_options change_ts_option
- | change_ts_options ',' change_ts_option
- ;
-
-change_ts_option:
- opt_ts_initial_size
- | opt_ts_autoextend_size
- | opt_ts_max_size
- ;
-
-tablespace_option_list:
- tablespace_options
- ;
-
-tablespace_options:
- tablespace_option
- | tablespace_options tablespace_option
- | tablespace_options ',' tablespace_option
- ;
-
-tablespace_option:
- opt_ts_initial_size
- | opt_ts_autoextend_size
- | opt_ts_max_size
- | opt_ts_extent_size
- | opt_ts_nodegroup
- | opt_ts_engine
- | ts_wait
- | opt_ts_comment
- ;
-
-alter_tablespace_option_list:
- alter_tablespace_options
- ;
-
-alter_tablespace_options:
- alter_tablespace_option
- | alter_tablespace_options alter_tablespace_option
- | alter_tablespace_options ',' alter_tablespace_option
- ;
-
-alter_tablespace_option:
- opt_ts_initial_size
- | opt_ts_autoextend_size
- | opt_ts_max_size
- | opt_ts_engine
- | ts_wait
- ;
-
-logfile_group_option_list:
- logfile_group_options
- ;
-
-logfile_group_options:
- logfile_group_option
- | logfile_group_options logfile_group_option
- | logfile_group_options ',' logfile_group_option
- ;
-
-logfile_group_option:
- opt_ts_initial_size
- | opt_ts_undo_buffer_size
- | opt_ts_redo_buffer_size
- | opt_ts_nodegroup
- | opt_ts_engine
- | ts_wait
- | opt_ts_comment
- ;
-
-alter_logfile_group_option_list:
- alter_logfile_group_options
- ;
-
-alter_logfile_group_options:
- alter_logfile_group_option
- | alter_logfile_group_options alter_logfile_group_option
- | alter_logfile_group_options ',' alter_logfile_group_option
- ;
-
-alter_logfile_group_option:
- opt_ts_initial_size
- | opt_ts_engine
- | ts_wait
- ;
-
-
-ts_datafile:
- DATAFILE_SYM TEXT_STRING_sys
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->data_file_name= $2.str;
- }
- ;
-
-lg_undofile:
- UNDOFILE_SYM TEXT_STRING_sys
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->undo_file_name= $2.str;
- }
- ;
-
-lg_redofile:
- REDOFILE_SYM TEXT_STRING_sys
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->redo_file_name= $2.str;
- }
- ;
-
-tablespace_name:
- ident
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info= (new (thd->mem_root)
- st_alter_tablespace());
- if (unlikely(lex->alter_tablespace_info == NULL))
- MYSQL_YYABORT;
- lex->alter_tablespace_info->tablespace_name= $1.str;
- lex->sql_command= SQLCOM_ALTER_TABLESPACE;
- }
- ;
-
-logfile_group_name:
- ident
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info= (new (thd->mem_root)
- st_alter_tablespace());
- if (unlikely(lex->alter_tablespace_info == NULL))
- MYSQL_YYABORT;
- lex->alter_tablespace_info->logfile_group_name= $1.str;
- lex->sql_command= SQLCOM_ALTER_TABLESPACE;
- }
- ;
-
-ts_access_mode:
- READ_ONLY_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_access_mode= TS_READ_ONLY;
- }
- | READ_WRITE_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_access_mode= TS_READ_WRITE;
- }
- | NOT_SYM ACCESSIBLE_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_access_mode= TS_NOT_ACCESSIBLE;
- }
- ;
-
-opt_ts_initial_size:
- INITIAL_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->initial_size= $3;
- }
- ;
-
-opt_ts_autoextend_size:
- AUTOEXTEND_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->autoextend_size= $3;
- }
- ;
-
-opt_ts_max_size:
- MAX_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->max_size= $3;
- }
- ;
-
-opt_ts_extent_size:
- EXTENT_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->extent_size= $3;
- }
- ;
-
-opt_ts_undo_buffer_size:
- UNDO_BUFFER_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->undo_buffer_size= $3;
- }
- ;
-
-opt_ts_redo_buffer_size:
- REDO_BUFFER_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->redo_buffer_size= $3;
- }
- ;
-
-opt_ts_nodegroup:
- NODEGROUP_SYM opt_equal real_ulong_num
- {
- LEX *lex= Lex;
- if (unlikely(lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP"));
- lex->alter_tablespace_info->nodegroup_id= $3;
- }
- ;
-
-opt_ts_comment:
- COMMENT_SYM opt_equal TEXT_STRING_sys
- {
- LEX *lex= Lex;
- if (unlikely(lex->alter_tablespace_info->ts_comment != NULL))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT"));
- lex->alter_tablespace_info->ts_comment= $3.str;
- }
- ;
-
-opt_ts_engine:
- opt_storage ENGINE_SYM opt_equal storage_engines
- {
- LEX *lex= Lex;
- if (unlikely(lex->alter_tablespace_info->storage_engine != NULL))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE, MYF(0),
- "STORAGE ENGINE"));
- lex->alter_tablespace_info->storage_engine= $4;
- }
- ;
-
-opt_ts_wait:
- /* empty */
- | ts_wait
- ;
-
-ts_wait:
- WAIT_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->wait_until_completed= TRUE;
- }
- | NO_WAIT_SYM
- {
- LEX *lex= Lex;
- if (unlikely(!(lex->alter_tablespace_info->wait_until_completed)))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT"));
- lex->alter_tablespace_info->wait_until_completed= FALSE;
- }
- ;
-
-size_number:
- real_ulonglong_num { $$= $1;}
- | IDENT_sys
- {
- if ($1.to_size_number(&$$))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- End tablespace part
-*/
create_body:
create_field_list_parens
@@ -5025,8 +4712,13 @@ part_def_list:
| part_def_list ',' part_definition {}
;
+opt_partition:
+ /* empty */
+ | PARTITION_SYM
+ ;
+
part_definition:
- PARTITION_SYM
+ opt_partition
{
partition_info *part_info= Lex->part_info;
partition_element *p_elem= new (thd->mem_root) partition_element();
@@ -5372,7 +5064,7 @@ opt_part_option_list:
opt_part_option:
TABLESPACE opt_equal ident_or_text
- { Lex->part_info->curr_part_elem->tablespace_name= $3.str; }
+ { /* Compatibility with MySQL */ }
| opt_storage ENGINE_SYM opt_equal storage_engines
{
partition_info *part_info= Lex->part_info;
@@ -5711,7 +5403,7 @@ create_table_option:
Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR;
}
| TABLESPACE ident
- {Lex->create_info.tablespace= $2.str;}
+ { /* Compatiblity with MySQL */ }
| STORAGE_SYM DISK_SYM
{Lex->create_info.storage_media= HA_SM_DISK;}
| STORAGE_SYM MEMORY_SYM
@@ -5780,7 +5472,7 @@ versioning_option:
{
if (unlikely(Lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
- if (DBUG_EVALUATE_IF("sysvers_force", 0, 1))
+ if (!DBUG_IF("sysvers_force"))
{
my_error(ER_VERS_NOT_SUPPORTED, MYF(0), "CREATE TEMPORARY TABLE");
MYSQL_YYABORT;
@@ -7360,26 +7052,6 @@ alter:
Lex->pop_select(); //main select
}
- | ALTER TABLESPACE alter_tablespace_info
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE;
- }
- | ALTER LOGFILE_SYM GROUP_SYM alter_logfile_group_info
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP;
- }
- | ALTER TABLESPACE change_tablespace_info
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= CHANGE_FILE_TABLESPACE;
- }
- | ALTER TABLESPACE change_tablespace_access
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= ALTER_ACCESS_MODE_TABLESPACE;
- }
| ALTER SERVER_SYM ident_or_text
{
LEX *lex= Lex;
@@ -7613,6 +7285,54 @@ alter_commands:
if (Lex->stmt_alter_table_exchange_partition($6))
MYSQL_YYABORT;
}
+ | CONVERT_SYM PARTITION_SYM alt_part_name_item
+ TO_SYM TABLE_SYM table_ident have_partitioning
+ {
+ LEX *lex= Lex;
+ if (Lex->stmt_alter_table($6))
+ MYSQL_YYABORT;
+ lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table();
+ if (unlikely(lex->m_sql_cmd == NULL))
+ MYSQL_YYABORT;
+ lex->alter_info.partition_flags|= ALTER_PARTITION_CONVERT_OUT;
+ }
+ | CONVERT_SYM TABLE_SYM table_ident
+ {
+ LEX *lex= Lex;
+ if (!lex->first_select_lex()->add_table_to_list(thd, $3, nullptr, 0,
+ TL_READ_NO_INSERT,
+ MDL_SHARED_NO_WRITE))
+ MYSQL_YYABORT;
+
+ /*
+ This will appear as (new_db, new_name) in alter_ctx.
+ new_db will be IX-locked and new_name X-locked.
+ */
+ lex->first_select_lex()->db= $3->db;
+ lex->name= $3->table;
+ if (lex->first_select_lex()->db.str == NULL &&
+ lex->copy_db_to(&lex->first_select_lex()->db))
+ MYSQL_YYABORT;
+
+ lex->part_info= new (thd->mem_root) partition_info();
+ if (unlikely(!lex->part_info))
+ MYSQL_YYABORT;
+
+ lex->part_info->num_parts= 1;
+ /*
+ OR-ed with ALTER_PARTITION_ADD because too many checks of
+ ALTER_PARTITION_ADD required.
+ */
+ lex->alter_info.partition_flags|= ALTER_PARTITION_ADD |
+ ALTER_PARTITION_CONVERT_IN;
+ }
+ TO_SYM PARTITION_SYM part_definition
+ {
+ LEX *lex= Lex;
+ lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table();
+ if (unlikely(lex->m_sql_cmd == NULL))
+ MYSQL_YYABORT;
+ }
;
remove_partitioning:
@@ -7861,17 +7581,9 @@ alter_list_item:
}
| RENAME opt_to table_ident
{
- LEX *lex=Lex;
- lex->first_select_lex()->db= $3->db;
- if (lex->first_select_lex()->db.str == NULL &&
- lex->copy_db_to(&lex->first_select_lex()->db))
+ if (Lex->stmt_alter_table($3))
MYSQL_YYABORT;
- if (unlikely(check_table_name($3->table.str,$3->table.length,
- FALSE)) ||
- ($3->db.str && unlikely(check_db_name((LEX_STRING*) &$3->db))))
- my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3->table.str));
- lex->name= $3->table;
- lex->alter_info.flags|= ALTER_RENAME;
+ Lex->alter_info.flags|= ALTER_RENAME;
}
| RENAME COLUMN_SYM opt_if_exists_table_element ident TO_SYM ident
{
@@ -8038,7 +7750,7 @@ opt_to:
;
slave:
- START_SYM SLAVE optional_connection_name slave_thread_opts
+ START_SYM SLAVE optional_connection_name slave_thread_opts optional_for_channel
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_START;
@@ -8055,7 +7767,7 @@ slave:
/* If you change this code don't forget to update STOP SLAVE too */
}
{}
- | STOP_SYM SLAVE optional_connection_name slave_thread_opts
+ | STOP_SYM SLAVE optional_connection_name slave_thread_opts optional_for_channel
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_STOP;
@@ -11278,6 +10990,11 @@ variable_aux:
ident_or_text SET_VAR expr
{
Item_func_set_user_var *item;
+ if (!$1.length)
+ {
+ thd->parse_error();
+ YYABORT;
+ }
$$= item= new (thd->mem_root) Item_func_set_user_var(thd, &$1, $3);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
@@ -11287,6 +11004,11 @@ variable_aux:
}
| ident_or_text
{
+ if (!$1.length)
+ {
+ thd->parse_error();
+ YYABORT;
+ }
$$= new (thd->mem_root) Item_func_get_user_var(thd, &$1);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
@@ -12928,6 +12650,12 @@ select_var_ident: select_outvar
select_outvar:
'@' ident_or_text
{
+ if (!$2.length)
+ {
+ thd->parse_error();
+ YYABORT;
+ }
+
$$ = Lex->result ? new (thd->mem_root) my_var_user(&$2) : NULL;
}
| ident_or_text
@@ -13076,16 +12804,6 @@ drop:
lex->set_command(SQLCOM_DROP_TRIGGER, $3);
lex->spname= $4;
}
- | DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE;
- }
- | DROP LOGFILE_SYM GROUP_SYM logfile_group_name opt_ts_engine opt_ts_wait
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
- }
| DROP SERVER_SYM opt_if_exists ident_or_text
{
Lex->set_command(SQLCOM_DROP_SERVER, $3);
@@ -13190,6 +12908,8 @@ insert:
{
Lex->sql_command= SQLCOM_INSERT;
Lex->duplicates= DUP_ERROR;
+ thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
}
insert_start insert_lock_option opt_ignore opt_into insert_table
{
@@ -13199,6 +12919,7 @@ insert:
stmt_end
{
Lex->mark_first_table_as_inserting();
+ thd->get_stmt_da()->reset_current_row_for_warning(0);
}
;
@@ -13207,6 +12928,8 @@ replace:
{
Lex->sql_command = SQLCOM_REPLACE;
Lex->duplicates= DUP_REPLACE;
+ thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
+ thd->get_stmt_da()->reset_current_row_for_warning(1);
}
insert_start replace_lock_option opt_into insert_table
{
@@ -13216,6 +12939,7 @@ replace:
stmt_end
{
Lex->mark_first_table_as_inserting();
+ thd->get_stmt_da()->reset_current_row_for_warning(0);
}
;
@@ -13366,6 +13090,7 @@ no_braces:
opt_values ')'
{
LEX *lex=Lex;
+ thd->get_stmt_da()->inc_current_row_for_warning();
if (unlikely(lex->many_values.push_back(lex->insert_list,
thd->mem_root)))
MYSQL_YYABORT;
@@ -13381,6 +13106,7 @@ no_braces_with_names:
opt_values_with_names ')'
{
LEX *lex=Lex;
+ thd->get_stmt_da()->inc_current_row_for_warning();
if (unlikely(lex->many_values.push_back(lex->insert_list,
thd->mem_root)))
MYSQL_YYABORT;
@@ -13942,7 +13668,8 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS;
}
- opt_global_limit_clause
+ opt_global_limit_clause optional_for_channel
+ { }
| keys_or_index from_or_in table_ident opt_db opt_where_clause
{
LEX *lex= Lex;
@@ -14087,16 +13814,7 @@ show_param:
MYSQL_YYABORT;
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
}
- | SLAVE STATUS_SYM
- {
- LEX *lex= thd->lex;
- lex->mi.connection_name= null_clex_str;
- if (!(lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_show_slave_status()))
- MYSQL_YYABORT;
- lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- }
- | SLAVE connection_name STATUS_SYM
+ | SLAVE optional_connection_name STATUS_SYM optional_for_channel
{
if (!(Lex->m_sql_cmd= new (thd->mem_root)
Sql_cmd_show_slave_status()))
@@ -14481,7 +14199,7 @@ flush_option:
{ Lex->type|= REFRESH_SLOW_LOG; }
| BINARY LOGS_SYM opt_delete_gtid_domain
{ Lex->type|= REFRESH_BINARY_LOG; }
- | RELAY LOGS_SYM optional_connection_name
+ | RELAY LOGS_SYM optional_connection_name optional_for_channel
{
LEX *lex= Lex;
if (unlikely(lex->type & REFRESH_RELAY_LOG))
@@ -14632,7 +14350,8 @@ reset_options:
reset_option:
SLAVE { Lex->type|= REFRESH_SLAVE; }
optional_connection_name
- slave_reset_options { }
+ slave_reset_options optional_for_channel
+ { }
| MASTER_SYM
{
Lex->type|= REFRESH_MASTER;
@@ -14922,6 +14641,12 @@ field_or_var:
simple_ident_nospvar {$$= $1;}
| '@' ident_or_text
{
+ if (!$2.length)
+ {
+ thd->parse_error();
+ YYABORT;
+ }
+
$$= new (thd->mem_root) Item_user_var_as_out_param(thd, &$2);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
@@ -15929,6 +15654,7 @@ keyword_sp_var_and_label:
| CASCADED
| CATALOG_NAME_SYM
| CHAIN_SYM
+ | CHANNEL_SYM
| CHANGED
| CIPHER_SYM
| CLIENT_SYM
@@ -16736,6 +16462,12 @@ option_value_no_option_type:
}
| '@' ident_or_text equal
{
+ if (!$2.length)
+ {
+ thd->parse_error();
+ YYABORT;
+ }
+
if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index aa2ec70e3b3..7127cbc00f6 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -740,6 +740,23 @@ static Sys_var_charptr_fscs Sys_character_sets_dir(
READ_ONLY GLOBAL_VAR(charsets_dir), CMD_LINE(REQUIRED_ARG),
DEFAULT(0));
+static bool check_engine_supports_temporary(sys_var *self, THD *thd, set_var *var)
+{
+ plugin_ref plugin= var->save_result.plugin;
+ if (!plugin)
+ return false;
+ DBUG_ASSERT(plugin);
+ handlerton *hton= plugin_hton(plugin);
+ DBUG_ASSERT(hton);
+ if (ha_check_storage_engine_flag(hton, HTON_TEMPORARY_NOT_SUPPORTED))
+ {
+ my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), hton_name(hton)->str,
+ "TEMPORARY");
+ return true;
+ }
+ return false;
+}
+
static bool check_not_null(sys_var *self, THD *thd, set_var *var)
{
return var->value && var->value->is_null();
@@ -4245,7 +4262,8 @@ static Sys_var_plugin Sys_storage_engine(
static Sys_var_plugin Sys_default_tmp_storage_engine(
"default_tmp_storage_engine", "The default storage engine for user-created temporary tables",
SESSION_VAR(tmp_table_plugin), NO_CMD_LINE,
- MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_tmp_storage_engine));
+ MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_tmp_storage_engine),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_engine_supports_temporary));
static Sys_var_plugin Sys_enforce_storage_engine(
"enforce_storage_engine", "Force the use of a storage engine for new tables",
@@ -6015,16 +6033,6 @@ static Sys_var_mybool Sys_wsrep_desync (
ON_CHECK(wsrep_desync_check),
ON_UPDATE(wsrep_desync_update));
-static Sys_var_mybool Sys_wsrep_strict_ddl (
- "wsrep_strict_ddl",
- "If set, reject DDL on affected tables not supporting Galera replication",
- GLOBAL_VAR(wsrep_strict_ddl),
- CMD_LINE(OPT_ARG), DEFAULT(FALSE),
- NO_MUTEX_GUARD, NOT_IN_BINLOG,
- ON_CHECK(0),
- ON_UPDATE(wsrep_strict_ddl_update),
- DEPRECATED("'@@wsrep_mode=STRICT_REPLICATION'")); // since 10.6.0
-
static const char *wsrep_reject_queries_names[]= { "NONE", "ALL", "ALL_KILL", NullS };
static Sys_var_enum Sys_wsrep_reject_queries(
"wsrep_reject_queries", "Variable to set to reject queries",
@@ -6045,13 +6053,6 @@ static Sys_var_mybool Sys_wsrep_recover_datadir(
READ_ONLY GLOBAL_VAR(wsrep_recovery),
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
-static Sys_var_mybool Sys_wsrep_replicate_myisam(
- "wsrep_replicate_myisam", "To enable myisam replication",
- GLOBAL_VAR(wsrep_replicate_myisam), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
- ON_UPDATE(wsrep_replicate_myisam_update),
- DEPRECATED("'@@wsrep_mode=REPLICATE_MYISAM'")); // since 10.6.0
-
static Sys_var_mybool Sys_wsrep_log_conflicts(
"wsrep_log_conflicts", "To log multi-master conflicts",
GLOBAL_VAR(wsrep_log_conflicts), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
diff --git a/sql/table.cc b/sql/table.cc
index 5a622f9dbfa..b1a7b6bfe2b 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -3337,7 +3337,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->column_bitmap_size *
bitmap_count)))
goto err;
- my_bitmap_init(&share->all_set, bitmaps, share->fields, FALSE);
+ my_bitmap_init(&share->all_set, bitmaps, share->fields);
bitmap_set_all(&share->all_set);
if (share->check_set)
{
@@ -3348,7 +3348,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
my_bitmap_init(share->check_set,
(my_bitmap_map*) ((uchar*) bitmaps +
share->column_bitmap_size),
- share->fields, FALSE);
+ share->fields);
bitmap_clear_all(share->check_set);
}
@@ -4300,26 +4300,26 @@ partititon_err:
goto err;
my_bitmap_init(&outparam->def_read_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ (my_bitmap_map*) bitmaps, share->fields);
bitmaps+= bitmap_size;
my_bitmap_init(&outparam->def_write_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ (my_bitmap_map*) bitmaps, share->fields);
bitmaps+= bitmap_size;
my_bitmap_init(&outparam->has_value_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ (my_bitmap_map*) bitmaps, share->fields);
bitmaps+= bitmap_size;
my_bitmap_init(&outparam->tmp_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ (my_bitmap_map*) bitmaps, share->fields);
bitmaps+= bitmap_size;
my_bitmap_init(&outparam->eq_join_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ (my_bitmap_map*) bitmaps, share->fields);
bitmaps+= bitmap_size;
my_bitmap_init(&outparam->cond_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ (my_bitmap_map*) bitmaps, share->fields);
bitmaps+= bitmap_size;
my_bitmap_init(&outparam->def_rpl_write_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ (my_bitmap_map*) bitmaps, share->fields);
outparam->default_column_bitmaps();
outparam->cond_selectivity= 1.0;
@@ -9716,6 +9716,9 @@ bool TR_table::update(ulonglong start_id, ulonglong end_id)
int error= table->file->ha_write_row(table->record[0]);
if (unlikely(error))
table->file->print_error(error, MYF(0));
+ /* extra() is used to apply the bulk insert operation
+ on mysql/transaction_registry table */
+ table->file->extra(HA_EXTRA_IGNORE_INSERT);
return error;
}
diff --git a/sql/thread_pool_info.cc b/sql/thread_pool_info.cc
index 90ac6871784..e3ffd160a11 100644
--- a/sql/thread_pool_info.cc
+++ b/sql/thread_pool_info.cc
@@ -14,9 +14,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
#include <mysql_version.h>
-#include <mysql/plugin.h>
#include <my_global.h>
+#include <mysql/plugin.h>
#include <sql_class.h>
#include <sql_i_s.h>
#include <mysql/plugin.h>
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 0e334bec3dd..1f393e24ec2 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2524,7 +2524,7 @@ scan_tz_dir(char * name_end, uint symlink_recursion_level, uint verbose)
{
MY_DIR *cur_dir;
char *name_end_tmp;
- uint i;
+ size_t i;
/* Sort directory data, to pass mtr tests on different platforms. */
if (!(cur_dir= my_dir(fullname, MYF(MY_WANT_STAT|MY_WANT_SORT))))
diff --git a/sql/uniques.cc b/sql/uniques.cc
index a0cebe3e4dd..572d80f0b64 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -709,7 +709,7 @@ bool Unique::merge(TABLE *table, uchar *buff, size_t buff_size,
{
IO_CACHE *outfile= &sort.io_cache;
Merge_chunk *file_ptr= (Merge_chunk*) file_ptrs.buffer;
- uint maxbuffer= file_ptrs.elements - 1;
+ uint maxbuffer= (uint)file_ptrs.elements - 1;
my_off_t save_pos;
bool error= 1;
Sort_param sort_param;
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 06cd65dd01a..641e203d442 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -90,7 +90,6 @@ my_bool wsrep_drupal_282555_workaround; // Retry autoinc insert after du
my_bool wsrep_certify_nonPK; // Certify, even when no primary key
ulong wsrep_certification_rules = WSREP_CERTIFICATION_RULES_STRICT;
my_bool wsrep_recovery; // Recovery
-my_bool wsrep_replicate_myisam; // Enable MyISAM replication
my_bool wsrep_log_conflicts;
my_bool wsrep_load_data_splitting= 0; // Commit load data every 10K intervals
my_bool wsrep_slave_UK_checks; // Slave thread does UK checks
@@ -100,9 +99,6 @@ my_bool wsrep_restart_slave; // Should mysql slave thread be
my_bool wsrep_desync; // De(re)synchronize the node from the
// cluster
ulonglong wsrep_mode;
-my_bool wsrep_strict_ddl; // Deprecated: Reject DDL to
- // effected tables not
- // supporting Galera replication
bool wsrep_service_started; // If Galera was initialized
long wsrep_slave_threads; // No. of slave appliers threads
ulong wsrep_retry_autocommit; // Retry aborted autocommit trx
@@ -1607,11 +1603,18 @@ wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* tables, wsrep::key_array* key
{
bool fail= false;
TABLE_LIST *table;
+ TABLE_LIST *table_last_in_list;
thd->release_transactional_locks();
uint counter;
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ for (table_last_in_list= tables;;table_last_in_list= table_last_in_list->next_local) {
+ if (!table_last_in_list->next_local) {
+ break;
+ }
+ }
+
if (thd->open_temporary_tables(tables) ||
open_tables(thd, &tables, &counter, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
{
@@ -1643,11 +1646,19 @@ exit:
/* close the table and release MDL locks */
close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+ bool invalidate_next_global= false;
for (table= tables; table; table= table->next_local)
{
table->table= NULL;
- table->next_global= NULL;
table->mdl_request.ticket= NULL;
+ // We should invalidate `next_global` only for entries that are added
+ // in this function
+ if (table == table_last_in_list) {
+ invalidate_next_global= true;
+ }
+ if (invalidate_next_global) {
+ table->next_global= NULL;
+ }
}
return fail;
@@ -2556,6 +2567,8 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
}
thd_proc_info(thd, "acquiring total order isolation");
+ WSREP_DEBUG("wsrep_TOI_begin for %s", wsrep_thd_query(thd));
+ THD_STAGE_INFO(thd, stage_waiting_isolation);
wsrep::client_state& cs(thd->wsrep_cs());
@@ -2898,39 +2911,49 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
const MDL_ticket *ticket,
const MDL_key *key)
{
- /* Fallback to the non-wsrep behaviour */
- if (!WSREP_ON) return;
-
THD *request_thd= requestor_ctx->get_thd();
THD *granted_thd= ticket->get_ctx()->get_thd();
+ /* Fallback to the non-wsrep behaviour */
+ if (!WSREP(request_thd)) return;
+
const char* schema= key->db_name();
int schema_len= key->db_name_length();
mysql_mutex_lock(&request_thd->LOCK_thd_data);
- if (wsrep_thd_is_toi(request_thd) ||
- wsrep_thd_is_applying(request_thd)) {
+ if (wsrep_thd_is_toi(request_thd) ||
+ wsrep_thd_is_applying(request_thd))
+ {
+ WSREP_DEBUG("wsrep_handle_mdl_conflict request TOI/APPLY for %s",
+ wsrep_thd_query(request_thd));
+ THD_STAGE_INFO(request_thd, stage_waiting_isolation);
mysql_mutex_unlock(&request_thd->LOCK_thd_data);
WSREP_MDL_LOG(DEBUG, "MDL conflict ", schema, schema_len,
request_thd, granted_thd);
ticket->wsrep_report(wsrep_debug);
mysql_mutex_lock(&granted_thd->LOCK_thd_data);
+
if (wsrep_thd_is_toi(granted_thd) ||
wsrep_thd_is_applying(granted_thd))
{
if (wsrep_thd_is_aborting(granted_thd))
{
- WSREP_DEBUG("BF thread waiting for SR in aborting state");
+ WSREP_DEBUG("BF thread waiting for SR in aborting state for %s",
+ wsrep_thd_query(request_thd));
+ THD_STAGE_INFO(request_thd, stage_waiting_isolation);
ticket->wsrep_report(wsrep_debug);
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
}
else if (wsrep_thd_is_SR(granted_thd) && !wsrep_thd_is_SR(request_thd))
{
- WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
+ WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
schema, schema_len, request_thd, granted_thd);
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
+ WSREP_DEBUG("wsrep_handle_mdl_conflict DDL vs SR for %s",
+ wsrep_thd_query(request_thd));
+ THD_STAGE_INFO(request_thd, stage_waiting_isolation);
wsrep_abort_thd(request_thd, granted_thd, 1);
}
else
@@ -2945,14 +2968,18 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
else if (granted_thd->lex->sql_command == SQLCOM_FLUSH ||
granted_thd->mdl_context.has_explicit_locks())
{
- WSREP_DEBUG("BF thread waiting for FLUSH");
+ WSREP_DEBUG("BF thread waiting for FLUSH for %s",
+ wsrep_thd_query(request_thd));
+ THD_STAGE_INFO(request_thd, stage_waiting_ddl);
ticket->wsrep_report(wsrep_debug);
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
}
else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE)
{
- WSREP_DEBUG("DROP caused BF abort, conf %s",
- wsrep_thd_transaction_state_str(granted_thd));
+ WSREP_DEBUG("DROP caused BF abort, conf %s for %s",
+ wsrep_thd_transaction_state_str(granted_thd),
+ wsrep_thd_query(request_thd));
+ THD_STAGE_INFO(request_thd, stage_waiting_isolation);
ticket->wsrep_report(wsrep_debug);
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
wsrep_abort_thd(request_thd, granted_thd, 1);
@@ -2961,7 +2988,11 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
{
WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", schema, schema_len,
request_thd, granted_thd);
+ WSREP_DEBUG("wsrep_handle_mdl_conflict -> BF abort for %s",
+ wsrep_thd_query(request_thd));
+ THD_STAGE_INFO(request_thd, stage_waiting_isolation);
ticket->wsrep_report(wsrep_debug);
+
if (granted_thd->wsrep_trx().active())
{
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
@@ -2974,14 +3005,16 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
thd is BF, BF abort and wait.
*/
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
+
if (wsrep_thd_is_BF(request_thd, FALSE))
{
ha_abort_transaction(request_thd, granted_thd, TRUE);
}
else
{
- WSREP_MDL_LOG(INFO, "MDL unknown BF-BF conflict", schema, schema_len,
- request_thd, granted_thd);
+ WSREP_MDL_LOG(INFO, "MDL unknown BF-BF conflict",
+ schema, schema_len,
+ request_thd, granted_thd);
ticket->wsrep_report(true);
unireg_abort(1);
}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 1d72f884966..9cbe186aedf 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -85,7 +85,6 @@ extern ulong wsrep_forced_binlog_format;
extern my_bool wsrep_desync;
extern ulong wsrep_reject_queries;
extern my_bool wsrep_recovery;
-extern my_bool wsrep_replicate_myisam;
extern my_bool wsrep_log_conflicts;
extern ulong wsrep_mysql_replication_bundle;
extern my_bool wsrep_load_data_splitting;
@@ -103,7 +102,6 @@ extern bool wsrep_new_cluster;
extern bool wsrep_gtid_mode;
extern uint wsrep_gtid_domain_id;
extern ulonglong wsrep_mode;
-extern my_bool wsrep_strict_ddl;
enum enum_wsrep_reject_types {
WSREP_REJECT_NONE, /* nothing rejected */
diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h
index c4528b8ef2a..70759e381a5 100644
--- a/sql/wsrep_trans_observer.h
+++ b/sql/wsrep_trans_observer.h
@@ -1,4 +1,4 @@
-/* Copyright 2016-2019 Codership Oy <http://www.codership.com>
+/* Copyright 2016-2021 Codership Oy <http://www.codership.com>
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
@@ -272,12 +272,14 @@ static inline int wsrep_before_commit(THD* thd, bool all)
WSREP_DEBUG("wsrep_before_commit: %d, %lld",
wsrep_is_real(thd, all),
(long long)wsrep_thd_trx_seqno(thd));
+ THD_STAGE_INFO(thd, stage_waiting_certification);
int ret= 0;
DBUG_ASSERT(wsrep_run_commit_hook(thd, all));
+
if ((ret= thd->wsrep_cs().before_commit()) == 0)
{
DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined());
- if (!thd->variables.gtid_seq_no &&
+ if (!thd->variables.gtid_seq_no &&
(thd->wsrep_trx().ws_meta().flags() & wsrep::provider::flag::commit))
{
uint64 seqno= 0;
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index 1790141b37d..178ec603e72 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -836,10 +836,11 @@ bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
return true;
}
} else {
+ THD_STAGE_INFO(thd, stage_waiting_flow);
ret= Wsrep_server_state::instance().provider().resync();
if (ret != WSREP_OK) {
WSREP_WARN ("SET resync failed %d for schema: %s, query: %s", ret,
- thd->get_db(), thd->query());
+ thd->get_db(), wsrep_thd_query(thd));
my_error (ER_CANNOT_USER, MYF(0), "'resync'", thd->query());
return true;
}
@@ -1100,24 +1101,3 @@ bool wsrep_gtid_domain_id_update(sys_var* self, THD *thd, enum_var_type)
return false;
}
-bool wsrep_strict_ddl_update(sys_var *self, THD* thd, enum_var_type var_type)
-{
- // In case user still sets wsrep_strict_ddl we set new
- // option to wsrep_mode
- if (wsrep_strict_ddl)
- wsrep_mode|= WSREP_MODE_STRICT_REPLICATION;
- else
- wsrep_mode&= (~WSREP_MODE_STRICT_REPLICATION);
- return false;
-}
-
-bool wsrep_replicate_myisam_update(sys_var *self, THD* thd, enum_var_type var_type)
-{
- // In case user still sets wsrep_replicate_myisam we set new
- // option to wsrep_mode
- if (wsrep_replicate_myisam)
- wsrep_mode|= WSREP_MODE_REPLICATE_MYISAM;
- else
- wsrep_mode&= (~WSREP_MODE_REPLICATE_MYISAM);
- return false;
-}
diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h
index 7908e873795..0f811d70928 100644
--- a/sql/wsrep_var.h
+++ b/sql/wsrep_var.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Codership Oy <info@codership.com>
+/* Copyright (C) 2013-2021 Codership Oy <info@codership.com>
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
@@ -109,8 +109,6 @@ extern bool wsrep_gtid_seq_no_check CHECK_ARGS;
extern bool wsrep_gtid_domain_id_update UPDATE_ARGS;
extern bool wsrep_mode_check CHECK_ARGS;
-extern bool wsrep_strict_ddl_update UPDATE_ARGS;
-extern bool wsrep_replicate_myisam_update UPDATE_ARGS;
#else /* WITH_WSREP */
#define wsrep_provider_init(X)