diff options
Diffstat (limited to 'sql')
49 files changed, 802 insertions, 531 deletions
diff --git a/sql/field.cc b/sql/field.cc index 8fa3bbd538c..fd0ebe66bd8 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7555,22 +7555,10 @@ Field_string::compatible_field_size(uint field_metadata, int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) const { - size_t a_len, b_len; - - if (mbmaxlen() != 1) - { - size_t char_len= Field_string::char_length(); - a_len= field_charset()->charpos(a_ptr, a_ptr + field_length, char_len); - b_len= field_charset()->charpos(b_ptr, b_ptr + field_length, char_len); - } - else - a_len= b_len= field_length; - /* - We have to remove end space to be able to compare multi-byte-characters - like in latin_de 'ae' and 0xe4 - */ - return field_charset()->strnncollsp(a_ptr, a_len, - b_ptr, b_len); + return field_charset()->coll->strnncollsp_nchars(field_charset(), + a_ptr, field_length, + b_ptr, field_length, + Field_string::char_length()); } @@ -7936,19 +7924,6 @@ int Field_varstring::cmp(const uchar *a_ptr, const uchar *b_ptr) const } -static int cmp_str_prefix(const uchar *ua, size_t alen, const uchar *ub, - size_t blen, size_t prefix, CHARSET_INFO *cs) -{ - const char *a= (char*)ua, *b= (char*)ub; - MY_STRCOPY_STATUS status; - prefix/= cs->mbmaxlen; - alen= cs->cset->well_formed_char_length(cs, a, a + alen, prefix, &status); - blen= cs->cset->well_formed_char_length(cs, b, b + blen, prefix, &status); - return cs->coll->strnncollsp(cs, ua, alen, ub, blen); -} - - - int Field_varstring::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr, size_t prefix_len) const { @@ -7968,8 +7943,13 @@ int Field_varstring::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr, a_length= uint2korr(a_ptr); b_length= uint2korr(b_ptr); } - return cmp_str_prefix(a_ptr+length_bytes, a_length, b_ptr+length_bytes, - b_length, prefix_len, field_charset()); + return field_charset()->coll->strnncollsp_nchars(field_charset(), + a_ptr + length_bytes, + a_length, + b_ptr + length_bytes, + b_length, + prefix_len / + field_charset()->mbmaxlen); } @@ -8756,8 +8736,11 @@ int Field_blob::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr, memcpy(&blob1, a_ptr+packlength, sizeof(char*)); memcpy(&blob2, b_ptr+packlength, sizeof(char*)); size_t a_len= get_length(a_ptr), b_len= get_length(b_ptr); - return cmp_str_prefix(blob1, a_len, blob2, b_len, prefix_len, - field_charset()); + return field_charset()->coll->strnncollsp_nchars(field_charset(), + blob1, a_len, + blob2, b_len, + prefix_len / + field_charset()->mbmaxlen); } @@ -9656,16 +9639,8 @@ bool Field_num::is_equal(const Column_definition &new_field) const } -bool Field_enum::can_optimize_range(const Item_bool_func *cond, - const Item *item, - bool is_eq_func) const -{ - return item->cmp_type() != TIME_RESULT; -} - - -bool Field_enum::can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const +bool Field_enum::can_optimize_range_or_keypart_ref(const Item_bool_func *cond, + const Item *item) const { switch (item->cmp_type()) { diff --git a/sql/field.h b/sql/field.h index 34446b2befe..8843c7745b0 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4713,6 +4713,8 @@ private: class Field_enum :public Field_str { static void do_field_enum(Copy_field *copy_field); longlong val_int(const uchar *) const; + bool can_optimize_range_or_keypart_ref(const Item_bool_func *cond, + const Item *item) const; protected: uint packlength; public: @@ -4805,9 +4807,12 @@ public: uint param_data) override; bool can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const override; - bool can_optimize_group_min_max(const Item_bool_func *, const Item *) - const override + const Item *item) const override + { + return can_optimize_range_or_keypart_ref(cond, item); + } + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const override { /* Can't use GROUP_MIN_MAX optimization for ENUM and SET, @@ -4820,7 +4825,10 @@ public: } bool can_optimize_range(const Item_bool_func *cond, const Item *item, - bool is_eq_func) const override; + bool is_eq_func) const override + { + return can_optimize_range_or_keypart_ref(cond, item); + } Binlog_type_info binlog_type_info() const override; private: bool is_equal(const Column_definition &new_field) const override; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 2c6233a6837..337ef684520 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4084,8 +4084,9 @@ int ha_partition::external_lock(THD *thd, int lock_type) These commands may be excluded because working history partition is needed only for versioned DML. */ thd->lex->sql_command != SQLCOM_SELECT && - thd->lex->sql_command != SQLCOM_INSERT_SELECT) - m_part_info->vers_set_hist_part(thd); + thd->lex->sql_command != SQLCOM_INSERT_SELECT && + (error= m_part_info->vers_set_hist_part(thd))) + goto err_handler; } DBUG_RETURN(0); @@ -4222,7 +4223,7 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type) i= bitmap_get_next_set(&m_part_info->lock_partitions, i)) { if (unlikely((error= m_file[i]->start_stmt(thd, lock_type)))) - break; + DBUG_RETURN(error); /* Add partition to be called in reset(). */ bitmap_set_bit(&m_partitions_to_reset, i); } @@ -4241,7 +4242,7 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type) // TODO: MDEV-20345 (see above) thd->lex->sql_command != SQLCOM_SELECT && thd->lex->sql_command != SQLCOM_INSERT_SELECT) - m_part_info->vers_set_hist_part(thd); + error= m_part_info->vers_set_hist_part(thd); default:; } DBUG_RETURN(error); diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 596f8584041..2447242593c 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -30,6 +30,10 @@ #include "sql_base.h" #include "log_event.h" +#ifdef WITH_WSREP +#include "wsrep_trans_observer.h" /* wsrep_start_transaction() */ +#endif + /* Table flags we should inherit and disable from the original engine. We add HA_STATS_RECORDS_IS_EXACT as ha_sequence::info() will ensure @@ -204,6 +208,7 @@ int ha_sequence::write_row(const uchar *buf) int error; sequence_definition tmp_seq; bool sequence_locked; + THD *thd= table->in_use; DBUG_ENTER("ha_sequence::write_row"); DBUG_ASSERT(table->record[0] == buf); @@ -245,8 +250,6 @@ int ha_sequence::write_row(const uchar *buf) on master and slaves - Check that the new row is an accurate SEQUENCE object */ - - THD *thd= table->in_use; if (table->s->tmp_table == NO_TMP_TABLE && thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE, @@ -265,6 +268,16 @@ int ha_sequence::write_row(const uchar *buf) sequence->write_lock(table); } +#ifdef WITH_WSREP + /* We need to start Galera transaction for select NEXT VALUE FOR + sequence if it is not yet started. Note that ALTER is handled + as TOI. */ + if (WSREP_ON && WSREP(thd) && + !thd->wsrep_trx().active() && + wsrep_thd_is_local(thd)) + wsrep_start_transaction(thd, thd->wsrep_next_trx_id()); +#endif + if (likely(!(error= file->update_first_row(buf)))) { Log_func *log_func= Write_rows_log_event::binlog_row_logging_function; diff --git a/sql/handler.cc b/sql/handler.cc index 3c75eb23088..5f5162f3e08 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1692,14 +1692,13 @@ int ha_commit_trans(THD *thd, bool all) #endif TR_table trt(thd, true); if (trt.update(trx_start_id, trx_end_id)) -#ifdef WITH_WSREP { +#ifdef WITH_WSREP thd->variables.wsrep_on= saved_wsrep_on; #endif + (void) trans_rollback_stmt(thd); goto err; -#ifdef WITH_WSREP } -#endif // Here, the call will not commit inside InnoDB. It is only working // around closing thd->transaction.stmt open by TR_table::open(). if (all) @@ -2107,7 +2106,8 @@ int ha_rollback_trans(THD *thd, bool all) Thanks to possibility of MDL deadlock rollback request can come even if transaction hasn't been started in any transactional storage engine. */ - if (thd->transaction_rollback_request) + if (thd->transaction_rollback_request && + thd->transaction->xid_state.is_explicit_XA()) thd->transaction->xid_state.set_error(thd->get_stmt_da()->sql_errno()); thd->has_waiter= false; @@ -4220,6 +4220,9 @@ void handler::print_error(int error, myf errflag) case HA_ERR_COMMIT_ERROR: textno= ER_ERROR_DURING_COMMIT; break; + case HA_ERR_PARTITION_LIST: + my_error(ER_VERS_NOT_ALLOWED, errflag, table->s->db.str, table->s->table_name.str); + DBUG_VOID_RETURN; default: { /* The error was "unknown" to this function. @@ -7956,6 +7959,8 @@ bool Table_scope_and_contents_source_st::vers_fix_system_fields( List_iterator<Create_field> it(alter_info->create_list); while (Create_field *f= it++) { + if (f->vers_sys_field()) + continue; if ((f->versioning == Column_definition::VERSIONING_NOT_SET && !add_versioning) || f->versioning == Column_definition::WITHOUT_VERSIONING) { @@ -7977,9 +7982,10 @@ bool Table_scope_and_contents_source_st::vers_check_system_fields( if (!(options & HA_VERSIONED_TABLE)) return false; + uint versioned_fields= 0; + if (!(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING)) { - uint versioned_fields= 0; uint fieldnr= 0; List_iterator<Create_field> field_it(alter_info->create_list); while (Create_field *f= field_it++) @@ -8010,7 +8016,7 @@ bool Table_scope_and_contents_source_st::vers_check_system_fields( } } - if (!(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING)) + if (!(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING) && !versioned_fields) return false; return vers_info.check_sys_fields(table_name, db, alter_info); diff --git a/sql/handler.h b/sql/handler.h index 673283b9bd5..b1f59681602 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -352,8 +352,17 @@ enum chf_create_flags { run ANALYZE TABLE on it */ #define HA_ONLINE_ANALYZE (1ULL << 59) +/* + Rowid's are not comparable. This is set if the rowid is unique to the + current open handler, like it is with federated where the rowid is a + pointer to a local result set buffer. The effect of having this set is + that the optimizer will not consirer the following optimizations for + the table: + ror scans or filtering +*/ +#define HA_NON_COMPARABLE_ROWID (1ULL << 60) -#define HA_LAST_TABLE_FLAG HA_ONLINE_ANALYZE +#define HA_LAST_TABLE_FLAG HA_NON_COMPARABLE_ROWID /* bits in index_flags(index_number) for what you can do with index */ @@ -3224,6 +3233,9 @@ public: Rowid_filter *pushed_rowid_filter; /* true when the pushed rowid filter has been already filled */ bool rowid_filter_is_active; + /* Used for disabling/enabling pushed_rowid_filter */ + Rowid_filter *save_pushed_rowid_filter; + bool save_rowid_filter_is_active; Discrete_interval auto_inc_interval_for_cur_row; /** @@ -3345,6 +3357,8 @@ public: pushed_idx_cond_keyno(MAX_KEY), pushed_rowid_filter(NULL), rowid_filter_is_active(0), + save_pushed_rowid_filter(NULL), + save_rowid_filter_is_active(false), auto_inc_intervals_count(0), m_psi(NULL), m_psi_batch_mode(PSI_BATCH_MODE_NONE), @@ -4418,6 +4432,27 @@ public: rowid_filter_is_active= false; } + virtual void disable_pushed_rowid_filter() + { + DBUG_ASSERT(pushed_rowid_filter != NULL && + save_pushed_rowid_filter == NULL); + save_pushed_rowid_filter= pushed_rowid_filter; + if (rowid_filter_is_active) + save_rowid_filter_is_active= rowid_filter_is_active; + pushed_rowid_filter= NULL; + rowid_filter_is_active= false; + } + + virtual void enable_pushed_rowid_filter() + { + DBUG_ASSERT(save_pushed_rowid_filter != NULL && + pushed_rowid_filter == NULL); + pushed_rowid_filter= save_pushed_rowid_filter; + if (save_rowid_filter_is_active) + rowid_filter_is_active= true; + save_pushed_rowid_filter= NULL; + } + virtual bool rowid_filter_push(Rowid_filter *rowid_filter) { return true; } /* Needed for partition / spider */ diff --git a/sql/item.cc b/sql/item.cc index 3d98031db11..5271adb7d50 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -70,12 +70,11 @@ bool cmp_items(Item *a, Item *b) /** Set max_sum_func_level if it is needed */ -inline void set_max_sum_func_level(SELECT_LEX *select) +inline void set_max_sum_func_level(THD *thd, SELECT_LEX *select) { - LEX *lex_s= select->parent_lex; - if (lex_s->in_sum_func && - lex_s->in_sum_func->nest_level >= select->nest_level) - set_if_bigger(lex_s->in_sum_func->max_sum_func_level, + if (thd->lex->in_sum_func && + thd->lex->in_sum_func->nest_level >= select->nest_level) + set_if_bigger(thd->lex->in_sum_func->max_sum_func_level, select->nest_level - 1); } @@ -644,7 +643,6 @@ Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg, cached_table(0), depended_from(0), can_be_depended(TRUE) { name= field_name_arg; - DBUG_ASSERT(!context || context->select_lex); } @@ -661,7 +659,6 @@ Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, cached_table(NULL), depended_from(NULL), can_be_depended(TRUE) { name= field_name_arg; - DBUG_ASSERT(!context || context->select_lex); } @@ -683,9 +680,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item) cached_table(item->cached_table), depended_from(item->depended_from), can_be_depended(item->can_be_depended) -{ - DBUG_ASSERT(!context || context->select_lex); -} +{} void Item_ident::cleanup() { @@ -5588,14 +5583,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) */ Name_resolution_context *last_checked_context= context; Item **ref= (Item **) not_found_item; - /* - There are cases when name resolution context is absent (when we are not - doing name resolution), but here the name resolution context should - be present because we are doing name resolution - */ - DBUG_ASSERT(context); - SELECT_LEX *current_sel= context->select_lex; - LEX *lex_s= context->select_lex->parent_lex; + SELECT_LEX *current_sel= thd->lex->current_select; Name_resolution_context *outer_context= 0; SELECT_LEX *select= 0; /* Currently derived tables cannot be correlated */ @@ -5697,18 +5685,19 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) return -1; thd->change_item_tree(reference, rf); select->inner_refs_list.push_back(rf, thd->mem_root); - rf->in_sum_func= lex_s->in_sum_func; + rf->in_sum_func= thd->lex->in_sum_func; } /* A reference is resolved to a nest level that's outer or the same as the nest level of the enclosing set function : adjust the value of max_arg_level for the function if it's needed. */ - if (lex_s->in_sum_func && - lex_s->in_sum_func->nest_level >= select->nest_level) + if (thd->lex->in_sum_func && + thd->lex == context->select_lex->parent_lex && + thd->lex->in_sum_func->nest_level >= select->nest_level) { Item::Type ref_type= (*reference)->type(); - set_if_bigger(lex_s->in_sum_func->max_arg_level, + set_if_bigger(thd->lex->in_sum_func->max_arg_level, select->nest_level); set_field(*from_field); fixed= 1; @@ -5729,10 +5718,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0), false); - if (lex_s->in_sum_func && - lex_s->in_sum_func->nest_level >= select->nest_level) + if (thd->lex->in_sum_func && + thd->lex == context->select_lex->parent_lex && + thd->lex->in_sum_func->nest_level >= select->nest_level) { - set_if_bigger(lex_s->in_sum_func->max_arg_level, + set_if_bigger(thd->lex->in_sum_func->max_arg_level, select->nest_level); } /* @@ -5824,7 +5814,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) { outer_context->select_lex->inner_refs_list.push_back((Item_outer_ref*)rf, thd->mem_root); - ((Item_outer_ref*)rf)->in_sum_func= lex_s->in_sum_func; + ((Item_outer_ref*)rf)->in_sum_func= thd->lex->in_sum_func; } thd->change_item_tree(reference, rf); /* @@ -5839,7 +5829,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(select); + set_max_sum_func_level(thd, select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, rf, rf, false); @@ -5852,7 +5842,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(select); + set_max_sum_func_level(thd, select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, (Item_ident*)*reference, false); @@ -5931,20 +5921,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) DBUG_ASSERT(fixed == 0); Field *from_field= (Field *)not_found_field; bool outer_fixed= false; - SELECT_LEX *select; - LEX *lex_s; - if (context) - { - select= context->select_lex; - lex_s= context->select_lex->parent_lex; - } - else - { - // No real name resolution, used somewhere in SP - DBUG_ASSERT(field); - select= NULL; - lex_s= NULL; - } + SELECT_LEX *select= thd->lex->current_select; if (select && select->in_tvc) { @@ -6012,7 +5989,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(select); + set_max_sum_func_level(thd, select); set_field(new_field); depended_from= (*((Item_field**)res))->depended_from; return 0; @@ -6041,7 +6018,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(select); + set_max_sum_func_level(thd, select); return FALSE; } } @@ -6078,11 +6055,12 @@ bool Item_field::fix_fields(THD *thd, Item **reference) goto mark_non_agg_field; } - if (lex_s && - lex_s->in_sum_func && - lex_s->in_sum_func->nest_level == + if (!thd->lex->current_select->no_wrap_view_item && + thd->lex->in_sum_func && + thd->lex == select->parent_lex && + thd->lex->in_sum_func->nest_level == select->nest_level) - set_if_bigger(lex_s->in_sum_func->max_arg_level, + set_if_bigger(thd->lex->in_sum_func->max_arg_level, select->nest_level); /* if it is not expression from merged VIEW we will set this field. @@ -6148,9 +6126,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (field->vcol_info) fix_session_vcol_expr_for_read(thd, field, field->vcol_info); if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && - !outer_fixed && + !outer_fixed && !thd->lex->in_sum_func && select && - !lex_s->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS && select->join) { @@ -6185,13 +6162,13 @@ mark_non_agg_field: */ select_lex= context->select_lex; } - if (!lex_s || !lex_s->in_sum_func) + if (!thd->lex->in_sum_func) select_lex->set_non_agg_field_used(true); else { if (outer_fixed) - lex_s->in_sum_func->outer_fields.push_back(this, thd->mem_root); - else if (lex_s->in_sum_func->nest_level != + thd->lex->in_sum_func->outer_fields.push_back(this, thd->mem_root); + else if (thd->lex->in_sum_func->nest_level != select->nest_level) select_lex->set_non_agg_field_used(true); } @@ -7651,12 +7628,6 @@ Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel) return NULL; } -Item *Item_ident::derived_field_transformer_for_having(THD *thd, uchar *arg) -{ - st_select_lex *sel= (st_select_lex *)arg; - context= &sel->context; - return this; -} Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg) { @@ -7676,13 +7647,12 @@ Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg) Item *Item_direct_view_ref::derived_field_transformer_for_having(THD *thd, uchar *arg) { - st_select_lex *sel= (st_select_lex *)arg; - context= &sel->context; if ((*ref)->marker & SUBSTITUTION_FL) { this->marker|= SUBSTITUTION_FL; return this; } + st_select_lex *sel= (st_select_lex *)arg; table_map tab_map= sel->master_unit()->derived->table->map; if ((item_equal && !(item_equal->used_tables() & tab_map)) || !item_equal) @@ -7945,9 +7915,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) { enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); - - SELECT_LEX *current_sel= context->select_lex; - LEX *lex_s= context->select_lex->parent_lex; + SELECT_LEX *current_sel= thd->lex->current_select; if (set_properties_only) { @@ -8108,10 +8076,11 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) the nest level of the enclosing set function : adjust the value of max_arg_level for the function if it's needed. */ - if (lex_s->in_sum_func && - lex_s->in_sum_func->nest_level >= + if (thd->lex->in_sum_func && + thd->lex == context->select_lex->parent_lex && + thd->lex->in_sum_func->nest_level >= last_checked_context->select_lex->nest_level) - set_if_bigger(lex_s->in_sum_func->max_arg_level, + set_if_bigger(thd->lex->in_sum_func->max_arg_level, last_checked_context->select_lex->nest_level); return FALSE; } @@ -8131,10 +8100,11 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) the nest level of the enclosing set function : adjust the value of max_arg_level for the function if it's needed. */ - if (lex_s->in_sum_func && - lex_s->in_sum_func->nest_level >= + if (thd->lex->in_sum_func && + thd->lex == context->select_lex->parent_lex && + thd->lex->in_sum_func->nest_level >= last_checked_context->select_lex->nest_level) - set_if_bigger(lex_s->in_sum_func->max_arg_level, + set_if_bigger(thd->lex->in_sum_func->max_arg_level, last_checked_context->select_lex->nest_level); } } @@ -9660,6 +9630,7 @@ bool Item_default_value::val_native_result(THD *thd, Native *to) return Item_field::val_native_result(thd, to); } + table_map Item_default_value::used_tables() const { if (!field || !field->default_value) diff --git a/sql/item.h b/sql/item.h index cab3d3fca02..09d5880d149 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3362,7 +3362,6 @@ public: Collect outer references */ bool collect_outer_ref_processor(void *arg) override; - Item *derived_field_transformer_for_having(THD *thd, uchar *arg) override; friend bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator<Item> *it, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index e7abb51893c..0635556be40 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -734,7 +734,7 @@ String *Item_func_des_encrypt::val_str(String *str) if ((null_value= args[0]->null_value)) return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) - return make_empty_result(); + return make_empty_result(str); if (arg_count == 1) { /* Protect against someone doing FLUSH DES_KEY_FILE */ @@ -937,7 +937,7 @@ String *Item_func_concat_ws::val_str(String *str) } if (i == arg_count) - return make_empty_result(); + return make_empty_result(str); for (i++; i < arg_count ; i++) { @@ -1088,7 +1088,7 @@ String *Item_func_reverse::val_str(String *str) return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) - return make_empty_result(); + return make_empty_result(str); if (str->alloc(res->length())) { null_value= 1; @@ -1626,7 +1626,7 @@ String *Item_func_left::val_str(String *str) /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); if ((res->length() <= (ulonglong) length) || (res->length() <= (char_pos= res->charpos((int) length)))) return res; @@ -1670,7 +1670,7 @@ String *Item_func_right::val_str(String *str) /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return make_empty_result(); /* purecov: inspected */ + return make_empty_result(str); /* purecov: inspected */ if (res->length() <= (ulonglong) length) return res; /* purecov: inspected */ @@ -1712,7 +1712,7 @@ String *Item_func_substr::val_str(String *str) /* Negative or zero length, will return empty string. */ if ((arg_count == 3) && (length <= 0) && (length == 0 || !args[2]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -1723,12 +1723,12 @@ String *Item_func_substr::val_str(String *str) /* Assumes that the maximum length of a String is < INT_MAX32. */ if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) || (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32))) - return make_empty_result(); + return make_empty_result(str); start= ((start < 0) ? res->numchars() + start : start - 1); start= res->charpos((int) start); if ((start < 0) || ((uint) start + 1 > res->length())) - return make_empty_result(); + return make_empty_result(str); length= res->charpos((int) length, (uint32) start); tmp_length= res->length() - start; @@ -1798,7 +1798,7 @@ String *Item_func_substr_index::val_str(String *str) null_value=0; uint delimiter_length= delimiter->length(); if (!res->length() || !delimiter_length || !count) - return make_empty_result(); // Wrong parameters + return make_empty_result(str); // Wrong parameters res->set_charset(collation.collation); @@ -2208,7 +2208,7 @@ String *Item_func_password::val_str_ascii(String *str) switch (alg){ case NEW: if (args[0]->null_value || res->length() == 0) - return make_empty_result(); + return make_empty_result(str); my_make_scrambled_password(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1); break; @@ -2216,7 +2216,7 @@ String *Item_func_password::val_str_ascii(String *str) if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return make_empty_result(); + return make_empty_result(str); my_make_scrambled_password_323(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1); break; @@ -2255,13 +2255,15 @@ char *Item_func_password::alloc(THD *thd, const char *password, String *Item_func_encrypt::val_str(String *str) { DBUG_ASSERT(fixed == 1); + #ifdef HAVE_CRYPT String *res =args[0]->val_str(str); + char salt[3],*salt_ptr; if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return make_empty_result(); + return make_empty_result(str); if (arg_count == 1) { // generate random salt time_t timestamp=current_thd->query_start(); @@ -2556,8 +2558,8 @@ String *Item_func_soundex::val_str(String *str) for ( ; ; ) /* Skip pre-space */ { if ((rc= cs->mb_wc(&wc, (uchar*) from, (uchar*) end)) <= 0) - return make_empty_result(); /* EOL or invalid byte sequence */ - + return make_empty_result(str); /* EOL or invalid byte sequence */ + if (rc == 1 && cs->m_ctype) { /* Single byte letter found */ @@ -2581,7 +2583,7 @@ String *Item_func_soundex::val_str(String *str) { /* Extra safety - should not really happen */ DBUG_ASSERT(false); - return make_empty_result(); + return make_empty_result(str); } to+= rc; break; @@ -2882,7 +2884,7 @@ String *Item_func_make_set::val_str(String *str) ulonglong bits; bool first_found=0; Item **ptr=args+1; - String *result= make_empty_result(); + String *result= make_empty_result(str); bits=args[0]->val_int(); if ((null_value=args[0]->null_value)) @@ -2906,7 +2908,7 @@ String *Item_func_make_set::val_str(String *str) else { if (tmp_str.copy(*res)) // Don't use 'str' - return make_empty_result(); + return make_empty_result(str); result= &tmp_str; } } @@ -2916,11 +2918,11 @@ String *Item_func_make_set::val_str(String *str) { // Copy data to tmp_str if (tmp_str.alloc(result->length()+res->length()+1) || tmp_str.copy(*result)) - return make_empty_result(); + return make_empty_result(str); result= &tmp_str; } if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res)) - return make_empty_result(); + return make_empty_result(str); } } } @@ -3061,7 +3063,7 @@ String *Item_func_repeat::val_str(String *str) null_value= 0; if (count <= 0 && (count == 0 || !args[1]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Bounds check on count: If this is triggered, we will error. */ @@ -3126,7 +3128,7 @@ String *Item_func_space::val_str(String *str) null_value= 0; if (count <= 0 && (count == 0 || !args[0]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. Bounds check on count: If this is triggered, we will error. @@ -3292,7 +3294,7 @@ String *Item_func_rpad::val_str(String *str) null_value=0; if (count == 0) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -3384,7 +3386,7 @@ String *Item_func_lpad::val_str(String *str) null_value=0; if (count == 0) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -3733,7 +3735,7 @@ String *Item_func_hex::val_str_ascii_from_val_real(String *str) dec= ~(longlong) 0; else dec= (ulonglong) (val + (val > 0 ? 0.5 : -0.5)); - return str->set_hex(dec) ? make_empty_result() : str; + return str->set_hex(dec) ? make_empty_result(str) : str; } @@ -3744,7 +3746,7 @@ String *Item_func_hex::val_str_ascii_from_val_str(String *str) DBUG_ASSERT(res != str); if ((null_value= (res == NULL))) return NULL; - return str->set_hex(res->ptr(), res->length()) ? make_empty_result() : str; + return str->set_hex(res->ptr(), res->length()) ? make_empty_result(str) : str; } @@ -3753,7 +3755,7 @@ String *Item_func_hex::val_str_ascii_from_val_int(String *str) ulonglong dec= (ulonglong) args[0]->val_int(); if ((null_value= args[0]->null_value)) return 0; - return str->set_hex(dec) ? make_empty_result() : str; + return str->set_hex(dec) ? make_empty_result(str) : str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 11d543dc474..0c4967a5247 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -35,21 +35,21 @@ protected: character set. No memory is allocated. @retval A pointer to the str_value member. */ - virtual String *make_empty_result() + virtual String *make_empty_result(String *str) { /* Reset string length to an empty string. We don't use str_value.set() as we don't want to free and potentially have to reallocate the buffer for each call. */ - if (!str_value.is_alloced()) - str_value.set("", 0, collation.collation); /* Avoid null ptrs */ + if (!str->is_alloced()) + str->set("", 0, collation.collation); /* Avoid null ptrs */ else { - str_value.length(0); /* Reuse allocated area */ - str_value.set_charset(collation.collation); + str->length(0); /* Reuse allocated area */ + str->set_charset(collation.collation); } - return &str_value; + return str; } public: Item_str_func(THD *thd): Item_func(thd) { decimals=NOT_FIXED_DEC; } @@ -501,7 +501,7 @@ class Item_func_substr_oracle :public Item_func_substr protected: longlong get_position() { longlong pos= args[1]->val_int(); return pos == 0 ? 1 : pos; } - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } public: Item_func_substr_oracle(THD *thd, Item *a, Item *b): @@ -542,7 +542,7 @@ protected: String *trimmed_value(String *res, uint32 offset, uint32 length) { if (length == 0) - return make_empty_result(); + return make_empty_result(&tmp_value); tmp_value.set(*res, offset, length); /* @@ -575,7 +575,7 @@ public: class Item_func_trim_oracle :public Item_func_trim { protected: - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } const char *func_name_ext() const { return "_oracle"; } public: @@ -614,7 +614,7 @@ public: class Item_func_ltrim_oracle :public Item_func_ltrim { protected: - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } const char *func_name_ext() const { return "_oracle"; } public: @@ -649,7 +649,7 @@ public: class Item_func_rtrim_oracle :public Item_func_rtrim { protected: - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } const char *func_name_ext() const { return "_oracle"; } public: @@ -854,7 +854,7 @@ public: String *val_str(String *); bool fix_length_and_dec() { - max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen; + max_length= NAME_CHAR_LEN * system_charset_info->mbmaxlen; maybe_null=1; return FALSE; } @@ -1144,7 +1144,7 @@ public: class Item_func_rpad_oracle :public Item_func_rpad { - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } public: Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): @@ -1179,7 +1179,7 @@ public: class Item_func_lpad_oracle :public Item_func_lpad { - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } public: Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index df362ced656..44145c1f958 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4061,6 +4061,8 @@ int subselect_single_select_engine::exec() tab->save_read_record= tab->read_record.read_record_func; tab->read_record.read_record_func= rr_sequential; tab->read_first_record= read_first_record_seq; + if (tab->rowid_filter) + tab->table->file->disable_pushed_rowid_filter(); tab->read_record.thd= join->thd; tab->read_record.ref_length= tab->table->file->ref_length; tab->read_record.unlock_row= rr_unlock_row; @@ -4081,6 +4083,8 @@ int subselect_single_select_engine::exec() tab->read_record.ref_length= 0; tab->read_first_record= tab->save_read_first_record; tab->read_record.read_record_func= tab->save_read_record; + if (tab->rowid_filter) + tab->table->file->enable_pushed_rowid_filter(); } executed= 1; if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN) && @@ -5264,9 +5268,8 @@ bool subselect_hash_sj_engine::make_semi_join_conds() tmp_table_ref->init_one_table(&empty_clex_str, &table_name, NULL, TL_READ); tmp_table_ref->table= tmp_table; - context= new (thd->mem_root) Name_resolution_context; + context= new Name_resolution_context; context->init(); - context->select_lex= item_in->unit->first_select(); context->first_name_resolution_table= context->last_name_resolution_table= tmp_table_ref; semi_join_conds_context= context; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index a674cfe8ff9..537eaaf8dcd 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -73,7 +73,6 @@ size_t Item_sum::ram_limitation(THD *thd) bool Item_sum::init_sum_func_check(THD *thd) { SELECT_LEX *curr_sel= thd->lex->current_select; - LEX *lex_s= (curr_sel ? curr_sel->parent_lex : thd->lex); if (curr_sel && curr_sel->name_visibility_map.is_clear_all()) { for (SELECT_LEX *sl= curr_sel; sl; sl= sl->context.outer_select()) @@ -89,9 +88,9 @@ bool Item_sum::init_sum_func_check(THD *thd) return TRUE; } /* Set a reference to the nesting set function if there is any */ - in_sum_func= lex_s->in_sum_func; + in_sum_func= thd->lex->in_sum_func; /* Save a pointer to object to be used in items for nested set functions */ - lex_s->in_sum_func= this; + thd->lex->in_sum_func= this; nest_level= thd->lex->current_select->nest_level; ref_by= 0; aggr_level= -1; @@ -158,7 +157,6 @@ bool Item_sum::init_sum_func_check(THD *thd) bool Item_sum::check_sum_func(THD *thd, Item **ref) { SELECT_LEX *curr_sel= thd->lex->current_select; - LEX *lex_s= curr_sel->parent_lex; nesting_map allow_sum_func(thd->lex->allow_sum_func); allow_sum_func.intersect(curr_sel->name_visibility_map); bool invalid= FALSE; @@ -321,7 +319,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) if (sum_func() == SP_AGGREGATE_FUNC) aggr_sel->set_custom_agg_func_used(true); update_used_tables(); - lex_s->in_sum_func= in_sum_func; + thd->lex->in_sum_func= in_sum_func; return FALSE; } diff --git a/sql/log.cc b/sql/log.cc index 0aec4144656..d0dcb5d3725 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1700,7 +1700,7 @@ static int binlog_close_connection(handlerton *hton, THD *thd) binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); #ifdef WITH_WSREP - if (cache_mngr && !cache_mngr->trx_cache.empty()) { + if (WSREP(thd) && cache_mngr && !cache_mngr->trx_cache.empty()) { IO_CACHE* cache= cache_mngr->get_binlog_cache_log(true); uchar *buf; size_t len=0; @@ -3706,6 +3706,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, opt_slave_sql_verify_checksum ? (enum_binlog_checksum_alg) binlog_checksum_options : BINLOG_CHECKSUM_ALG_OFF; s.checksum_alg= relay_log_checksum_alg; + s.set_relay_log_event(); } else s.checksum_alg= (enum_binlog_checksum_alg)binlog_checksum_options; diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index 7c4ea488f9e..72702daab36 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -124,6 +124,7 @@ static const char *HA_ERR(int i) case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE"; case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY"; + case HA_ERR_PARTITION_LIST : return "HA_ERR_PARTITION_LIST"; } return "No Error!"; } @@ -2386,7 +2387,8 @@ int Format_description_log_event::do_apply_event(rpl_group_info *rgi) original place when it comes to us; we'll know this by checking log_pos ("artificial" events have log_pos == 0). */ - if (!is_artificial_event() && created && thd->transaction->all.ha_list) + if (!thd->rli_fake && + !is_artificial_event() && created && thd->transaction->all.ha_list) { /* This is not an error (XA is safe), just an information */ rli->report(INFORMATION_LEVEL, 0, NULL, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 243e260a4c5..51db77a2f19 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1759,6 +1759,7 @@ static void close_connections(void) { wsrep_deinit(true); } + wsrep_sst_auth_free(); #endif /* All threads has now been aborted */ DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)", THD_count::value())); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ae24a257aaa..1744d5b58bf 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2695,6 +2695,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, notnull_cond= head->notnull_cond; if (!records) records++; /* purecov: inspected */ + if (head->file->ha_table_flags() & HA_NON_COMPARABLE_ROWID) + only_single_index_range_scan= 1; if (head->force_index || force_quick_range) scan_time= read_time= DBL_MAX; @@ -3283,6 +3285,25 @@ double records_in_column_ranges(PARAM *param, uint idx, /* + Compare quick select ranges according to number of found rows + If there is equal amounts of rows, use the long key part. + The idea is that if we have keys (a),(a,b) and (a,b,c) and we have + a query like WHERE a=1 and b=1 and c=1, + it is better to use key (a,b,c) than (a) as it will ensure we don't also + use histograms for columns b and c +*/ + +static +int cmp_quick_ranges(TABLE *table, uint *a, uint *b) +{ + int tmp= CMP_NUM(table->opt_range[*a].rows, table->opt_range[*b].rows); + if (tmp) + return tmp; + return -CMP_NUM(table->opt_range[*a].key_parts, table->opt_range[*b].key_parts); +} + + +/* Calculate the selectivity of the condition imposed on the rows of a table SYNOPSIS @@ -3318,10 +3339,10 @@ double records_in_column_ranges(PARAM *param, uint idx, bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) { - uint keynr; - uint max_quick_key_parts= 0; + uint keynr, range_index, ranges; MY_BITMAP *used_fields= &table->cond_set; - double table_records= (double)table->stat_records(); + double table_records= (double)table->stat_records(); + uint optimal_key_order[MAX_KEY]; DBUG_ENTER("calculate_cond_selectivity_for_table"); table->cond_selectivity= 1.0; @@ -3360,23 +3381,21 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) Json_writer_object trace_wrapper(thd); Json_writer_array selectivity_for_indexes(thd, "selectivity_for_indexes"); - for (keynr= 0; keynr < table->s->keys; keynr++) - { + /* + Walk through all quick ranges in the order of least found rows. + */ + for (ranges= keynr= 0 ; keynr < table->s->keys; keynr++) if (table->opt_range_keys.is_set(keynr)) - set_if_bigger(max_quick_key_parts, table->opt_range[keynr].key_parts); - } + optimal_key_order[ranges++]= keynr; - /* - Walk through all indexes, indexes where range access uses more keyparts - go first. - */ - for (uint quick_key_parts= max_quick_key_parts; - quick_key_parts; quick_key_parts--) + my_qsort2(optimal_key_order, ranges, + sizeof(optimal_key_order[0]), + (qsort2_cmp) cmp_quick_ranges, table); + + for (range_index= 0 ; range_index < ranges ; range_index++) { - for (keynr= 0; keynr < table->s->keys; keynr++) + uint keynr= optimal_key_order[range_index]; { - if (table->opt_range_keys.is_set(keynr) && - table->opt_range[keynr].key_parts == quick_key_parts) { uint i; uint used_key_parts= table->opt_range[keynr].key_parts; @@ -10270,7 +10289,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) uint max_part_no= MY_MAX(key1->max_part_no, key2->max_part_no); - for (key2=key2->first(); key2; ) + for (key2=key2->first(); ; ) { /* key1 consists of one or more ranges. tmp is the range currently @@ -10284,6 +10303,16 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) ^ tmp */ + if (key1->min_flag & NO_MIN_RANGE && + key1->max_flag & NO_MAX_RANGE) + { + if (key1->maybe_flag) + return new SEL_ARG(SEL_ARG::MAYBE_KEY); + return 0; // Always true OR + } + if (!key2) + break; + SEL_ARG *tmp=key1->find_range(key2); /* @@ -10354,6 +10383,13 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) key2->copy_min(tmp); if (!(key1=key1->tree_delete(tmp))) { // Only one key in tree + if (key2->min_flag & NO_MIN_RANGE && + key2->max_flag & NO_MAX_RANGE) + { + if (key2->maybe_flag) + return new SEL_ARG(SEL_ARG::MAYBE_KEY); + return 0; // Always true OR + } key1=key2; key1->make_root(); key2=key2_next; @@ -11669,6 +11705,9 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts) table_key->user_defined_key_parts); uint pk_number; + if (param->table->file->ha_table_flags() & HA_NON_COMPARABLE_ROWID) + return false; + for (KEY_PART_INFO *kp= table_key->key_part; kp < key_part; kp++) { uint16 fieldnr= param->table->key_info[keynr]. diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 316919c4a81..e148dd42d1e 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -310,6 +310,8 @@ struct SplM_field_ext_info: public SplM_field_info occurred also in the select list of this join 9. There are defined some keys usable for ref access of fields from C with available statistics. + 10. The select doesn't use WITH ROLLUP (This limitation can probably be + lifted) @retval true if the answer is positive @@ -326,7 +328,8 @@ bool JOIN::check_for_splittable_materialized() (unit->first_select()->next_select()) || // !(3) (derived->prohibit_cond_pushdown) || // !(4) (derived->is_recursive_with_table()) || // !(5) - (table_count == 0 || const_tables == top_join_tab_count)) // !(6) + (table_count == 0 || const_tables == top_join_tab_count) || // !(6) + rollup.state != ROLLUP::STATE_NONE) // (10) return false; if (group_list) // (7.1) { @@ -1043,16 +1046,16 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count, Inject equalities for splitting used by the materialization join @param - remaining_tables used to filter out the equalities that cannot + excluded_tables used to filter out the equalities that cannot be pushed. @details - This function is called by JOIN_TAB::fix_splitting that is used - to fix the chosen splitting of a splittable materialized table T - in the final query execution plan. In this plan the table T - is joined just before the 'remaining_tables'. So all equalities - usable for splitting whose right parts do not depend on any of - remaining tables can be pushed into join for T. + This function injects equalities pushed into a derived table T for which + the split optimization has been chosen by the optimizer. The function + is called by JOIN::inject_splitting_cond_for_all_tables_with_split_op(). + All equalities usable for splitting T whose right parts do not depend on + any of the 'excluded_tables' can be pushed into the where clause of the + derived table T. The function also marks the select that specifies T as UNCACHEABLE_DEPENDENT_INJECTED. @@ -1061,7 +1064,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count, true on failure */ -bool JOIN::inject_best_splitting_cond(table_map remaining_tables) +bool JOIN::inject_best_splitting_cond(table_map excluded_tables) { Item *inj_cond= 0; List<Item> *inj_cond_list= &spl_opt_info->inj_cond_list; @@ -1069,7 +1072,7 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables) KEY_FIELD *added_key_field; while ((added_key_field= li++)) { - if (remaining_tables & added_key_field->val->used_tables()) + if (excluded_tables & added_key_field->val->used_tables()) continue; if (inj_cond_list->push_back(added_key_field->cond, thd->mem_root)) return true; @@ -1086,7 +1089,7 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables) if (inj_cond) inj_cond->fix_fields(thd,0); - if (inject_cond_into_where(inj_cond)) + if (inject_cond_into_where(inj_cond->copy_andor_structure(thd))) return true; select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; @@ -1163,8 +1166,6 @@ bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan, memcpy((char *) md_join->best_positions, (char *) spl_plan->best_positions, sizeof(POSITION) * md_join->table_count); - if (md_join->inject_best_splitting_cond(remaining_tables)) - return true; /* This is called for a proper work of JOIN::get_best_combination() called for the join that materializes T @@ -1208,7 +1209,8 @@ bool JOIN::fix_all_splittings_in_plan() if (tab->table->is_splittable()) { SplM_plan_info *spl_plan= cur_pos->spl_plan; - if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables, + if (tab->fix_splitting(spl_plan, + all_tables & ~prev_tables, tablenr < const_tables )) return true; } @@ -1216,3 +1218,44 @@ bool JOIN::fix_all_splittings_in_plan() } return false; } + + +/** + @brief + Inject splitting conditions into WHERE of split derived + + @details + The function calls JOIN_TAB::inject_best_splitting_cond() for each + materialized derived table T used in this join for which the split + optimization has been chosen by the optimizer. It is done in order to + inject equalities pushed into the where clause of the specification + of T that would be helpful to employ the splitting technique. + + @retval + false on success + true on failure +*/ + +bool JOIN::inject_splitting_cond_for_all_tables_with_split_opt() +{ + table_map prev_tables= 0; + table_map all_tables= (table_map(1) << table_count) - 1; + for (uint tablenr= 0; tablenr < table_count; tablenr++) + { + POSITION *cur_pos= &best_positions[tablenr]; + JOIN_TAB *tab= cur_pos->table; + prev_tables|= tab->table->map; + if (!(tab->table->is_splittable() && cur_pos->spl_plan)) + continue; + SplM_opt_info *spl_opt_info= tab->table->spl_opt_info; + JOIN *join= spl_opt_info->join; + /* + Currently the equalities referencing columns of SJM tables with + look-up access cannot be pushed into materialized derived. + */ + if (join->inject_best_splitting_cond((all_tables & ~prev_tables) | + sjm_lookup_tables)) + return true; + } + return false; +} diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 0ddfe3e5051..79ab0e21cfe 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1605,8 +1605,15 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) { SELECT_LEX *parent_lex= parent_join->select_lex; TABLE_LIST *emb_tbl_nest= NULL; + TABLE_LIST *orig_tl; List<TABLE_LIST> *emb_join_list= &parent_lex->top_join_list; THD *thd= parent_join->thd; + SELECT_LEX *save_lex; + Item **left; + Item *left_exp; + Item *left_exp_orig; + + uint ncols; DBUG_ENTER("convert_subq_to_sj"); /* @@ -1766,17 +1773,17 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) because view's tables are inserted after the view) */ - for (tl= (TABLE_LIST*)(parent_lex->table_list.first); tl->next_local; tl= tl->next_local) + for (orig_tl= (TABLE_LIST*)(parent_lex->table_list.first); + orig_tl->next_local; + orig_tl= orig_tl->next_local) {} - tl->next_local= subq_lex->join->tables_list; + orig_tl->next_local= subq_lex->join->tables_list; /* A theory: no need to re-connect the next_global chain */ /* 3. Remove the original subquery predicate from the WHERE/ON */ - // The subqueries were replaced for Item_int(1) earlier - subq_pred->reset_strategy(SUBS_SEMI_JOIN); // for subsequent executions /*TODO: also reset the 'm_with_subquery' there. */ /* n. Adjust the parent_join->table_count counter */ @@ -1808,16 +1815,18 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) Put the subquery's WHERE into semi-join's sj_on_expr Add the subquery-induced equalities too. */ - SELECT_LEX *save_lex= thd->lex->current_select; + save_lex= thd->lex->current_select; + table_map subq_pred_used_tables; + thd->lex->current_select=subq_lex; - Item **left= subq_pred->left_exp_ptr(); + left= subq_pred->left_exp_ptr(); if ((*left)->fix_fields_if_needed(thd, left)) - DBUG_RETURN(TRUE); - Item *left_exp= *left; - Item *left_exp_orig= subq_pred->left_exp_orig(); + goto restore_tl_and_exit; + left_exp= *left; + left_exp_orig= subq_pred->left_exp_orig(); thd->lex->current_select=save_lex; - table_map subq_pred_used_tables= subq_pred->used_tables(); + subq_pred_used_tables= subq_pred->used_tables(); sj_nest->nested_join->sj_corr_tables= subq_pred_used_tables; sj_nest->nested_join->sj_depends_on= subq_pred_used_tables | left_exp->used_tables(); @@ -1838,7 +1847,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) Item_direct_view_refs doesn't substitute itself with anything in Item_direct_view_ref::fix_fields. */ - uint ncols= sj_nest->sj_in_exprs= left_exp->cols(); + ncols= sj_nest->sj_in_exprs= left_exp->cols(); sj_nest->nested_join->sj_outer_expr_list.empty(); reset_equality_number_for_subq_conds(sj_nest->sj_on_expr); @@ -1860,7 +1869,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) new (thd->mem_root) Item_func_eq(thd, left_exp_orig, subq_lex->ref_pointer_array[0]); if (!item_eq) - DBUG_RETURN(TRUE); + goto restore_tl_and_exit; if (left_exp_orig != left_exp) thd->change_item_tree(item_eq->arguments(), left_exp); item_eq->in_equality_no= 0; @@ -1881,7 +1890,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) Item_func_eq(thd, left_exp_orig->element_index(i), subq_lex->ref_pointer_array[i]); if (!item_eq) - DBUG_RETURN(TRUE); + goto restore_tl_and_exit; DBUG_ASSERT(left_exp->element_index(i)->is_fixed()); if (left_exp_orig->element_index(i) != left_exp->element_index(i)) @@ -1900,13 +1909,13 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) Item_row *row= new (thd->mem_root) Item_row(thd, subq_lex->pre_fix); /* fix fields on subquery was call so they should be the same */ if (!row) - DBUG_RETURN(TRUE); + goto restore_tl_and_exit; DBUG_ASSERT(ncols == row->cols()); nested_join->sj_outer_expr_list.push_back(left); Item_func_eq *item_eq= new (thd->mem_root) Item_func_eq(thd, left_exp_orig, row); if (!item_eq) - DBUG_RETURN(TRUE); + goto restore_tl_and_exit; for (uint i= 0; i < row->cols(); i++) { if (row->element_index(i) != subq_lex->ref_pointer_array[i]) @@ -1925,9 +1934,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) we have in here). */ if (sj_nest->sj_on_expr->fix_fields_if_needed(thd, &sj_nest->sj_on_expr)) - { - DBUG_RETURN(TRUE); - } + goto restore_tl_and_exit; /* Walk through sj nest's WHERE and ON expressions and call @@ -1952,9 +1959,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) emb_tbl_nest->on_expr->top_level_item(); if (emb_tbl_nest->on_expr->fix_fields_if_needed(thd, &emb_tbl_nest->on_expr)) - { - DBUG_RETURN(TRUE); - } + goto restore_tl_and_exit; } else { @@ -1968,9 +1973,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) save_lex= thd->lex->current_select; thd->lex->current_select=parent_join->select_lex; if (parent_join->conds->fix_fields_if_needed(thd, &parent_join->conds)) - { - DBUG_RETURN(1); - } + goto restore_tl_and_exit; + thd->lex->current_select=save_lex; parent_join->select_lex->where= parent_join->conds; } @@ -1983,9 +1987,16 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) parent_lex->ftfunc_list->push_front(ifm, thd->mem_root); } + // The subqueries were replaced for Item_int(1) earlier + subq_pred->reset_strategy(SUBS_SEMI_JOIN); // for subsequent executions + parent_lex->have_merged_subqueries= TRUE; /* Fatal error may have been set to by fix_after_pullout() */ DBUG_RETURN(thd->is_fatal_error); + +restore_tl_and_exit: + orig_tl->next_local= NULL; + DBUG_RETURN(TRUE); } diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 871411cf6c4..3c74fd4b9c7 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -40,7 +40,7 @@ #include "ha_partition.h" -partition_info *partition_info::get_clone(THD *thd) +partition_info *partition_info::get_clone(THD *thd, bool empty_data_and_index_file) { MEM_ROOT *mem_root= thd->mem_root; DBUG_ENTER("partition_info::get_clone"); @@ -60,21 +60,22 @@ partition_info *partition_info::get_clone(THD *thd) { List_iterator<partition_element> subpart_it(part->subpartitions); partition_element *subpart; - partition_element *part_clone= new (mem_root) partition_element(); + partition_element *part_clone= new (mem_root) partition_element(*part); if (!part_clone) DBUG_RETURN(NULL); - - *part_clone= *part; part_clone->subpartitions.empty(); while ((subpart= (subpart_it++))) { - partition_element *subpart_clone= new (mem_root) partition_element(); + partition_element *subpart_clone= new (mem_root) partition_element(*subpart); if (!subpart_clone) DBUG_RETURN(NULL); - - *subpart_clone= *subpart; + if (empty_data_and_index_file) + subpart_clone->data_file_name= subpart_clone->index_file_name= NULL; part_clone->subpartitions.push_back(subpart_clone, mem_root); } + + if (empty_data_and_index_file) + part_clone->data_file_name= part_clone->index_file_name= NULL; clone->partitions.push_back(part_clone, mem_root); part_clone->list_val_list.empty(); List_iterator<part_elem_value> list_val_it(part->list_val_list); @@ -816,8 +817,13 @@ bool partition_info::has_unique_name(partition_element *element) vers_info->interval Limit by fixed time interval vers_info->hist_part (out) Working history partition */ -void partition_info::vers_set_hist_part(THD *thd) +int partition_info::vers_set_hist_part(THD *thd) { + if (table->pos_in_table_list && + table->pos_in_table_list->partition_names) + { + return HA_ERR_PARTITION_LIST; + } if (vers_info->limit) { ha_partition *hp= (ha_partition*)(table->file); @@ -825,9 +831,11 @@ void partition_info::vers_set_hist_part(THD *thd) List_iterator<partition_element> it(partitions); while (next != vers_info->hist_part) next= it++; + DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id)); ha_rows records= hp->part_records(next); while ((next= it++) != vers_info->now_part) { + DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id)); ha_rows next_records= hp->part_records(next); if (next_records == 0) break; @@ -845,13 +853,13 @@ void partition_info::vers_set_hist_part(THD *thd) else vers_info->hist_part= next; } - return; + return 0; } if (vers_info->interval.is_set()) { if (vers_info->hist_part->range_value > thd->query_start()) - return; + return 0; partition_element *next= NULL; List_iterator<partition_element> it(partitions); @@ -862,9 +870,10 @@ void partition_info::vers_set_hist_part(THD *thd) { vers_info->hist_part= next; if (next->range_value > thd->query_start()) - return; + return 0; } } + return 0; } diff --git a/sql/partition_info.h b/sql/partition_info.h index 0656238ec07..f69a3f68495 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -330,7 +330,7 @@ public: } ~partition_info() {} - partition_info *get_clone(THD *thd); + partition_info *get_clone(THD *thd, bool empty_data_and_index_file= FALSE); bool set_named_partition_bitmap(const char *part_name, size_t length); bool set_partition_bitmaps(List<String> *partition_names); bool set_partition_bitmaps_from_table(TABLE_LIST *table_list); @@ -404,7 +404,7 @@ public: vers_info->limit= limit; return !limit; } - void vers_set_hist_part(THD *thd); + int vers_set_hist_part(THD *thd); bool vers_fix_field_list(THD *thd); void vers_update_el_ids(); partition_element *get_partition(uint part_id) diff --git a/sql/protocol.cc b/sql/protocol.cc index 18b41363a96..008ae13d9f0 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -466,8 +466,12 @@ bool Protocol::net_send_error_packet(THD *thd, uint sql_errno, const char *err, coming from server to have seq_no > 0, due to missing awareness of "out-of-band" operations. Make these clients happy. */ - if (!net->pkt_nr) - net->pkt_nr= 1; + if (!net->pkt_nr && + (sql_errno == ER_CONNECTION_KILLED || sql_errno == ER_SERVER_SHUTDOWN || + sql_errno == ER_QUERY_INTERRUPTED)) + { + net->pkt_nr= 1; + } ret= net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) buff, length); diff --git a/sql/rowid_filter.cc b/sql/rowid_filter.cc index 4a3746d72db..0589b587ba2 100644 --- a/sql/rowid_filter.cc +++ b/sql/rowid_filter.cc @@ -350,6 +350,9 @@ void TABLE::init_cost_info_for_usable_range_rowid_filters(THD *thd) usable_range_filter_keys.clear_all(); key_map::Iterator it(opt_range_keys); + if (file->ha_table_flags() & HA_NON_COMPARABLE_ROWID) + return; // Cannot create filtering + /* From all indexes that can be used for range accesses select only such that - range filter pushdown is supported by the engine for them (1) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index a4549e314ce..abeefd3092b 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6639,8 +6639,8 @@ ER_BINLOG_UNSAFE_INSERT_TWO_KEYS ER_TABLE_IN_FK_CHECK eng "Table is being used in foreign key check" -ER_UNUSED_1 - eng "You should never see it" +ER_VERS_NOT_ALLOWED + eng "Not allowed for system-versioned table %`s.%`s" ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST eng "INSERT into autoincrement field which is not the first part in the composed primary key is unsafe" diff --git a/sql/slave.cc b/sql/slave.cc index 62ceb07b224..efd9e72ba75 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4432,6 +4432,15 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, #ifdef WITH_WSREP wsrep_after_statement(thd); #endif /* WITH_WSREP */ + DBUG_EXECUTE_IF( + "pause_sql_thread_on_fde", + if (ev && typ == FORMAT_DESCRIPTION_EVENT) { + DBUG_ASSERT(!debug_sync_set_action( + thd, + STRING_WITH_LEN( + "now SIGNAL paused_on_fde WAIT_FOR sql_thread_continue"))); + }); + DBUG_RETURN(exec_res); } mysql_mutex_unlock(&rli->data_lock); diff --git a/sql/sp_head.h b/sql/sp_head.h index 34dd09fd88f..b6bf868a05b 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -625,6 +625,23 @@ public: DBUG_RETURN(false); } + /** + Iterate through the LEX stack from the top (the newest) to the bottom + (the oldest) and find the one that contains a non-zero spname. + @returns - the address of spname, or NULL of no spname found. + */ + const sp_name *find_spname_recursive() + { + uint count= m_lex.elements; + for (uint i= 0; i < count; i++) + { + const LEX *tmp= m_lex.elem(count - i - 1); + if (tmp->spname) + return tmp->spname; + } + return NULL; + } + /// Put the instruction on the backpatch list, associated with the label. int push_backpatch(THD *thd, sp_instr *, sp_label *); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9d8d678b052..c4e66cf5d73 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2263,6 +2263,12 @@ static int set_user_auth(THD *thd, const LEX_CSTRING &user, goto end; } + if (thd->lex->sql_command == SQLCOM_SET_OPTION && !info->hash_password) + { + res= ER_SET_PASSWORD_AUTH_PLUGIN; + goto end; + } + if (info->hash_password && validate_password(thd, user, pwtext, auth->auth_string.length)) { @@ -14322,61 +14328,6 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) if (initialized) // if not --skip-grant-tables { -#ifndef NO_EMBEDDED_ACCESS_CHECKS - bool is_proxy_user= FALSE; - const char *auth_user = acl_user->user.str; - ACL_PROXY_USER *proxy_user; - /* check if the user is allowed to proxy as another user */ - proxy_user= acl_find_proxy_user(auth_user, sctx->host, sctx->ip, - mpvio.auth_info.authenticated_as, - &is_proxy_user); - if (is_proxy_user) - { - ACL_USER *acl_proxy_user; - - /* we need to find the proxy user, but there was none */ - if (!proxy_user) - { - Host_errors errors; - errors.m_proxy_user= 1; - inc_host_errors(mpvio.auth_info.thd->security_ctx->ip, &errors); - if (!thd->is_error()) - login_failed_error(thd); - DBUG_RETURN(1); - } - - my_snprintf(sctx->proxy_user, sizeof(sctx->proxy_user) - 1, - "'%s'@'%s'", auth_user, - safe_str(acl_user->host.hostname)); - - /* we're proxying : find the proxy user definition */ - mysql_mutex_lock(&acl_cache->lock); - acl_proxy_user= find_user_exact(safe_str(proxy_user->get_proxied_host()), - mpvio.auth_info.authenticated_as); - if (!acl_proxy_user) - { - mysql_mutex_unlock(&acl_cache->lock); - - Host_errors errors; - errors.m_proxy_user_acl= 1; - inc_host_errors(mpvio.auth_info.thd->security_ctx->ip, &errors); - if (!thd->is_error()) - login_failed_error(thd); - DBUG_RETURN(1); - } - acl_user= acl_proxy_user->copy(thd->mem_root); - mysql_mutex_unlock(&acl_cache->lock); - } -#endif - - sctx->master_access= acl_user->access; - strmake_buf(sctx->priv_user, acl_user->user.str); - - if (acl_user->host.hostname) - strmake_buf(sctx->priv_host, acl_user->host.hostname); - else - *sctx->priv_host= 0; - /* OK. Let's check the SSL. Historically it was checked after the password, as an additional layer, not instead of the password @@ -14413,6 +14364,65 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) sctx->password_expired= password_expired; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (!password_expired) + { + bool is_proxy_user= FALSE; + const char *auth_user = acl_user->user.str; + ACL_PROXY_USER *proxy_user; + /* check if the user is allowed to proxy as another user */ + proxy_user= acl_find_proxy_user(auth_user, sctx->host, sctx->ip, + mpvio.auth_info.authenticated_as, + &is_proxy_user); + if (is_proxy_user) + { + ACL_USER *acl_proxy_user; + + /* we need to find the proxy user, but there was none */ + if (!proxy_user) + { + Host_errors errors; + errors.m_proxy_user= 1; + inc_host_errors(mpvio.auth_info.thd->security_ctx->ip, &errors); + if (!thd->is_error()) + login_failed_error(thd); + DBUG_RETURN(1); + } + + my_snprintf(sctx->proxy_user, sizeof(sctx->proxy_user) - 1, + "'%s'@'%s'", auth_user, + safe_str(acl_user->host.hostname)); + + /* we're proxying : find the proxy user definition */ + mysql_mutex_lock(&acl_cache->lock); + acl_proxy_user= find_user_exact(safe_str(proxy_user->get_proxied_host()), + mpvio.auth_info.authenticated_as); + if (!acl_proxy_user) + { + mysql_mutex_unlock(&acl_cache->lock); + + Host_errors errors; + errors.m_proxy_user_acl= 1; + inc_host_errors(mpvio.auth_info.thd->security_ctx->ip, &errors); + if (!thd->is_error()) + login_failed_error(thd); + DBUG_RETURN(1); + } + acl_user= acl_proxy_user->copy(thd->mem_root); + mysql_mutex_unlock(&acl_cache->lock); + } + } +#endif + + sctx->master_access= acl_user->access; + strmake_buf(sctx->priv_user, acl_user->user.str); + + if (acl_user->host.hostname) + strmake_buf(sctx->priv_host, acl_user->host.hostname); + else + *sctx->priv_host= 0; + + /* Don't allow the user to connect if he has done too many queries. As we are testing max_user_connections == 0 here, it means that we diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index b9d0d65df11..060dcc059b5 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -432,49 +432,6 @@ dbug_err: return open_error; } -#ifdef WITH_WSREP - /* - OPTIMIZE, REPAIR and ALTER may take MDL locks not only for the affected table, but - also for the table referenced by foreign key constraint. - This wsrep_toi_replication() function handles TOI replication for OPTIMIZE and REPAIR - so that certification keys for potential FK parent tables are also appended in the - write set. - ALTER TABLE case is handled elsewhere. - */ -static bool wsrep_toi_replication(THD *thd, TABLE_LIST *tables) -{ - LEX *lex= thd->lex; - /* only handle OPTIMIZE and REPAIR here */ - switch (lex->sql_command) - { - case SQLCOM_OPTIMIZE: - case SQLCOM_REPAIR: - break; - default: - return false; - } - - close_thread_tables(thd); - wsrep::key_array keys; - - wsrep_append_fk_parent_table(thd, tables, &keys); - - /* now TOI replication, with no locks held */ - if (keys.empty()) - { - if (!thd->lex->no_write_to_binlog && - wsrep_to_isolation_begin(thd, NULL, NULL, tables)) - return true; - } - else - { - if (!thd->lex->no_write_to_binlog && - wsrep_to_isolation_begin(thd, NULL, NULL, tables, NULL, &keys)) - return true; - } - return false; -} -#endif /* WITH_WSREP */ static void send_read_only_warning(THD *thd, const LEX_CSTRING *msg_status, @@ -561,16 +518,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, close_thread_tables(thd); for (table= tables; table; table= table->next_local) table->table= NULL; -#ifdef WITH_WSREP - if (WSREP(thd)) - { - if(wsrep_toi_replication(thd, tables)) - { - WSREP_INFO("wsrep TOI replication of has failed."); - goto err; - } - } -#endif /* WITH_WSREP */ for (table= tables; table; table= table->next_local) { @@ -1497,6 +1444,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ + WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); res= (specialflag & SPECIAL_NO_NEW_FUNC) ? mysql_recreate_table(thd, first_table, true) : mysql_admin_table(thd, first_table, &m_lex->check_opt, @@ -1506,6 +1454,9 @@ bool Sql_cmd_optimize_table::execute(THD *thd) m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; +#ifdef WITH_WSREP +wsrep_error_label: +#endif /* WITH_WSREP */ error: DBUG_RETURN(res); } @@ -1521,6 +1472,8 @@ bool Sql_cmd_repair_table::execute(THD *thd) if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ + + WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair", TL_WRITE, 1, MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM), @@ -1530,6 +1483,9 @@ bool Sql_cmd_repair_table::execute(THD *thd) m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; +#ifdef WITH_WSREP +wsrep_error_label: +#endif /* WITH_WSREP */ error: DBUG_RETURN(res); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 87d7f65fed5..0509b200842 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4437,6 +4437,7 @@ restart: wsrep_thd_is_local(thd) && !is_stat_table(&(*start)->db, &(*start)->alias) && thd->get_command() != COM_STMT_PREPARE && + !thd->stmt_arena->is_stmt_prepare() && ((thd->lex->sql_command == SQLCOM_INSERT || thd->lex->sql_command == SQLCOM_INSERT_SELECT || thd->lex->sql_command == SQLCOM_REPLACE || @@ -6365,8 +6366,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TRUE, &(item->cached_field_index)); #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Check if there are sufficient access rights to the found field. */ - if (found && check_privileges && - check_column_grant_in_table_ref(thd, table_ref, name, length, found)) + if (found && check_privileges && !is_temporary_table(table_ref) && + check_column_grant_in_table_ref(thd, table_ref, name, length, + found)) found= WRONG_GRANT; #endif } @@ -6830,7 +6832,6 @@ set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref) if (!(context= new (thd->mem_root) Name_resolution_context)) return TRUE; context->init(); - context->select_lex= table_ref->select_lex; context->first_name_resolution_table= context->last_name_resolution_table= table_ref; item->context= context; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 969d831bc4e..108a0c59665 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2503,6 +2503,11 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, di->table_list.alias.length= di->table_list.table_name.length= di->thd.query_length(); di->table_list.db= di->thd.db; /* + Nulify select_lex because, if the thread that spawned the current one + disconnects, the select_lex will point to freed memory. + */ + di->table_list.select_lex= NULL; + /* We need the tickets so that they can be cloned in handle_delayed_insert */ @@ -3162,6 +3167,8 @@ pthread_handler_t handle_delayed_insert(void *arg) di->handler_thread_initialized= TRUE; di->table_list.mdl_request.ticket= NULL; + thd->set_query_id(next_query_id()); + if (di->open_and_lock_table()) goto err; @@ -3280,6 +3287,7 @@ pthread_handler_t handle_delayed_insert(void *arg) if (di->tables_in_use && ! thd->lock && (!thd->killed || di->stacked_inserts)) { + thd->set_query_id(next_query_id()); /* Request for new delayed insert. Lock the table, but avoid to be blocked by a global read lock. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index fea1e8f6022..3a738783f8e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5820,18 +5820,19 @@ void LEX::free_arena_for_set_stmt() DBUG_VOID_RETURN; } -void LEX::restore_set_statement_var() +bool LEX::restore_set_statement_var() { + bool err= false; DBUG_ENTER("LEX::restore_set_statement_var"); if (!old_var_list.is_empty()) { DBUG_PRINT("info", ("vars: %d", old_var_list.elements)); - sql_set_variables(thd, &old_var_list, false); + err= sql_set_variables(thd, &old_var_list, false); old_var_list.empty(); free_arena_for_set_stmt(); } DBUG_ASSERT(!is_arena_for_set_stmt()); - DBUG_VOID_RETURN; + DBUG_RETURN(err); } unit_common_op st_select_lex_unit::common_op() diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d9e29b06a91..74772cb4b1c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3777,7 +3777,7 @@ public: int print_explain(select_result_sink *output, uint8 explain_flags, bool is_analyze, bool *printed_anything); - void restore_set_statement_var(); + bool restore_set_statement_var(); void init_last_field(Column_definition *field, const LEX_CSTRING *name, const CHARSET_INFO *cs); diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 45f81da80c9..fb7fa26f245 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -563,8 +563,8 @@ MY_LOCALE my_locale_es_ES 10, 9, ',', /* decimal point es_ES */ - '\0', /* thousands_sep es_ES */ - "\x80\x80", /* grouping es_ES */ + '.', /* thousands_sep es_ES */ + "\x03\x03", /* grouping es_ES */ &global_errmsgs[es_ES] ); /***** LOCALE END es_ES *****/ @@ -2649,8 +2649,8 @@ MY_LOCALE my_locale_es_BO 10, 9, ',', /* decimal point es_BO */ - '\0', /* thousands_sep es_BO */ - "\x80\x80", /* grouping es_BO */ + '.', /* thousands_sep es_BO */ + "\x03\x03", /* grouping es_BO */ &global_errmsgs[es_ES] ); /***** LOCALE END es_BO *****/ @@ -2669,8 +2669,8 @@ MY_LOCALE my_locale_es_CL 10, 9, ',', /* decimal point es_CL */ - '\0', /* thousands_sep es_CL */ - "\x80\x80", /* grouping es_CL */ + '.', /* thousands_sep es_CL */ + "\x03\x03", /* grouping es_CL */ &global_errmsgs[es_ES] ); /***** LOCALE END es_CL *****/ @@ -2689,8 +2689,8 @@ MY_LOCALE my_locale_es_CO 10, 9, ',', /* decimal point es_CO */ - '\0', /* thousands_sep es_CO */ - "\x80\x80", /* grouping es_CO */ + '.', /* thousands_sep es_CO */ + "\x03\x03", /* grouping es_CO */ &global_errmsgs[es_ES] ); /***** LOCALE END es_CO *****/ @@ -2708,9 +2708,9 @@ MY_LOCALE my_locale_es_CR &my_locale_typelib_ab_day_names_es_ES, 10, 9, - '.', /* decimal point es_CR */ - '\0', /* thousands_sep es_CR */ - "\x80\x80", /* grouping es_CR */ + ',', /* decimal point es_CR */ + ' ', /* thousands_sep es_CR */ + "\x03\x03", /* grouping es_CR */ &global_errmsgs[es_ES] ); /***** LOCALE END es_CR *****/ @@ -2729,8 +2729,8 @@ MY_LOCALE my_locale_es_DO 10, 9, '.', /* decimal point es_DO */ - '\0', /* thousands_sep es_DO */ - "\x80\x80", /* grouping es_DO */ + ',', /* thousands_sep es_DO */ + "\x03\x03", /* grouping es_DO */ &global_errmsgs[es_ES] ); /***** LOCALE END es_DO *****/ @@ -2749,8 +2749,8 @@ MY_LOCALE my_locale_es_EC 10, 9, ',', /* decimal point es_EC */ - '\0', /* thousands_sep es_EC */ - "\x80\x80", /* grouping es_EC */ + '.', /* thousands_sep es_EC */ + "\x03\x03", /* grouping es_EC */ &global_errmsgs[es_ES] ); /***** LOCALE END es_EC *****/ @@ -2769,8 +2769,8 @@ MY_LOCALE my_locale_es_GT 10, 9, '.', /* decimal point es_GT */ - '\0', /* thousands_sep es_GT */ - "\x80\x80", /* grouping es_GT */ + ',', /* thousands_sep es_GT */ + "\x03\x03", /* grouping es_GT */ &global_errmsgs[es_ES] ); /***** LOCALE END es_GT *****/ @@ -2789,8 +2789,8 @@ MY_LOCALE my_locale_es_HN 10, 9, '.', /* decimal point es_HN */ - '\0', /* thousands_sep es_HN */ - "\x80\x80", /* grouping es_HN */ + ',', /* thousands_sep es_HN */ + "\x03\x03", /* grouping es_HN */ &global_errmsgs[es_ES] ); /***** LOCALE END es_HN *****/ @@ -2809,8 +2809,8 @@ MY_LOCALE my_locale_es_MX 10, 9, '.', /* decimal point es_MX */ - '\0', /* thousands_sep es_MX */ - "\x80\x80", /* grouping es_MX */ + ',', /* thousands_sep es_MX */ + "\x03\x03", /* grouping es_MX */ &global_errmsgs[es_ES] ); /***** LOCALE END es_MX *****/ @@ -2829,8 +2829,8 @@ MY_LOCALE my_locale_es_NI 10, 9, '.', /* decimal point es_NI */ - '\0', /* thousands_sep es_NI */ - "\x80\x80", /* grouping es_NI */ + ',', /* thousands_sep es_NI */ + "\x03\x03", /* grouping es_NI */ &global_errmsgs[es_ES] ); /***** LOCALE END es_NI *****/ @@ -2849,8 +2849,8 @@ MY_LOCALE my_locale_es_PA 10, 9, '.', /* decimal point es_PA */ - '\0', /* thousands_sep es_PA */ - "\x80\x80", /* grouping es_PA */ + ',', /* thousands_sep es_PA */ + "\x03\x03", /* grouping es_PA */ &global_errmsgs[es_ES] ); /***** LOCALE END es_PA *****/ @@ -2869,8 +2869,8 @@ MY_LOCALE my_locale_es_PE 10, 9, '.', /* decimal point es_PE */ - '\0', /* thousands_sep es_PE */ - "\x80\x80", /* grouping es_PE */ + ',', /* thousands_sep es_PE */ + "\x03\x03", /* grouping es_PE */ &global_errmsgs[es_ES] ); /***** LOCALE END es_PE *****/ @@ -2889,8 +2889,8 @@ MY_LOCALE my_locale_es_PR 10, 9, '.', /* decimal point es_PR */ - '\0', /* thousands_sep es_PR */ - "\x80\x80", /* grouping es_PR */ + ',', /* thousands_sep es_PR */ + "\x03\x03", /* grouping es_PR */ &global_errmsgs[es_ES] ); /***** LOCALE END es_PR *****/ @@ -2909,8 +2909,8 @@ MY_LOCALE my_locale_es_PY 10, 9, ',', /* decimal point es_PY */ - '\0', /* thousands_sep es_PY */ - "\x80\x80", /* grouping es_PY */ + '.', /* thousands_sep es_PY */ + "\x03\x03", /* grouping es_PY */ &global_errmsgs[es_ES] ); /***** LOCALE END es_PY *****/ @@ -2929,8 +2929,8 @@ MY_LOCALE my_locale_es_SV 10, 9, '.', /* decimal point es_SV */ - '\0', /* thousands_sep es_SV */ - "\x80\x80", /* grouping es_SV */ + ',', /* thousands_sep es_SV */ + "\x03\x03", /* grouping es_SV */ &global_errmsgs[es_ES] ); /***** LOCALE END es_SV *****/ @@ -2969,8 +2969,8 @@ MY_LOCALE my_locale_es_UY 10, 9, ',', /* decimal point es_UY */ - '\0', /* thousands_sep es_UY */ - "\x80\x80", /* grouping es_UY */ + '.', /* thousands_sep es_UY */ + "\x03\x03", /* grouping es_UY */ &global_errmsgs[es_ES] ); /***** LOCALE END es_UY *****/ @@ -2989,8 +2989,8 @@ MY_LOCALE my_locale_es_VE 10, 9, ',', /* decimal point es_VE */ - '\0', /* thousands_sep es_VE */ - "\x80\x80", /* grouping es_VE */ + '.', /* thousands_sep es_VE */ + "\x03\x03", /* grouping es_VE */ &global_errmsgs[es_ES] ); /***** LOCALE END es_VE *****/ diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 330d8b668ed..980ecb2f70c 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -233,7 +233,7 @@ static struct /* support for Services */ -#include "sql_plugin_services.ic" +#include "sql_plugin_services.inl" /* A mutex LOCK_plugin must be acquired before accessing the diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.inl index c6f07158003..c6f07158003 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.inl diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index dd9c7981fcf..a88ee423203 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3040,7 +3040,6 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) } for (; sl; sl= sl->next_select_in_list()) { - sl->parent_lex->in_sum_func= NULL; if (sl->changed_elements & TOUCHED_SEL_COND) { /* remove option which was put by mysql_explain_union() */ @@ -3175,6 +3174,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) lex->result->set_thd(thd); } lex->allow_sum_func.clear_all(); + lex->in_sum_func= NULL; DBUG_VOID_RETURN; } @@ -4313,7 +4313,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) Restore original values of variables modified on handling SET STATEMENT clause. */ - thd->lex->restore_set_statement_var(); + error|= thd->lex->restore_set_statement_var(); /* The order is important */ lex->unit.cleanup(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6fdde5f82dd..a76eb2a4692 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3074,6 +3074,14 @@ setup_subq_exit: } if (make_aggr_tables_info()) DBUG_RETURN(1); + + /* + It could be that we've only done optimization stage 1 for + some of the derived tables, and never did stage 2. + Do it now, otherwise Explain data structure will not be complete. + */ + if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE)) + DBUG_RETURN(1); } /* Even with zero matching rows, subqueries in the HAVING clause may @@ -10491,7 +10499,10 @@ bool JOIN::get_best_combination() if (!(join_tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)* (top_join_tab_count + aggr_tables)))) DBUG_RETURN(TRUE); - + + if (inject_splitting_cond_for_all_tables_with_split_opt()) + DBUG_RETURN(TRUE); + JOIN_TAB_RANGE *root_range; if (!(root_range= new (thd->mem_root) JOIN_TAB_RANGE)) DBUG_RETURN(TRUE); @@ -14546,8 +14557,6 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables, DBUG_RETURN(0); } - join->join_free(); - if (send_row) { /* @@ -14594,6 +14603,14 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables, if (likely(!send_error)) result->send_eof(); // Should be safe } + /* + JOIN::join_free() must be called after the virtual method + select::send_result_set_metadata() returned control since + implementation of this method could use data strutcures + that are released by the method JOIN::join_free(). + */ + join->join_free(); + DBUG_RETURN(0); } @@ -18796,7 +18813,7 @@ bool Create_tmp_table::add_fields(THD *thd, */ item->marker == 4 || param->bit_fields_as_long, param->force_copy_fields); - if (!new_field) + if (unlikely(!new_field)) { if (unlikely(thd->is_fatal_error)) goto err; // Got OOM @@ -21126,11 +21143,8 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, */ if (shortcut_for_distinct && found_records != join->found_records) DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); - } - else - { - join->thd->get_stmt_da()->inc_current_row_for_warning(); - join_tab->read_record.unlock_row(join_tab); + + DBUG_RETURN(NESTED_LOOP_OK); } } else @@ -21140,9 +21154,11 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, with the beginning coinciding with the current partial join. */ join->join_examined_rows++; - join->thd->get_stmt_da()->inc_current_row_for_warning(); - join_tab->read_record.unlock_row(join_tab); } + + join->thd->get_stmt_da()->inc_current_row_for_warning(); + join_tab->read_record.unlock_row(join_tab); + DBUG_RETURN(NESTED_LOOP_OK); } @@ -22901,21 +22917,6 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond, cond->marker=3; // Checked when read return (COND*) 0; } - /* - If cond is an equality injected for split optimization then - a. when retain_ref_cond == false : cond is removed unconditionally - (cond that supports ref access is removed by the preceding code) - b. when retain_ref_cond == true : cond is removed if it does not - support ref access - */ - if (left_item->type() == Item::FIELD_ITEM && - is_eq_cond_injected_for_split_opt((Item_func_eq *) cond) && - (!retain_ref_cond || - !test_if_ref(root_cond, (Item_field*) left_item,right_item))) - { - cond->marker=3; - return (COND*) 0; - } } cond->marker=2; cond->set_join_tab_idx(join_tab_idx_arg); @@ -29235,6 +29236,12 @@ AGGR_OP::end_send() table->reginfo.lock_type= TL_UNLOCK; bool in_first_read= true; + + /* + Reset the counter before copying rows from internal temporary table to + INSERT table. + */ + join_tab->join->thd->get_stmt_da()->reset_current_row_for_warning(); while (rc == NESTED_LOOP_OK) { int error; diff --git a/sql/sql_select.h b/sql/sql_select.h index 29e42ff8ef8..24a2ccd8ec1 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1797,6 +1797,7 @@ public: void add_keyuses_for_splitting(); bool inject_best_splitting_cond(table_map remaining_tables); bool fix_all_splittings_in_plan(); + bool inject_splitting_cond_for_all_tables_with_split_opt(); void make_notnull_conds_for_range_scans(); bool transform_in_predicates_into_in_subq(THD *thd); diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 307a0b29c57..91ee97f7822 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -365,9 +365,14 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *org_table_list) seq->reserved_until= seq->start; error= seq->write_initial_sequence(table); - - if (trans_commit_stmt(thd)) - error= 1; + { + uint save_unsafe_rollback_flags= + thd->transaction->stmt.m_unsafe_rollback_flags; + if (trans_commit_stmt(thd)) + error= 1; + thd->transaction->stmt.m_unsafe_rollback_flags= + save_unsafe_rollback_flags; + } if (trans_commit_implicit(thd)) error= 1; @@ -905,6 +910,13 @@ bool Sql_cmd_alter_sequence::execute(THD *thd) if (check_grant(thd, ALTER_ACL, first_table, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); /* purecov: inspected */ +#ifdef WITH_WSREP + if (WSREP_ON && WSREP(thd) && + wsrep_to_isolation_begin(thd, first_table->db.str, + first_table->table_name.str, + first_table)) + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ if (if_exists()) thd->push_internal_handler(&no_such_table_handler); error= open_and_lock_tables(thd, first_table, FALSE, 0); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f4fc8d2decf..ff6ec637025 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -9201,7 +9201,7 @@ ST_FIELD_INFO stat_fields_info[]= Column("INDEX_NAME", Name(), NOT_NULL, "Key_name", OPEN_FRM_ONLY), Column("SEQ_IN_INDEX", SLonglong(2),NOT_NULL, "Seq_in_index",OPEN_FRM_ONLY), Column("COLUMN_NAME", Name(), NOT_NULL, "Column_name", OPEN_FRM_ONLY), - Column("COLLATION", Varchar(1), NULLABLE, "Collation", OPEN_FRM_ONLY), + Column("COLLATION", Varchar(1), NULLABLE, "Collation", OPEN_FULL_TABLE), Column("CARDINALITY", SLonglong(), NULLABLE, "Cardinality", OPEN_FULL_TABLE), Column("SUB_PART", SLonglong(3),NULLABLE, "Sub_part", OPEN_FRM_ONLY), Column("PACKED", Varchar(10), NULLABLE, "Packed", OPEN_FRM_ONLY), diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6956b41bdc5..129b96971ff 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2010, 2021, MariaDB + Copyright (c) 2010, 2022, 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 @@ -6039,8 +6039,15 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, #ifdef WITH_PARTITION_STORAGE_ENGINE /* Partition info is not handled by mysql_prepare_alter_table() call. */ if (src_table->table->part_info) - thd->work_part_info= src_table->table->part_info->get_clone(thd); -#endif + { + /* + The CREATE TABLE LIKE should not inherit the DATA DIRECTORY + and INDEX DIRECTORY from the base table. + So that TRUE argument for the get_clone. + */ + thd->work_part_info= src_table->table->part_info->get_clone(thd, TRUE); + } +#endif /*WITH_PARTITION_STORAGE_ENGINE*/ /* Adjust description of source table before using it for creation of @@ -8591,9 +8598,14 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, def->invisible= INVISIBLE_SYSTEM; alter_info->flags|= ALTER_CHANGE_COLUMN; if (field->flags & VERS_ROW_START) - create_info->vers_info.as_row.start= def->field_name= Vers_parse_info::default_start; + create_info->vers_info.period.start= + create_info->vers_info.as_row.start= + def->field_name= Vers_parse_info::default_start; + else - create_info->vers_info.as_row.end= def->field_name= Vers_parse_info::default_end; + create_info->vers_info.period.end= + create_info->vers_info.as_row.end= + def->field_name= Vers_parse_info::default_end; new_create_list.push_back(def, thd->mem_root); dropped_sys_vers_fields|= field->flags; drop_it.remove(); @@ -8622,9 +8634,15 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, def->field_name= alter->new_name; column_rename_param.fields.push_back(def); if (field->flags & VERS_ROW_START) + { create_info->vers_info.as_row.start= alter->new_name; + create_info->vers_info.period.start= alter->new_name; + } else if (field->flags & VERS_ROW_END) + { create_info->vers_info.as_row.end= alter->new_name; + create_info->vers_info.period.end= alter->new_name; + } if (table->s->period.name) { if (field == table->period_start_field()) @@ -12229,20 +12247,30 @@ bool Sql_cmd_create_table_like::execute(THD *thd) 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())) - { + if (WSREP(thd)) + { + handlerton *orig_ht= create_info.db_type; + if (!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())) + { #ifdef WITH_WSREP - WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, create_table->table_name.str, - first_table, &alter_info, NULL, &create_info) - { - WSREP_WARN("CREATE TABLE isolation failure"); - DBUG_RETURN(true); - } + WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, + create_table->table_name.str, + first_table, &alter_info, NULL, + &create_info) + { + WSREP_WARN("CREATE TABLE isolation failure"); + DBUG_RETURN(true); + } #endif /* WITH_WSREP */ + } + // check_engine will set db_type to NULL if e.g. TEMPORARY is + // not supported by the storage engine, this case is checked + // again in mysql_create_table + create_info.db_type= orig_ht; } /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 250ff859222..7d9dc25f483 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -292,7 +292,7 @@ class Deprecated_trigger_syntax_handler : public Internal_error_handler private: char m_message[MYSQL_ERRMSG_SIZE]; - LEX_CSTRING *m_trigger_name; + const LEX_CSTRING *m_trigger_name; public: @@ -308,8 +308,23 @@ public: if (sql_errno != EE_OUTOFMEMORY && sql_errno != ER_OUT_OF_RESOURCES) { + // Check if the current LEX contains a non-empty spname if(thd->lex->spname) m_trigger_name= &thd->lex->spname->m_name; + else if (thd->lex->sphead) + { + /* + Some SP statements, for example IF, create their own local LEX. + All LEX instances are available in the LEX stack in sphead::m_lex. + Let's find the one that contains a non-zero spname. + Note, although a parse error has happened, the LEX instances + in sphead::m_lex are not freed yet at this point. The first + found non-zero spname contains the valid trigger name. + */ + const sp_name *spname= thd->lex->sphead->find_spname_recursive(); + if (spname) + m_trigger_name= &spname->m_name; + } if (m_trigger_name) my_snprintf(m_message, sizeof(m_message), ER_THD(thd, ER_ERROR_IN_TRIGGER_BODY), @@ -322,7 +337,7 @@ public: return false; } - LEX_CSTRING *get_trigger_name() { return m_trigger_name; } + const LEX_CSTRING *get_trigger_name() { return m_trigger_name; } char *get_error_message() { return m_message; } }; @@ -1527,7 +1542,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db, if (unlikely(parse_error)) { - LEX_CSTRING *name; + const LEX_CSTRING *name; /* In case of errors, disable all triggers for the table, but keep diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 29d24649bb3..8571d893a8e 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -406,8 +406,18 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, bool res= FALSE; DBUG_ENTER("mysql_create_view"); - /* This is ensured in the parser. */ - DBUG_ASSERT(!lex->proc_list.first && !lex->result && + /* + This is ensured in the parser. + NOTE: Originally, the assert below contained the extra condition + && !lex->result + but in this form the assert is failed in case CREATE VIEW run under + cursor (the case when the byte 'flags' in the COM_STMT_EXECUTE packet has + the flag CURSOR_TYPE_READ_ONLY set). For the cursor use case + thd->lex->result is assigned a pointer to the class Select_materialize + inside the function mysql_open_cursor() just before handling of a statement + will be started and the function mysql_create_view() called. + */ + DBUG_ASSERT(!lex->proc_list.first && !lex->param_list.elements); /* diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 70fe301940d..fde7041ac85 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -34,7 +34,7 @@ #include "sql_plugin.h" #include "sql_priv.h" #include "sql_class.h" // set_var.h: THD -#include "sys_vars.ic" +#include "sys_vars.inl" #include "my_sys.h" #include "events.h" diff --git a/sql/sys_vars.ic b/sql/sys_vars.inl index 97e3a28b67e..97e3a28b67e 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.inl diff --git a/sql/table.cc b/sql/table.cc index 007c8c7cc1a..5ac4e2ed365 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8905,14 +8905,18 @@ void TABLE::vers_update_fields() return; } - if (versioned(VERS_TIMESTAMP) && - vers_start_field()->store_timestamp(in_use->query_start(), - in_use->query_start_sec_part())) + if (versioned(VERS_TIMESTAMP)) { - DBUG_ASSERT(0); + if (vers_start_field()->store_timestamp(in_use->query_start(), + in_use->query_start_sec_part())) + { + DBUG_ASSERT(0); + } + vers_start_field()->set_has_explicit_value(); } vers_end_field()->set_max(); + vers_end_field()->set_has_explicit_value(); bitmap_set_bit(read_set, vers_end_field()->field_index); file->column_bitmaps_signal(); if (vfield) @@ -8925,6 +8929,7 @@ void TABLE::vers_update_end() if (vers_end_field()->store_timestamp(in_use->query_start(), in_use->query_start_sec_part())) DBUG_ASSERT(0); + vers_end_field()->set_has_explicit_value(); } /** @@ -9234,6 +9239,24 @@ void TABLE_LIST::wrap_into_nested_join(List<TABLE_LIST> &join_list) /** + Check whether optimization has been performed and a derived table either + been merged to upper select level or materialized. + + @param table a TABLE_LIST object containing a derived table + + @return true in case the derived table has been merged to surrounding select, + false otherwise +*/ + +static inline bool derived_table_optimization_done(TABLE_LIST *table) +{ + return table->derived && + (table->derived->is_excluded() || + table->is_materialized_derived()); +} + + +/** @brief Initialize this derived table/view @@ -9283,13 +9306,15 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view) } } - if (init_view && !view) + if (init_view && !view && + !derived_table_optimization_done(this)) { /* This is all what we can do for a derived table for now. */ set_derived(); } - if (!is_view()) + if (!is_view() && + !derived_table_optimization_done(this)) { /* A subquery might be forced to be materialized due to a side-effect. */ if (!is_materialized_derived() && first_select->is_mergeable() && diff --git a/sql/table.h b/sql/table.h index 9540a4292de..6cf9113a1ae 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1765,7 +1765,9 @@ public: bool vers_check_update(List<Item> &items); static bool check_period_overlaps(const KEY &key, const uchar *lhs, const uchar *rhs); int delete_row(); + /* Used in majority of DML (called from fill_record()) */ void vers_update_fields(); + /* Used in DELETE, DUP REPLACE and insert history row */ void vers_update_end(); void find_constraint_correlated_indexes(); diff --git a/sql/tztime.cc b/sql/tztime.cc index 23c015e4a5e..0eb0de89048 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2637,24 +2637,33 @@ static struct my_option my_long_options[] = {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef DBUG_OFF - {"debug", '#', "This is a non-debug version. Catch this and exit", + {"debug", '#', "This is a non-debug version. Catch this and exit.", 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, #else {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"leap", 'l', "Print the leap second information from the given time zone file. By convention, when --leap is used the next argument is the timezonefile", + {"leap", 'l', "Print the leap second information from the given time zone file. By convention, when --leap is used the next argument is the timezonefile.", &opt_leap, &opt_leap, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Write non critical warnings", + {"verbose", 'v', "Write non critical warnings.", &opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-write-binlog", 'S', "Do not replicate changes to time zone tables to other nodes in a Galera cluster", + {"skip-write-binlog", 'S', "Do not replicate changes to time zone tables to the binary log, or to other nodes in a Galera cluster (if wsrep_on=ON).", &opt_skip_write_binlog,&opt_skip_write_binlog, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; +static char **default_argv; + +static void free_allocated_data() +{ + free_defaults(default_argv); + my_end(0); +} + + C_MODE_START static my_bool get_one_option(const struct my_option *, const char *, const char *); @@ -2666,11 +2675,21 @@ static void print_version(void) MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); } +static const char *default_timezone_dir= "/usr/share/zoneinfo/"; + + static void print_usage(void) { - fprintf(stderr, "Usage:\n"); - fprintf(stderr, " %s [options] timezonedir\n", my_progname); - fprintf(stderr, " %s [options] timezonefile timezonename\n", my_progname); + fprintf(stdout, "Create SQL commands for loading system timezeone data for " + "MariaDB\n\n"); + fprintf(stdout, "Usage:\n"); + fprintf(stdout, " %s [options] timezonedir\n", my_progname); + fprintf(stdout, "or\n"); + fprintf(stdout, " %s [options] timezonefile timezonename\n", my_progname); + + fprintf(stdout, "\nA typical place for the system timezone directory is " + "\"%s\"\n", default_timezone_dir); + print_defaults("my",load_default_groups); puts(""); my_print_help(my_long_options); @@ -2691,19 +2710,33 @@ get_one_option(const struct my_option *opt, const char *argument, const char *) print_version(); puts(""); print_usage(); + free_allocated_data(); exit(0); case 'V': print_version(); + free_allocated_data(); exit(0); } return 0; } +static const char *lock_tables= + "LOCK TABLES time_zone WRITE,\n" + " time_zone_leap_second WRITE,\n" + " time_zone_name WRITE,\n" + " time_zone_transition WRITE,\n" + " time_zone_transition_type WRITE;\n"; +static const char *trunc_tables_const= + "TRUNCATE TABLE time_zone;\n" + "TRUNCATE TABLE time_zone_name;\n" + "TRUNCATE TABLE time_zone_transition;\n" + "TRUNCATE TABLE time_zone_transition_type;\n"; + int main(int argc, char **argv) { - char **default_argv; + const char *trunc_tables; MY_INIT(argv[0]); load_defaults_or_exit("my", load_default_groups, &argc, &argv); @@ -2715,34 +2748,42 @@ main(int argc, char **argv) if ((argc != 1 && argc != 2) || (opt_leap && argc != 1)) { print_usage(); - free_defaults(default_argv); + free_allocated_data(); return 1; } + if (!(argc == 1 && !opt_leap)) + trunc_tables= "SELECT 'skip truncate tables';\n"; // No-op - needed for ELSE clause + else + trunc_tables= trunc_tables_const; + if (opt_skip_write_binlog) - { /* If skip_write_binlog is set and wsrep is compiled in we disable sql_log_bin and wsrep_on to avoid Galera replicating below - truncate table clauses. This will allow user to set different + TRUNCATE TABLE clauses. This will allow user to set different time zones to nodes in Galera cluster. */ printf("set @prep1=if((select count(*) from information_schema.global_variables where variable_name='wsrep_on' and variable_value='ON'), 'SET SESSION SQL_LOG_BIN=?, WSREP_ON=OFF;', 'do ?');\n" "prepare set_wsrep_write_binlog from @prep1;\n" - "set @toggle=0; execute set_wsrep_write_binlog using @toggle;\n"); - } + "set @toggle=0; execute set_wsrep_write_binlog using @toggle;\n" + "%s%s", trunc_tables, lock_tables); else - { - // Alter time zone tables to InnoDB if wsrep_on is enabled - // to allow changes to them to replicate with Galera - printf("\\d |\n" - "IF (select count(*) from information_schema.global_variables where\n" - "variable_name='wsrep_on' and variable_value='ON') = 1 THEN\n" - "ALTER TABLE time_zone ENGINE=InnoDB;\n" - "ALTER TABLE time_zone_name ENGINE=InnoDB;\n" - "ALTER TABLE time_zone_transition ENGINE=InnoDB;\n" - "ALTER TABLE time_zone_transition_type ENGINE=InnoDB;\n" - "END IF|\n" - "\\d ;\n"); - } + // Alter time zone tables to InnoDB if wsrep_on is enabled + // to allow changes to them to replicate with Galera + printf("\\d |\n" + "IF (select count(*) from information_schema.global_variables where\n" + "variable_name='wsrep_on' and variable_value='ON') = 1 THEN\n" + "ALTER TABLE time_zone ENGINE=InnoDB;\n" + "ALTER TABLE time_zone_name ENGINE=InnoDB;\n" + "ALTER TABLE time_zone_transition ENGINE=InnoDB;\n" + "ALTER TABLE time_zone_transition_type ENGINE=InnoDB;\n" + "%s" + "START TRANSACTION;\n" + "ELSE\n%s" + "END IF|\n" + "\\d ;\n", + trunc_tables, trunc_tables); + // Ideally we'd like to put lock_tables in the ELSE branch however + // "ERROR 1314 (0A000) at line 2: LOCK is not allowed in stored procedures" if (argc == 1 && !opt_leap) { @@ -2750,12 +2791,6 @@ main(int argc, char **argv) root_name_end= strmake_buf(fullname, argv[0]); - printf("TRUNCATE TABLE time_zone;\n"); - printf("TRUNCATE TABLE time_zone_name;\n"); - printf("TRUNCATE TABLE time_zone_transition;\n"); - printf("TRUNCATE TABLE time_zone_transition_type;\n"); - printf("START TRANSACTION;\n"); - if (scan_tz_dir(root_name_end, 0, opt_verbose)) { printf("ROLLBACK;\n"); @@ -2766,7 +2801,8 @@ main(int argc, char **argv) return 1; } - printf("COMMIT;\n"); + printf("UNLOCK TABLES;\n" + "COMMIT;\n"); printf("ALTER TABLE time_zone_transition " "ORDER BY Time_zone_id, Transition_time;\n"); printf("ALTER TABLE time_zone_transition_type " @@ -2790,25 +2826,24 @@ main(int argc, char **argv) print_tz_leaps_as_sql(&tz_info); else print_tz_as_sql(argv[1], &tz_info); - + printf("UNLOCK TABLES;\n" + "COMMIT;\n"); free_root(&tz_storage, MYF(0)); } if(!opt_skip_write_binlog) - { - // Fall back to Aria - printf("\\d |\n" - "IF (select count(*) from information_schema.global_variables where\n" - "variable_name='wsrep_on' and variable_value='ON') = 1 THEN\n" - "ALTER TABLE time_zone ENGINE=Aria;\n" - "ALTER TABLE time_zone_name ENGINE=Aria;\n" - "ALTER TABLE time_zone_transition ENGINE=Aria;\n" - "ALTER TABLE time_zone_transition_type ENGINE=Aria;\n" - "END IF|\n" - "\\d ;\n"); - } - - free_defaults(default_argv); + // Fall back to Aria + printf("\\d |\n" + "IF (select count(*) from information_schema.global_variables where\n" + "variable_name='wsrep_on' and variable_value='ON') = 1 THEN\n" + "ALTER TABLE time_zone ENGINE=Aria;\n" + "ALTER TABLE time_zone_name ENGINE=Aria;\n" + "ALTER TABLE time_zone_transition ENGINE=Aria, ORDER BY Time_zone_id, Transition_time;\n" + "ALTER TABLE time_zone_transition_type ENGINE=Aria, ORDER BY Time_zone_id, Transition_type_id;\n" + "END IF|\n" + "\\d ;\n"); + + free_allocated_data(); my_end(0); return 0; } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 0784b1afc17..00d8c55eb16 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1301,14 +1301,23 @@ wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* tables, wsrep::key_array* key bool fail= false; TABLE_LIST *table; + for (table= tables; table; table= table->next_local) + { + if (is_temporary_table(table)) + { + WSREP_DEBUG("Temporary table %s.%s already opened query=%s", table->db.str, + table->table_name.str, wsrep_thd_query(thd)); + return false; + } + } + thd->release_transactional_locks(); uint counter; MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); - if (thd->open_temporary_tables(tables) || - open_tables(thd, &tables, &counter, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)) + if (open_tables(thd, &tables, &counter, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)) { - WSREP_DEBUG("unable to open table for FK checks for %s", thd->query()); + WSREP_DEBUG("Unable to open table for FK checks for %s", wsrep_thd_query(thd)); fail= true; goto exit; } @@ -2963,21 +2972,17 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, } else { - /* here we have CREATE TABLE LIKE <temporary table> - the temporary table definition will be needed in slaves to - enable the create to succeed - */ - TABLE_LIST tbl; - bzero((void*) &tbl, sizeof(tbl)); - tbl.db= src_table->db; - tbl.table_name= tbl.alias= src_table->table_name; - tbl.table= src_table->table; + /* Non-MERGE tables ignore this call. */ + if (src_table->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST)) + return (true); + char buf[2048]; String query(buf, sizeof(buf), system_charset_info); query.length(0); // Have to zero it since constructor doesn't - (void) show_create_table(thd, &tbl, &query, NULL, WITH_DB_NAME); - WSREP_DEBUG("TMP TABLE: %s", query.ptr()); + int result __attribute__((unused))= + show_create_table(thd, src_table, &query, NULL, WITH_DB_NAME); + WSREP_DEBUG("TMP TABLE: %s ret_code %d", query.ptr(), result); thd->wsrep_TOI_pre_query= query.ptr(); thd->wsrep_TOI_pre_query_len= query.length(); @@ -2986,6 +2991,9 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, thd->wsrep_TOI_pre_query= NULL; thd->wsrep_TOI_pre_query_len= 0; + + /* Non-MERGE tables ignore this call. */ + src_table->table->file->extra(HA_EXTRA_DETACH_CHILDREN); } return(false); diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index fe45c4d1711..591a2f17bc2 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -623,9 +623,11 @@ static int init_for_index_scan(TABLE* table, const uchar* key, */ static int end_index_scan(TABLE* table) { int error; - if ((error= table->file->ha_index_end())) { - WSREP_ERROR("Failed to end scan: %d", error); - return 1; + if (table->file->inited) { + if ((error= table->file->ha_index_end())) { + WSREP_ERROR("Failed to end scan: %d", error); + return 1; + } } return 0; } |