diff options
author | Sergei Golubchik <serg@mariadb.org> | 2018-05-22 11:47:09 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2018-05-22 11:47:09 +0200 |
commit | 4ec8598c1dcb63499bce998142b8e5b8b09b2d30 (patch) | |
tree | 23010dcb3489b54b4bc9b26481a4a16a4378914a /sql | |
parent | fe3bf136b6cf83aac5a6e21d3db1c4e821612017 (diff) | |
parent | afe5a51c2df95aa282e4459afeb7f037563def92 (diff) | |
download | mariadb-git-4ec8598c1dcb63499bce998142b8e5b8b09b2d30.tar.gz |
Merge branch 'github/10.2' into 10.3
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 8 | ||||
-rw-r--r-- | sql/sp_head.cc | 12 | ||||
-rw-r--r-- | sql/sql_base.cc | 46 | ||||
-rw-r--r-- | sql/sql_base.h | 6 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 | ||||
-rw-r--r-- | sql/sql_class.h | 17 | ||||
-rw-r--r-- | sql/sql_cte.cc | 15 | ||||
-rw-r--r-- | sql/sql_delete.cc | 2 | ||||
-rw-r--r-- | sql/sql_insert.cc | 3 | ||||
-rw-r--r-- | sql/sql_lex.cc | 7 | ||||
-rw-r--r-- | sql/sql_lex.h | 18 | ||||
-rw-r--r-- | sql/sql_parse.cc | 9 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 36 | ||||
-rw-r--r-- | sql/sql_statistics.cc | 14 | ||||
-rw-r--r-- | sql/sql_table.cc | 39 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 6 | ||||
-rw-r--r-- | sql/sql_union.cc | 30 | ||||
-rw-r--r-- | sql/sql_view.cc | 4 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 6 |
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; |