summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/handler.cc96
-rw-r--r--sql/handler.h17
-rw-r--r--sql/log.cc2
-rw-r--r--sql/log_event.h4
-rw-r--r--sql/log_event_client.cc2
-rw-r--r--sql/log_event_server.cc18
-rw-r--r--sql/share/errmsg-utf8.txt7
-rw-r--r--sql/sql_alter.cc3
-rw-r--r--sql/sql_class.h3
-rw-r--r--sql/sql_insert.cc91
-rw-r--r--sql/sql_insert.h2
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_parse.cc32
-rw-r--r--sql/sql_priv.h4
-rw-r--r--sql/sql_rename.cc23
-rw-r--r--sql/sql_table.cc251
-rw-r--r--sql/sql_table.h6
-rw-r--r--sql/sql_union.cc4
-rw-r--r--sql/sys_vars.cc5
19 files changed, 459 insertions, 115 deletions
diff --git a/sql/handler.cc b/sql/handler.cc
index 2a92a041920..bcd7da1c711 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -4822,6 +4822,8 @@ handler::ha_rename_table(const char *from, const char *to)
int
handler::ha_delete_table(const char *name)
{
+ if (ha_check_if_updates_are_ignored(current_thd, ht, "DROP"))
+ return 0; // Simulate dropped
mark_trx_read_write();
return delete_table(name);
}
@@ -4840,9 +4842,11 @@ void
handler::ha_drop_table(const char *name)
{
DBUG_ASSERT(m_lock_type == F_UNLCK);
- mark_trx_read_write();
+ if (ha_check_if_updates_are_ignored(current_thd, ht, "DROP"))
+ return;
- return drop_table(name);
+ mark_trx_read_write();
+ drop_table(name);
}
@@ -5719,6 +5723,28 @@ bool ha_table_exists(THD *thd, const LEX_CSTRING *db,
DBUG_RETURN(FALSE);
}
+
+/*
+ Check if the CREATE/ALTER table should be ignored
+ This could happen for slaves where the table is shared between master
+ and slave
+
+ If statement is ignored, write a note
+*/
+
+bool ha_check_if_updates_are_ignored(THD *thd, handlerton *hton,
+ const char *op)
+{
+ DBUG_ENTER("ha_check_if_updates_are_ignored");
+ if (!thd->slave_thread || !(hton= ha_checktype(thd, hton, 1)))
+ DBUG_RETURN(0); // Not slave or no engine
+ if (!(hton->flags & HTON_IGNORE_UPDATES))
+ DBUG_RETURN(0); // Not shared table
+ my_error(ER_SLAVE_IGNORED_SHARED_TABLE, MYF(ME_NOTE), op);
+ DBUG_RETURN(1);
+}
+
+
/**
Discover all table names in a given database
*/
@@ -6406,33 +6432,12 @@ static int write_locked_table_maps(THD *thd)
++table_ptr)
{
TABLE *const table= *table_ptr;
- DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str));
if (table->current_lock == F_WRLCK &&
table->file->check_table_binlog_row_based(0))
{
- /*
- We need to have a transactional behavior for SQLCOM_CREATE_TABLE
- (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
- compatible behavior with the STMT based replication even when
- the table is not transactional. In other words, if the operation
- fails while executing the insert phase nothing is written to the
- binlog.
-
- Note that at this point, we check the type of a set of tables to
- create the table map events. In the function binlog_log_row(),
- which calls the current function, we check the type of the table
- of the current row.
- */
- bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
- table->file->has_transactions();
- int const error= thd->binlog_write_table_map(table, has_trans,
- &with_annotate);
- /*
- If an error occurs, it is the responsibility of the caller to
- roll back the transaction.
- */
- if (unlikely(error))
+ if (binlog_write_table_map(thd, table, with_annotate))
DBUG_RETURN(1);
+ with_annotate= 0;
}
}
}
@@ -6440,6 +6445,38 @@ static int write_locked_table_maps(THD *thd)
}
+int binlog_write_table_map(THD *thd, TABLE *table, bool with_annotate)
+{
+ DBUG_ENTER("binlog_write_table_map");
+ DBUG_PRINT("info", ("table %s", table->s->table_name.str));
+ /*
+ We need to have a transactional behavior for SQLCOM_CREATE_TABLE
+ (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
+ compatible behavior with the STMT based replication even when
+ the table is not transactional. In other words, if the operation
+ fails while executing the insert phase nothing is written to the
+ binlog.
+
+ Note that at this point, we check the type of a set of tables to
+ create the table map events. In the function binlog_log_row(),
+ which calls the current function, we check the type of the table
+ of the current row.
+ */
+ bool const has_trans= ((sql_command_flags[thd->lex->sql_command] &
+ (CF_SCHEMA_CHANGE | CF_ADMIN_COMMAND)) ||
+ table->file->has_transactions());
+ int const error= thd->binlog_write_table_map(table, has_trans,
+ &with_annotate);
+ /*
+ If an error occurs, it is the responsibility of the caller to
+ roll back the transaction.
+ */
+ if (unlikely(error))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
static int binlog_log_row_internal(TABLE* table,
const uchar *before_record,
const uchar *after_record,
@@ -6462,10 +6499,13 @@ static int binlog_log_row_internal(TABLE* table,
compatible behavior with the STMT based replication even when
the table is not transactional. In other words, if the operation
fails while executing the insert phase nothing is written to the
- binlog.
+ binlog. We need the same also for ALTER TABLE in the case we convert
+ a shared table to a not shared table as in this case we will log all
+ rows.
*/
- bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
- table->file->has_transactions();
+ bool const has_trans= ((sql_command_flags[thd->lex->sql_command] &
+ (CF_SCHEMA_CHANGE | CF_ADMIN_COMMAND)) ||
+ table->file->has_transactions());
error= (*log_func)(thd, table, has_trans, before_record, after_record);
}
return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
diff --git a/sql/handler.h b/sql/handler.h
index b99d33874e9..01e10d9c4c6 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1728,6 +1728,20 @@ handlerton *ha_default_tmp_handlerton(THD *thd);
/* can be replicated by wsrep replication provider plugin */
#define HTON_WSREP_REPLICATION (1 << 13)
+/* Shared storage on slave. Ignore on slave any CREATE TABLE, DROP or updates */
+#define HTON_IGNORE_UPDATES (1 << 14)
+
+/*
+ The table may not exists on the slave. The effects of having this flag are:
+ - ALTER TABLE that changes engine from this table to another engine will
+ be replicated as CREATE + INSERT
+ - CREATE ... LIKE shared_table will be replicated as a full CREATE TABLE
+ - ALTER TABLE for this engine will have "IF EXISTS" added.
+ - RENAME TABLE for this engine will have "IF EXISTS" added.
+ - DROP TABLE for this engine will have "IF EXISTS" added.
+*/
+#define HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE (1 << 15)
+
class Ha_trx_info;
struct THD_TRANS
@@ -5044,6 +5058,7 @@ int ha_discover_table_names(THD *thd, LEX_CSTRING *db, MY_DIR *dirp,
Discovered_table_list *result, bool reusable);
bool ha_table_exists(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name,
handlerton **hton= 0, bool *is_sequence= 0);
+bool ha_check_if_updates_are_ignored(THD *thd, handlerton *hton, const char *op);
#endif
/* key cache */
@@ -5181,7 +5196,7 @@ int binlog_log_row(TABLE* table,
if (unlikely(this_tracker)) \
tracker->stop_tracking(table->in_use); \
}
-
+int binlog_write_table_map(THD *thd, TABLE *table, bool with_annotate);
void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag);
void print_keydup_error(TABLE *table, KEY *key, myf errflag);
diff --git a/sql/log.cc b/sql/log.cc
index 647e5fbd60d..271fe647d87 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5916,7 +5916,7 @@ binlog_start_consistent_snapshot(handlerton *hton, THD *thd)
nonzero if an error pops up when writing the table map event.
*/
int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
- my_bool *with_annotate)
+ bool *with_annotate)
{
int error;
DBUG_ENTER("THD::binlog_write_table_map");
diff --git a/sql/log_event.h b/sql/log_event.h
index b634c6e2c94..6401ae326e3 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -524,11 +524,11 @@ class String;
*/
#define OPTIONS_WRITTEN_TO_BIN_LOG \
(OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \
- OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NOT_AUTOCOMMIT)
+ OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NOT_AUTOCOMMIT | OPTION_IF_EXISTS)
/* Shouldn't be defined before */
#define EXPECTED_OPTIONS \
- ((1ULL << 14) | (1ULL << 26) | (1ULL << 27) | (1ULL << 19))
+ ((1ULL << 14) | (1ULL << 26) | (1ULL << 27) | (1ULL << 19) | (1ULL << 28))
#if OPTIONS_WRITTEN_TO_BIN_LOG != EXPECTED_OPTIONS
#error OPTIONS_WRITTEN_TO_BIN_LOG must NOT change their values!
diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc
index faec2a29407..5686148ceb3 100644
--- a/sql/log_event_client.cc
+++ b/sql/log_event_client.cc
@@ -1899,6 +1899,8 @@ bool Query_log_event::print_query_header(IO_CACHE* file,
print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS,
~flags2,
"@@session.check_constraint_checks", &need_comma) ||
+ print_set_option(file, tmp, OPTION_IF_EXISTS, flags2,
+ "@@session.sql_if_exists", &need_comma)||
my_b_printf(file,"%s\n", print_event_info->delimiter))
goto err;
print_event_info->flags2= flags2;
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
index f7156013069..bc7e7d7b7a1 100644
--- a/sql/log_event_server.cc
+++ b/sql/log_event_server.cc
@@ -1024,6 +1024,24 @@ void Query_log_event::pack_info(Protocol *protocol)
append_identifier(protocol->thd, &buf, db, db_len);
buf.append(STRING_WITH_LEN("; "));
}
+ if (flags2 & (OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_AUTO_IS_NULL |
+ OPTION_RELAXED_UNIQUE_CHECKS |
+ OPTION_NO_CHECK_CONSTRAINT_CHECKS |
+ OPTION_IF_EXISTS))
+ {
+ buf.append(STRING_WITH_LEN("set "));
+ if (flags2 & OPTION_NO_FOREIGN_KEY_CHECKS)
+ buf.append(STRING_WITH_LEN("foreign_key_checks=1, "));
+ if (flags2 & OPTION_AUTO_IS_NULL)
+ buf.append(STRING_WITH_LEN("sql_auto_is_null, "));
+ if (flags2 & OPTION_RELAXED_UNIQUE_CHECKS)
+ buf.append(STRING_WITH_LEN("unique_checks=1, "));
+ if (flags2 & OPTION_NO_CHECK_CONSTRAINT_CHECKS)
+ buf.append(STRING_WITH_LEN("check_constraint_checks=1, "));
+ if (flags2 & OPTION_IF_EXISTS)
+ buf.append(STRING_WITH_LEN("@@sql_if_exists=1, "));
+ buf[buf.length()-2]=';';
+ }
if (query && q_len)
buf.append(query, q_len);
protocol->store(&buf);
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index afa9d72f2d8..2ff60a98c2b 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7950,3 +7950,10 @@ ER_LOAD_INFILE_CAPABILITY_DISABLED
rum "Comanda folosită nu este permisă deoarece clientul sau serverul MariaDB a dezactivat această capabilitate"
ER_NO_SECURE_TRANSPORTS_CONFIGURED
eng "No secure transports are configured, unable to set --require_secure_transport=ON"
+ER_SLAVE_IGNORED_SHARED_TABLE
+ eng "Slave SQL thread ignored the '%s' because table is shared"
+ ger "Slave-SQL-Thread hat die Abfrage '%s' ignoriert"
+ nla "Slave SQL thread negeerde de query '%s'"
+ por "Slave SQL thread ignorado a consulta devido '%s'"
+ spa "Slave SQL thread ignorado el query '%s'"
+ swe "Slav SQL tråden ignorerade '%s' pga tabellen är delad"
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 131f74c2753..9ac0ac7a551 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -376,6 +376,9 @@ bool Sql_cmd_alter_table::execute(THD *thd)
/* first table of first SELECT_LEX */
TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
const bool used_engine= lex->create_info.used_fields & HA_CREATE_USED_ENGINE;
DBUG_ASSERT((m_storage_engine_name.str != NULL) == used_engine);
if (used_engine)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 6d3a18259a0..def9cc9a05d 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2577,7 +2577,7 @@ public:
void binlog_start_trans_and_stmt();
void binlog_set_stmt_begin();
int binlog_write_table_map(TABLE *table, bool is_transactional,
- my_bool *with_annotate= 0);
+ bool *with_annotate= 0);
int binlog_write_row(TABLE* table, bool is_transactional,
const uchar *buf);
int binlog_delete_row(TABLE* table, bool is_transactional,
@@ -5702,7 +5702,6 @@ public:
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int binlog_show_create_table(TABLE **tables, uint count);
void store_values(List<Item> &values);
bool send_eof();
virtual void abort_result_set();
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 708423c6214..d2331fd71ef 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -77,6 +77,7 @@
#include "sql_audit.h"
#include "sql_derived.h" // mysql_handle_derived
#include "sql_prepare.h"
+#include "rpl_filter.h" // binlog_filter
#include <my_bit.h>
#include "debug_sync.h"
@@ -95,6 +96,8 @@ pthread_handler_t handle_delayed_insert(void *arg);
static void unlink_blobs(TABLE *table);
#endif
static bool check_view_insertability(THD *thd, TABLE_LIST *view);
+static int binlog_show_create_table(THD *thd, TABLE *table,
+ Table_specification_st *create_info);
/*
Check that insert/update fields are from the same single table of a view.
@@ -4545,13 +4548,9 @@ select_create::prepare(List<Item> &_values, SELECT_LEX_UNIT *u)
return error;
TABLE const *const table = *tables;
- if (thd->is_current_stmt_binlog_format_row() &&
+ if (thd->is_current_stmt_binlog_format_row() &&
!table->s->tmp_table)
- {
- int error;
- if (unlikely((error= ptr->binlog_show_create_table(tables, count))))
- return error;
- }
+ return binlog_show_create_table(thd, *tables, ptr->create_info);
return 0;
}
select_create *ptr;
@@ -4650,8 +4649,9 @@ select_create::prepare(List<Item> &_values, SELECT_LEX_UNIT *u)
DBUG_RETURN(0);
}
-int
-select_create::binlog_show_create_table(TABLE **tables, uint count)
+
+static int binlog_show_create_table(THD *thd, TABLE *table,
+ Table_specification_st *create_info)
{
/*
Note 1: In RBR mode, we generate a CREATE TABLE statement for the
@@ -4670,14 +4670,12 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
statement transaction cache.
*/
DBUG_ASSERT(thd->is_current_stmt_binlog_format_row());
- DBUG_ASSERT(tables && *tables && count > 0);
-
StringBuffer<2048> query(system_charset_info);
int result;
TABLE_LIST tmp_table_list;
tmp_table_list.reset();
- tmp_table_list.table = *tables;
+ tmp_table_list.table = table;
result= show_create_table(thd, &tmp_table_list, &query,
create_info, WITH_DB_NAME);
@@ -4706,6 +4704,77 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
return result;
}
+
+/**
+ Log CREATE TABLE to binary log
+
+ @param thd Thread handler
+ @param table Log create statement for this table
+
+ This function is called from ALTER TABLE for a shared table converted
+ to a not shared table.
+*/
+
+bool binlog_create_table(THD *thd, TABLE *table)
+{
+ /* Don't log temporary tables in row format */
+ if (thd->variables.binlog_format == BINLOG_FORMAT_ROW &&
+ table->s->tmp_table)
+ return 0;
+ if (!mysql_bin_log.is_open() ||
+ !(thd->variables.option_bits & OPTION_BIN_LOG) ||
+ (thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
+ !binlog_filter->db_ok(table->s->db.str)))
+ return 0;
+
+ /*
+ We have to use ROW format to ensure that future row inserts will be
+ logged
+ */
+ thd->set_current_stmt_binlog_format_row();
+ return binlog_show_create_table(thd, table, 0) != 0;
+}
+
+
+/**
+ Log DROP TABLE to binary log
+
+ @param thd Thread handler
+ @param table Log create statement for this table
+
+ This function is called from ALTER TABLE for a shared table converted
+ to a not shared table.
+*/
+
+bool binlog_drop_table(THD *thd, TABLE *table)
+{
+ StringBuffer<2048> query(system_charset_info);
+ /* Don't log temporary tables in row format */
+ if (!table->s->table_creation_was_logged)
+ return 0;
+ if (!mysql_bin_log.is_open() ||
+ !(thd->variables.option_bits & OPTION_BIN_LOG) ||
+ (thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
+ !binlog_filter->db_ok(table->s->db.str)))
+ return 0;
+
+ query.append("DROP ");
+ if (table->s->tmp_table)
+ query.append("TEMPORARY ");
+ query.append("TABLE IF EXISTS ");
+ append_identifier(thd, &query, &table->s->db);
+ query.append(".");
+ append_identifier(thd, &query, &table->s->table_name);
+
+ return thd->binlog_query(THD::STMT_QUERY_TYPE,
+ query.ptr(), query.length(),
+ /* is_trans */ TRUE,
+ /* direct */ FALSE,
+ /* suppress_use */ TRUE,
+ 0) > 0;
+}
+
+
void select_create::store_values(List<Item> &values)
{
fill_record_n_invoke_before_triggers(thd, table, field, values, 1,
diff --git a/sql/sql_insert.h b/sql/sql_insert.h
index 977a0eb23c8..f1c2334235d 100644
--- a/sql/sql_insert.h
+++ b/sql/sql_insert.h
@@ -41,6 +41,8 @@ int vers_insert_history_row(TABLE *table);
int write_record(THD *thd, TABLE *table, COPY_INFO *info,
select_result *returning= NULL);
void kill_delayed_threads(void);
+bool binlog_create_table(THD *thd, TABLE *table);
+bool binlog_drop_table(THD *thd, TABLE *table);
#ifdef EMBEDDED_LIBRARY
inline void kill_delayed_threads(void) {}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b2f0272a7d2..56142023c82 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -859,7 +859,7 @@ protected:
bool saved_error;
bool prepare_join(THD *thd, SELECT_LEX *sl, select_result *result,
- ulong additional_options,
+ ulonglong additional_options,
bool is_union_select);
bool join_union_type_handlers(THD *thd,
class Type_holder *holders, uint count);
@@ -981,7 +981,7 @@ public:
/* UNION methods */
bool prepare(TABLE_LIST *derived_arg, select_result *sel_result,
- ulong additional_options);
+ ulonglong additional_options);
bool optimize();
void optimize_bag_operation(bool is_outer_distinct);
bool exec();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0c863a8c02d..6d40d951615 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3395,7 +3395,8 @@ mysql_execute_command(THD *thd)
according to slave filtering rules.
Returning success without producing any errors in this case.
*/
- if (!thd->lex->create_info.if_exists())
+ if (!thd->lex->create_info.if_exists() &&
+ !(thd->variables.option_bits & OPTION_IF_EXISTS))
DBUG_RETURN(0);
/*
DROP TRIGGER IF NOT EXISTS will return without an error later
@@ -4128,8 +4129,11 @@ mysql_execute_command(THD *thd)
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
break;
}
- case SQLCOM_CREATE_INDEX:
case SQLCOM_DROP_INDEX:
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+ /* fall through */
+ case SQLCOM_CREATE_INDEX:
/*
CREATE INDEX and DROP INDEX are implemented by calling ALTER
TABLE with proper arguments.
@@ -4272,6 +4276,9 @@ mysql_execute_command(THD *thd)
WSREP_TO_ISOLATION_BEGIN(0, 0, first_table);
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
if (mysql_rename_tables(thd, first_table, 0, lex->if_exists()))
goto error;
break;
@@ -4856,8 +4863,9 @@ mysql_execute_command(THD *thd)
recover from multi-table DROP TABLE that was aborted in the
middle.
*/
- if (thd->slave_thread && !thd->slave_expected_error &&
- slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT)
+ if ((thd->slave_thread && !thd->slave_expected_error &&
+ slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT) ||
+ thd->variables.option_bits & OPTION_IF_EXISTS)
lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
#ifdef WITH_WSREP
@@ -4878,7 +4886,7 @@ mysql_execute_command(THD *thd)
/* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(),
- lex->table_type == TABLE_TYPE_SEQUENCE);
+ lex->table_type == TABLE_TYPE_SEQUENCE, 0);
/*
When dropping temporary tables if @@session_track_state_change is ON
@@ -5085,6 +5093,9 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_DROP_DB:
{
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
if (prepare_db_action(thd, DROP_ACL, &lex->name))
break;
@@ -5633,6 +5644,8 @@ mysql_execute_command(THD *thd)
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_FUNCTION:
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
if (alter_routine(thd, lex))
goto error;
break;
@@ -5640,8 +5653,9 @@ mysql_execute_command(THD *thd)
case SQLCOM_DROP_FUNCTION:
case SQLCOM_DROP_PACKAGE:
case SQLCOM_DROP_PACKAGE_BODY:
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
if (drop_routine(thd, lex))
-
goto error;
break;
case SQLCOM_SHOW_CREATE_PROC:
@@ -5710,6 +5724,9 @@ mysql_execute_command(THD *thd)
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
/* Conditionally writes to binlog. */
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
break;
@@ -5723,6 +5740,9 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_DROP_TRIGGER:
{
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 7be2692a33b..c3ea9226643 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -146,7 +146,7 @@
/** The following speeds up inserts to InnoDB tables by suppressing unique
key checks in some cases */
#define OPTION_RELAXED_UNIQUE_CHECKS (1ULL << 27) // THD, user, binlog
-#define SELECT_NO_UNLOCK (1ULL << 28) // SELECT, intern
+#define OPTION_IF_EXISTS (1ULL << 28) // binlog
#define OPTION_SCHEMA_TABLE (1ULL << 29) // SELECT, intern
/** Flag set if setup_tables already done */
#define OPTION_SETUP_TABLES_DONE (1ULL << 30) // intern
@@ -179,7 +179,7 @@
#define OPTION_RPL_SKIP_PARALLEL (1ULL << 38)
#define OPTION_NO_QUERY_CACHE (1ULL << 39) // SELECT, user
#define OPTION_PROCEDURE_CLAUSE (1ULL << 40) // Internal usage
-
+#define SELECT_NO_UNLOCK (1ULL << 41) // SELECT, intern
#define OPTION_LEX_FOUND_COMMENT (1ULL << 0) // intern, parser
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index f6a0c53a022..73d0f377dd9 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -180,7 +180,15 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent,
if (likely(!silent && !error))
{
+ ulonglong save_option_bits= thd->variables.option_bits;
+ if (force_if_exists && ! if_exists)
+ {
+ /* Add IF EXISTS to binary log */
+ thd->variables.option_bits|= OPTION_IF_EXISTS;
+ }
binlog_error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ thd->variables.option_bits= save_option_bits;
+
if (likely(!binlog_error))
my_ok(thd);
}
@@ -295,6 +303,18 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db,
DBUG_RETURN(skip_error || if_exists ? 0 : 1);
}
+ if (ha_check_if_updates_are_ignored(thd, hton, "RENAME"))
+ {
+ /*
+ Shared table. Just drop the old .frm as it's not correct anymore
+ Discovery will find the old table when it's accessed
+ */
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
+ ren_table->db.str, ren_table->table_name.str);
+ quick_rm_table(thd, 0, &ren_table->db, &old_alias, FRM_ONLY, 0);
+ DBUG_RETURN(0);
+ }
+
if (ha_table_exists(thd, new_db, &new_alias, &new_hton))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias.str);
@@ -315,6 +335,9 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db,
if (hton != view_pseudo_hton)
{
+ if (hton->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
+ *force_if_exists= 1;
+
if (!(rc= mysql_rename_table(hton, &ren_table->db, &old_alias,
new_db, &new_alias, 0)))
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ed1f6fe7cbd..d589fbfb32d 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -54,6 +54,7 @@
#include "sql_audit.h"
#include "sql_sequence.h"
#include "tztime.h"
+#include "sql_insert.h" // binlog_drop_table
#include <algorithm>
#ifdef __WIN__
@@ -1995,6 +1996,26 @@ int write_bin_log(THD *thd, bool clear_error,
/*
+ Write to binary log with optional adding "IF EXISTS"
+
+ The query is taken from thd->query()
+*/
+
+int write_bin_log_with_if_exists(THD *thd, bool clear_error,
+ bool is_trans, bool add_if_exists)
+{
+ int result;
+ ulonglong save_option_bits= thd->variables.option_bits;
+ if (add_if_exists)
+ thd->variables.option_bits|= OPTION_IF_EXISTS;
+ result= write_bin_log(thd, clear_error, thd->query(), thd->query_length(),
+ is_trans);
+ thd->variables.option_bits= save_option_bits;
+ return result;
+}
+
+
+/*
delete (drop) tables.
SYNOPSIS
@@ -2004,6 +2025,7 @@ int write_bin_log(THD *thd, bool clear_error,
if_exists If 1, don't give error if one table doesn't exists
drop_temporary 1 if DROP TEMPORARY
drop_sequence 1 if DROP SEQUENCE
+ dont_log_query 1 if no write to binary log and no send of ok
NOTES
Will delete all tables that can be deleted and give a compact error
@@ -2021,7 +2043,8 @@ int write_bin_log(THD *thd, bool clear_error,
*/
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
- bool drop_temporary, bool drop_sequence)
+ bool drop_temporary, bool drop_sequence,
+ bool dont_log_query)
{
bool error;
Drop_table_error_handler err_handler;
@@ -2119,12 +2142,14 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
/* mark for close and remove all cached entries */
thd->push_internal_handler(&err_handler);
error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
- false, drop_sequence, false, false);
+ false, drop_sequence, dont_log_query,
+ false);
thd->pop_internal_handler();
if (unlikely(error))
DBUG_RETURN(TRUE);
- my_ok(thd);
+ if (!dont_log_query)
+ my_ok(thd);
DBUG_RETURN(FALSE);
}
@@ -2223,8 +2248,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
bool non_tmp_table_deleted= 0;
bool is_drop_tmp_if_exists_added= 0;
- bool was_view= 0, was_table= 0, is_sequence;
- String built_query;
+ bool was_view= 0, was_table= 0, is_sequence, log_if_exists= if_exists;
+ const char *object_to_drop= (drop_sequence) ? "SEQUENCE" : "TABLE";
+ String normal_tables;
String built_trans_tmp_query, built_non_trans_tmp_query;
DBUG_ENTER("mysql_rm_table_no_locks");
@@ -2263,30 +2289,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
logging, these commands will be written with fully qualified table names
and use `db` will be suppressed.
*/
+
+ normal_tables.set_charset(thd->charset());
if (!dont_log_query)
{
- const char *object_to_drop= (drop_sequence) ? "SEQUENCE" : "TABLE";
-
- if (!drop_temporary)
- {
- const char *comment_start;
- uint32 comment_len;
-
- built_query.set_charset(thd->charset());
- built_query.append("DROP ");
- built_query.append(object_to_drop);
- built_query.append(' ');
- if (if_exists)
- built_query.append("IF EXISTS ");
-
- /* Preserve comment in original query */
- if ((comment_len= comment_length(thd, if_exists ? 17:9, &comment_start)))
- {
- built_query.append(comment_start, comment_len);
- built_query.append(" ");
- }
- }
-
built_trans_tmp_query.set_charset(system_charset_info);
built_trans_tmp_query.append("DROP TEMPORARY ");
built_trans_tmp_query.append(object_to_drop);
@@ -2393,8 +2399,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove .frm file and engine files */
- path_length= build_table_filename(path, sizeof(path) - 1, db.str, alias.str,
- reg_ext, 0);
+ path_length= build_table_filename(path, sizeof(path) - 1, db.str,
+ alias.str, reg_ext, 0);
}
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
error= 0;
@@ -2408,7 +2414,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
One of the following cases happened:
. "DROP TEMPORARY" but a temporary table was not found.
. "DROP" but table was not found
- . "DROP TABLE" statement, but it's a view.
+ . "DROP TABLE" statement, but it's a view.
. "DROP SEQUENCE", but it's not a sequence
*/
was_table= drop_sequence && table_type;
@@ -2491,8 +2497,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
// Remove extension for delete
*(end= path + path_length - reg_ext_length)= '\0';
- if ((error= ha_delete_table(thd, table_type, path, &db, &table->table_name,
- !dont_log_query)))
+ if (table_type && table_type != view_pseudo_hton &&
+ table_type->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
+ log_if_exists= 1;
+
+ if ((error= ha_delete_table(thd, table_type, path, &db,
+ &table->table_name, !dont_log_query)))
{
if (thd->is_killed())
{
@@ -2529,7 +2539,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{
non_tmp_table_deleted= TRUE;
trigger_drop_error=
- Table_triggers_list::drop_all_triggers(thd, &db, &table->table_name);
+ Table_triggers_list::drop_all_triggers(thd, &db,
+ &table->table_name);
}
if (unlikely(trigger_drop_error) ||
@@ -2567,12 +2578,12 @@ log_query:
*/
if (thd->db.str == NULL || cmp(&db, &thd->db) != 0)
{
- append_identifier(thd, &built_query, &db);
- built_query.append(".");
+ append_identifier(thd, &normal_tables, &db);
+ normal_tables.append(".");
}
- append_identifier(thd, &built_query, &table->table_name);
- built_query.append(",");
+ append_identifier(thd, &normal_tables, &table->table_name);
+ normal_tables.append(",");
}
DBUG_PRINT("table", ("table: %p s: %p", table->table,
table->table ? table->table->s : NULL));
@@ -2642,16 +2653,35 @@ err:
}
if (non_tmp_table_deleted)
{
- /* Chop of the last comma */
- built_query.chop();
- built_query.append(" /* generated by server */");
- int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno()
- : 0;
- error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
- built_query.ptr(),
- built_query.length(),
- TRUE, FALSE, FALSE,
- error_code) > 0);
+ String built_query;
+ const char *comment_start;
+ uint32 comment_len;
+
+ built_query.set_charset(thd->charset());
+ built_query.append("DROP ");
+ built_query.append(object_to_drop);
+ built_query.append(' ');
+ if (log_if_exists)
+ built_query.append("IF EXISTS ");
+
+ /* Preserve comment in original query */
+ if ((comment_len= comment_length(thd, if_exists ? 17:9,
+ &comment_start)))
+ {
+ built_query.append(comment_start, comment_len);
+ built_query.append(" ");
+ }
+
+ /* Chop of the last comma */
+ normal_tables.chop();
+ built_query.append(normal_tables.ptr(), normal_tables.length());
+ built_query.append(" /* generated by server */");
+ int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno() : 0;
+ error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
+ built_query.ptr(),
+ built_query.length(),
+ TRUE, FALSE, FALSE,
+ error_code) > 0);
}
}
}
@@ -4960,6 +4990,17 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
}
else
{
+ if (ha_check_if_updates_are_ignored(thd, create_info->db_type, "CREATE"))
+ {
+ /*
+ Don't create table. CREATE will still be logged in binary log
+ This can happen for shared storage engines that supports
+ ENGINE= in the create statement (Note that S3 doesn't support this.
+ */
+ error= 0;
+ goto err;
+ }
+
if (!internal_tmp_table && ha_table_exists(thd, &db, &table_name))
{
if (options.or_replace())
@@ -5629,6 +5670,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
int res= 1;
bool is_trans= FALSE;
bool do_logging= FALSE;
+ bool force_generated_create;
uint not_used;
int create_res;
DBUG_ENTER("mysql_create_like_table");
@@ -5780,12 +5822,22 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
if (thd->is_current_stmt_binlog_disabled())
goto err;
- if (thd->is_current_stmt_binlog_format_row())
+ /*
+ If we do a create based on a shared table, log the full create of the
+ resulting table. This is needed as a shared table may look different
+ when the slave executes the command.
+ */
+ force_generated_create=
+ (((src_table->table->s->db_type()->flags &
+ HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE) &&
+ src_table->table->s->db_type() != local_create_info.db_type));
+
+ if (thd->is_current_stmt_binlog_format_row() || force_generated_create)
{
/*
Since temporary tables are not replicated under row-based
replication, CREATE TABLE ... LIKE ... needs special
- treatement. We have four cases to consider, according to the
+ treatement. We have some cases to consider, according to the
following decision table:
==== ========= ========= ==============================
@@ -5796,11 +5848,14 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
was created.
3 temporary normal Nothing
4 temporary temporary Nothing
+ 5 any shared Generated statement if the table
+ was created if engine changed
==== ========= ========= ==============================
*/
- if (!(create_info->tmp_table()))
+ if (!(create_info->tmp_table()) || force_generated_create)
{
- if (src_table->table->s->tmp_table) // Case 2
+ // Case 2 & 5
+ if (src_table->table->s->tmp_table || force_generated_create)
{
char buf[2048];
String query(buf, sizeof(buf), system_charset_info);
@@ -9493,6 +9548,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
mysql_prepare_create_table().
*/
bool varchar= create_info->varchar, table_creation_was_logged= 0;
+ bool binlog_done= 0, log_if_exists= 0;
uint tables_opened;
handlerton *new_db_type, *old_db_type;
ha_rows copied=0, deleted=0;
@@ -9541,6 +9597,23 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
THD_STAGE_INFO(thd, stage_init_update);
+ /* Check if the new table type is a shared table */
+ if (ha_check_if_updates_are_ignored(thd, create_info->db_type, "ALTER"))
+ {
+ /*
+ Remove old local .frm file if it exists. We should use the new
+ shared one in the future. The drop is not logged, the ALTER table is
+ logged.
+ */
+ table_list->mdl_request.type= MDL_EXCLUSIVE;
+ /* This will only drop the .frm file and local tables, not shared ones */
+ error= mysql_rm_table(thd, table_list, 1, 0, 0, 1);
+ if (write_bin_log(thd, true, thd->query(), thd->query_length()) || error)
+ DBUG_RETURN(true);
+ my_ok(thd);
+ DBUG_RETURN(0);
+ }
+
/*
Code below can handle only base tables so ensure that we won't open a view.
Note that RENAME TABLE the only ALTER clause which is supported for views
@@ -9630,6 +9703,29 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
Alter_table_ctx alter_ctx(thd, table_list, tables_opened, new_db, new_name);
mdl_ticket= table->mdl_ticket;
+ if (ha_check_if_updates_are_ignored(thd, table->s->db_type(), "ALTER"))
+ {
+ /*
+ Table is a shared table. Remove the .frm file. Discovery will create
+ a new one if needed.
+ */
+ if (thd->mdl_context.upgrade_shared_lock(mdl_ticket,
+ MDL_EXCLUSIVE,
+ thd->variables.lock_wait_timeout))
+ DBUG_RETURN(1);
+ quick_rm_table(thd, 0, &table_list->db, &table_list->table_name,
+ FRM_ONLY, 0);
+ goto end_inplace;
+ }
+ if (!if_exists &&
+ (table->s->db_type()->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE))
+ {
+ /*
+ Table is a shared table that may not exist on the slave.
+ We add 'if_exists' to the query if it was not used
+ */
+ log_if_exists= 1;
+ }
table_creation_was_logged= table->s->table_creation_was_logged;
table->use_all_columns();
@@ -9882,7 +9978,7 @@ do_continue:;
/* We don't replicate alter table statement on temporary tables */
if (table_creation_was_logged)
{
- if (write_bin_log(thd, true, thd->query(), thd->query_length()))
+ if (write_bin_log_with_if_exists(thd, true, false, log_if_exists))
DBUG_RETURN(true);
}
@@ -10328,6 +10424,42 @@ do_continue:;
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
goto err_new_table_cleanup;
});
+
+ /*
+ If old table was a shared table and new table is not same type,
+ the slaves will not be able to recreate the data. In this case we
+ write the CREATE TABLE statement for the new table to the log and
+ log all inserted rows to the table.
+ */
+ if ((table->s->db_type()->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE) &&
+ (table->s->db_type() != new_table->s->db_type()) &&
+ (mysql_bin_log.is_open() &&
+ (thd->variables.option_bits & OPTION_BIN_LOG)))
+ {
+ /*
+ We new_table is marked as internal temp table, but we want to have
+ the logging based on the original table type
+ */
+ bool res;
+ tmp_table_type org_tmp_table= new_table->s->tmp_table;
+ new_table->s->tmp_table= table->s->tmp_table;
+
+ /* Force row logging, even if the table was created as 'temporary' */
+ new_table->s->can_do_row_logging= 1;
+
+ thd->binlog_start_trans_and_stmt();
+ res= binlog_drop_table(thd, table) || binlog_create_table(thd, new_table);
+ new_table->s->tmp_table= org_tmp_table;
+ if (res)
+ goto err_new_table_cleanup;
+ /*
+ ha_write_row() will log inserted rows in copy_data_between_tables().
+ No additional logging of query is needed
+ */
+ binlog_done= 1;
+ new_table->mark_columns_needed_for_insert();
+ thd->binlog_write_table_map(new_table, 1);
+ }
if (copy_data_between_tables(thd, table, new_table,
alter_info->create_list, ignore,
order_num, order, &copied, &deleted,
@@ -10378,7 +10510,9 @@ do_continue:;
goto err_new_table_cleanup;
/* We don't replicate alter table statement on temporary tables */
if (!thd->is_current_stmt_binlog_format_row() &&
- write_bin_log(thd, true, thd->query(), thd->query_length()))
+ table_creation_was_logged &&
+ !binlog_done &&
+ write_bin_log_with_if_exists(thd, true, false, log_if_exists))
DBUG_RETURN(true);
my_free(const_cast<uchar*>(frm.str));
goto end_temporary;
@@ -10560,9 +10694,11 @@ end_inplace:
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
thd->is_current_stmt_binlog_format_row() &&
(create_info->tmp_table())));
- if (write_bin_log(thd, true, thd->query(), thd->query_length()))
- DBUG_RETURN(true);
-
+ if (!binlog_done)
+ {
+ if (write_bin_log_with_if_exists(thd, true, false, log_if_exists))
+ DBUG_RETURN(true);
+ }
table_list->table= NULL; // For query cache
query_cache_invalidate3(thd, table_list, false);
@@ -10622,7 +10758,8 @@ err_with_mdl_after_alter:
We can't reset error as we will return 'true' below and the server
expects that error is set
*/
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ if (!binlog_done)
+ write_bin_log_with_if_exists(thd, FALSE, FALSE, log_if_exists);
err_with_mdl:
/*
diff --git a/sql/sql_table.h b/sql/sql_table.h
index debd55e7ab9..b9dada41e80 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -29,6 +29,7 @@ class THD;
struct TABLE;
struct handlerton;
class handler;
+class String;
typedef struct st_ha_check_opt HA_CHECK_OPT;
struct HA_CREATE_INFO;
struct Table_specification_st;
@@ -154,6 +155,8 @@ uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen);
bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
Table_specification_st *create_info,
Alter_info *alter_info);
+bool add_keyword_to_query(THD *thd, String *result, const LEX_CSTRING *keyword,
+ const LEX_CSTRING *add);
/*
mysql_create_table_no_lock can be called in one of the following
@@ -242,7 +245,8 @@ bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
HA_CHECK_OPT* check_opt);
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
- bool drop_temporary, bool drop_sequence);
+ bool drop_temporary, bool drop_sequence,
+ bool dont_log_query);
int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool drop_view,
bool drop_sequence,
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index f8025cdf701..bb2ab527754 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1072,7 +1072,7 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg,
bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl,
select_result *tmp_result,
- ulong additional_options,
+ ulonglong additional_options,
bool is_union_select)
{
DBUG_ENTER("st_select_lex_unit::prepare_join");
@@ -1278,7 +1278,7 @@ bool init_item_int(THD* thd, Item_int* &item)
bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
select_result *sel_result,
- ulong additional_options)
+ ulonglong additional_options)
{
SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *sl, *first_sl= first_select();
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 04db55d11ab..8268ee26019 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -4469,6 +4469,11 @@ static Sys_var_bit Sys_auto_is_null(
SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_AUTO_IS_NULL,
DEFAULT(FALSE), NO_MUTEX_GUARD, IN_BINLOG);
+static Sys_var_bit Sys_if_exists(
+ "sql_if_exists", "If set to 1 adds an implicate IF EXISTS to ALTER, RENAME and DROP of TABLES, VIEWS, FUNCTIONS and PACKAGES",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_IF_EXISTS,
+ DEFAULT(FALSE), NO_MUTEX_GUARD, IN_BINLOG);
+
static Sys_var_bit Sys_safe_updates(
"sql_safe_updates", "If set to 1, UPDATEs and DELETEs need either a key in "
"the WHERE clause, or a LIMIT clause, or else they will aborted. Prevents "