summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-05-22 11:47:09 +0200
committerSergei Golubchik <serg@mariadb.org>2018-05-22 11:47:09 +0200
commit4ec8598c1dcb63499bce998142b8e5b8b09b2d30 (patch)
tree23010dcb3489b54b4bc9b26481a4a16a4378914a /sql
parentfe3bf136b6cf83aac5a6e21d3db1c4e821612017 (diff)
parentafe5a51c2df95aa282e4459afeb7f037563def92 (diff)
downloadmariadb-git-4ec8598c1dcb63499bce998142b8e5b8b09b2d30.tar.gz
Merge branch 'github/10.2' into 10.3
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc8
-rw-r--r--sql/sp_head.cc12
-rw-r--r--sql/sql_base.cc46
-rw-r--r--sql/sql_base.h6
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_class.h17
-rw-r--r--sql/sql_cte.cc15
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_insert.cc3
-rw-r--r--sql/sql_lex.cc7
-rw-r--r--sql/sql_lex.h18
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc36
-rw-r--r--sql/sql_statistics.cc14
-rw-r--r--sql/sql_table.cc39
-rw-r--r--sql/sql_trigger.cc6
-rw-r--r--sql/sql_union.cc30
-rw-r--r--sql/sql_view.cc4
-rw-r--r--sql/sql_yacc.yy6
20 files changed, 185 insertions, 98 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 69b62b41fe2..8fae773f487 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -9544,10 +9544,10 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
}
else
{
- Field *tmp_field= field_arg->field;
- /* charset doesn't matter here, it's to avoid sigsegv only */
- tmp_field= new Field_null(0, 0, Field::NONE, &field_arg->field->field_name,
- &my_charset_bin);
+ static uchar null_bit=1;
+ /* charset doesn't matter here */
+ Field *tmp_field= new Field_string(0, 0, &null_bit, 1, Field::NONE,
+ &field_arg->field->field_name, &my_charset_bin);
if (tmp_field)
{
tmp_field->init(field_arg->field->table);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 151023aa24c..ba682beb9c8 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -838,7 +838,7 @@ sp_head::~sp_head()
thd->lex->sphead= NULL;
lex_end(thd->lex);
delete thd->lex;
- thd->lex= thd->stmt_lex= lex;
+ thd->lex= lex;
}
my_hash_free(&m_sptabs);
@@ -1155,7 +1155,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
backup_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
- LEX *old_lex, *old_stmt_lex;
+ LEX *old_lex;
Item_change_list old_change_list;
String old_packet;
uint old_server_status;
@@ -1262,7 +1262,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
do it in each instruction
*/
old_lex= thd->lex;
- old_stmt_lex= thd->stmt_lex;
/*
We should also save Item tree change list to avoid rollback something
too early in the calling query.
@@ -1419,7 +1418,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
DBUG_ASSERT(thd->Item_change_list::is_empty());
old_change_list.move_elements_to(thd);
thd->lex= old_lex;
- thd->stmt_lex= old_stmt_lex;
thd->set_query_id(old_query_id);
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
@@ -3280,7 +3278,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
We should not save old value since it is saved/restored in
sp_head::execute() when we are entering/leaving routine.
*/
- thd->lex= thd->stmt_lex= m_lex;
+ thd->lex= m_lex;
thd->set_query_id(next_query_id());
@@ -5164,7 +5162,5 @@ err:
ulong sp_head::sp_cache_version() const
{
- return m_parent ? m_parent->sp_cache_version() :
- m_sp_cache_version;
-
+ return m_parent ? m_parent->sp_cache_version() : m_sp_cache_version;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b17b2b31ba7..f89fbc59b14 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -951,7 +951,8 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
@param thd thread handle
@param table table which should be checked
@param table_list list of tables
- @param check_alias whether to check tables' aliases
+ @param check_flag whether to check tables' aliases
+ Currently this is only used by INSERT
NOTE: to exclude derived tables from check we use following mechanism:
a) during derived table processing set THD::derived_tables_processing
@@ -980,9 +981,9 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
static
TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
- bool check_alias)
+ uint check_flag)
{
- TABLE_LIST *res;
+ TABLE_LIST *res= 0;
LEX_CSTRING *d_name, *t_name, *t_alias;
DBUG_ENTER("find_dup_table");
DBUG_PRINT("enter", ("table alias: %s", table->alias.str));
@@ -1015,17 +1016,15 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
retry:
DBUG_PRINT("info", ("real table: %s.%s", d_name->str, t_name->str));
- for (TABLE_LIST *tl= table_list;;)
+ for (TABLE_LIST *tl= table_list; tl ; tl= tl->next_global, res= 0)
{
- if (tl &&
- tl->select_lex && tl->select_lex->master_unit() &&
+ if (tl->select_lex && tl->select_lex->master_unit() &&
tl->select_lex->master_unit()->executed)
{
/*
There is no sense to check tables of already executed parts
of the query
*/
- tl= tl->next_global;
continue;
}
/*
@@ -1034,21 +1033,29 @@ retry:
*/
if (! (res= find_table_in_global_list(tl, d_name, t_name)))
break;
+ tl= res; // We can continue search after this table
/* Skip if same underlying table. */
if (res->table && (res->table == table->table))
- goto next;
+ continue;
+
+ if (check_flag & CHECK_DUP_FOR_CREATE)
+ DBUG_RETURN(res);
/* Skip if table alias does not match. */
- if (check_alias)
+ if (check_flag & CHECK_DUP_ALLOW_DIFFERENT_ALIAS)
{
if (my_strcasecmp(table_alias_charset, t_alias->str, res->alias.str))
- goto next;
+ continue;
}
/*
- Skip if marked to be excluded (could be a derived table) or if
- entry is a prelocking placeholder.
+ If table is not excluded (could be a derived table) and table is not
+ a prelocking placeholder then we found either a duplicate entry
+ or a table that is part of a derived table (handled below).
+ Examples are:
+ INSERT INTO t1 SELECT * FROM t1;
+ INSERT INTO t1 SELECT * FROM view_containing_t1;
*/
if (res->select_lex &&
!res->select_lex->exclude_from_table_unique_test &&
@@ -1060,14 +1067,17 @@ retry:
processed in derived table or top select of multi-update/multi-delete
(exclude_from_table_unique_test) or prelocking placeholder.
*/
-next:
- tl= res->next_global;
DBUG_PRINT("info",
("found same copy of table or table which we should skip"));
}
if (res && res->belong_to_derived)
{
- /* Try to fix */
+ /*
+ We come here for queries of type:
+ INSERT INTO t1 (SELECT tmp.a FROM (select * FROM t1) as tmp);
+
+ Try to fix by materializing the derived table
+ */
TABLE_LIST *derived= res->belong_to_derived;
if (derived->is_merged_derived() && !derived->derived->is_excluded())
{
@@ -1099,7 +1109,7 @@ next:
TABLE_LIST*
unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
- bool check_alias)
+ uint check_flag)
{
TABLE_LIST *dup;
@@ -1131,12 +1141,12 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
if (!tmp_parent)
break;
- if ((dup= find_dup_table(thd, child, child->next_global, check_alias)))
+ if ((dup= find_dup_table(thd, child, child->next_global, check_flag)))
break;
}
}
else
- dup= find_dup_table(thd, table, table_list, check_alias);
+ dup= find_dup_table(thd, table, table_list, check_flag);
return dup;
}
diff --git a/sql/sql_base.h b/sql/sql_base.h
index b85e01032fa..01892c0b938 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -61,6 +61,10 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
IGNORE_EXCEPT_NON_UNIQUE};
+/* Flag bits for unique_table() */
+#define CHECK_DUP_ALLOW_DIFFERENT_ALIAS 1
+#define CHECK_DUP_FOR_CREATE 2
+
uint get_table_def_key(const TABLE_LIST *table_list, const char **key);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
uint lock_flags);
@@ -267,7 +271,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
int decide_logging_format(THD *thd, TABLE_LIST *tables);
void close_thread_table(THD *thd, TABLE **table_ptr);
TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
- bool check_alias);
+ uint check_flag);
bool is_equal(const LEX_CSTRING *a, const LEX_CSTRING *b);
class Open_tables_backup;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b58ed52db31..a5f69d63ad0 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -805,7 +805,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
statement_id_counter= 0UL;
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
- stmt_lex= 0;
start_utime= utime_after_query= 0;
system_time.start.val= system_time.sec= system_time.sec_part= 0;
utime_after_lock= 0L;
@@ -3845,7 +3844,7 @@ void Statement::set_statement(Statement *stmt)
{
id= stmt->id;
column_usage= stmt->column_usage;
- stmt_lex= lex= stmt->lex;
+ lex= stmt->lex;
query_string= stmt->query_string;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 0ff588a6d38..37e4697e708 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1103,21 +1103,6 @@ public:
LEX_CSTRING name; /* name for named prepared statements */
LEX *lex; // parse tree descriptor
/*
- LEX which represents current statement (conventional, SP or PS)
-
- For example during view parsing THD::lex will point to the views LEX and
- THD::stmt_lex will point to LEX of the statement where the view will be
- included
-
- Currently it is used to have always correct select numbering inside
- statement (LEX::current_select_number) without storing and restoring a
- global counter which was THD::select_number.
-
- TODO: make some unified statement representation (now SP has different)
- to store such data like LEX::current_select_number.
- */
- LEX *stmt_lex;
- /*
Points to the query associated with this statement. It's const, but
we need to declare it char * because all table handlers are written
in C and need to point to it.
@@ -4801,7 +4786,7 @@ public:
void set_local_lex(sp_lex_local *sublex)
{
DBUG_ASSERT(lex->sphead);
- lex= stmt_lex= sublex;
+ lex= sublex;
/* Reset part of parser state which needs this. */
m_parser_state->m_yacc.reset_before_substatement();
}
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index c92fb3d97ba..97bbf8f73bd 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -682,7 +682,6 @@ void With_element::move_anchors_ahead()
{
st_select_lex *next_sl;
st_select_lex *new_pos= spec->first_select();
- st_select_lex *UNINIT_VAR(last_sl);
new_pos->linkage= UNION_TYPE;
for (st_select_lex *sl= new_pos; sl; sl= next_sl)
{
@@ -690,6 +689,14 @@ void With_element::move_anchors_ahead()
if (is_anchor(sl))
{
sl->move_node(new_pos);
+ if (new_pos == spec->first_select())
+ {
+ enum sub_select_type type= new_pos->linkage;
+ new_pos->linkage= sl->linkage;
+ sl->linkage= type;
+ new_pos->with_all_modifier= sl->with_all_modifier;
+ sl->with_all_modifier= false;
+ }
new_pos= sl->next_select();
}
else if (!sq_rec_ref && no_rec_ref_on_top_level())
@@ -697,10 +704,7 @@ void With_element::move_anchors_ahead()
sq_rec_ref= find_first_sq_rec_ref_in_select(sl);
DBUG_ASSERT(sq_rec_ref != NULL);
}
- last_sl= sl;
}
- if (spec->union_distinct)
- spec->union_distinct= last_sl;
first_recursive= new_pos;
}
@@ -829,8 +833,9 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
if (parser_state.init(thd, (char*) unparsed_spec.str, (unsigned int)unparsed_spec.length))
goto err;
lex_start(thd);
+ lex->stmt_lex= old_lex;
with_select= &lex->select_lex;
- with_select->select_number= ++thd->stmt_lex->current_select_number;
+ with_select->select_number= ++thd->lex->stmt_lex->current_select_number;
parse_status= parse_sql(thd, &parser_state, 0);
if (parse_status)
goto err;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 2781bd50d26..3686f866e23 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -1130,7 +1130,7 @@ multi_delete::initialize_tables(JOIN *join)
TABLE_LIST *tbl= walk->correspondent_table->find_table_for_update();
tables_to_delete_from|= tbl->table->map;
if (delete_while_scanning &&
- unique_table(thd, tbl, join->tables_list, false))
+ unique_table(thd, tbl, join->tables_list, 0))
{
/*
If the table we are going to delete from appears
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 9cb6a88fd4d..b03cde54abb 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1583,7 +1583,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
{
Item *fake_conds= 0;
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, table_list, table_list->next_global, 1)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global,
+ CHECK_DUP_ALLOW_DIFFERENT_ALIAS)))
{
update_non_unique_table_error(table_list, "INSERT", duplicate);
DBUG_RETURN(TRUE);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 80baf7478a0..47557d562a8 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -652,11 +652,11 @@ void lex_start(THD *thd)
void LEX::start(THD *thd_arg)
{
DBUG_ENTER("LEX::start");
- DBUG_PRINT("info", ("This: %p thd_arg->lex: %p thd_arg->stmt_lex: %p",
- this, thd_arg->lex, thd_arg->stmt_lex));
+ DBUG_PRINT("info", ("This: %p thd_arg->lex: %p", this, thd_arg->lex));
thd= unit.thd= thd_arg;
-
+ stmt_lex= this; // default, should be rewritten for VIEWs And CTEs
+
DBUG_ASSERT(!explain);
context_stack.empty();
@@ -2323,6 +2323,7 @@ void st_select_lex::init_select()
select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
offset_limit= 0; /* denotes the default offset = 0 */
with_sum_func= 0;
+ with_all_modifier= 0;
is_correlated= 0;
cur_pos_in_select_list= UNDEF_POS;
cond_value= having_value= Item::COND_UNDEF;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index bfb201185b1..a462ba3d252 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -935,7 +935,7 @@ public:
/*
Point to the LEX in which it was created, used in view subquery detection.
- TODO: make also st_select_lex::parent_stmt_lex (see THD::stmt_lex)
+ TODO: make also st_select_lex::parent_stmt_lex (see LEX::stmt_lex)
and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex
instead of global (from THD) references where it is possible.
*/
@@ -1084,6 +1084,7 @@ public:
*/
bool subquery_in_having;
/* TRUE <=> this SELECT is correlated w.r.t. some ancestor select */
+ bool with_all_modifier; /* used for selects in union */
bool is_correlated;
/*
This variable is required to ensure proper work of subqueries and
@@ -2805,6 +2806,21 @@ struct LEX: public Query_tables_list
// type information
CHARSET_INFO *charset;
+ /*
+ LEX which represents current statement (conventional, SP or PS)
+
+ For example during view parsing THD::lex will point to the views LEX and
+ lex::stmt_lex will point to LEX of the statement where the view will be
+ included
+
+ Currently it is used to have always correct select numbering inside
+ statement (LEX::current_select_number) without storing and restoring a
+ global counter which was THD::select_number.
+
+ TODO: make some unified statement representation (now SP has different)
+ to store such data like LEX::current_select_number.
+ */
+ LEX *stmt_lex;
LEX_CSTRING name;
const char *help_arg;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index cab433d7196..40a5490b908 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4199,7 +4199,7 @@ mysql_execute_command(THD *thd)
TABLE_LIST *duplicate;
if (unlikely((duplicate= unique_table(thd, lex->query_tables,
lex->query_tables->next_global,
- 0))))
+ CHECK_DUP_FOR_CREATE))))
{
update_non_unique_table_error(lex->query_tables, "CREATE",
duplicate);
@@ -7540,8 +7540,9 @@ void THD::reset_for_next_command(bool do_clear_error)
We also assign stmt_lex in lex_start(), but during bootstrap this
code is executed first.
*/
- stmt_lex= &main_lex; stmt_lex->current_select_number= 1;
- DBUG_PRINT("info", ("Lex %p stmt_lex: %p", lex, stmt_lex));
+ DBUG_ASSERT(lex == &main_lex);
+ main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 1;
+ DBUG_PRINT("info", ("Lex and stmt_lex: %p", &main_lex));
/*
Those two lines below are theoretically unneeded as
THD::cleanup_after_query() should take care of this already.
@@ -7658,7 +7659,7 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex)
{
if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
- select_lex->select_number= ++thd->stmt_lex->current_select_number;
+ select_lex->select_number= ++thd->lex->stmt_lex->current_select_number;
select_lex->parent_lex= lex; /* Used in init_query. */
select_lex->init_query();
select_lex->init_select();
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 2b5bac87835..d4c96ebc535 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -3911,7 +3911,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (! (lex= new (mem_root) st_lex_local))
DBUG_RETURN(TRUE);
- stmt_lex= lex;
+ lex->stmt_lex= lex;
if (set_db(&thd->db))
DBUG_RETURN(TRUE);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0f2a3236942..1285835fe7c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1396,16 +1396,28 @@ bool JOIN::build_explain()
{
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
have_query_plan= QEP_AVAILABLE;
- if (save_explain_data(thd->lex->explain, false /* can overwrite */,
+
+ /*
+ explain data must be created on the Explain_query::mem_root. Because it's
+ just a memroot, not an arena, explain data must not contain any Items
+ */
+ MEM_ROOT *old_mem_root= thd->mem_root;
+ Item *old_free_list __attribute__((unused))= thd->free_list;
+ thd->mem_root= thd->lex->explain->mem_root;
+ bool res= save_explain_data(thd->lex->explain, false /* can overwrite */,
need_tmp,
!skip_sort_order && !no_order && (order || group_list),
- select_distinct))
+ select_distinct);
+ thd->mem_root= old_mem_root;
+ DBUG_ASSERT(thd->free_list == old_free_list); // no Items were created
+ if (res)
return 1;
+
uint select_nr= select_lex->select_number;
JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
for (uint i= 0; i < aggr_tables; i++, curr_tab++)
{
- if (select_nr == INT_MAX)
+ if (select_nr == INT_MAX)
{
/* this is a fake_select_lex of a union */
select_nr= select_lex->master_unit()->first_select()->select_number;
@@ -1599,7 +1611,11 @@ JOIN::optimize_inner()
/*
The following code will allocate the new items in a permanent
MEMROOT for prepared statements and stored procedures.
+
+ But first we need to ensure that thd->lex->explain is allocated
+ in the execution arena
*/
+ create_explain_query_if_not_exists(thd->lex, thd->mem_root);
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
@@ -3722,7 +3738,7 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
bool distinct)
{
/*
- If there is SELECT in this statemet with the same number it must be the
+ If there is SELECT in this statement with the same number it must be the
same SELECT
*/
DBUG_ASSERT(select_lex->select_number == UINT_MAX ||
@@ -24918,9 +24934,9 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
if (filesort)
{
if (!(eta->pre_join_sort=
- new Explain_aggr_filesort(thd->mem_root,
- thd->lex->analyze_stmt,
- filesort)))
+ new (thd->mem_root) Explain_aggr_filesort(thd->mem_root,
+ thd->lex->analyze_stmt,
+ filesort)))
return 1;
}
@@ -25358,7 +25374,7 @@ bool save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
{
// Each aggregate means a temp.table
prev_node= node;
- if (!(node= new Explain_aggr_tmp_table))
+ if (!(node= new (thd->mem_root) Explain_aggr_tmp_table))
return 1;
node->child= prev_node;
@@ -25379,7 +25395,7 @@ bool save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
if (join_tab->distinct)
{
prev_node= node;
- if (!(node= new Explain_aggr_remove_dups))
+ if (!(node= new (thd->mem_root) Explain_aggr_remove_dups))
return 1;
node->child= prev_node;
}
@@ -25387,7 +25403,7 @@ bool save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
if (join_tab->filesort)
{
Explain_aggr_filesort *eaf =
- new Explain_aggr_filesort(thd->mem_root, is_analyze, join_tab->filesort);
+ new (thd->mem_root) Explain_aggr_filesort(thd->mem_root, is_analyze, join_tab->filesort);
if (!eaf)
return 1;
prev_node= node;
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 7bb03740bf4..92c019d3f1b 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1799,6 +1799,7 @@ private:
public:
bool is_single_comp_pk;
+ bool is_partial_fields_present;
Index_prefix_calc(THD *thd, TABLE *table, KEY *key_info)
: index_table(table), index_info(key_info)
@@ -1810,7 +1811,7 @@ public:
prefixes= 0;
LINT_INIT_STRUCT(calc_state);
- is_single_comp_pk= FALSE;
+ is_partial_fields_present= is_single_comp_pk= FALSE;
uint pk= table->s->primary_key;
if ((uint) (table->key_info - key_info) == pk &&
table->key_info[pk].user_defined_key_parts == 1)
@@ -1832,7 +1833,10 @@ public:
calculating the values of 'avg_frequency' for prefixes.
*/
if (!key_info->key_part[i].field->part_of_key.is_set(keyno))
+ {
+ is_partial_fields_present= TRUE;
break;
+ }
if (!(state->last_prefix=
new (thd->mem_root) Cached_item_field(thd,
@@ -2631,7 +2635,13 @@ int collect_statistics_for_index(THD *thd, TABLE *table, uint index)
DBUG_RETURN(rc);
}
- table->file->ha_start_keyread(index);
+ /*
+ Request "only index read" in case of absence of fields which are
+ partially in the index to avoid problems with partitioning (for example)
+ which want to get whole field value.
+ */
+ if (!index_prefix_calc.is_partial_fields_present)
+ table->file->ha_start_keyread(index);
table->file->ha_index_init(index, TRUE);
rc= table->file->ha_index_first(table->record[0]);
while (rc != HA_ERR_END_OF_FILE)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 550b11d813e..648e05a4116 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -10060,9 +10060,7 @@ bool mysql_trans_prepare_alter_copy_data(THD *thd)
This needs to be done before external_lock.
*/
- if (ha_enable_transaction(thd, FALSE))
- DBUG_RETURN(TRUE);
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(ha_enable_transaction(thd, FALSE) != 0);
}
@@ -10115,6 +10113,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
List<Item> fields;
List<Item> all_fields;
bool auto_increment_field_copied= 0;
+ bool cleanup_done= 0;
bool init_read_record_done= 0;
sql_mode_t save_sql_mode= thd->variables.sql_mode;
ulonglong prev_insert_id, time_to_report_progress;
@@ -10130,15 +10129,23 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
/* Two or 3 stages; Sorting, copying data and update indexes */
thd_progress_init(thd, 2 + MY_TEST(order));
- if (mysql_trans_prepare_alter_copy_data(thd))
+ if (!(copy= new (thd->mem_root) Copy_field[to->s->fields]))
DBUG_RETURN(-1);
- if (!(copy= new (thd->mem_root) Copy_field[to->s->fields]))
- DBUG_RETURN(-1); /* purecov: inspected */
+ if (mysql_trans_prepare_alter_copy_data(thd))
+ {
+ delete [] copy;
+ DBUG_RETURN(-1);
+ }
/* We need external lock before we can disable/enable keys */
if (to->file->ha_external_lock(thd, F_WRLCK))
+ {
+ /* Undo call to mysql_trans_prepare_alter_copy_data() */
+ ha_enable_transaction(thd, TRUE);
+ delete [] copy;
DBUG_RETURN(-1);
+ }
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
@@ -10149,7 +10156,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE);
to->file->ha_start_bulk_insert(from->file->stats.records,
ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT);
-
List_iterator<Create_field> it(create);
Create_field *def;
copy_end=copy;
@@ -10407,6 +10413,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
}
if (!ignore)
to->file->extra(HA_EXTRA_END_ALTER_COPY);
+
+ cleanup_done= 1;
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (unlikely(mysql_trans_commit_alter_copy_data(thd)))
@@ -10424,10 +10432,19 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
*copied= found_count;
*deleted=delete_count;
to->file->ha_release_auto_increment();
- if (unlikely(to->file->ha_external_lock(thd,F_UNLCK)))
- error= 1;
- if (likely(error < 0) && !from->s->tmp_table &&
- unlikely(to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME)))
+
+ if (!cleanup_done)
+ {
+ /* This happens if we get an error during initialzation of data */
+ DBUG_ASSERT(error);
+ to->file->ha_end_bulk_insert();
+ ha_enable_transaction(thd, TRUE);
+ }
+
+ if (to->file->ha_external_lock(thd,F_UNLCK))
+ error=1;
+ if (error < 0 && !from->s->tmp_table &&
+ to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
error= 1;
thd_progress_end(thd);
DBUG_RETURN(error > 0 ? -1 : 0);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index aa222eaad1d..3318faf3f90 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1370,12 +1370,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
List_iterator_fast<LEX_CSTRING> it_connection_cl_name(trigger_list->connection_cl_names);
List_iterator_fast<LEX_CSTRING> it_db_cl_name(trigger_list->db_cl_names);
List_iterator_fast<ulonglong> it_create_times(trigger_list->create_times);
- LEX *old_lex= thd->lex, *old_stmt_lex= thd->stmt_lex;
+ LEX *old_lex= thd->lex;
LEX lex;
sp_rcontext *save_spcont= thd->spcont;
sql_mode_t save_sql_mode= thd->variables.sql_mode;
- thd->lex= thd->stmt_lex= &lex;
+ thd->lex= &lex;
save_db= thd->db;
thd->reset_db(db);
@@ -1592,7 +1592,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
}
thd->reset_db(&save_db);
thd->lex= old_lex;
- thd->stmt_lex= old_stmt_lex;
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
@@ -1606,7 +1605,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
err_with_lex_cleanup:
lex_end(&lex);
thd->lex= old_lex;
- thd->stmt_lex= old_stmt_lex;
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
thd->reset_db(&save_db);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index f74c7b5e27a..a1963c33a42 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -834,6 +834,23 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
DBUG_ENTER("st_select_lex_unit::prepare");
DBUG_ASSERT(thd == current_thd);
+ if (is_recursive && (sl= first_sl->next_select()))
+ {
+ SELECT_LEX *next_sl;
+ for ( ; ; sl= next_sl)
+ {
+ next_sl= sl->next_select();
+ if (!next_sl)
+ break;
+ if (next_sl->with_all_modifier != sl->with_all_modifier)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "mix of ALL and DISTINCT UNION operations in recursive CTE spec");
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+
describe= additional_options & SELECT_DESCRIBE;
/*
@@ -927,7 +944,18 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
with_element->rec_result=
new (thd->mem_root) select_union_recursive(thd);
union_result= with_element->rec_result;
- fake_select_lex= NULL;
+ if (fake_select_lex)
+ {
+ if (fake_select_lex->order_list.first ||
+ fake_select_lex->explicit_limit)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "global ORDER_BY/LIMIT in recursive CTE spec");
+ goto err;
+ }
+ fake_select_lex->cleanup();
+ fake_select_lex= NULL;
+ }
}
if (!(tmp_result= union_result))
goto err; /* purecov: inspected */
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 29c61d4abcc..6679334552b 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1333,6 +1333,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
now Lex placed in statement memory
*/
+
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
if (!table->view)
{
@@ -1359,8 +1360,9 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
goto end;
lex_start(thd);
+ lex->stmt_lex= old_lex;
view_select= &lex->select_lex;
- view_select->select_number= ++thd->stmt_lex->current_select_number;
+ view_select->select_number= ++thd->lex->stmt_lex->current_select_number;
sql_mode_t saved_mode= thd->variables.sql_mode;
/* switch off modes which can prevent normal parsing of VIEW
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 41c05e9df34..c389b09d54c 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -571,11 +571,9 @@ bool LEX::add_select_to_union_list(bool is_union_distinct,
return TRUE;
mysql_init_select(this);
current_select->linkage= type;
+ current_select->with_all_modifier= !is_union_distinct;
if (is_union_distinct) /* UNION DISTINCT - remember position */
- {
- current_select->master_unit()->union_distinct=
- current_select;
- }
+ current_select->master_unit()->union_distinct= current_select;
else
DBUG_ASSERT(type == UNION_TYPE);
return FALSE;