summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2019-06-14 07:36:47 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2019-06-14 07:36:47 +0200
commit4a3d51c76c131e7b5348d7c714a619f82de32d39 (patch)
tree4fb180861c733e364af930529565a7b799c4833a /sql
parentd9fe615ef6862c85c5aada96d4f5b62b7093177c (diff)
parent50653e021f1678c3c28c6b5886fadb9fcf8d87ff (diff)
downloadmariadb-git-4a3d51c76c131e7b5348d7c714a619f82de32d39.tar.gz
Merge branch '10.2' into 10.3
Diffstat (limited to 'sql')
-rw-r--r--sql/handler.cc28
-rw-r--r--sql/my_json_writer.cc7
-rw-r--r--sql/my_json_writer.h1
-rw-r--r--sql/rpl_mi.cc2
-rw-r--r--sql/sql_alter.cc12
-rw-r--r--sql/sql_alter.h5
-rw-r--r--sql/sql_base.cc11
-rw-r--r--sql/sql_base.h14
-rw-r--r--sql/sql_cmd.h51
-rw-r--r--sql/sql_explain.cc8
-rw-r--r--sql/sql_join_cache.cc3
-rw-r--r--sql/sql_lex.cc5
-rw-r--r--sql/sql_parse.cc285
-rw-r--r--sql/sql_select.cc110
-rw-r--r--sql/sql_table.cc311
-rw-r--r--sql/sql_update.cc227
-rw-r--r--sql/sql_yacc.yy67
-rw-r--r--sql/sql_yacc_ora.yy67
-rw-r--r--sql/table.cc23
19 files changed, 697 insertions, 540 deletions
diff --git a/sql/handler.cc b/sql/handler.cc
index 993ba5947dc..37811e08ac8 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2018, MariaDB Corporation.
+ Copyright (c) 2009, 2019, 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
@@ -213,6 +213,32 @@ redo:
}
+bool
+Storage_engine_name::resolve_storage_engine_with_error(THD *thd,
+ handlerton **ha,
+ bool tmp_table)
+{
+ if (plugin_ref plugin= ha_resolve_by_name(thd, &m_storage_engine_name,
+ tmp_table))
+ {
+ *ha= plugin_hton(plugin);
+ return false;
+ }
+
+ *ha= NULL;
+ if (thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
+ {
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), m_storage_engine_name.str);
+ return true;
+ }
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_STORAGE_ENGINE,
+ ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE),
+ m_storage_engine_name.str);
+ return false;
+}
+
+
plugin_ref ha_lock_engine(THD *thd, const handlerton *hton)
{
if (hton)
diff --git a/sql/my_json_writer.cc b/sql/my_json_writer.cc
index c96fc9fc0e1..656023d4033 100644
--- a/sql/my_json_writer.cc
+++ b/sql/my_json_writer.cc
@@ -129,6 +129,13 @@ void Json_writer::add_ll(longlong val)
add_unquoted_str(buf);
}
+void Json_writer::add_ull(ulonglong val)
+{
+ char buf[64];
+ my_snprintf(buf, sizeof(buf), "%llu", val);
+ add_unquoted_str(buf);
+}
+
/* Add a memory size, printing in Kb, Kb, Gb if necessary */
void Json_writer::add_size(longlong val)
diff --git a/sql/my_json_writer.h b/sql/my_json_writer.h
index da56396d7d9..4c7ca46ef7c 100644
--- a/sql/my_json_writer.h
+++ b/sql/my_json_writer.h
@@ -108,6 +108,7 @@ public:
void add_str(const String &str);
void add_ll(longlong val);
+ void add_ull(ulonglong val);
void add_size(longlong val);
void add_double(double val);
void add_bool(bool val);
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index c11e96abe38..50c5c7b1969 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -1233,7 +1233,7 @@ bool Master_info_index::init_all_master_info()
if (!err_num) // No Error on read Master_info
{
if (global_system_variables.log_warnings > 1)
- sql_print_information("Reading of all Master_info entries succeded");
+ sql_print_information("Reading of all Master_info entries succeeded");
DBUG_RETURN(0);
}
if (succ_num) // Have some Error and some Success
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 0de39e4970f..b3a036eda9e 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -359,6 +359,18 @@ bool Sql_cmd_alter_table::execute(THD *thd)
SELECT_LEX *select_lex= &lex->select_lex;
/* first table of first SELECT_LEX */
TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
+
+ 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)
+ {
+ if (resolve_storage_engine_with_error(thd, &lex->create_info.db_type,
+ lex->create_info.tmp_table()))
+ return true; // Engine not found, substitution is not allowed
+ if (!lex->create_info.db_type) // Not found, but substitution is allowed
+ lex->create_info.used_fields&= ~HA_CREATE_USED_ENGINE;
+ }
+
/*
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
so we have to use a copy of this structure to make execution
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index a40c980b692..10aafe1ab37 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -355,7 +355,8 @@ protected:
Sql_cmd_alter_table represents the generic ALTER TABLE statement.
@todo move Alter_info and other ALTER specific structures from Lex here.
*/
-class Sql_cmd_alter_table : public Sql_cmd_common_alter_table
+class Sql_cmd_alter_table : public Sql_cmd_common_alter_table,
+ public Storage_engine_name
{
public:
/**
@@ -367,6 +368,8 @@ public:
~Sql_cmd_alter_table()
{}
+ Storage_engine_name *option_storage_engine_name() { return this; }
+
bool execute(THD *thd);
};
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b1fa78b5ec6..b7294fbc304 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -4045,8 +4045,7 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
*/
bool open_tables(THD *thd, const DDL_options_st &options,
- TABLE_LIST **start, uint *counter,
- Sroutine_hash_entry **sroutine_to_open_list, uint flags,
+ TABLE_LIST **start, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy)
{
/*
@@ -4089,9 +4088,10 @@ restart:
has_prelocking_list= thd->lex->requires_prelocking();
table_to_open= start;
- sroutine_to_open= sroutine_to_open_list;
+ sroutine_to_open= &thd->lex->sroutines_list.first;
*counter= 0;
THD_STAGE_INFO(thd, stage_opening_tables);
+ prelocking_strategy->reset(thd);
/*
If we are executing LOCK TABLES statement or a DDL statement
@@ -4149,8 +4149,7 @@ restart:
elements in prelocking list/set.
*/
while (*table_to_open ||
- (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
- *sroutine_to_open))
+ (thd->locked_tables_mode <= LTM_LOCK_TABLES && *sroutine_to_open))
{
/*
For every table in the list of tables to open, try to find or open
@@ -4270,6 +4269,8 @@ restart:
}
}
}
+ if ((error= prelocking_strategy->handle_end(thd)))
+ goto error;
}
/*
diff --git a/sql/sql_base.h b/sql/sql_base.h
index bd84cfe2336..c9fb9bc6a62 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -241,17 +241,7 @@ lock_table_names(THD *thd, TABLE_LIST *table_list,
}
bool open_tables(THD *thd, const DDL_options_st &options,
TABLE_LIST **tables, uint *counter,
- Sroutine_hash_entry **sroutine_to_open, uint flags,
- Prelocking_strategy *prelocking_strategy);
-
-static inline bool
-open_tables(THD *thd, const DDL_options_st &options, TABLE_LIST **tables,
- uint *counter, uint flags, Prelocking_strategy *prelocking_strategy)
-{
- return open_tables(thd, options, tables, counter,
- &thd->lex->sroutines_list.first, flags,
- prelocking_strategy);
-}
+ uint flags, Prelocking_strategy *prelocking_strategy);
static inline bool
open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags,
@@ -400,6 +390,7 @@ class Prelocking_strategy
public:
virtual ~Prelocking_strategy() { }
+ virtual void reset(THD *thd) { };
virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
Sroutine_hash_entry *rt, sp_head *sp,
bool *need_prelocking) = 0;
@@ -407,6 +398,7 @@ public:
TABLE_LIST *table_list, bool *need_prelocking) = 0;
virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking)= 0;
+ virtual bool handle_end(THD *thd) { return 0; };
};
diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h
index a9d8178d3f8..f5df73216d8 100644
--- a/sql/sql_cmd.h
+++ b/sql/sql_cmd.h
@@ -117,6 +117,32 @@ enum enum_sql_command {
SQLCOM_END
};
+
+class Storage_engine_name
+{
+protected:
+ LEX_CSTRING m_storage_engine_name;
+public:
+ Storage_engine_name()
+ {
+ m_storage_engine_name.str= NULL;
+ m_storage_engine_name.length= 0;
+ }
+ Storage_engine_name(const LEX_CSTRING &name)
+ :m_storage_engine_name(name)
+ { }
+ Storage_engine_name(const LEX_STRING &name)
+ {
+ m_storage_engine_name.str= name.str;
+ m_storage_engine_name.length= name.length;
+ }
+ bool resolve_storage_engine_with_error(THD *thd,
+ handlerton **ha,
+ bool tmp_table);
+ bool is_set() { return m_storage_engine_name.str != NULL; }
+};
+
+
/**
@class Sql_cmd - Representation of an SQL command.
@@ -160,6 +186,11 @@ public:
*/
virtual bool execute(THD *thd) = 0;
+ virtual Storage_engine_name *option_storage_engine_name()
+ {
+ return NULL;
+ }
+
protected:
Sql_cmd()
{}
@@ -176,6 +207,26 @@ protected:
}
};
+class Sql_cmd_create_table_like: public Sql_cmd,
+ public Storage_engine_name
+{
+public:
+ Storage_engine_name *option_storage_engine_name() { return this; }
+ bool execute(THD *thd);
+};
+
+class Sql_cmd_create_table: public Sql_cmd_create_table_like
+{
+public:
+ enum_sql_command sql_command_code() const { return SQLCOM_CREATE_TABLE; }
+};
+
+class Sql_cmd_create_sequence: public Sql_cmd_create_table_like
+{
+public:
+ enum_sql_command sql_command_code() const { return SQLCOM_CREATE_SEQUENCE; }
+};
+
/**
Sql_cmd_call represents the CALL statement.
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index a1c1156cd27..ca538752627 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -1282,7 +1282,7 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
if (rows_set)
{
item_list.push_back(new (mem_root)
- Item_int(thd, (longlong) (ulonglong) rows,
+ Item_int(thd, (ulonglong) rows,
MY_INT64_NUM_DECIMAL_DIGITS),
mem_root);
}
@@ -1657,7 +1657,7 @@ void Explain_table_access::print_explain_json(Explain_query *query,
/* `rows` */
if (rows_set)
- writer->add_member("rows").add_ll(rows);
+ writer->add_member("rows").add_ull(rows);
/* `r_rows` */
if (is_analyze)
@@ -2295,7 +2295,7 @@ void Explain_update::print_explain_json(Explain_query *query,
}
/* `rows` */
- writer->add_member("rows").add_ll(rows);
+ writer->add_member("rows").add_ull(rows);
if (mrr_type.length() != 0)
@@ -2324,7 +2324,7 @@ void Explain_update::print_explain_json(Explain_query *query,
r_rows= 0;
r_filtered= buf_tracker.get_filtered_after_where() * 100.0;
}
- writer->add_member("r_rows").add_ll(r_rows);
+ writer->add_member("r_rows").add_ull(r_rows);
writer->add_member("r_filtered").add_double(r_filtered);
}
else /* Not doing buffering */
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index 8986e4c42ac..3b051259ad6 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -2147,7 +2147,8 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last)
}
finish:
- if (outer_join_first_inner)
+ if (outer_join_first_inner &&
+ join_tab->first_inner == join_tab->first_unmatched)
{
/*
All null complemented rows have been already generated for all
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index ef58dfb2b28..bd9725cbe0f 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4745,7 +4745,10 @@ void SELECT_LEX::increase_derived_records(ha_rows records)
break;
default:
// usual UNION
- result->est_records+= records;
+ if (HA_ROWS_MAX - records > result->est_records)
+ result->est_records+= records;
+ else
+ result->est_records= HA_ROWS_MAX;
break;
}
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4ca8abb64a4..01d13ac8789 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4064,289 +4064,6 @@ mysql_execute_command(THD *thd)
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
break;
}
- case SQLCOM_CREATE_SEQUENCE:
- case SQLCOM_CREATE_TABLE:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- bool link_to_local;
- TABLE_LIST *create_table= first_table;
- TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
-
- if (lex->tmp_table())
- {
- status_var_decrement(thd->status_var.com_stat[SQLCOM_CREATE_TABLE]);
- status_var_increment(thd->status_var.com_create_tmp_table);
- }
-
- /*
- Code below (especially in mysql_create_table() and select_create
- methods) may modify HA_CREATE_INFO structure in LEX, so we have to
- use a copy of this structure to make execution prepared statement-
- safe. A shallow copy is enough as this code won't modify any memory
- referenced from this structure.
- */
- Table_specification_st create_info(lex->create_info);
- /*
- We need to copy alter_info for the same reasons of re-execution
- safety, only in case of Alter_info we have to do (almost) a deep
- copy.
- */
- Alter_info alter_info(lex->alter_info, thd->mem_root);
- if (unlikely(thd->is_fatal_error))
- {
- /* If out of memory when creating a copy of alter_info. */
- res= 1;
- goto end_with_restore_list;
- }
-
- /* Check privileges */
- if ((res= create_table_precheck(thd, select_tables, create_table)))
- goto end_with_restore_list;
-
- /* Might have been updated in create_table_precheck */
- create_info.alias= create_table->alias;
-
- /* Fix names if symlinked or relocated tables */
- if (append_file_to_dir(thd, &create_info.data_file_name,
- &create_table->table_name) ||
- append_file_to_dir(thd, &create_info.index_file_name,
- &create_table->table_name))
- goto end_with_restore_list;
-
- /*
- If no engine type was given, work out the default now
- rather than at parse-time.
- */
- if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
- create_info.use_default_db_type(thd);
-
- /*
- If we are using SET CHARSET without DEFAULT, add an implicit
- DEFAULT to not confuse old users. (This may change).
- */
- if ((create_info.used_fields &
- (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
- HA_CREATE_USED_CHARSET)
- {
- create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
- create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- create_info.default_table_charset= create_info.table_charset;
- create_info.table_charset= 0;
- }
-
- /*
- If we are a slave, we should add OR REPLACE if we don't have
- IF EXISTS. This will help a slave to recover from
- CREATE TABLE OR EXISTS failures by dropping the table and
- retrying the create.
- */
- if (thd->slave_thread &&
- slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT &&
- !lex->create_info.if_not_exists())
- {
- create_info.add(DDL_options_st::OPT_OR_REPLACE);
- create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);
- }
-
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- thd->work_part_info= 0;
- {
- partition_info *part_info= thd->lex->part_info;
- if (part_info && !(part_info= part_info->get_clone(thd)))
- {
- res= -1;
- goto end_with_restore_list;
- }
- thd->work_part_info= part_info;
- }
-#endif
-
- if (select_lex->item_list.elements) // With select
- {
- select_result *result;
-
- /*
- CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless
- ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore
- use row based logging if mixed or row based logging is available.
- TODO: Check if the order of the output of the select statement is
- deterministic. Waiting for BUG#42415
- */
- if(lex->ignore)
- lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT);
-
- if(lex->duplicates == DUP_REPLACE)
- lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT);
-
- /*
- If:
- a) we inside an SP and there was NAME_CONST substitution,
- b) binlogging is on (STMT mode),
- c) we log the SP as separate statements
- raise a warning, as it may cause problems
- (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs')
- */
- if (thd->query_name_consts && mysql_bin_log.is_open() &&
- thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
- !mysql_bin_log.is_query_in_union(thd, thd->query_id))
- {
- List_iterator_fast<Item> it(select_lex->item_list);
- Item *item;
- uint splocal_refs= 0;
- /* Count SP local vars in the top-level SELECT list */
- while ((item= it++))
- {
- if (item->get_item_splocal())
- splocal_refs++;
- }
- /*
- If it differs from number of NAME_CONST substitution applied,
- we may have a SOME_FUNC(NAME_CONST()) in the SELECT list,
- that may cause a problem with binary log (see BUG#35383),
- raise a warning.
- */
- if (splocal_refs != thd->query_name_consts)
- push_warning(thd,
- Sql_condition::WARN_LEVEL_WARN,
- ER_UNKNOWN_ERROR,
-"Invoked routine ran a statement that may cause problems with "
-"binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' "
-"section of the manual.");
- }
-
- select_lex->options|= SELECT_NO_UNLOCK;
- unit->set_limit(select_lex);
-
- /*
- Disable non-empty MERGE tables with CREATE...SELECT. Too
- complicated. See Bug #26379. Empty MERGE tables are read-only
- and don't allow CREATE...SELECT anyway.
- */
- if (create_info.used_fields & HA_CREATE_USED_UNION)
- {
- my_error(ER_WRONG_OBJECT, MYF(0), create_table->db.str,
- create_table->table_name.str, "BASE TABLE");
- res= 1;
- goto end_with_restore_list;
- }
-
- /* Copy temporarily the statement flags to thd for lock_table_names() */
- uint save_thd_create_info_options= thd->lex->create_info.options;
- thd->lex->create_info.options|= create_info.options;
- res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
- thd->lex->create_info.options= save_thd_create_info_options;
- if (unlikely(res))
- {
- /* Got error or warning. Set res to 1 if error */
- if (!(res= thd->is_error()))
- my_ok(thd); // CREATE ... IF NOT EXISTS
- goto end_with_restore_list;
- }
-
- /* Ensure we don't try to create something from which we select from */
- if (create_info.or_replace() && !create_info.tmp_table())
- {
- TABLE_LIST *duplicate;
- if (unlikely((duplicate= unique_table(thd, lex->query_tables,
- lex->query_tables->next_global,
- CHECK_DUP_FOR_CREATE |
- CHECK_DUP_SKIP_TEMP_TABLE))))
- {
- update_non_unique_table_error(lex->query_tables, "CREATE",
- duplicate);
- res= TRUE;
- goto end_with_restore_list;
- }
- }
- {
- /*
- Remove target table from main select and name resolution
- context. This can't be done earlier as it will break view merging in
- statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT".
- */
- lex->unlink_first_table(&link_to_local);
-
- /* Store reference to table in case of LOCK TABLES */
- create_info.table= create_table->table;
-
- /*
- select_create is currently not re-execution friendly and
- needs to be created for every execution of a PS/SP.
- Note: In wsrep-patch, CTAS is handled like a regular transaction.
- */
- if (unlikely((result= new (thd->mem_root)
- select_create(thd, create_table,
- &create_info,
- &alter_info,
- select_lex->item_list,
- lex->duplicates,
- lex->ignore,
- select_tables))))
- {
- /*
- CREATE from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- if (!(res= handle_select(thd, lex, result, 0)))
- {
- if (create_info.tmp_table())
- thd->variables.option_bits|= OPTION_KEEP_LOG;
- }
- delete result;
- }
- lex->link_first_table_back(create_table, link_to_local);
- }
- }
- else
- {
- /* regular create */
- if (create_info.like())
- {
- /* CREATE TABLE ... LIKE ... */
- res= mysql_create_like_table(thd, create_table, select_tables,
- &create_info);
- }
- else
- {
- if (create_info.vers_fix_system_fields(thd, &alter_info, *create_table) ||
- create_info.vers_check_system_fields(thd, &alter_info, *create_table))
- goto end_with_restore_list;
-
- /*
- In STATEMENT format, we probably have to replicate also temporary
- tables, like mysql replication does. Also check if the requested
- engine is allowed/supported.
- */
- if (WSREP(thd) &&
- !check_engine(thd, create_table->db.str, create_table->table_name.str,
- &create_info) &&
- (!thd->is_current_stmt_binlog_format_row() ||
- !create_info.tmp_table()))
- {
- WSREP_TO_ISOLATION_BEGIN(create_table->db.str, create_table->table_name.str, NULL);
- }
- /* Regular CREATE TABLE */
- res= mysql_create_table(thd, create_table, &create_info, &alter_info);
- }
-
- if (!res)
- {
- /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
- if (create_info.tmp_table())
- thd->variables.option_bits|= OPTION_KEEP_LOG;
- /* in case of create temp tables if @@session_track_state_change is
- ON then send session state notification in OK packet */
- if(create_info.options & HA_LEX_CREATE_TMP_TABLE)
- {
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
- }
- my_ok(thd);
- }
- }
-
-end_with_restore_list:
- break;
- }
case SQLCOM_CREATE_INDEX:
case SQLCOM_DROP_INDEX:
/*
@@ -6287,6 +6004,8 @@ end_with_restore_list:
case SQLCOM_OPTIMIZE:
case SQLCOM_REPAIR:
case SQLCOM_TRUNCATE:
+ case SQLCOM_CREATE_TABLE:
+ case SQLCOM_CREATE_SEQUENCE:
case SQLCOM_ALTER_TABLE:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/* fall through */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1876f6067fa..426fcd6dbb4 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -214,7 +214,8 @@ static COND *make_cond_for_table_from_pred(THD *thd, Item *root_cond,
table_map used_table,
int join_tab_idx_arg,
bool exclude_expensive_cond,
- bool retain_ref_cond);
+ bool retain_ref_cond,
+ bool is_top_and_level);
static Item* part_of_refkey(TABLE *form,Field *field);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
@@ -5078,7 +5079,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
DBUG_RETURN(TRUE); /* purecov: inspected */
{
- ha_rows records= 1;
+ double records= 1;
SELECT_LEX_UNIT *unit= join->select_lex->master_unit();
/* Find an optimal join order of the non-constant tables. */
@@ -5103,10 +5104,11 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
table/view.
*/
for (i= 0; i < join->table_count ; i++)
- records*= join->best_positions[i].records_read ?
- (ha_rows)join->best_positions[i].records_read : 1;
- set_if_smaller(records, unit->select_limit_cnt);
- join->select_lex->increase_derived_records(records);
+ if (double rr= join->best_positions[i].records_read)
+ records= COST_MULT(records, rr);
+ ha_rows rows= records > HA_ROWS_MAX ? HA_ROWS_MAX : (ha_rows) records;
+ set_if_smaller(rows, unit->select_limit_cnt);
+ join->select_lex->increase_derived_records(rows);
}
}
@@ -8258,18 +8260,23 @@ double JOIN::get_examined_rows()
{
double examined_rows;
double prev_fanout= 1;
+ double records;
JOIN_TAB *tab= first_breadth_first_tab();
JOIN_TAB *prev_tab= tab;
- examined_rows= (double)tab->get_examined_rows();
+ records= (double)tab->get_examined_rows();
while ((tab= next_breadth_first_tab(first_breadth_first_tab(),
top_join_tab_count, tab)))
{
- prev_fanout *= prev_tab->records_read;
- examined_rows+= tab->get_examined_rows() * prev_fanout;
+ prev_fanout= COST_MULT(prev_fanout, prev_tab->records_read);
+ records=
+ COST_ADD(records,
+ COST_MULT((double) (tab->get_examined_rows()), prev_fanout));
prev_tab= tab;
}
+ examined_rows= (double)
+ (records > (double) HA_ROWS_MAX ? HA_ROWS_MAX : (ha_rows) records);
return examined_rows;
}
@@ -10582,12 +10589,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
RAND_TABLE_BIT;
}
- /*
- Following force including random expression in last table condition.
- It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
- */
- if (tab == join->join_tab + last_top_base_tab_idx)
- current_map|= RAND_TABLE_BIT;
used_tables|=current_map;
if (tab->type == JT_REF && tab->quick &&
@@ -10629,6 +10630,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
tmp= make_cond_for_table(thd, cond, used_tables, current_map, i,
FALSE, FALSE);
+ if (tab == join->join_tab + last_top_base_tab_idx)
+ {
+ /*
+ This pushes conjunctive conditions of WHERE condition such that:
+ - their used_tables() contain RAND_TABLE_BIT
+ - the conditions does not refer to any fields
+ (such like rand() > 0.5)
+ */
+ table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
+ COND *rand_cond= make_cond_for_table(thd, cond, used_tables,
+ rand_table_bit, -1,
+ FALSE, FALSE);
+ add_cond_and_fix(thd, &tmp, rand_cond);
+ }
}
/* Add conditions added by add_not_null_conds(). */
if (tab->select_cond)
@@ -10964,6 +10979,21 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
current_map,
/*(inner_tab - first_tab)*/ -1,
FALSE, FALSE);
+ if (tab == last_tab)
+ {
+ /*
+ This pushes conjunctive conditions of ON expression of an outer
+ join such that:
+ - their used_tables() contain RAND_TABLE_BIT
+ - the conditions does not refer to any fields
+ (such like rand() > 0.5)
+ */
+ table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
+ COND *rand_cond= make_cond_for_table(thd, on_expr, used_tables2,
+ rand_table_bit, -1,
+ FALSE, FALSE);
+ add_cond_and_fix(thd, &tmp_cond, rand_cond);
+ }
bool is_sjm_lookup_tab= FALSE;
if (inner_tab->bush_children)
{
@@ -12589,6 +12619,8 @@ ha_rows JOIN_TAB::get_examined_rows()
else
examined_rows= records_read;
+ if (examined_rows >= (double) HA_ROWS_MAX)
+ return HA_ROWS_MAX;
return (ha_rows) examined_rows;
}
@@ -21282,7 +21314,7 @@ make_cond_for_table(THD *thd, Item *cond, table_map tables,
return make_cond_for_table_from_pred(thd, cond, cond, tables, used_table,
join_tab_idx_arg,
exclude_expensive_cond,
- retain_ref_cond);
+ retain_ref_cond, true);
}
@@ -21292,9 +21324,12 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
int join_tab_idx_arg,
bool exclude_expensive_cond __attribute__
((unused)),
- bool retain_ref_cond)
+ bool retain_ref_cond,
+ bool is_top_and_level)
{
+ table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
+
if (used_table && !(cond->used_tables() & used_table))
return (COND*) 0; // Already checked
@@ -21310,11 +21345,28 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
Item *item;
while ((item=li++))
{
+ /*
+ Special handling of top level conjuncts with RAND_TABLE_BIT:
+ if such a conjunct contains a reference to a field that is not
+ an outer field then it is pushed to the corresponding table by
+ the same rule as all other conjuncts. Otherwise, if the conjunct
+ is used in WHERE is is pushed to the last joined table, if is it
+ is used in ON condition of an outer join it is pushed into the
+ last inner table of the outer join. Such conjuncts are pushed in
+ a call of make_cond_for_table_from_pred() with the
+ parameter 'used_table' equal to PSEUDO_TABLE_BITS.
+ */
+ if (is_top_and_level && used_table == rand_table_bit &&
+ (item->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
+ {
+ /* The conjunct with RAND_TABLE_BIT has been allready pushed */
+ continue;
+ }
Item *fix=make_cond_for_table_from_pred(thd, root_cond, item,
tables, used_table,
- join_tab_idx_arg,
+ join_tab_idx_arg,
exclude_expensive_cond,
- retain_ref_cond);
+ retain_ref_cond, false);
if (fix)
new_cond->argument_list()->push_back(fix, thd->mem_root);
}
@@ -21339,6 +21391,13 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
}
else
{ // Or list
+ if (is_top_and_level && used_table == rand_table_bit &&
+ (cond->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
+ {
+ /* This top level formula with RAND_TABLE_BIT has been already pushed */
+ return (COND*) 0;
+ }
+
Item_cond_or *new_cond=new (thd->mem_root) Item_cond_or(thd);
if (!new_cond)
return (COND*) 0; // OOM /* purecov: inspected */
@@ -21350,7 +21409,7 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
tables, 0L,
join_tab_idx_arg,
exclude_expensive_cond,
- retain_ref_cond);
+ retain_ref_cond, false);
if (!fix)
return (COND*) 0; // Always true
new_cond->argument_list()->push_back(fix, thd->mem_root);
@@ -21367,6 +21426,13 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
}
}
+ if (is_top_and_level && used_table == rand_table_bit &&
+ (cond->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
+ {
+ /* This top level formula with RAND_TABLE_BIT has been already pushed */
+ return (COND*) 0;
+ }
+
/*
Because the following test takes a while and it can be done
table_count times, we mark each item that we have examined with the result
@@ -25377,10 +25443,10 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
}
else
{
- double examined_rows= (double)get_examined_rows();
+ ha_rows examined_rows= get_examined_rows();
eta->rows_set= true;
- eta->rows= (ha_rows) examined_rows;
+ eta->rows= examined_rows;
/* "filtered" */
float f= 0.0;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ad86cdf8514..9da889852b2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -10830,3 +10830,314 @@ bool check_engine(THD *thd, const char *db_name,
DBUG_RETURN(false);
}
+
+
+bool Sql_cmd_create_table_like::execute(THD *thd)
+{
+ DBUG_ENTER("Sql_cmd_create_table::execute");
+ LEX *lex= thd->lex;
+ TABLE_LIST *all_tables= lex->query_tables;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ TABLE_LIST *first_table= select_lex->table_list.first;
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ bool link_to_local;
+ TABLE_LIST *create_table= first_table;
+ TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
+ /* most outer SELECT_LEX_UNIT of query */
+ SELECT_LEX_UNIT *unit= &lex->unit;
+ int res= 0;
+
+ 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)
+ {
+ if (resolve_storage_engine_with_error(thd, &lex->create_info.db_type,
+ lex->create_info.tmp_table()))
+ DBUG_RETURN(true); // Engine not found, substitution is not allowed
+
+ if (!lex->create_info.db_type) // Not found, but substitution is allowed
+ {
+ lex->create_info.use_default_db_type(thd);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_USING_OTHER_HANDLER,
+ ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
+ hton_name(lex->create_info.db_type)->str,
+ create_table->table_name.str);
+ }
+ }
+
+ if (lex->tmp_table())
+ {
+ status_var_decrement(thd->status_var.com_stat[SQLCOM_CREATE_TABLE]);
+ status_var_increment(thd->status_var.com_create_tmp_table);
+ }
+
+ /*
+ Code below (especially in mysql_create_table() and select_create
+ methods) may modify HA_CREATE_INFO structure in LEX, so we have to
+ use a copy of this structure to make execution prepared statement-
+ safe. A shallow copy is enough as this code won't modify any memory
+ referenced from this structure.
+ */
+ Table_specification_st create_info(lex->create_info);
+ /*
+ We need to copy alter_info for the same reasons of re-execution
+ safety, only in case of Alter_info we have to do (almost) a deep
+ copy.
+ */
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+ if (unlikely(thd->is_fatal_error))
+ {
+ /* If out of memory when creating a copy of alter_info. */
+ res= 1;
+ goto end_with_restore_list;
+ }
+
+ /* Check privileges */
+ if ((res= create_table_precheck(thd, select_tables, create_table)))
+ goto end_with_restore_list;
+
+ /* Might have been updated in create_table_precheck */
+ create_info.alias= create_table->alias;
+
+ /* Fix names if symlinked or relocated tables */
+ if (append_file_to_dir(thd, &create_info.data_file_name,
+ &create_table->table_name) ||
+ append_file_to_dir(thd, &create_info.index_file_name,
+ &create_table->table_name))
+ goto end_with_restore_list;
+
+ /*
+ If no engine type was given, work out the default now
+ rather than at parse-time.
+ */
+ if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
+ create_info.use_default_db_type(thd);
+ /*
+ If we are using SET CHARSET without DEFAULT, add an implicit
+ DEFAULT to not confuse old users. (This may change).
+ */
+ if ((create_info.used_fields &
+ (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
+ HA_CREATE_USED_CHARSET)
+ {
+ create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
+ create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ create_info.default_table_charset= create_info.table_charset;
+ create_info.table_charset= 0;
+ }
+
+ /*
+ If we are a slave, we should add OR REPLACE if we don't have
+ IF EXISTS. This will help a slave to recover from
+ CREATE TABLE OR EXISTS failures by dropping the table and
+ retrying the create.
+ */
+ if (thd->slave_thread &&
+ slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT &&
+ !lex->create_info.if_not_exists())
+ {
+ create_info.add(DDL_options_st::OPT_OR_REPLACE);
+ create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);
+ }
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ thd->work_part_info= 0;
+ {
+ partition_info *part_info= thd->lex->part_info;
+ if (part_info && !(part_info= part_info->get_clone(thd)))
+ {
+ res= -1;
+ goto end_with_restore_list;
+ }
+ thd->work_part_info= part_info;
+ }
+#endif
+
+ if (select_lex->item_list.elements) // With select
+ {
+ select_result *result;
+
+ /*
+ CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless
+ ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore
+ use row based logging if mixed or row based logging is available.
+ TODO: Check if the order of the output of the select statement is
+ deterministic. Waiting for BUG#42415
+ */
+ if(lex->ignore)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT);
+
+ if(lex->duplicates == DUP_REPLACE)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT);
+
+ /*
+ If:
+ a) we inside an SP and there was NAME_CONST substitution,
+ b) binlogging is on (STMT mode),
+ c) we log the SP as separate statements
+ raise a warning, as it may cause problems
+ (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs')
+ */
+ if (thd->query_name_consts && mysql_bin_log.is_open() &&
+ thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
+ !mysql_bin_log.is_query_in_union(thd, thd->query_id))
+ {
+ List_iterator_fast<Item> it(select_lex->item_list);
+ Item *item;
+ uint splocal_refs= 0;
+ /* Count SP local vars in the top-level SELECT list */
+ while ((item= it++))
+ {
+ if (item->get_item_splocal())
+ splocal_refs++;
+ }
+ /*
+ If it differs from number of NAME_CONST substitution applied,
+ we may have a SOME_FUNC(NAME_CONST()) in the SELECT list,
+ that may cause a problem with binary log (see BUG#35383),
+ raise a warning.
+ */
+ if (splocal_refs != thd->query_name_consts)
+ push_warning(thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR,
+"Invoked routine ran a statement that may cause problems with "
+"binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' "
+"section of the manual.");
+ }
+
+ select_lex->options|= SELECT_NO_UNLOCK;
+ unit->set_limit(select_lex);
+
+ /*
+ Disable non-empty MERGE tables with CREATE...SELECT. Too
+ complicated. See Bug #26379. Empty MERGE tables are read-only
+ and don't allow CREATE...SELECT anyway.
+ */
+ if (create_info.used_fields & HA_CREATE_USED_UNION)
+ {
+ my_error(ER_WRONG_OBJECT, MYF(0), create_table->db.str,
+ create_table->table_name.str, "BASE TABLE");
+ res= 1;
+ goto end_with_restore_list;
+ }
+
+ /* Copy temporarily the statement flags to thd for lock_table_names() */
+ uint save_thd_create_info_options= thd->lex->create_info.options;
+ thd->lex->create_info.options|= create_info.options;
+ res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
+ thd->lex->create_info.options= save_thd_create_info_options;
+ if (unlikely(res))
+ {
+ /* Got error or warning. Set res to 1 if error */
+ if (!(res= thd->is_error()))
+ my_ok(thd); // CREATE ... IF NOT EXISTS
+ goto end_with_restore_list;
+ }
+
+ /* Ensure we don't try to create something from which we select from */
+ if (create_info.or_replace() && !create_info.tmp_table())
+ {
+ if (TABLE_LIST *duplicate= unique_table(thd, lex->query_tables,
+ lex->query_tables->next_global,
+ CHECK_DUP_FOR_CREATE |
+ CHECK_DUP_SKIP_TEMP_TABLE))
+ {
+ update_non_unique_table_error(lex->query_tables, "CREATE",
+ duplicate);
+ res= TRUE;
+ goto end_with_restore_list;
+ }
+ }
+ {
+ /*
+ Remove target table from main select and name resolution
+ context. This can't be done earlier as it will break view merging in
+ statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT".
+ */
+ lex->unlink_first_table(&link_to_local);
+
+ /* Store reference to table in case of LOCK TABLES */
+ create_info.table= create_table->table;
+
+ /*
+ select_create is currently not re-execution friendly and
+ needs to be created for every execution of a PS/SP.
+ Note: In wsrep-patch, CTAS is handled like a regular transaction.
+ */
+ if ((result= new (thd->mem_root) select_create(thd, create_table,
+ &create_info,
+ &alter_info,
+ select_lex->item_list,
+ lex->duplicates,
+ lex->ignore,
+ select_tables)))
+ {
+ /*
+ CREATE from SELECT give its SELECT_LEX for SELECT,
+ and item_list belong to SELECT
+ */
+ if (!(res= handle_select(thd, lex, result, 0)))
+ {
+ if (create_info.tmp_table())
+ thd->variables.option_bits|= OPTION_KEEP_LOG;
+ }
+ delete result;
+ }
+ lex->link_first_table_back(create_table, link_to_local);
+ }
+ }
+ else
+ {
+ /* regular create */
+ if (create_info.like())
+ {
+ /* CREATE TABLE ... LIKE ... */
+ res= mysql_create_like_table(thd, create_table, select_tables,
+ &create_info);
+ }
+ else
+ {
+ if (create_info.vers_fix_system_fields(thd, &alter_info, *create_table) ||
+ create_info.vers_check_system_fields(thd, &alter_info, *create_table))
+ goto end_with_restore_list;
+
+ /*
+ In STATEMENT format, we probably have to replicate also temporary
+ tables, like mysql replication does. Also check if the requested
+ engine is allowed/supported.
+ */
+ if (WSREP(thd) &&
+ !check_engine(thd, create_table->db.str, create_table->table_name.str,
+ &create_info) &&
+ (!thd->is_current_stmt_binlog_format_row() ||
+ !create_info.tmp_table()))
+ {
+ WSREP_TO_ISOLATION_BEGIN(create_table->db.str, create_table->table_name.str, NULL)
+ }
+ /* Regular CREATE TABLE */
+ res= mysql_create_table(thd, create_table, &create_info, &alter_info);
+ }
+ if (!res)
+ {
+ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
+ if (create_info.tmp_table())
+ thd->variables.option_bits|= OPTION_KEEP_LOG;
+ /* in case of create temp tables if @@session_track_state_change is
+ ON then send session state notification in OK packet */
+ if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ }
+ my_ok(thd);
+ }
+ }
+
+end_with_restore_list:
+ DBUG_RETURN(res);
+
+WSREP_ERROR_LABEL:
+ DBUG_RETURN(true);
+}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 681e3bb0b64..e846424ef13 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1516,108 +1516,81 @@ static bool multi_update_check_table_access(THD *thd, TABLE_LIST *table,
}
-/*
- make update specific preparation and checks after opening tables
+class Multiupdate_prelocking_strategy : public DML_prelocking_strategy
+{
+ bool done;
+ bool has_prelocking_list;
+public:
+ void reset(THD *thd);
+ bool handle_end(THD *thd);
+};
+
+void Multiupdate_prelocking_strategy::reset(THD *thd)
+{
+ done= false;
+ has_prelocking_list= thd->lex->requires_prelocking();
+}
- SYNOPSIS
- mysql_multi_update_prepare()
- thd thread handler
+/**
+ Determine what tables could be updated in the multi-update
- RETURN
- FALSE OK
- TRUE Error
+ For these tables we'll need to open triggers and continue prelocking
+ until all is open.
*/
-
-int mysql_multi_update_prepare(THD *thd)
+bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
{
- LEX *lex= thd->lex;
- TABLE_LIST *table_list= lex->query_tables;
- TABLE_LIST *tl;
- List<Item> *fields= &lex->select_lex.item_list;
- table_map tables_for_update;
- bool update_view= 0;
- DML_prelocking_strategy prelocking_strategy;
- bool has_prelocking_list= thd->lex->requires_prelocking();
+ DBUG_ENTER("Multiupdate_prelocking_strategy::handle_end");
+ if (done)
+ DBUG_RETURN(0);
- /*
- if this multi-update was converted from usual update, here is table
- counter else junk will be assigned here, but then replaced with real
- count in open_tables()
- */
- uint table_count= lex->table_count;
- const bool using_lock_tables= thd->locked_tables_mode != LTM_NONE;
- bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
- DBUG_ENTER("mysql_multi_update_prepare");
+ LEX *lex= thd->lex;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ TABLE_LIST *table_list= lex->query_tables, *tl;
- /* following need for prepared statements, to run next time multi-update */
- thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
+ done= true;
- /*
- Open tables and create derived ones, but do not lock and fill them yet.
+ if (mysql_handle_derived(lex, DT_INIT) ||
+ mysql_handle_derived(lex, DT_MERGE_FOR_INSERT) ||
+ mysql_handle_derived(lex, DT_PREPARE))
+ DBUG_RETURN(1);
- During prepare phase acquire only S metadata locks instead of SW locks to
- keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
- and global read lock.
- */
- if ((original_multiupdate && open_tables(thd, &table_list, &table_count,
- thd->stmt_arena->is_stmt_prepare()
- ? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
- &prelocking_strategy)) ||
- mysql_handle_derived(lex, DT_INIT))
- DBUG_RETURN(TRUE);
/*
setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
second time, but this call will do nothing (there are check for second
call in setup_tables()).
*/
- //We need to merge for insert prior to prepare.
- if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT))
- DBUG_RETURN(TRUE);
-
- if (mysql_handle_derived(lex, DT_PREPARE))
- DBUG_RETURN(TRUE);
-
- if (setup_tables_and_check_access(thd, &lex->select_lex.context,
- &lex->select_lex.top_join_list,
- table_list,
- lex->select_lex.leaf_tables, FALSE,
- UPDATE_ACL, SELECT_ACL, FALSE))
- DBUG_RETURN(TRUE);
+ if (setup_tables_and_check_access(thd, &select_lex->context,
+ &select_lex->top_join_list, table_list, select_lex->leaf_tables,
+ FALSE, UPDATE_ACL, SELECT_ACL, FALSE))
+ DBUG_RETURN(1);
- if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))
- DBUG_RETURN(TRUE);
+ if (select_lex->handle_derived(thd->lex, DT_MERGE))
+ DBUG_RETURN(1);
+ List<Item> *fields= &lex->select_lex.item_list;
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
*fields, MARK_COLUMNS_WRITE, 0, 0))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
+ // Check if we have a view in the list ...
for (tl= table_list; tl ; tl= tl->next_local)
- {
if (tl->view)
- {
- update_view= 1;
break;
- }
- }
-
- if (check_fields(thd, *fields, update_view))
- {
- DBUG_RETURN(TRUE);
- }
-
- thd->table_map_for_update= tables_for_update= get_table_map(fields);
+ // ... and pass this knowlage in check_fields call
+ if (check_fields(thd, *fields, tl != NULL ))
+ DBUG_RETURN(1);
- if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update))
- DBUG_RETURN(true);
+ table_map tables_for_update= thd->table_map_for_update= get_table_map(fields);
- TABLE_LIST **new_tables= lex->query_tables_last;
- DBUG_ASSERT(*new_tables== NULL);
+ if (unsafe_key_update(select_lex->leaf_tables, tables_for_update))
+ DBUG_RETURN(1);
/*
Setup timestamp handling and locking mode
*/
- List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
+ List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
+ const bool using_lock_tables= thd->locked_tables_mode != LTM_NONE;
while ((tl= ti++))
{
TABLE *table= tl->table;
@@ -1632,7 +1605,7 @@ int mysql_multi_update_prepare(THD *thd)
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
tl->top_table()->alias.str, "UPDATE");
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
}
DBUG_PRINT("info",("setting table `%s` for update",
@@ -1644,8 +1617,8 @@ int mysql_multi_update_prepare(THD *thd)
tl->updating= 1;
if (tl->belong_to_view)
tl->belong_to_view->updating= 1;
- if (extend_table_list(thd, tl, &prelocking_strategy, has_prelocking_list))
- DBUG_RETURN(TRUE);
+ if (extend_table_list(thd, tl, this, has_prelocking_list))
+ DBUG_RETURN(1);
}
else
{
@@ -1677,19 +1650,6 @@ int mysql_multi_update_prepare(THD *thd)
through all leaf tables but also through all view hierarchy.
*/
- uint addon_table_count= 0;
- if (*new_tables)
- {
- Sroutine_hash_entry **new_routines= thd->lex->sroutines_list.next;
- DBUG_ASSERT(*new_routines == NULL);
- if (open_tables(thd, thd->lex->create_info, new_tables,
- &addon_table_count, new_routines,
- thd->stmt_arena->is_stmt_prepare()
- ? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
- &prelocking_strategy))
- DBUG_RETURN(TRUE);
- }
-
for (tl= table_list; tl; tl= tl->next_local)
{
bool not_used= false;
@@ -1702,23 +1662,67 @@ int mysql_multi_update_prepare(THD *thd)
/* check single table update for view compound from several tables */
for (tl= table_list; tl; tl= tl->next_local)
{
+ TABLE_LIST *for_update= 0;
if (tl->is_jtbm())
continue;
- if (tl->is_merged_derived())
+ if (tl->is_merged_derived() &&
+ tl->check_single_table(&for_update, tables_for_update, tl))
{
- TABLE_LIST *for_update= 0;
- if (tl->check_single_table(&for_update, tables_for_update, tl))
- {
- my_error(ER_VIEW_MULTIUPDATE, MYF(0),
- tl->view_db.str, tl->view_name.str);
- DBUG_RETURN(-1);
- }
+ my_error(ER_VIEW_MULTIUPDATE, MYF(0), tl->view_db.str, tl->view_name.str);
+ DBUG_RETURN(1);
}
}
+ DBUG_RETURN(0);
+}
+
+/*
+ make update specific preparation and checks after opening tables
+
+ SYNOPSIS
+ mysql_multi_update_prepare()
+ thd thread handler
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+int mysql_multi_update_prepare(THD *thd)
+{
+ LEX *lex= thd->lex;
+ TABLE_LIST *table_list= lex->query_tables;
+ TABLE_LIST *tl;
+ Multiupdate_prelocking_strategy prelocking_strategy;
+ uint table_count= lex->table_count;
+ DBUG_ENTER("mysql_multi_update_prepare");
+
+ /*
+ Open tables and create derived ones, but do not lock and fill them yet.
+
+ During prepare phase acquire only S metadata locks instead of SW locks to
+ keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
+ and global read lock.
+ */
+ if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI)
+ {
+ if (open_tables(thd, &table_list, &table_count,
+ thd->stmt_arena->is_stmt_prepare() ? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
+ &prelocking_strategy))
+ DBUG_RETURN(TRUE);
+ }
+ else
+ {
+ /* following need for prepared statements, to run next time multi-update */
+ thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
+ prelocking_strategy.reset(thd);
+ if (prelocking_strategy.handle_end(thd))
+ DBUG_RETURN(TRUE);
+ }
+
/* now lock and fill tables */
if (!thd->stmt_arena->is_stmt_prepare() &&
- lock_tables(thd, table_list, table_count + addon_table_count, 0))
+ lock_tables(thd, table_list, table_count, 0))
{
DBUG_RETURN(TRUE);
}
@@ -1731,7 +1735,7 @@ int mysql_multi_update_prepare(THD *thd)
*/
lex->select_lex.exclude_from_table_unique_test= TRUE;
/* We only need SELECT privilege for columns in the values list */
- ti.rewind();
+ List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
while ((tl= ti++))
{
if (tl->is_jtbm())
@@ -1764,25 +1768,18 @@ int mysql_multi_update_prepare(THD *thd)
Setup multi-update handling and call SELECT to do the join
*/
-bool mysql_multi_update(THD *thd,
- TABLE_LIST *table_list,
- List<Item> *fields,
- List<Item> *values,
- COND *conds,
- ulonglong options,
+bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields,
+ List<Item> *values, COND *conds, ulonglong options,
enum enum_duplicates handle_duplicates,
- bool ignore,
- SELECT_LEX_UNIT *unit,
- SELECT_LEX *select_lex,
- multi_update **result)
+ bool ignore, SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex, multi_update **result)
{
bool res;
DBUG_ENTER("mysql_multi_update");
-
+
if (!(*result= new (thd->mem_root) multi_update(thd, table_list,
&thd->lex->select_lex.leaf_tables,
- fields, values,
- handle_duplicates, ignore)))
+ fields, values, handle_duplicates, ignore)))
{
DBUG_RETURN(TRUE);
}
@@ -1792,8 +1789,8 @@ bool mysql_multi_update(THD *thd,
res= mysql_select(thd,
table_list, select_lex->with_wild, total_list, conds,
- select_lex->order_list.elements, select_lex->order_list.first,
- (ORDER *)NULL, (Item *) NULL, (ORDER *)NULL,
+ select_lex->order_list.elements,
+ select_lex->order_list.first, NULL, NULL, NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
*result, unit, select_lex);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a333bd79dd3..814017f0231 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2016, MariaDB
+ Copyright (c) 2010, 2019, 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
@@ -2693,6 +2693,8 @@ create:
create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident
{
LEX *lex= thd->lex;
+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_table()))
+ MYSQL_YYABORT;
lex->create_info.init();
if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2,
$1 | $4)))
@@ -2716,21 +2718,13 @@ create:
{
LEX *lex= thd->lex;
lex->current_select= &lex->select_lex;
- if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type)
- {
- lex->create_info.use_default_db_type(thd);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
- hton_name(lex->create_info.db_type)->str,
- $5->table.str);
- }
create_table_set_open_action_and_adjust_tables(lex);
}
| create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident
{
LEX *lex= thd->lex;
+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_sequence()))
+ MYSQL_YYABORT;
lex->create_info.init();
if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2,
$1 | $4)))
@@ -2777,17 +2771,6 @@ create:
Lex->create_info.sequence= 1;
lex->current_select= &lex->select_lex;
- if (unlikely((lex->create_info.used_fields &
- HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type))
- {
- lex->create_info.use_default_db_type(thd);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
- hton_name(lex->create_info.db_type)->str,
- $5->table.str);
- }
create_table_set_open_action_and_adjust_tables(lex);
}
| create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident
@@ -6222,10 +6205,20 @@ create_table_options:
;
create_table_option:
- ENGINE_SYM opt_equal storage_engines
+ ENGINE_SYM opt_equal ident_or_text
{
- Lex->create_info.db_type= $3;
- Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
+ LEX *lex= Lex;
+ if (!lex->m_sql_cmd)
+ {
+ DBUG_ASSERT(lex->sql_command == SQLCOM_ALTER_TABLE);
+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table()))
+ MYSQL_YYABORT;
+ }
+ Storage_engine_name *opt=
+ lex->m_sql_cmd->option_storage_engine_name();
+ DBUG_ASSERT(opt); // Expect a proper Sql_cmd
+ *opt= Storage_engine_name($3);
+ lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
}
| MAX_ROWS opt_equal ulonglong_num
{
@@ -6520,21 +6513,10 @@ default_collation:
storage_engines:
ident_or_text
{
- plugin_ref plugin= ha_resolve_by_name(thd, &$1,
- thd->lex->create_info.tmp_table());
-
- if (likely(plugin))
- $$= plugin_hton(plugin);
- else
- {
- if (thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
- my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str));
- $$= 0;
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_UNKNOWN_STORAGE_ENGINE,
- ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE),
- $1.str);
- }
+ if (Storage_engine_name($1).
+ resolve_storage_engine_with_error(thd, &$$,
+ thd->lex->create_info.tmp_table()))
+ MYSQL_YYABORT;
}
;
@@ -8454,11 +8436,6 @@ alter_list_item:
{
LEX *lex=Lex;
lex->alter_info.flags|= ALTER_OPTIONS;
- if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type)
- {
- lex->create_info.used_fields&= ~HA_CREATE_USED_ENGINE;
- }
}
| FORCE_SYM
{
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 7d561e7c34a..fcf0dc01562 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2016, MariaDB
+ Copyright (c) 2010, 2019, 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
@@ -2115,6 +2115,8 @@ create:
create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident
{
LEX *lex= thd->lex;
+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_table()))
+ MYSQL_YYABORT;
lex->create_info.init();
if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2,
$1 | $4)))
@@ -2138,21 +2140,13 @@ create:
{
LEX *lex= thd->lex;
lex->current_select= &lex->select_lex;
- if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type)
- {
- lex->create_info.use_default_db_type(thd);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
- hton_name(lex->create_info.db_type)->str,
- $5->table.str);
- }
create_table_set_open_action_and_adjust_tables(lex);
}
| create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident
{
LEX *lex= thd->lex;
+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_sequence()))
+ MYSQL_YYABORT;
lex->create_info.init();
if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2,
$1 | $4)))
@@ -2199,17 +2193,6 @@ create:
Lex->create_info.sequence= 1;
lex->current_select= &lex->select_lex;
- if (unlikely((lex->create_info.used_fields &
- HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type))
- {
- lex->create_info.use_default_db_type(thd);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
- hton_name(lex->create_info.db_type)->str,
- $5->table.str);
- }
create_table_set_open_action_and_adjust_tables(lex);
}
| create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident
@@ -6068,10 +6051,20 @@ create_table_options:
;
create_table_option:
- ENGINE_SYM opt_equal storage_engines
+ ENGINE_SYM opt_equal ident_or_text
{
- Lex->create_info.db_type= $3;
- Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
+ LEX *lex= Lex;
+ if (!lex->m_sql_cmd)
+ {
+ DBUG_ASSERT(lex->sql_command == SQLCOM_ALTER_TABLE);
+ if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table()))
+ MYSQL_YYABORT;
+ }
+ Storage_engine_name *opt=
+ lex->m_sql_cmd->option_storage_engine_name();
+ DBUG_ASSERT(opt); // Expect a proper Sql_cmd
+ *opt= Storage_engine_name($3);
+ lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
}
| MAX_ROWS opt_equal ulonglong_num
{
@@ -6366,21 +6359,10 @@ default_collation:
storage_engines:
ident_or_text
{
- plugin_ref plugin= ha_resolve_by_name(thd, &$1,
- thd->lex->create_info.tmp_table());
-
- if (likely(plugin))
- $$= plugin_hton(plugin);
- else
- {
- if (thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
- my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str));
- $$= 0;
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_UNKNOWN_STORAGE_ENGINE,
- ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE),
- $1.str);
- }
+ if (Storage_engine_name($1).
+ resolve_storage_engine_with_error(thd, &$$,
+ thd->lex->create_info.tmp_table()))
+ MYSQL_YYABORT;
}
;
@@ -8391,11 +8373,6 @@ alter_list_item:
{
LEX *lex=Lex;
lex->alter_info.flags|= ALTER_OPTIONS;
- if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type)
- {
- lex->create_info.used_fields&= ~HA_CREATE_USED_ENGINE;
- }
}
| FORCE_SYM
{
diff --git a/sql/table.cc b/sql/table.cc
index 4805017972c..8f60d3ff1d5 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2008, 2018, MariaDB
+ Copyright (c) 2008, 2019, 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
@@ -1386,8 +1386,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
if (!share->table_charset)
{
+ const CHARSET_INFO *cs= thd->variables.collation_database;
/* unknown charset in frm_image[38] or pre-3.23 frm */
- if (use_mb(default_charset_info))
+ if (use_mb(cs))
{
/* Warn that we may be changing the size of character columns */
sql_print_warning("'%s' had no or invalid character set, "
@@ -1395,7 +1396,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
"so character column sizes may have changed",
share->path.str);
}
- share->table_charset= default_charset_info;
+ share->table_charset= cs;
}
share->db_record_offset= 1;
@@ -2720,8 +2721,20 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
if (create_info->data_file_name || create_info->index_file_name)
return 1;
// ... engine
- if (create_info->db_type && create_info->db_type != engine)
- return 1;
+ DBUG_ASSERT(lex->m_sql_cmd);
+ if (lex->create_info.used_fields & HA_CREATE_USED_ENGINE)
+ {
+ /*
+ TODO: we could just compare engine names here, without resolving.
+ But this optimization is too late for 10.1.
+ */
+ Storage_engine_name *opt= lex->m_sql_cmd->option_storage_engine_name();
+ DBUG_ASSERT(opt); // lex->m_sql_cmd must be an Sql_cmd_create_table instance
+ if (opt->resolve_storage_engine_with_error(thd, &create_info->db_type,
+ false) ||
+ (create_info->db_type && create_info->db_type != engine))
+ return 1;
+ }
// ... WITH SYSTEM VERSIONING
if (create_info->versioned())
return 1;