diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-08-04 07:55:16 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-08-04 07:55:16 +0300 |
commit | 9a7948e3f6d3fd7528e49f43eb4d41f8f55c8a35 (patch) | |
tree | 68f8e54f6c2484dc7791bee8c594d3d07c611d29 /sql | |
parent | 56990b18d914b8150c9f777d134724d2b3390360 (diff) | |
parent | bbd70fcc43cc889e4593594ee5ca436fe1433aac (diff) | |
download | mariadb-git-9a7948e3f6d3fd7528e49f43eb4d41f8f55c8a35.tar.gz |
Merge 10.5 into 10.6
Diffstat (limited to 'sql')
82 files changed, 1553 insertions, 783 deletions
diff --git a/sql/field.cc b/sql/field.cc index e73cc380196..8cd619571c4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -57,7 +57,7 @@ const char field_separator=','; #define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \ ((ulong) ((1LL << MY_MIN(arg, 4) * 8) - 1)) -// Column marked for read or the field set to read out or record[0] or [1] +// Column marked for read or the field set to read out of record[0] bool Field::marked_for_read() const { return !table || @@ -68,7 +68,7 @@ bool Field::marked_for_read() const } /* - The name of this function is a bit missleading as in 10.4 we don't + The name of this function is a bit misleading as in 10.4 we don't have to test anymore if the field is computed. Instead we mark changed fields with DBUG_FIX_WRITE_SET() in table.cc */ @@ -1078,17 +1078,16 @@ Field_longstr::make_packed_sort_key_part(uchar *buff, *buff++=1; } uchar *end= pack_sort_string(buff, sort_field); - return static_cast<int>(end-buff); + return (uint) (end-buff); } uchar* Field_longstr::pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field) { - String buf; + StringBuffer<LONGLONG_BUFFER_SIZE> buf; val_str(&buf, &buf); - return to + sort_field->pack_sort_string(to, buf.lex_cstring(), - field_charset()); + return to + sort_field->pack_sort_string(to, &buf); } @@ -2106,7 +2105,7 @@ void Field::make_send_field(Send_field *field) field->org_table_name= field->db_name= empty_clex_str; if (orig_table && orig_table->alias.ptr()) { - field->table_name= orig_table->alias.lex_cstring(); + orig_table->alias.get_value(&field->table_name); field->org_col_name= field_name; } else @@ -2402,7 +2401,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) bool Field::get_date(MYSQL_TIME *to, date_mode_t mode) { StringBuffer<40> tmp; - Temporal::Warn_push warn(get_thd(), NULL, NullS, to, mode); + Temporal::Warn_push warn(get_thd(), nullptr, nullptr, nullptr, to, mode); Temporal_hybrid *t= new(to) Temporal_hybrid(get_thd(), &warn, val_str(&tmp), mode); return !t->is_valid_temporal(); @@ -10888,14 +10887,16 @@ void Field::set_datetime_warning(Sql_condition::enum_warning_level level, if (thd->really_abort_on_warning() && level >= Sql_condition::WARN_LEVEL_WARN) { /* - field_str.name can be NULL when field is not in the select list: + field_name.str can be NULL when field is not in the select list: SET SESSION SQL_MODE= 'STRICT_ALL_TABLES,NO_ZERO_DATE'; CREATE OR REPLACE TABLE t2 SELECT 1 AS f FROM t1 GROUP BY FROM_DAYS(d); Can't call push_warning_truncated_value_for_field() directly here, as it expect a non-NULL name. */ thd->push_warning_wrong_or_truncated_value(level, false, typestr, - str->ptr(), table->s, + str->ptr(), + table->s->db.str, + table->s->table_name.str, field_name.str); } else diff --git a/sql/filesort.cc b/sql/filesort.cc index 03af9c7b49a..1e811473a32 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -316,7 +316,8 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, while (memory_available >= min_sort_memory) { ulonglong keys= memory_available / (param.rec_length + sizeof(char*)); - param.max_keys_per_buffer= (uint) MY_MIN(num_rows, keys); + param.max_keys_per_buffer= (uint) MY_MAX(MERGEBUFF2, + MY_MIN(num_rows, keys)); sort->alloc_sort_buffer(param.max_keys_per_buffer, param.rec_length); if (sort->sort_buffer_size() > 0) break; @@ -2110,9 +2111,7 @@ Type_handler_string_result::sort_length(THD *thd, SORT_FIELD_ATTR *sortorder) const { CHARSET_INFO *cs; - sortorder->length= item->max_length; - set_if_smaller(sortorder->length, thd->variables.max_sort_length); - sortorder->original_length= item->max_length; + sortorder->set_length_and_original_length(thd, item->max_length); if (use_strnxfrm((cs= item->collation.collation))) { @@ -2219,9 +2218,9 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys) { Field *field= sortorder->field; CHARSET_INFO *cs= sortorder->field->sort_charset(); - sortorder->length= sortorder->field->sort_length(); + sortorder->set_length_and_original_length(thd, field->sort_length()); + sortorder->suffix_length= sortorder->field->sort_suffix_length(); - sortorder->original_length= sortorder->length; sortorder->type= field->is_packable() ? SORT_FIELD_ATTR::VARIABLE_SIZE : SORT_FIELD_ATTR::FIXED_SIZE; @@ -2554,7 +2553,6 @@ Type_handler_string_result::make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const { - CHARSET_INFO *cs= item->collation.collation; bool maybe_null= item->maybe_null; if (maybe_null) @@ -2584,7 +2582,7 @@ Type_handler_string_result::make_packed_sort_key_part(uchar *to, Item *item, return sort_field->original_length; } } - return sort_field->pack_sort_string(to, res->lex_cstring(), cs); + return sort_field->pack_sort_string(to, res); } @@ -2757,6 +2755,14 @@ bool SORT_FIELD_ATTR::check_if_packing_possible(THD *thd) const } +void SORT_FIELD_ATTR::set_length_and_original_length(THD *thd, uint length_arg) +{ + length= length_arg; + set_if_smaller(length, thd->variables.max_sort_length); + original_length= length_arg; +} + + /* Compare function used for packing sort keys */ @@ -2940,13 +2946,12 @@ int compare_packed_sort_keys(void *sort_param, */ uint -SORT_FIELD_ATTR::pack_sort_string(uchar *to, const LEX_CSTRING &str, - CHARSET_INFO *cs) const +SORT_FIELD_ATTR::pack_sort_string(uchar *to, String *str) const { uchar *orig_to= to; uint32 length, data_length; - DBUG_ASSERT(str.length <= UINT32_MAX); - length= (uint32)str.length; + DBUG_ASSERT(str->length() <= UINT32_MAX); + length= (uint32) str->length(); if (length + suffix_length <= original_length) data_length= length; @@ -2957,13 +2962,13 @@ SORT_FIELD_ATTR::pack_sort_string(uchar *to, const LEX_CSTRING &str, store_key_part_length(data_length + suffix_length, to, length_bytes); to+= length_bytes; // copying data length bytes to the buffer - memcpy(to, (uchar*)str.str, data_length); + memcpy(to, (uchar*)str->ptr(), data_length); to+= data_length; - if (cs == &my_charset_bin && suffix_length) + if (str->charset() == &my_charset_bin && suffix_length) { // suffix length stored in bigendian form - store_bigendian(str.length, to, suffix_length); + store_bigendian(length, to, suffix_length); to+= suffix_length; } return static_cast<uint>(to - orig_to); diff --git a/sql/filesort_utils.cc b/sql/filesort_utils.cc index 27f37d1d507..5a51300a0fa 100644 --- a/sql/filesort_utils.cc +++ b/sql/filesort_utils.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2020, 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 @@ -108,14 +109,6 @@ uchar *Filesort_buffer::alloc_sort_buffer(uint num_records, buff_size= ALIGN_SIZE(num_records * (record_length + sizeof(uchar*))); - /* - The minimum memory required should be each merge buffer can hold atmost - one key. - TODO varun: move this to the place where min_sort_memory is used. - */ - set_if_bigger(buff_size, - ALIGN_SIZE((record_length +sizeof(uchar*)) * MERGEBUFF2)); - if (m_rawmem) { /* diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index f5eab028755..307f7ff24af 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5712,8 +5712,9 @@ extern "C" int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2) { return res; } - if ((res= file->m_file[0]->cmp_ref(ref1 + PARTITION_BYTES_IN_POS + file->m_rec_length, - ref2 + PARTITION_BYTES_IN_POS + file->m_rec_length))) + if ((res= file->get_open_file_sample()->cmp_ref(ref1 + + PARTITION_BYTES_IN_POS + file->m_rec_length, + ref2 + PARTITION_BYTES_IN_POS + file->m_rec_length))) { return res; } @@ -9744,7 +9745,7 @@ uint8 ha_partition::table_cache_type() { DBUG_ENTER("ha_partition::table_cache_type"); - DBUG_RETURN(m_file[0]->table_cache_type()); + DBUG_RETURN(get_open_file_sample()->table_cache_type()); } diff --git a/sql/handler.cc b/sql/handler.cc index ace58869145..58f1c60edf9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -188,7 +188,7 @@ private: static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, - bool is_real_trans); + bool is_real_trans, bool rw_trans); static plugin_ref ha_default_plugin(THD *thd) @@ -1621,39 +1621,9 @@ int ha_commit_trans(THD *thd, bool all) /* rw_trans is TRUE when we in a transaction changing data */ bool rw_trans= is_real_trans && (rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U)); - MDL_request mdl_request; - mdl_request.ticket= 0; DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d", is_real_trans, rw_trans, rw_ha_count)); - /* - We need to test maria_hton because of plugin_innodb.test that changes - the plugin table to innodb and thus plugin_load will call - mysql_close_tables() which calls trans_commit_trans() with maria_hton = 0 - */ - if (rw_trans) - { - /* - Acquire a metadata lock which will ensure that COMMIT is blocked - by an active FLUSH TABLES WITH READ LOCK (and vice versa: - COMMIT in progress blocks FTWRL). - - We allow the owner of FTWRL to COMMIT; we assume that it knows - what it does. - */ - MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, - MDL_EXPLICIT); - - if (!WSREP(thd) && - thd->mdl_context.acquire_lock(&mdl_request, - thd->variables.lock_wait_timeout)) - { - ha_rollback_trans(thd, all); - DBUG_RETURN(1); - } - - DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); - } if (rw_trans && opt_readonly && !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) && @@ -1693,7 +1663,7 @@ int ha_commit_trans(THD *thd, bool all) // Here, the call will not commit inside InnoDB. It is only working // around closing thd->transaction.stmt open by TR_table::open(). if (all) - commit_one_phase_2(thd, false, &thd->transaction->stmt, false); + commit_one_phase_2(thd, false, &thd->transaction->stmt, false, false); } } #endif @@ -1713,7 +1683,7 @@ int ha_commit_trans(THD *thd, bool all) goto wsrep_err; } #endif /* WITH_WSREP */ - error= ha_commit_one_phase(thd, all); + error= ha_commit_one_phase(thd, all, rw_trans); #ifdef WITH_WSREP // Here in case of error we must return 2 for inconsistency if (run_wsrep_hooks && !error) @@ -1750,7 +1720,7 @@ int ha_commit_trans(THD *thd, bool all) if (!is_real_trans) { - error= commit_one_phase_2(thd, all, trans, is_real_trans); + error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans); goto done; } @@ -1784,7 +1754,7 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order"); DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE();); - error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0; + error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans) ? 2 : 0; #ifdef WITH_WSREP if (run_wsrep_hooks && (error || (error = wsrep_after_commit(thd, all)))) @@ -1848,22 +1818,16 @@ err: ha_rollback_trans(thd, all); else { + /* + We are not really doing a rollback here, but the code in trans_commit() + requres that m_transaction_psi is 0 when we return from this function. + */ MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi); thd->m_transaction_psi= NULL; WSREP_DEBUG("rollback skipped %p %d",thd->rgi_slave, thd->rgi_slave->is_parallel_exec); } end: - if (mdl_request.ticket) - { - /* - We do not always immediately release transactional locks - after ha_commit_trans() (see uses of ha_enable_transaction()), - thus we release the commit blocker lock as soon as it's - not needed. - */ - thd->mdl_context.release_lock(mdl_request.ticket); - } #ifdef WITH_WSREP if (wsrep_is_active(thd) && is_real_trans && !error && (rw_ha_count == 0 || all) && @@ -1879,6 +1843,7 @@ end: /** @note This function does not care about global read lock. A caller should. + However backup locks are handled in commit_one_phase_2. @param[in] all Is set in case of explicit commit (COMMIT statement), or implicit commit @@ -1887,7 +1852,7 @@ end: autocommit=1. */ -int ha_commit_one_phase(THD *thd, bool all) +int ha_commit_one_phase(THD *thd, bool all, bool rw_trans) { THD_TRANS *trans=all ? &thd->transaction->all : &thd->transaction->stmt; /* @@ -1913,20 +1878,48 @@ int ha_commit_one_phase(THD *thd, bool all) if ((res= thd->wait_for_prior_commit())) DBUG_RETURN(res); } - res= commit_one_phase_2(thd, all, trans, is_real_trans); + res= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans); DBUG_RETURN(res); } static int -commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) +commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans, + bool rw_trans) { int error= 0; uint count= 0; Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; + MDL_request mdl_request; + mdl_request.ticket= 0; DBUG_ENTER("commit_one_phase_2"); if (is_real_trans) DEBUG_SYNC(thd, "commit_one_phase_2"); + + if (rw_trans) + { + /* + Acquire a metadata lock which will ensure that COMMIT is blocked + by an active FLUSH TABLES WITH READ LOCK (and vice versa: + COMMIT in progress blocks FTWRL). + + We allow the owner of FTWRL to COMMIT; we assume that it knows + what it does. + */ + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, + MDL_EXPLICIT); + + if (!WSREP(thd) && + thd->mdl_context.acquire_lock(&mdl_request, + thd->variables.lock_wait_timeout)) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1); + ha_rollback_trans(thd, all); + DBUG_RETURN(1); + } + DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); + } + if (ha_info) { for (; ha_info; ha_info= ha_info_next) @@ -1955,6 +1948,17 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) #endif } } + if (mdl_request.ticket) + { + /* + We do not always immediately release transactional locks + after ha_commit_trans() (see uses of ha_enable_transaction()), + thus we release the commit blocker lock as soon as it's + not needed. + */ + thd->mdl_context.release_lock(mdl_request.ticket); + } + /* Free resources and perform other cleanup even for 'empty' transactions. */ if (is_real_trans) { diff --git a/sql/handler.h b/sql/handler.h index 0f72a394333..e3831eacd7a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2514,6 +2514,9 @@ public: /** true for online operation (LOCK=NONE) */ bool online; + /** which ALGORITHM and LOCK are supported by the storage engine */ + enum_alter_inplace_result inplace_supported; + /** Can be set by handler to describe why a given operation cannot be done in-place (HA_ALTER_INPLACE_NOT_SUPPORTED) or why it cannot be done @@ -5176,7 +5179,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); /* transactions: interface to handlerton functions */ int ha_start_consistent_snapshot(THD *thd); int ha_commit_or_rollback_by_xid(XID *xid, bool commit); -int ha_commit_one_phase(THD *thd, bool all); +int ha_commit_one_phase(THD *thd, bool all, bool rw_trans); int ha_commit_trans(THD *thd, bool all); int ha_rollback_trans(THD *thd, bool all); int ha_prepare(THD *thd); diff --git a/sql/item.cc b/sql/item.cc index 9b321103e07..3ea1a493db2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1394,9 +1394,11 @@ bool Item::get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate bool Item::get_date_from_string(THD *thd, MYSQL_TIME *to, date_mode_t mode) { - StringBuffer<40> tmp; - Temporal::Warn_push warn(thd, field_table_or_null(), field_name_or_null(), - to, mode); + StringBuffer<MAX_DATETIME_FULL_WIDTH+1> tmp; + const TABLE_SHARE *s = field_table_or_null(); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name_or_null(), to, mode); Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, val_str(&tmp), mode); return !t->is_valid_temporal(); } @@ -2076,7 +2078,7 @@ Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val): Item::maybe_null= TRUE; if (name_item->basic_const_item() && (name_str= name_item->val_str(&name_buffer))) // Can't have a NULL name - set_name(thd, name_str->lex_cstring(), name_str->charset()); + set_name(thd, name_str); } @@ -2430,7 +2432,7 @@ bool DTCollation::aggregate(const DTCollation &dt, uint flags) { if (derivation == DERIVATION_EXPLICIT) { - set(0, DERIVATION_NONE, 0); + set(0, DERIVATION_NONE, MY_REPERTOIRE_NONE); return 1; } if (collation->state & MY_CS_BINSORT && @@ -2562,14 +2564,7 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, bool res= FALSE; uint i; - /* - In case we're in statement prepare, create conversion item - in its memory: it will be reused on each execute. - */ - Query_arena backup; - Query_arena *arena= thd->stmt_arena->is_stmt_prepare() ? - thd->activate_stmt_arena_if_needed(&backup) : - NULL; + DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare()); for (i= 0, arg= args; i < nargs; i++, arg+= item_sep) { @@ -2591,20 +2586,8 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, res= TRUE; break; // we cannot return here, we need to restore "arena". } - /* - If in statement prepare, then we create a converter for two - constant items, do it once and then reuse it. - If we're in execution of a prepared statement, arena is NULL, - and the conv was created in runtime memory. This can be - the case only if the argument is a parameter marker ('?'), - because for all true constants the charset converter has already - been created in prepare. In this case register the change for - rollback. - */ - if (thd->stmt_arena->is_stmt_prepare()) - *arg= conv; - else - thd->change_item_tree(arg, conv); + + thd->change_item_tree(arg, conv); if (conv->fix_fields_if_needed(thd, arg)) { @@ -2612,8 +2595,6 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, break; // we cannot return here, we need to restore "arena". } } - if (arena) - thd->restore_active_arena(arena, &backup); return res; } @@ -3626,9 +3607,10 @@ String *Item_int::val_str(String *str) void Item_int::print(String *str, enum_query_type query_type) { + StringBuffer<LONGLONG_BUFFER_SIZE> buf; // my_charset_bin is good enough for numbers - str_value.set_int(value, unsigned_flag, &my_charset_bin); - str->append(str_value); + buf.set_int(value, unsigned_flag, &my_charset_bin); + str->append(buf); } @@ -3654,21 +3636,6 @@ Item_uint::Item_uint(THD *thd, const char *str_arg, longlong i, uint length): } -String *Item_uint::val_str(String *str) -{ - str->set((ulonglong) value, collation.collation); - return str; -} - - -void Item_uint::print(String *str, enum_query_type query_type) -{ - // latin1 is good enough for numbers - str_value.set((ulonglong) value, default_charset()); - str->append(str_value); -} - - Item_decimal::Item_decimal(THD *thd, const char *str_arg, size_t length, CHARSET_INFO *charset): Item_num(thd) @@ -3911,7 +3878,7 @@ Item_null::make_string_literal_concat(THD *thd, const LEX_CSTRING *str) if (str->length) { CHARSET_INFO *cs= thd->variables.collation_connection; - uint repertoire= my_string_repertoire(cs, str->str, str->length); + my_repertoire_t repertoire= my_string_repertoire(cs, str->str, str->length); return new (thd->mem_root) Item_string(thd, str->str, (uint) str->length, cs, DERIVATION_COERCIBLE, repertoire); @@ -4156,7 +4123,7 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type, { ErrConvTime str(&value.time); make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, - &str, time_type, 0, 0); + &str, time_type, NULL, NULL, NULL); set_zero_time(&value.time, time_type); } maybe_null= 0; @@ -6688,8 +6655,9 @@ int Item_string::save_in_field(Field *field, bool no_conversions) Item *Item_string::clone_item(THD *thd) { - return new (thd->mem_root) - Item_string(thd, name, str_value.lex_cstring(), collation.collation); + LEX_CSTRING val; + str_value.get_value(&val); + return new (thd->mem_root) Item_string(thd, name, val, collation.collation); } diff --git a/sql/item.h b/sql/item.h index 8118b079ca1..150d9cd215e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -962,6 +962,10 @@ public: #endif } /*lint -e1509 */ void set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs); + void set_name(THD *thd, String *str) + { + set_name(thd, str->ptr(), str->length(), str->charset()); + } void set_name(THD *thd, const LEX_CSTRING &str, CHARSET_INFO *cs= system_charset_info) { @@ -1841,6 +1845,18 @@ public: */ virtual void top_level_item() {} /* + Return TRUE if it is item of top WHERE level (AND/OR) and it is + important, return FALSE if it not important (we can not use to simplify + calculations) or not top level + */ + virtual bool is_top_level_item() const + { return FALSE; /* not important */} + /* + return IN/ALL/ANY subquery or NULL + */ + virtual Item_in_subselect* get_IN_subquery() + { return NULL; /* in is not IN/ALL/ANY */ } + /* set field of temporary table for Item which can be switched on temporary table during query processing (grouping and so on) */ @@ -2435,7 +2451,8 @@ public: } bool pushable_cond_checker_for_subquery(uchar *arg) { - return excl_dep_on_in_subq_left_part((Item_in_subselect *)arg); + DBUG_ASSERT(((Item*) arg)->get_IN_subquery()); + return excl_dep_on_in_subq_left_part(((Item*)arg)->get_IN_subquery()); } Item *build_pushable_cond(THD *thd, Pushdown_checker checker, @@ -2754,12 +2771,15 @@ protected: { my_string_metadata_get(this, str->charset(), str->ptr(), str->length()); } - Metadata(const String *str, uint repertoire_arg) + Metadata(const String *str, my_repertoire_t repertoire_arg) { MY_STRING_METADATA::repertoire= repertoire_arg; MY_STRING_METADATA::char_length= str->numchars(); } - uint repertoire() const { return MY_STRING_METADATA::repertoire; } + my_repertoire_t repertoire() const + { + return MY_STRING_METADATA::repertoire; + } size_t char_length() const { return MY_STRING_METADATA::char_length; } }; void fix_charset_and_length(CHARSET_INFO *cs, @@ -4222,9 +4242,7 @@ public: Item_uint(THD *thd, ulonglong i): Item_int(thd, i, 10) {} Item_uint(THD *thd, const char *str_arg, longlong i, uint length); double val_real() { return ulonglong2double((ulonglong)value); } - String *val_str(String*); Item *clone_item(THD *thd); - virtual void print(String *str, enum_query_type query_type); Item *neg(THD *thd); uint decimal_precision() const { return max_length; } Item *get_copy(THD *thd) @@ -4363,7 +4381,7 @@ protected: const Metadata metadata) { fix_from_value(dv, metadata); - set_name(thd, str_value.lex_cstring(), str_value.charset()); + set_name(thd, &str_value); } protected: /* Just create an item and do not fill string representation */ @@ -4387,7 +4405,7 @@ public: } // Constructors with the item name set from its value Item_string(THD *thd, const char *str, uint length, CHARSET_INFO *cs, - Derivation dv, uint repertoire) + Derivation dv, my_repertoire_t repertoire) :Item_literal(thd) { str_value.set_or_copy_aligned(str, length, cs); @@ -4401,7 +4419,7 @@ public: fix_and_set_name_from_value(thd, dv, Metadata(&str_value)); } Item_string(THD *thd, const String *str, CHARSET_INFO *tocs, uint *conv_errors, - Derivation dv, uint repertoire) + Derivation dv, my_repertoire_t repertoire) :Item_literal(thd) { if (str_value.copy(str, tocs, conv_errors)) @@ -4419,7 +4437,7 @@ public: set_name(thd, name_par); } Item_string(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str, - CHARSET_INFO *cs, Derivation dv, uint repertoire) + CHARSET_INFO *cs, Derivation dv, my_repertoire_t repertoire) :Item_literal(thd) { str_value.set_or_copy_aligned(str.str, str.length, cs); @@ -4552,7 +4570,7 @@ public: Item_static_string_func(THD *thd, const LEX_CSTRING &name_par, const String *str, CHARSET_INFO *tocs, uint *conv_errors, - Derivation dv, uint repertoire): + Derivation dv, my_repertoire_t repertoire): Item_string(thd, str, tocs, conv_errors, dv, repertoire), func_name(name_par) {} diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 24914accc6f..8203af5c7dc 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1197,11 +1197,9 @@ longlong Item_func_truth::val_int() } -bool Item_in_optimizer::is_top_level_item() +bool Item_in_optimizer::is_top_level_item() const { - if (invisible_mode()) - return FALSE; - return ((Item_in_subselect *)args[1])->is_top_level_item(); + return args[1]->is_top_level_item(); } @@ -1265,10 +1263,9 @@ void Item_in_optimizer::print(String *str, enum_query_type query_type) void Item_in_optimizer::restore_first_argument() { - if (!invisible_mode()) - { - args[0]= ((Item_in_subselect *)args[1])->left_expr; - } + Item_in_subselect *in_subs= args[1]->get_IN_subquery(); + if (in_subs) + args[0]= in_subs->left_exp(); } @@ -1292,8 +1289,8 @@ bool Item_in_optimizer::fix_left(THD *thd) the pointer to the post-transformation item. Because of that, on the next execution we need to copy args[1]->left_expr again. */ - ref0= &(((Item_in_subselect *)args[1])->left_expr); - args[0]= ((Item_in_subselect *)args[1])->left_expr; + ref0= args[1]->get_IN_subquery()->left_exp_ptr(); + args[0]= (*ref0); } if ((*ref0)->fix_fields_if_needed(thd, ref0) || (!cache && !(cache= (*ref0)->get_cache(thd)))) @@ -1419,9 +1416,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) bool Item_in_optimizer::invisible_mode() { /* MAX/MIN transformed or EXISTS->IN prepared => do nothing */ - return (args[1]->type() != Item::SUBSELECT_ITEM || - ((Item_subselect *)args[1])->substype() == - Item_subselect::EXISTS_SUBS); + return (args[1]->get_IN_subquery() == NULL); } @@ -1583,7 +1578,7 @@ longlong Item_in_optimizer::val_int() "<outer_value_list> [NOT] IN (SELECT <inner_value_list>...)" where one or more of the outer values is NULL. */ - if (((Item_in_subselect*)args[1])->is_top_level_item()) + if (args[1]->is_top_level_item()) { /* We're evaluating a top level item, e.g. @@ -1606,7 +1601,7 @@ longlong Item_in_optimizer::val_int() SELECT evaluated over the non-NULL values produces at least one row, FALSE otherwise */ - Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; + Item_in_subselect *item_subs= args[1]->get_IN_subquery(); bool all_left_cols_null= true; const uint ncols= cache->cols(); @@ -1752,8 +1747,7 @@ Item *Item_in_optimizer::transform(THD *thd, Item_transformer transformer, ((Item_subselect*)(args[1]))->substype() == Item_subselect::ANY_SUBS)); - Item_in_subselect *in_arg= (Item_in_subselect*)args[1]; - thd->change_item_tree(&in_arg->left_expr, args[0]); + thd->change_item_tree(args[1]->get_IN_subquery()->left_exp_ptr(), args[0]); } return (this->*transformer)(thd, argument); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 6d02d6642e2..b943bfc90da 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -367,36 +367,37 @@ public: Item_bool_func(thd, a, b), cache(0), expr_cache(0), save_cache(0), result_for_null_param(UNKNOWN) { m_with_subquery= true; } - bool fix_fields(THD *, Item **); + bool fix_fields(THD *, Item **) override; bool fix_left(THD *thd); - table_map not_null_tables() const { return 0; } - bool is_null(); - longlong val_int(); - void cleanup(); - enum Functype functype() const { return IN_OPTIMIZER_FUNC; } - const char *func_name() const { return "<in_optimizer>"; } + table_map not_null_tables() const override { return 0; } + bool is_null() override; + longlong val_int() override; + void cleanup() override; + enum Functype functype() const override { return IN_OPTIMIZER_FUNC; } + const char *func_name() const override { return "<in_optimizer>"; } Item_cache **get_cache() { return &cache; } void keep_top_level_cache(); - Item *transform(THD *thd, Item_transformer transformer, uchar *arg); - virtual Item *expr_cache_insert_transformer(THD *thd, uchar *unused); - bool is_expensive_processor(void *arg); - bool is_expensive(); - void set_join_tab_idx(uint join_tab_idx_arg) + Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override; + Item *expr_cache_insert_transformer(THD *thd, uchar *unused) override; + bool is_expensive_processor(void *arg) override; + bool is_expensive() override; + void set_join_tab_idx(uint join_tab_idx_arg) override { args[1]->set_join_tab_idx(join_tab_idx_arg); } - virtual void get_cache_parameters(List<Item> ¶meters); - bool is_top_level_item(); - bool eval_not_null_tables(void *opt_arg); - bool find_not_null_fields(table_map allowed); - void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); + void get_cache_parameters(List<Item> ¶meters) override; + bool is_top_level_item() const override; + bool eval_not_null_tables(void *opt_arg) override; + bool find_not_null_fields(table_map allowed) override; + void fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) override; bool invisible_mode(); void reset_cache() { cache= NULL; } - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type) override; void restore_first_argument(); Item* get_wrapped_in_subselect_item() { return args[1]; } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy<Item_in_optimizer>(thd, this); } - enum precedence precedence() const { return args[1]->precedence(); } + enum precedence precedence() const override { return args[1]->precedence(); } }; @@ -601,17 +602,17 @@ class Item_func_not :public Item_bool_func public: Item_func_not(THD *thd, Item *a): Item_bool_func(thd, a), abort_on_null(FALSE) {} - virtual void top_level_item() { abort_on_null= 1; } - bool is_top_level_item() { return abort_on_null; } - longlong val_int(); - enum Functype functype() const { return NOT_FUNC; } - const char *func_name() const { return "not"; } - bool find_not_null_fields(table_map allowed) { return false; } - enum precedence precedence() const { return BANG_PRECEDENCE; } - Item *neg_transformer(THD *thd); - bool fix_fields(THD *, Item **); - virtual void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd) + void top_level_item() override { abort_on_null= 1; } + bool is_top_level_item() const override { return abort_on_null; } + longlong val_int() override; + enum Functype functype() const override { return NOT_FUNC; } + const char *func_name() const override { return "not"; } + bool find_not_null_fields(table_map allowed) override { return false; } + enum precedence precedence() const override { return BANG_PRECEDENCE; } + Item *neg_transformer(THD *thd) override; + bool fix_fields(THD *, Item **) override; + void print(String *str, enum_query_type query_type) override; + Item *get_copy(THD *thd) override { return get_item_copy<Item_func_not>(thd, this); } }; @@ -889,19 +890,22 @@ public: Item_func_opt_neg(THD *thd, List<Item> &list): Item_bool_func(thd, list), negated(0), pred_level(0) {} public: - inline void top_level_item() { pred_level= 1; } - bool is_top_level_item() const { return pred_level; } - Item *neg_transformer(THD *thd) + void top_level_item() override { pred_level= 1; } + bool is_top_level_item() const override { return pred_level; } + Item *neg_transformer(THD *thd) override { negated= !negated; return this; } - bool eq(const Item *item, bool binary_cmp) const; - CHARSET_INFO *compare_collation() const { return cmp_collation.collation; } - Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) = 0; + bool eq(const Item *item, bool binary_cmp) const override; + CHARSET_INFO *compare_collation() const override + { + return cmp_collation.collation; + } + Item *propagate_equal_fields(THD *, const Context &, + COND_EQUAL *) override= 0; }; - class Item_func_between :public Item_func_opt_neg { protected: diff --git a/sql/item_create.cc b/sql/item_create.cc index edf44fc3cd3..62f4d9f9fee 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. - Copyright (c) 2008-2011 Monty Program Ab + Copyright (c) 2008, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/item_func.cc b/sql/item_func.cc index 9e30afd0239..813927df32b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2288,10 +2288,13 @@ bool Item_func_int_val::fix_length_and_dec() { DBUG_ENTER("Item_func_int_val::fix_length_and_dec"); DBUG_PRINT("info", ("name %s", func_name())); - if (args[0]->cast_to_int_type_handler()-> - Item_func_int_val_fix_length_and_dec(this)) + /* + We don't want to translate ENUM/SET to CHAR here. + So let's call real_type_handler(), not type_handler(). + */ + if (args[0]->real_type_handler()->Item_func_int_val_fix_length_and_dec(this)) DBUG_RETURN(TRUE); - DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); + DBUG_PRINT("info", ("Type: %s", real_type_handler()->name().ptr())); DBUG_RETURN(FALSE); } @@ -2299,6 +2302,7 @@ bool Item_func_int_val::fix_length_and_dec() longlong Item_func_ceiling::int_op() { switch (args[0]->result_type()) { + case STRING_RESULT: // hex hybrid case INT_RESULT: return val_int_from_item(args[0]); case DECIMAL_RESULT: @@ -2332,9 +2336,32 @@ my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value) } +bool Item_func_ceiling::date_op(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) +{ + Datetime::Options opt(thd, TIME_FRAC_TRUNCATE); + Datetime *tm= new (to) Datetime(thd, args[0], opt); + tm->ceiling(thd); + null_value= !tm->is_valid_datetime(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + +bool Item_func_ceiling::time_op(THD *thd, MYSQL_TIME *to) +{ + static const Time::Options_for_round opt; + Time *tm= new (to) Time(thd, args[0], opt); + tm->ceiling(); + null_value= !tm->is_valid_time(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + longlong Item_func_floor::int_op() { switch (args[0]->result_type()) { + case STRING_RESULT: // hex hybrid case INT_RESULT: return val_int_from_item(args[0]); case DECIMAL_RESULT: @@ -2372,6 +2399,28 @@ my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value) } +bool Item_func_floor::date_op(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) +{ + // DATETIME is not negative, so FLOOR means just truncation + Datetime::Options opt(thd, TIME_FRAC_TRUNCATE); + Datetime *tm= new (to) Datetime(thd, args[0], opt, 0); + null_value= !tm->is_valid_datetime(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + +bool Item_func_floor::time_op(THD *thd, MYSQL_TIME *to) +{ + static const Time::Options_for_round opt; + Time *tm= new (to) Time(thd, args[0], opt); + tm->floor(); + null_value= !tm->is_valid_time(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + void Item_func_round::fix_length_and_dec_decimal(uint decimals_to_set) { int decimals_delta= args[0]->decimals - decimals_to_set; @@ -2467,8 +2516,27 @@ void Item_func_round::fix_arg_datetime() } -void Item_func_round::fix_arg_int() +/** + Calculate data type and attributes for INT-alike input. + + @param [IN] preferred - The preferred data type handler for simple cases + such as ROUND(x) and TRUNCATE(x,0), when the input + is short enough to fit into an integer type + (without extending to DECIMAL). + - If `preferred` is not NULL, then the code tries + to preserve the given data type handler and + the data type attributes `preferred_attrs`. + - If `preferred` is NULL, then the code fully + calculates attributes using + args[0]->decimal_precision() and chooses between + INT and BIGINT, depending on attributes. + @param [IN] preferred_attrs - The preferred data type attributes for + simple cases. +*/ +void Item_func_round::fix_arg_int(const Type_handler *preferred, + const Type_std_attributes *preferred_attrs) { + DBUG_ASSERT(args[0]->decimals == 0); if (args[1]->const_item()) { Longlong_hybrid val1= args[1]->to_longlong_hybrid(); @@ -2477,13 +2545,35 @@ void Item_func_round::fix_arg_int() else if ((!val1.to_uint(DECIMAL_MAX_SCALE) && truncate) || args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS) { + // Here we can keep INT_RESULT // Length can increase in some cases: ROUND(9,-1) -> 10 int length_can_increase= MY_TEST(!truncate && val1.neg()); - max_length= args[0]->max_length + length_can_increase; - // Here we can keep INT_RESULT - unsigned_flag= args[0]->unsigned_flag; - decimals= 0; - set_handler(type_handler_long_or_longlong()); + if (preferred) + { + Type_std_attributes::set(preferred_attrs); + if (!length_can_increase) + { + // Preserve the exact data type and attributes + set_handler(preferred); + } + else + { + max_length++; + set_handler(type_handler_long_or_longlong()); + } + } + else + { + /* + This branch is currently used for hex hybrid only. + It's known to be unsigned. So sign length is 0. + */ + DBUG_ASSERT(args[0]->unsigned_flag); // no needs to add sign length + max_length= args[0]->decimal_precision() + length_can_increase; + unsigned_flag= true; + decimals= 0; + set_handler(type_handler_long_or_longlong()); + } } else fix_length_and_dec_decimal(val1.to_uint(DECIMAL_MAX_SCALE)); @@ -2610,9 +2700,7 @@ bool Item_func_round::time_op(THD *thd, MYSQL_TIME *to) { DBUG_ASSERT(args[0]->type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_TIME); - Time::Options opt(Time::default_flags_for_get_date(), - truncate ? TIME_FRAC_TRUNCATE : TIME_FRAC_ROUND, - Time::DATETIME_TO_TIME_DISALLOW); + Time::Options_for_round opt(truncate ? TIME_FRAC_TRUNCATE : TIME_FRAC_ROUND); Longlong_hybrid_null dec= args[1]->to_longlong_hybrid_null(); Time *tm= new (to) Time(thd, args[0], opt, dec.to_uint(TIME_SECOND_PART_DIGITS)); diff --git a/sql/item_func.h b/sql/item_func.h index 4922d20bd0c..07ee913b07d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -450,6 +450,25 @@ public: :Item_func(thd, item), Type_handler_hybrid_field_type(item) { } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } + void fix_length_and_dec_long_or_longlong(uint char_length, bool unsigned_arg) + { + collation= DTCollation_numeric(); + unsigned_flag= unsigned_arg; + max_length= char_length; + set_handler(Type_handler::type_handler_long_or_longlong(char_length, + unsigned_arg)); + } + void fix_length_and_dec_ulong_or_ulonglong_by_nbits(uint nbits) + { + uint digits= Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(nbits); + collation= DTCollation_numeric(); + unsigned_flag= true; + max_length= digits; + if (nbits > 32) + set_handler(&type_handler_ulonglong); + else + set_handler(&type_handler_ulong); + } }; @@ -1813,13 +1832,32 @@ public: }; -class Item_func_int_val :public Item_func_num1 +class Item_func_int_val :public Item_func_hybrid_field_type { public: - Item_func_int_val(THD *thd, Item *a): Item_func_num1(thd, a) {} + Item_func_int_val(THD *thd, Item *a): Item_func_hybrid_field_type(thd, a) {} + bool check_partition_func_processor(void *int_arg) { return FALSE; } + bool check_vcol_func_processor(void *arg) { return FALSE; } void fix_length_and_dec_double(); void fix_length_and_dec_int_or_decimal(); + void fix_length_and_dec_time() + { + fix_attributes_time(0); + set_handler(&type_handler_time2); + } + void fix_length_and_dec_datetime() + { + fix_attributes_datetime(0); + set_handler(&type_handler_datetime2); + maybe_null= true; // E.g. CEILING(TIMESTAMP'0000-01-01 23:59:59.9') + } bool fix_length_and_dec(); + String *str_op(String *str) { DBUG_ASSERT(0); return 0; } + bool native_op(THD *thd, Native *to) + { + DBUG_ASSERT(0); + return true; + } }; @@ -1831,6 +1869,8 @@ public: longlong int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); + bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + bool time_op(THD *thd, MYSQL_TIME *ltime); Item *get_copy(THD *thd) { return get_item_copy<Item_func_ceiling>(thd, this); } }; @@ -1844,6 +1884,8 @@ public: longlong int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); + bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + bool time_op(THD *thd, MYSQL_TIME *ltime); Item *get_copy(THD *thd) { return get_item_copy<Item_func_floor>(thd, this); } }; @@ -1875,14 +1917,19 @@ public: return NULL; } void fix_arg_decimal(); - void fix_arg_int(); + void fix_arg_int(const Type_handler *preferred, + const Type_std_attributes *preferred_attributes); void fix_arg_double(); void fix_arg_time(); void fix_arg_datetime(); void fix_arg_temporal(const Type_handler *h, uint int_part_length); bool fix_length_and_dec() { - return args[0]->type_handler()->Item_func_round_fix_length_and_dec(this); + /* + We don't want to translate ENUM/SET to CHAR here. + So let's real_type_handler(), not type_handler(). + */ + return args[0]->real_type_handler()->Item_func_round_fix_length_and_dec(this); } Item *get_copy(THD *thd) { return get_item_copy<Item_func_round>(thd, this); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index bcc041ae9c6..7f853a73c71 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1391,8 +1391,8 @@ String *Item_func_regexp_replace::val_str(String *str) !(replace= re.convert_if_needed(replace, &re.replace_converter))) goto err; - src= source->lex_cstring(); - rpl= replace->lex_cstring(); + source->get_value(&src); + replace->get_value(&rpl); str->length(0); str->set_charset(collation.collation); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1690ec96e65..16fa06f4cda 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4141,7 +4141,8 @@ int subselect_uniquesubquery_engine::exec() TABLE *table= tab->table; empty_result_set= TRUE; table->status= 0; - Item_in_subselect *in_subs= (Item_in_subselect *) item; + Item_in_subselect *in_subs= item->get_IN_subquery(); + DBUG_ASSERT(in_subs); if (!tab->preread_init_done && tab->preread_init()) DBUG_RETURN(1); @@ -4186,11 +4187,11 @@ int subselect_uniquesubquery_engine::exec() table->null_row= 0; if (!table->status && (!cond || cond->val_int())) { - ((Item_in_subselect *) item)->value= 1; + in_subs->value= 1; empty_result_set= FALSE; } else - ((Item_in_subselect *) item)->value= 0; + in_subs->value= 0; } DBUG_RETURN(error != 0); @@ -4229,9 +4230,9 @@ int subselect_uniquesubquery_engine::index_lookup() table->null_row= 0; if (!error && (!cond || cond->val_int())) - ((Item_in_subselect *) item)->value= 1; + item->get_IN_subquery()->value= 1; else - ((Item_in_subselect *) item)->value= 0; + item->get_IN_subquery()->value= 0; DBUG_RETURN(0); } @@ -4301,9 +4302,9 @@ int subselect_indexsubquery_engine::exec() int error; bool null_finding= 0; TABLE *table= tab->table; - Item_in_subselect *in_subs= (Item_in_subselect *) item; + Item_in_subselect *in_subs= item->get_IN_subquery(); - ((Item_in_subselect *) item)->value= 0; + in_subs->value= 0; empty_result_set= TRUE; table->status= 0; @@ -4311,7 +4312,7 @@ int subselect_indexsubquery_engine::exec() { /* We need to check for NULL if there wasn't a matching value */ *tab->ref.null_ref_key= 0; // Search first for not null - ((Item_in_subselect *) item)->was_null= 0; + in_subs->was_null= 0; } if (!tab->preread_init_done && tab->preread_init()) @@ -4363,9 +4364,9 @@ int subselect_indexsubquery_engine::exec() { empty_result_set= FALSE; if (null_finding) - ((Item_in_subselect *) item)->was_null= 1; + in_subs->was_null= 1; else - ((Item_in_subselect *) item)->value= 1; + in_subs->value= 1; break; } error= table->file->ha_index_next_same(table->record[0], @@ -4751,7 +4752,7 @@ bool subselect_uniquesubquery_engine::no_tables() subselect_hash_sj_engine::exec_strategy subselect_hash_sj_engine::get_strategy_using_schema() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); if (item_in->is_top_level_item()) return COMPLETE_MATCH; @@ -4798,7 +4799,7 @@ subselect_hash_sj_engine::get_strategy_using_schema() subselect_hash_sj_engine::exec_strategy subselect_hash_sj_engine::get_strategy_using_data() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); select_materialize_with_stats *result_sink= (select_materialize_with_stats *) result; Item *outer_col; @@ -5049,8 +5050,9 @@ bool subselect_hash_sj_engine::init(List<Item> *tmp_columns, uint subquery_id) DBUG_RETURN(TRUE); result_sink->get_tmp_table_param()->materialized_subquery= true; - if (item->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)item)->is_jtbm_merged) + + if (item->substype() == Item_subselect::IN_SUBS && + (item->get_IN_subquery()->is_jtbm_merged)) { result_sink->get_tmp_table_param()->force_not_null_cols= true; } @@ -5090,9 +5092,12 @@ bool subselect_hash_sj_engine::init(List<Item> *tmp_columns, uint subquery_id) /* Make sure there is only one index on the temp table, and it doesn't have the extra key part created when s->uniques > 0. + + NOTE: item have to be Item_in_subselect, because class constructor + accept Item_in_subselect as the parmeter. */ DBUG_ASSERT(tmp_table->s->keys == 1 && - ((Item_in_subselect *) item)->left_expr->cols() == + item->get_IN_subquery()->left_expr->cols() == tmp_table->key_info->user_defined_key_parts); if (make_semi_join_conds() || @@ -5141,7 +5146,7 @@ bool subselect_hash_sj_engine::make_semi_join_conds() TABLE_LIST *tmp_table_ref; /* Name resolution context for all tmp_table columns created below. */ Name_resolution_context *context; - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); LEX_CSTRING table_name; DBUG_ENTER("subselect_hash_sj_engine::make_semi_join_conds"); DBUG_ASSERT(semi_join_conds == NULL); @@ -5203,7 +5208,7 @@ bool subselect_hash_sj_engine::make_semi_join_conds() subselect_uniquesubquery_engine* subselect_hash_sj_engine::make_unique_engine() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); Item_iterator_row it(item_in->left_expr); /* The only index on the temporary table. */ KEY *tmp_key= tmp_table->key_info; @@ -5225,7 +5230,7 @@ subselect_hash_sj_engine::make_unique_engine() tab->preread_init_done= FALSE; tab->ref.tmp_table_index_lookup_init(thd, tmp_key, it, FALSE); - DBUG_RETURN(new subselect_uniquesubquery_engine(thd, tab, item, + DBUG_RETURN(new subselect_uniquesubquery_engine(thd, tab, item_in, semi_join_conds)); } @@ -5272,7 +5277,7 @@ void subselect_hash_sj_engine::cleanup() at parse time and stored across executions, while all other materialization related engines are created and chosen for each execution. */ - ((Item_in_subselect *) item)->engine= materialize_engine; + item->get_IN_subquery()->engine= materialize_engine; if (lookup_engine_type == TABLE_SCAN_ENGINE || lookup_engine_type == ROWID_MERGE_ENGINE) { @@ -5512,7 +5517,7 @@ double get_post_group_estimate(JOIN* join, double join_op_rows) int subselect_hash_sj_engine::exec() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); SELECT_LEX *save_select= thd->lex->current_select; subselect_partial_match_engine *pm_engine= NULL; int res= 0; @@ -6129,7 +6134,7 @@ subselect_partial_match_engine::subselect_partial_match_engine( int subselect_partial_match_engine::exec() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); int lookup_res; DBUG_ASSERT(!(item_in->left_expr_has_null() && @@ -6251,7 +6256,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, select_materialize_with_stats *result_sink= (select_materialize_with_stats *) result; uint cur_keyid= 0; - Item_in_subselect *item_in= (Item_in_subselect*) item; + Item *left= item->get_IN_subquery()->left_exp(); int error; if (merge_keys_count == 0) @@ -6286,7 +6291,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, /* Create the only non-NULL key if there is any. */ if (non_null_key_parts) { - non_null_key= new Ordered_key(cur_keyid, tmp_table, item_in->left_expr, + non_null_key= new Ordered_key(cur_keyid, tmp_table, left, 0, 0, 0, row_num_to_rowid); if (non_null_key->init(non_null_key_parts)) return TRUE; @@ -6318,7 +6323,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, merge_keys[cur_keyid]= new Ordered_key( cur_keyid, tmp_table, - item_in->left_expr->element_index(i), + left->element_index(i), result_sink->get_null_count_of_col(i), result_sink->get_min_null_of_col(i), result_sink->get_max_null_of_col(i), diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 8f6e4836ac7..b4b278083fc 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -151,9 +151,7 @@ public: virtual subs_type substype() { return UNKNOWN_SUBS; } bool is_in_predicate() { - return (substype() == Item_subselect::IN_SUBS || - substype() == Item_subselect::ALL_SUBS || - substype() == Item_subselect::ANY_SUBS); + return get_IN_subquery() != NULL; } /* @@ -165,7 +163,7 @@ public: select_result_interceptor *result); ~Item_subselect(); - void cleanup(); + void cleanup() override; virtual void reset() { eliminated= FALSE; @@ -175,22 +173,23 @@ public: Set the subquery result to a default value consistent with the semantics of the result row produced for queries with implicit grouping. */ - void no_rows_in_result()= 0; + void no_rows_in_result() override= 0; virtual bool select_transformer(JOIN *join); bool assigned() { return value_assigned; } void assigned(bool a) { value_assigned= a; } - enum Type type() const; - bool is_null() + enum Type type() const override; + bool is_null() override { update_null_value(); return null_value; } - bool fix_fields(THD *thd, Item **ref); - bool with_subquery() const { DBUG_ASSERT(fixed); return true; } - bool with_sum_func() const { return m_with_sum_func; } - With_sum_func_cache* get_with_sum_func_cache() { return this; } + bool fix_fields(THD *thd, Item **ref) override; + bool with_subquery() const override { DBUG_ASSERT(fixed); return true; } + bool with_sum_func() const override { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() override { return this; } bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item); - void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) override; void recalc_used_tables(st_select_lex *new_parent, bool after_pullout); virtual bool exec(); /* @@ -204,13 +203,13 @@ public: forced_const= TRUE; } virtual bool fix_length_and_dec(); - table_map used_tables() const; - table_map not_null_tables() const { return 0; } - bool const_item() const; + table_map used_tables() const override; + table_map not_null_tables() const override { return 0; } + bool const_item() const override; inline table_map get_used_tables_cache() { return used_tables_cache; } - Item *get_tmp_table_item(THD *thd); - void update_used_tables(); - virtual void print(String *str, enum_query_type query_type); + Item *get_tmp_table_item(THD *thd) override; + void update_used_tables() override; + void print(String *str, enum_query_type query_type) override; virtual bool have_guarded_conds() { return FALSE; } bool change_engine(subselect_engine *eng) { @@ -225,7 +224,7 @@ public: */ bool is_evaluated() const; bool is_uncacheable() const; - bool is_expensive(); + bool is_expensive() override; /* Used by max/min subquery to initialize value presence registration @@ -233,13 +232,13 @@ public: */ virtual void reset_value_registration() {} enum_parsing_place place() { return parsing_place; } - bool walk(Item_processor processor, bool walk_subquery, void *arg); - bool unknown_splocal_processor(void *arg); - bool mark_as_eliminated_processor(void *arg); - bool eliminate_subselect_processor(void *arg); - bool set_fake_select_as_master_processor(void *arg); - bool enumerate_field_refs_processor(void *arg); - bool check_vcol_func_processor(void *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) override; + bool unknown_splocal_processor(void *arg) override; + bool mark_as_eliminated_processor(void *arg) override; + bool eliminate_subselect_processor(void *arg) override; + bool set_fake_select_as_master_processor(void *arg) override; + bool enumerate_field_refs_processor(void *arg) override; + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("select ...", arg, VCOL_IMPOSSIBLE); } @@ -252,27 +251,27 @@ public: @retval TRUE if the predicate is expensive @retval FALSE otherwise */ - bool is_expensive_processor(void *arg) { return is_expensive(); } + bool is_expensive_processor(void *arg) override { return is_expensive(); } /** Get the SELECT_LEX structure associated with this Item. @return the SELECT_LEX structure associated with this Item */ st_select_lex* get_select_lex(); - virtual bool expr_cache_is_needed(THD *); - virtual void get_cache_parameters(List<Item> ¶meters); - virtual bool is_subquery_processor (void *opt_arg) { return 1; } - bool exists2in_processor(void *opt_arg) { return 0; } - bool limit_index_condition_pushdown_processor(void *opt_arg) + bool expr_cache_is_needed(THD *) override; + void get_cache_parameters(List<Item> ¶meters) override; + bool is_subquery_processor (void *opt_arg) override { return 1; } + bool exists2in_processor(void *opt_arg) override { return 0; } + bool limit_index_condition_pushdown_processor(void *opt_arg) override { return TRUE; } void register_as_with_rec_ref(With_element *with_elem); void init_expr_cache_tracker(THD *thd); - - Item* build_clone(THD *thd) { return 0; } - Item* get_copy(THD *thd) { return 0; } + + Item* build_clone(THD *thd) override { return 0; } + Item* get_copy(THD *thd) override { return 0; } bool wrap_tvc_into_select(THD *thd, st_select_lex *tvc_sl); @@ -395,37 +394,40 @@ public: emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0) {} - subs_type substype() { return EXISTS_SUBS; } - void reset() + subs_type substype() override { return EXISTS_SUBS; } + void reset() override { eliminated= FALSE; value= 0; } - void no_rows_in_result(); + void no_rows_in_result() override; - const Type_handler *type_handler() const { return &type_handler_bool; } - longlong val_int(); - double val_real(); - String *val_str(String*); - my_decimal *val_decimal(my_decimal *); - bool val_bool(); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + const Type_handler *type_handler() const override + { + return &type_handler_bool; + } + longlong val_int() override; + double val_real() override; + String *val_str(String*) override; + my_decimal *val_decimal(my_decimal *) override; + bool val_bool() override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_int(thd, ltime, fuzzydate); } - bool fix_fields(THD *thd, Item **ref); - bool fix_length_and_dec(); - void print(String *str, enum_query_type query_type); - bool select_transformer(JOIN *join); - void top_level_item() { abort_on_null=1; } - inline bool is_top_level_item() { return abort_on_null; } - bool exists2in_processor(void *opt_arg); + bool fix_fields(THD *thd, Item **ref) override; + bool fix_length_and_dec() override; + void print(String *str, enum_query_type query_type) override; + bool select_transformer(JOIN *join) override; + void top_level_item() override { abort_on_null=1; } + bool is_top_level_item() const override { return abort_on_null; } + bool exists2in_processor(void *opt_arg) override; - Item* expr_cache_insert_transformer(THD *thd, uchar *unused); + Item* expr_cache_insert_transformer(THD *thd, uchar *unused) override; - void mark_as_condition_AND_part(TABLE_LIST *embedding) + void mark_as_condition_AND_part(TABLE_LIST *embedding) override { emb_on_expr_nest= embedding; } - virtual void under_not(Item_func_not *upper) { upper_not= upper; }; + void under_not(Item_func_not *upper) override { upper_not= upper; }; void set_exists_transformed() { exists_transformed= TRUE; } @@ -507,7 +509,6 @@ protected: bool create_row_in_to_exists_cond(JOIN * join, Item **where_item, Item **having_item); -public: Item *left_expr; /* Important for PS/SP: left_expr_orig is the item that left_expr originally @@ -515,6 +516,7 @@ public: left_expr could later be changed to something on the execution arena. */ Item *left_expr_orig; +public: /* Priority of this predicate in the convert-to-semi-join-nest process. */ int sj_convert_priority; /* May be TRUE only for the candidates to semi-join conversion */ @@ -603,7 +605,7 @@ public: if ( pushed_cond_guards) pushed_cond_guards[i]= v; } - bool have_guarded_conds() { return MY_TEST(pushed_cond_guards); } + bool have_guarded_conds() override { return MY_TEST(pushed_cond_guards); } Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery @@ -613,41 +615,42 @@ public: in_strategy(SUBS_NOT_TRANSFORMED), pushed_cond_guards(NULL), func(NULL), do_not_convert_to_sj(FALSE), is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), upper_item(0) {} - void cleanup(); - subs_type substype() { return IN_SUBS; } - void reset() + void cleanup() override; + subs_type substype() override { return IN_SUBS; } + void reset() override { eliminated= FALSE; value= 0; null_value= 0; was_null= 0; } - bool select_transformer(JOIN *join); + bool select_transformer(JOIN *join) override; bool create_in_to_exists_cond(JOIN *join_arg); bool inject_in_to_exists_cond(JOIN *join_arg); - virtual bool exec(); - longlong val_int(); - double val_real(); - String *val_str(String*); - my_decimal *val_decimal(my_decimal *); - bool val_bool(); + bool exec() override; + longlong val_int() override; + double val_real() override; + String *val_str(String*) override; + my_decimal *val_decimal(my_decimal *) override; + bool val_bool() override; bool test_limit(st_select_lex_unit *unit); - void print(String *str, enum_query_type query_type); - enum precedence precedence() const { return CMP_PRECEDENCE; } - bool fix_fields(THD *thd, Item **ref); - bool fix_length_and_dec(); - void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); - bool const_item() const + void print(String *str, enum_query_type query_type) override; + enum precedence precedence() const override { return CMP_PRECEDENCE; } + bool fix_fields(THD *thd, Item **ref) override; + bool fix_length_and_dec() override; + void fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) override; + bool const_item() const override { return Item_subselect::const_item() && left_expr->const_item(); } - void update_used_tables(); + void update_used_tables() override; bool setup_mat_engine(); bool init_left_expr_cache(); /* Inform 'this' that it was computed, and contains a valid result. */ void set_first_execution() { if (first_execution) first_execution= FALSE; } - bool expr_cache_is_needed(THD *thd); + bool expr_cache_is_needed(THD *thd) override; inline bool left_expr_has_null(); void disable_cond_guard_for_const_null_left_expr(int i) @@ -739,19 +742,28 @@ public: DBUG_VOID_RETURN; } - bool walk(Item_processor processor, bool walk_subquery, void *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) override { return left_expr->walk(processor, walk_subquery, arg) || Item_subselect::walk(processor, walk_subquery, arg); } - bool exists2in_processor(void *opt_arg __attribute__((unused))) + bool exists2in_processor(void *opt_arg __attribute__((unused))) override { return 0; }; bool pushdown_cond_for_in_subquery(THD *thd, Item *cond); + Item_in_subselect *get_IN_subquery() override + { return this; } + inline Item** left_exp_ptr() + { return &left_expr; } + inline Item* left_exp() const + { return left_expr; } + inline Item* left_exp_orig() const + { return left_expr_orig; } + friend class Item_ref_null_helper; friend class Item_is_not_null_test; friend class Item_in_optimizer; @@ -964,9 +976,9 @@ public: // constructor can assign THD because it will be called after JOIN::prepare subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg, - Item_subselect *subs, Item *where) + Item_in_subselect *subs, Item *where) :subselect_engine(subs, 0), tab(tab_arg), cond(where) - {} + { DBUG_ASSERT(subs); } ~subselect_uniquesubquery_engine(); void cleanup(); int prepare(THD *); @@ -1027,12 +1039,12 @@ public: // constructor can assign THD because it will be called after JOIN::prepare subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg, - Item_subselect *subs, Item *where, + Item_in_subselect *subs, Item *where, Item *having_arg, bool chk_null) :subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where), check_null(chk_null), having(having_arg) - {} + { DBUG_ASSERT(subs); } int exec(); void print (String *str, enum_query_type query_type); virtual enum_engine_type engine_type() { return INDEXSUBQUERY_ENGINE; } @@ -1095,14 +1107,14 @@ public: Name_resolution_context *semi_join_conds_context; - subselect_hash_sj_engine(THD *thd_arg, Item_subselect *in_predicate, + subselect_hash_sj_engine(THD *thd_arg, Item_in_subselect *in_predicate, subselect_single_select_engine *old_engine) : subselect_engine(in_predicate, NULL), tmp_table(NULL), is_materialized(FALSE), materialize_engine(old_engine), materialize_join(NULL), semi_join_conds(NULL), lookup_engine(NULL), count_partial_match_columns(0), count_null_only_columns(0), count_columns_with_nulls(0), strategy(UNDEFINED) - {} + { DBUG_ASSERT(in_predicate); } ~subselect_hash_sj_engine(); bool init(List<Item> *tmp_columns, uint subquery_id); @@ -1410,7 +1422,7 @@ public: from Item_in_optimizer::val_int() sets Item_in_optimizer::null_value correctly. */ - return !(((Item_in_subselect *) item)->null_value); + return !(item->get_IN_subquery()->null_value); } void print(String*, enum_query_type); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index e47d4fa7f0e..7bc34ee688c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -449,7 +449,8 @@ static bool extract_date_time(THD *thd, DATE_TIME_FORMAT *format, { ErrConvString err(val_begin, length, &my_charset_bin); make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, - &err, cached_timestamp_type, 0, NullS); + &err, cached_timestamp_type, + nullptr, nullptr, nullptr); break; } } while (++val != val_end); @@ -473,7 +474,7 @@ err: Create a formated date/time value in a string. */ -static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time, +static bool make_date_time(String *format, MYSQL_TIME *l_time, timestamp_type type, const MY_LOCALE *locale, String *str) { @@ -488,7 +489,7 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time, if (l_time->neg) str->append('-'); - end= (ptr= format.str) + format.length; + end= (ptr= format->ptr()) + format->length(); for (; ptr != end ; ptr++) { if (*ptr != '%' || ptr+1 == end) @@ -1576,7 +1577,7 @@ static void set_sec_part(ulong sec_part, MYSQL_TIME *ltime, Item *item) { ltime->second_part= sec_part; if (item->decimals < TIME_SECOND_PART_DIGITS) - my_time_trunc(ltime, item->decimals); + my_datetime_trunc(ltime, item->decimals); } } @@ -1742,7 +1743,7 @@ bool Item_func_date_format::fix_length_and_dec() decimals=0; CHARSET_INFO *cs= thd->variables.collation_connection; - uint32 repertoire= arg1->collation.repertoire; + my_repertoire_t repertoire= arg1->collation.repertoire; if (!thd->variables.lc_time_names->is_ascii) repertoire|= MY_REPERTOIRE_EXTENDED; collation.set(cs, arg1->collation.derivation, repertoire); @@ -1877,6 +1878,7 @@ String *Item_func_date_format::val_str(String *str) DBUG_ASSERT(fixed == 1); date_conv_mode_t mode= is_time_format ? TIME_TIME_ONLY : TIME_CONV_NONE; THD *thd= current_thd; + if ((null_value= args[0]->get_date(thd, &l_time, Temporal::Options(mode, thd)))) return 0; @@ -1901,7 +1903,7 @@ String *Item_func_date_format::val_str(String *str) /* Create the result string */ str->set_charset(collation.collation); - if (!make_date_time(format->lex_cstring(), &l_time, + if (!make_date_time(format, &l_time, is_time_format ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATE, lc, str)) diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 25e86c5d777..24c2ef5a2f2 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -556,12 +556,10 @@ void Item_window_func::print(String *str, enum_query_type query_type) } window_func()->print(str, query_type); str->append(" over "); -#ifndef DBUG_OFF - if (!window_spec) // one can call dbug_print_item() anytime in gdb + if (!window_spec) str->append(window_name); else -#endif - window_spec->print(str, query_type); + window_spec->print(str, query_type); } void Item_window_func::print_for_percentile_functions(String *str, enum_query_type query_type) { diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index c3304122c1b..99ef738ac69 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2016,2019 MariaDB + Copyright (c) 2016, 2020, 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 @@ -651,7 +651,7 @@ class Item_sum_ntile : public Item_sum_int, { public: Item_sum_ntile(THD* thd, Item* num_quantiles_expr) : - Item_sum_int(thd, num_quantiles_expr) + Item_sum_int(thd, num_quantiles_expr), n_old_val_(0) { } longlong val_int() @@ -664,11 +664,13 @@ class Item_sum_ntile : public Item_sum_int, longlong num_quantiles= get_num_quantiles(); - if (num_quantiles <= 0) { + if (num_quantiles <= 0 || + (static_cast<ulonglong>(num_quantiles) != n_old_val_ && n_old_val_ > 0)) + { my_error(ER_INVALID_NTILE_ARGUMENT, MYF(0)); return true; } - + n_old_val_= static_cast<ulonglong>(num_quantiles); null_value= false; ulonglong quantile_size = get_row_count() / num_quantiles; ulonglong extra_rows = get_row_count() - quantile_size * num_quantiles; @@ -694,6 +696,7 @@ class Item_sum_ntile : public Item_sum_int, { current_row_count_= 0; partition_row_count_= 0; + n_old_val_= 0; } const char*func_name() const @@ -717,6 +720,7 @@ class Item_sum_ntile : public Item_sum_int, private: longlong get_num_quantiles() { return args[0]->val_int(); } + ulonglong n_old_val_; }; class Item_sum_percentile_disc : public Item_sum_num, diff --git a/sql/log.cc b/sql/log.cc index 5f4fd6bbcab..0bfe7d7ee8b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2828,7 +2828,9 @@ bool MYSQL_LOG::open( else if ((seek_offset= mysql_file_tell(file, MYF(MY_WME)))) goto err; - if (init_io_cache(&log_file, file, IO_SIZE, io_cache_type, seek_offset, 0, + if (init_io_cache(&log_file, file, (log_type == LOG_NORMAL ? IO_SIZE : + LOG_BIN_IO_SIZE), + io_cache_type, seek_offset, 0, MYF(MY_WME | MY_NABP | ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0)))) goto err; diff --git a/sql/log.h b/sql/log.h index 063513fe908..58e681985eb 100644 --- a/sql/log.h +++ b/sql/log.h @@ -295,6 +295,12 @@ enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN }; enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED }; /* + Use larger buffers when reading from and to binary log + We make it one step smaller than 64K to account for malloc overhead. +*/ +#define LOG_BIN_IO_SIZE MY_ALIGN_DOWN(65536-1, IO_SIZE) + +/* TODO use mmap instead of IO_CACHE for binlog (mmap+fsync is two times faster than write+fsync) */ diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index c53a2b53769..bdc42885312 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -2036,8 +2036,7 @@ bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) } else if (strcmp("COMMIT", query) == 0) { - if (my_b_write(&cache, (uchar*) "BEGIN", 5) || - my_b_printf(&cache, "\n%s\n", print_event_info->delimiter)) + if (my_b_printf(&cache, "START TRANSACTION\n%s\n", print_event_info->delimiter)) goto err; } } @@ -2396,7 +2395,7 @@ bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) my_b_printf(&cache, "\tXid = %s\n", buf)) goto err; } - if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n", + if (my_b_printf(&cache, is_flashback ? "START TRANSACTION%s\n" : "COMMIT%s\n", print_event_info->delimiter)) goto err; @@ -3899,8 +3898,8 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info) } else if (!(flags2 & FL_STANDALONE)) { - if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", - print_event_info->delimiter)) + if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : + "START TRANSACTION\n%s\n", print_event_info->delimiter)) goto err; } diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index a6e02413d4c..88e30827dfd 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -8028,7 +8028,6 @@ end: if (is_table_scan || is_index_scan) issue_long_find_row_warning(get_general_type_code(), m_table->alias.c_ptr(), is_index_scan, rgi); - table->default_column_bitmaps(); DBUG_RETURN(error); } @@ -8263,7 +8262,13 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); - int error= find_row(rgi); + // Temporary fix to find out why it fails [/Matz] + memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8); + memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8); + + m_table->mark_columns_per_binlog_row_image(); + + int error= find_row(rgi); if (unlikely(error)) { /* @@ -8333,11 +8338,6 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) goto err; } - // Temporary fix to find out why it fails [/Matz] - memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8); - memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8); - - m_table->mark_columns_per_binlog_row_image(); if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP)) m_table->vers_update_fields(); error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]); diff --git a/sql/mdl.cc b/sql/mdl.cc index 6cdea8c3ebd..4772dc017f9 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1035,7 +1035,7 @@ void MDL_ticket::destroy(MDL_ticket *ticket) /** Return the 'weight' of this ticket for the - victim selection algorithm. Requests with + victim selection algorithm. Requests with lower weight are preferred to requests with higher weight when choosing a victim. */ @@ -2179,7 +2179,7 @@ MDL_context::clone_ticket(MDL_request *mdl_request) to wait for another thread which is not ready to commit. This is always an error, as the upper level of parallel replication should not allow a scheduling of a conflicting DDL until all earlier - transactions has commited. + transactions have been committed. This function is only called for a slave using parallel replication and trying to get an exclusive lock for the table. diff --git a/sql/mdl.h b/sql/mdl.h index dd10b3a45d0..f6b7154fba0 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -124,6 +124,8 @@ public: */ enum enum_mdl_type { + /* This means that the MDL_request is not initialized */ + MDL_NOT_INITIALIZED= -1, /* An intention exclusive metadata lock (IX). Used only for scoped locks. Owner of this type of lock can acquire upgradable exclusive locks on @@ -599,12 +601,13 @@ public: */ MDL_request& operator=(const MDL_request &) { + type= MDL_NOT_INITIALIZED; ticket= NULL; /* Do nothing, in particular, don't try to copy the key. */ return *this; } /* Another piece of ugliness for TABLE_LIST constructor */ - MDL_request() {} + MDL_request(): type(MDL_NOT_INITIALIZED), ticket(NULL) {} MDL_request(const MDL_request *rhs) :type(rhs->type), diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d4341b17401..6f379b2e352 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4143,8 +4143,10 @@ static int init_common_variables() get corrupted if accesses with names of different case. */ DBUG_PRINT("info", ("lower_case_table_names: %d", lower_case_table_names)); + if(mysql_real_data_home_ptr == NULL || *mysql_real_data_home_ptr == 0) + mysql_real_data_home_ptr= mysql_real_data_home; SYSVAR_AUTOSIZE(lower_case_file_system, - test_if_case_insensitive(mysql_real_data_home)); + test_if_case_insensitive(mysql_real_data_home_ptr)); if (!lower_case_table_names && lower_case_file_system == 1) { if (lower_case_table_names_used) @@ -4161,7 +4163,7 @@ static int init_common_variables() { if (global_system_variables.log_warnings) sql_print_warning("Setting lower_case_table_names=2 because file " - "system for %s is case insensitive", mysql_real_data_home); + "system for %s is case insensitive", mysql_real_data_home_ptr); SYSVAR_AUTOSIZE(lower_case_table_names, 2); } } @@ -4172,7 +4174,7 @@ static int init_common_variables() sql_print_warning("lower_case_table_names was set to 2, even though your " "the file system '%s' is case sensitive. Now setting " "lower_case_table_names to 0 to avoid future problems.", - mysql_real_data_home); + mysql_real_data_home_ptr); SYSVAR_AUTOSIZE(lower_case_table_names, 0); } else diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 3e173a47f02..ebd92a0e45a 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -45,6 +45,7 @@ #include <violite.h> #include <signal.h> #include "probes_mysql.h" +#include <debug_sync.h> #include "proxy_protocol.h" PSI_memory_key key_memory_NET_buff; @@ -494,6 +495,17 @@ net_write_command(NET *net,uchar command, DBUG_ENTER("net_write_command"); DBUG_PRINT("enter",("length: %lu", (ulong) len)); + DBUG_EXECUTE_IF("simulate_error_on_packet_write", + { + if (command == COM_BINLOG_DUMP) + { + net->last_errno = ER_NET_ERROR_ON_WRITE; + DBUG_ASSERT(!debug_sync_set_action( + (THD *)net->thd, + STRING_WITH_LEN("now SIGNAL parked WAIT_FOR continue"))); + DBUG_RETURN(true); + } + };); MYSQL_NET_WRITE_START(length); buff[4]=command; /* For first packet */ diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index ca5f00cbdae..8ae3ce5c995 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -592,10 +592,11 @@ int check_and_do_in_subquery_rewrites(JOIN *join) Item_subselect::subs_type substype= subselect->substype(); switch (substype) { case Item_subselect::IN_SUBS: - in_subs= (Item_in_subselect *)subselect; + in_subs= subselect->get_IN_subquery(); break; case Item_subselect::ALL_SUBS: case Item_subselect::ANY_SUBS: + DBUG_ASSERT(subselect->get_IN_subquery()); allany_subs= (Item_allany_subselect *)subselect; break; default: @@ -640,13 +641,15 @@ int check_and_do_in_subquery_rewrites(JOIN *join) char const *save_where= thd->where; thd->where= "IN/ALL/ANY subquery"; - bool failure= in_subs->left_expr->fix_fields_if_needed(thd, - &in_subs->left_expr); + Item **left= in_subs->left_exp_ptr(); + bool failure= (*left)->fix_fields_if_needed(thd, left); thd->lex->current_select= current; thd->where= save_where; if (failure) DBUG_RETURN(-1); /* purecov: deadcode */ + // fix_field above can rewrite left expression + uint ncols= (*left)->cols(); /* Check if the left and right expressions have the same # of columns, i.e. we don't have a case like @@ -655,9 +658,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join) TODO why do we have this duplicated in IN->EXISTS transformers? psergey-todo: fix these: grep for duplicated_subselect_card_check */ - if (select_lex->item_list.elements != in_subs->left_expr->cols()) + if (select_lex->item_list.elements != ncols) { - my_error(ER_OPERAND_COLUMNS, MYF(0), in_subs->left_expr->cols()); + my_error(ER_OPERAND_COLUMNS, MYF(0), ncols); DBUG_RETURN(-1); } } @@ -724,9 +727,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join) { DBUG_PRINT("info", ("Subquery can't be converted to merged semi-join")); /* Test if the user has set a legal combination of optimizer switches. */ - if (!optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS) && - !optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION)) - my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0)); + DBUG_ASSERT(optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS | + OPTIMIZER_SWITCH_MATERIALIZATION)); /* Transform each subquery predicate according to its overloaded transformer. @@ -847,9 +849,10 @@ int check_and_do_in_subquery_rewrites(JOIN *join) static bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs) { + Item *left_exp= in_subs->left_exp(); DBUG_ENTER("subquery_types_allow_materialization"); - DBUG_ASSERT(in_subs->left_expr->is_fixed()); + DBUG_ASSERT(left_exp->is_fixed()); List_iterator<Item> it(in_subs->unit->first_select()->item_list); uint elements= in_subs->unit->first_select()->item_list.elements; @@ -871,7 +874,7 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs) uint32 total_key_length = 0; for (uint i= 0; i < elements; i++) { - Item *outer= in_subs->left_expr->element_index(i); + Item *outer= left_exp->element_index(i); Item *inner= it++; all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM && inner->real_item()->type() == Item::FIELD_ITEM); @@ -1706,7 +1709,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) sj_nest->alias= sj_nest_name; sj_nest->sj_subq_pred= subq_pred; sj_nest->original_subq_pred_used_tables= subq_pred->used_tables() | - subq_pred->left_expr->used_tables(); + subq_pred->left_exp()->used_tables(); /* Nests do not participate in those 'chains', so: */ /* sj_nest->next_leaf= sj_nest->next_local= sj_nest->next_global == NULL*/ emb_join_list->push_back(sj_nest, thd->mem_root); @@ -1794,14 +1797,17 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) */ SELECT_LEX *save_lex= thd->lex->current_select; thd->lex->current_select=subq_lex; - if (subq_pred->left_expr->fix_fields_if_needed(thd, &subq_pred->left_expr)) + Item **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(); thd->lex->current_select=save_lex; table_map 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 | - subq_pred->left_expr->used_tables(); + left_exp->used_tables(); sj_nest->sj_on_expr= subq_lex->join->conds; /* @@ -1819,14 +1825,14 @@ 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. */ - sj_nest->sj_in_exprs= subq_pred->left_expr->cols(); + uint 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); - if (subq_pred->left_expr->cols() == 1) + if (ncols == 1) { /* add left = select_list_element */ - nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr, + nested_join->sj_outer_expr_list.push_back(left, thd->mem_root); /* Create Item_func_eq. Note that @@ -1838,36 +1844,36 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) with thd->change_item_tree */ Item_func_eq *item_eq= - new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig, + new (thd->mem_root) Item_func_eq(thd, left_exp_orig, subq_lex->ref_pointer_array[0]); if (!item_eq) DBUG_RETURN(TRUE); - if (subq_pred->left_expr_orig != subq_pred->left_expr) - thd->change_item_tree(item_eq->arguments(), subq_pred->left_expr); + if (left_exp_orig != left_exp) + thd->change_item_tree(item_eq->arguments(), left_exp); item_eq->in_equality_no= 0; sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq); } - else if (subq_pred->left_expr->type() == Item::ROW_ITEM) + else if (left_exp->type() == Item::ROW_ITEM) { /* disassemple left expression and add left1 = select_list_element1 and left2 = select_list_element2 ... */ - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + for (uint i= 0; i < ncols; i++) { - nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->addr(i), + nested_join->sj_outer_expr_list.push_back(left_exp->addr(i), thd->mem_root); Item_func_eq *item_eq= new (thd->mem_root) - Item_func_eq(thd, subq_pred->left_expr_orig->element_index(i), + Item_func_eq(thd, left_exp_orig->element_index(i), subq_lex->ref_pointer_array[i]); if (!item_eq) DBUG_RETURN(TRUE); - DBUG_ASSERT(subq_pred->left_expr->element_index(i)->is_fixed()); - if (subq_pred->left_expr_orig->element_index(i) != - subq_pred->left_expr->element_index(i)) + DBUG_ASSERT(left_exp->element_index(i)->is_fixed()); + if (left_exp_orig->element_index(i) != + left_exp->element_index(i)) thd->change_item_tree(item_eq->arguments(), - subq_pred->left_expr->element_index(i)); + left_exp->element_index(i)); item_eq->in_equality_no= i; sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq); } @@ -1882,10 +1888,10 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) /* fix fields on subquery was call so they should be the same */ if (!row) DBUG_RETURN(TRUE); - DBUG_ASSERT(subq_pred->left_expr->cols() == row->cols()); - nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr); + 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, subq_pred->left_expr_orig, row); + new (thd->mem_root) Item_func_eq(thd, left_exp_orig, row); if (!item_eq) DBUG_RETURN(TRUE); for (uint i= 0; i < row->cols(); i++) @@ -4140,7 +4146,8 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab) for (i= 0; i < tmp_key_parts; i++, cur_key_part++, ref_key++) { - tab_ref->items[i]= emb_sj_nest->sj_subq_pred->left_expr->element_index(i); + tab_ref->items[i]= + emb_sj_nest->sj_subq_pred->left_exp()->element_index(i); int null_count= MY_TEST(cur_key_part->field->real_maybe_null()); *ref_key= new store_key_item(thd, cur_key_part->field, /* TODO: @@ -4325,18 +4332,20 @@ static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm, Item_in_subselect *subq_pred) { Item *res= NULL; - if (subq_pred->left_expr->cols() == 1) + Item *left_exp= subq_pred->left_exp(); + uint ncols= left_exp->cols(); + if (ncols == 1) { - if (!(res= new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr, + if (!(res= new (thd->mem_root) Item_func_eq(thd, left_exp, new (thd->mem_root) Item_field(thd, sjm->table->field[0])))) return NULL; /* purecov: inspected */ } else { Item *conj; - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + for (uint i= 0; i < ncols; i++) { - if (!(conj= new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr->element_index(i), + if (!(conj= new (thd->mem_root) Item_func_eq(thd, left_exp->element_index(i), new (thd->mem_root) Item_field(thd, sjm->table->field[i]))) || !(res= and_items(thd, res, conj))) return NULL; /* purecov: inspected */ @@ -5404,7 +5413,7 @@ int rewrite_to_index_subquery_engine(JOIN *join) change_engine(new subselect_uniquesubquery_engine(thd, join_tab, - unit->item, + unit->item->get_IN_subquery(), where))); } else if (join_tab[0].type == JT_REF && @@ -5418,7 +5427,7 @@ int rewrite_to_index_subquery_engine(JOIN *join) change_engine(new subselect_indexsubquery_engine(thd, join_tab, - unit->item, + unit->item->get_IN_subquery(), where, NULL, 0))); @@ -5434,7 +5443,7 @@ int rewrite_to_index_subquery_engine(JOIN *join) DBUG_RETURN(unit->item-> change_engine(new subselect_indexsubquery_engine(thd, join_tab, - unit->item, + unit->item->get_IN_subquery(), join->conds, join->having, 1))); @@ -6109,11 +6118,13 @@ bool execute_degenerate_jtbm_semi_join(THD *thd, subq_pred->jtbm_const_row_found= TRUE; Item *eq_cond; - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + Item *left_exp= subq_pred->left_exp(); + uint ncols= left_exp->cols(); + for (uint i= 0; i < ncols; i++) { eq_cond= new (thd->mem_root) Item_func_eq(thd, - subq_pred->left_expr->element_index(i), + left_exp->element_index(i), new_sink->row[i]); if (!eq_cond || eq_cond->fix_fields(thd, NULL) || eq_list.push_back(eq_cond, thd->mem_root)) @@ -6408,7 +6419,7 @@ bool JOIN::choose_subquery_plan(table_map join_tables) if (is_in_subquery()) { - in_subs= (Item_in_subselect*) unit->item; + in_subs= unit->item->get_IN_subquery(); if (in_subs->create_in_to_exists_cond(this)) return true; } @@ -6692,12 +6703,12 @@ bool JOIN::choose_tableless_subquery_plan() everything as-is, setup_jtbm_semi_joins() has special handling for cases like this. */ - if (subs_predicate->is_in_predicate() && - !(subs_predicate->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)subs_predicate)->is_jtbm_merged)) + Item_in_subselect *in_subs; + in_subs= subs_predicate->get_IN_subquery(); + if (in_subs && + !(subs_predicate->substype() == Item_subselect::IN_SUBS && + in_subs->is_jtbm_merged)) { - Item_in_subselect *in_subs; - in_subs= (Item_in_subselect*) subs_predicate; in_subs->set_strategy(SUBS_IN_TO_EXISTS); if (in_subs->create_in_to_exists_cond(this) || in_subs->inject_in_to_exists_cond(this)) @@ -6714,7 +6725,8 @@ bool Item::pushable_equality_checker_for_subquery(uchar *arg) { return get_corresponding_field_pair(this, - ((Item_in_subselect *)arg)->corresponding_fields); + ((Item *)arg)->get_IN_subquery()-> + corresponding_fields); } @@ -6853,7 +6865,7 @@ Item *get_corresponding_item(THD *thd, Item *item, Item *Item_field::in_subq_field_transformer_for_where(THD *thd, uchar *arg) { - Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item_in_subselect *subq_pred= ((Item *)arg)->get_IN_subquery(); Item *producing_item= get_corresponding_item(thd, this, subq_pred); if (producing_item) return producing_item->build_clone(thd); @@ -6866,7 +6878,7 @@ Item *Item_direct_view_ref::in_subq_field_transformer_for_where(THD *thd, { if (item_equal) { - Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item_in_subselect *subq_pred= ((Item *)arg)->get_IN_subquery(); Item *producing_item= get_corresponding_item(thd, this, subq_pred); DBUG_ASSERT (producing_item != NULL); return producing_item->build_clone(thd); @@ -6916,6 +6928,7 @@ get_corresponding_item_for_in_subq_having(THD *thd, Item *in_item, Item *Item_field::in_subq_field_transformer_for_having(THD *thd, uchar *arg) { + DBUG_ASSERT(((Item *)arg)->get_IN_subquery()); return get_corresponding_item_for_in_subq_having(thd, this, (Item_in_subselect *)arg); } @@ -6928,6 +6941,7 @@ Item *Item_direct_view_ref::in_subq_field_transformer_for_having(THD *thd, return this; else { + DBUG_ASSERT(((Item *)arg)->get_IN_subquery()); Item *new_item= get_corresponding_item_for_in_subq_having(thd, this, (Item_in_subselect *)arg); if (!new_item) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 10f82242bca..8ad14ca260c 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2006, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, MariaDB Corporation. + Copyright (c) 2010, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -864,9 +864,6 @@ void partition_info::vers_set_hist_part(THD *thd) if (next->range_value > thd->query_start()) return; } - my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG), - table->s->db.str, table->s->table_name.str, - vers_info->hist_part->partition_name, "INTERVAL"); } } diff --git a/sql/protocol.cc b/sql/protocol.cc index ebc0c3815aa..ce4558a13c1 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -43,6 +43,12 @@ bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); static bool write_eof_packet(THD *, NET *, uint, uint); #endif +CHARSET_INFO *Protocol::character_set_results() const +{ + return thd->variables.character_set_results; +} + + #ifndef EMBEDDED_LIBRARY bool Protocol::net_store_data(const uchar *from, size_t length) #else @@ -765,6 +771,7 @@ void Protocol::init(THD *thd_arg) convert= &thd->convert_buffer; #ifndef DBUG_OFF field_handlers= 0; + field_pos= 0; #endif } @@ -843,22 +850,25 @@ bool Protocol_text::store_field_metadata(const THD * thd, if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (store(STRING_WITH_LEN("def"), cs, thd_charset) || - store_str(field.db_name, cs, thd_charset) || - store_str(field.table_name, cs, thd_charset) || - store_str(field.org_table_name, cs, thd_charset) || - store_str(field.col_name, cs, thd_charset) || - store_str(field.org_col_name, cs, thd_charset)) + const LEX_CSTRING def= {STRING_WITH_LEN("def")}; + if (store_ident(def, MY_REPERTOIRE_ASCII) || + store_ident(field.db_name) || + store_ident(field.table_name) || + store_ident(field.org_table_name) || + store_ident(field.col_name) || + store_ident(field.org_col_name)) return true; if (thd->client_capabilities & MARIADB_CLIENT_EXTENDED_METADATA) { Send_field_packed_extended_metadata metadata; metadata.pack(field); + /* Don't apply character set conversion: extended metadata is a binary encoded data. */ - if (store_str(metadata.lex_cstring(), cs, &my_charset_bin)) + if (store_binary_string(&metadata, cs, + MY_REPERTOIRE_UNICODE30)) return true; } if (packet->realloc(packet->length() + 12)) @@ -891,8 +901,8 @@ bool Protocol_text::store_field_metadata(const THD * thd, } else { - if (store_str(field.table_name, cs, thd_charset) || - store_str(field.col_name, cs, thd_charset) || + if (store_ident(field.table_name) || + store_ident(field.col_name) || packet->realloc(packet->length() + 10)) return true; pos= (char*) packet->end(); @@ -1172,12 +1182,12 @@ bool Protocol_text::store_null() */ bool Protocol::store_string_aux(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs) + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs) { /* 'tocs' is set 0 when client issues SET character_set_results=NULL */ - if (tocs && !my_charset_same(fromcs, tocs) && - fromcs != &my_charset_bin && - tocs != &my_charset_bin) + if (needs_conversion(fromcs, from_repertoire, tocs)) { /* Store with conversion */ return net_store_data_cs((uchar*) from, length, fromcs, tocs); @@ -1199,29 +1209,19 @@ bool Protocol::store_warning(const char *from, size_t length) } -bool Protocol_text::store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs) +bool Protocol_text::store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs) { #ifndef DBUG_OFF - DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_STRING)); - field_pos++; -#endif - return store_string_aux(from, length, fromcs, tocs); -} - - -bool Protocol_text::store(const char *from, size_t length, - CHARSET_INFO *fromcs) -{ - CHARSET_INFO *tocs= this->thd->variables.character_set_results; -#ifndef DBUG_OFF - DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %.*b", field_pos, - field_count, (int) length, (length == 0 ? "" : from))); + DBUG_PRINT("info", ("Protocol_text::store field %u : %.*b", field_pos, + (int) length, (length == 0 ? "" : from))); DBUG_ASSERT(field_handlers == 0 || field_pos < field_count); DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_STRING)); field_pos++; #endif - return store_string_aux(from, length, fromcs, tocs); + return store_string_aux(from, length, fromcs, from_repertoire, tocs); } @@ -1334,7 +1334,8 @@ bool Protocol_text::store(Field *field) dbug_tmp_restore_column_map(table->read_set, old_map); #endif - return store_string_aux(str.ptr(), str.length(), str.charset(), tocs); + return store_string_aux(str.ptr(), str.length(), str.charset(), + field->dtcollation().repertoire, tocs); } @@ -1452,19 +1453,13 @@ void Protocol_binary::prepare_for_resend() } -bool Protocol_binary::store(const char *from, size_t length, - CHARSET_INFO *fromcs) -{ - CHARSET_INFO *tocs= thd->variables.character_set_results; - field_pos++; - return store_string_aux(from, length, fromcs, tocs); -} - -bool Protocol_binary::store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs) +bool Protocol_binary::store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs) { field_pos++; - return store_string_aux(from, length, fromcs, tocs); + return store_string_aux(from, length, fromcs, from_repertoire, tocs); } bool Protocol_binary::store_null() @@ -1523,11 +1518,12 @@ bool Protocol_binary::store_decimal(const my_decimal *d) { #ifndef DBUG_OFF DBUG_ASSERT(0); // This method is not used yet - field_pos++; #endif StringBuffer<DECIMAL_MAX_STR_LENGTH> str; (void) d->to_string(&str); - return store(str.ptr(), str.length(), str.charset()); + return store_str(str.ptr(), str.length(), str.charset(), + MY_REPERTOIRE_ASCII, + thd->variables.character_set_results); } bool Protocol_binary::store(float from, uint32 decimals, String *buffer) @@ -1580,7 +1576,7 @@ bool Protocol_binary::store(MYSQL_TIME *tm, int decimals) DBUG_ASSERT(decimals == AUTO_SEC_PART_DIGITS || (decimals >= 0 && decimals <= TIME_SECOND_PART_DIGITS)); if (decimals != AUTO_SEC_PART_DIGITS) - my_time_trunc(tm, decimals); + my_datetime_trunc(tm, decimals); int4store(pos+7, tm->second_part); if (tm->second_part) length=11; diff --git a/sql/protocol.h b/sql/protocol.h index 22d7990a194..188cea847c1 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -61,12 +61,26 @@ protected: MYSQL_FIELD *next_mysql_field; MEM_ROOT *alloc; #endif + bool needs_conversion(CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs) const + { + // 'tocs' is set 0 when client issues SET character_set_results=NULL + return tocs && !my_charset_same(fromcs, tocs) && + fromcs != &my_charset_bin && + tocs != &my_charset_bin && + (from_repertoire != MY_REPERTOIRE_ASCII || + (fromcs->state & MY_CS_NONASCII) || + (tocs->state & MY_CS_NONASCII)); + } /* The following two are low-level functions that are invoked from higher-level store_xxx() funcs. The data is stored into this->packet. */ bool store_string_aux(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs); virtual bool send_ok(uint server_status, uint statement_warn_count, ulonglong affected_rows, ulonglong last_insert_id, @@ -77,6 +91,8 @@ protected: virtual bool send_error(uint sql_errno, const char *err_msg, const char *sql_state); + CHARSET_INFO *character_set_results() const; + public: THD *thd; Protocol(THD *thd_arg) { init(thd_arg); } @@ -120,13 +136,10 @@ public: virtual bool store_long(longlong from)=0; virtual bool store_longlong(longlong from, bool unsigned_flag)=0; virtual bool store_decimal(const my_decimal *)=0; - virtual bool store(const char *from, size_t length, CHARSET_INFO *cs)=0; - virtual bool store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0; - bool store_str(const LEX_CSTRING &s, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) - { - return store(s.str, (uint) s.length, fromcs, tocs); - } + virtual bool store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs)=0; virtual bool store(float from, uint32 decimals, String *buffer)=0; virtual bool store(double from, uint32 decimals, String *buffer)=0; virtual bool store(MYSQL_TIME *time, int decimals)=0; @@ -134,6 +147,35 @@ public: virtual bool store_time(MYSQL_TIME *time, int decimals)=0; virtual bool store(Field *field)=0; + // Various useful wrappers for the virtual store*() methods. + // Backward wrapper for store_str() + inline bool store(const char *from, size_t length, CHARSET_INFO *cs, + my_repertoire_t repertoire= MY_REPERTOIRE_UNICODE30) + { + return store_str(from, length, cs, repertoire, character_set_results()); + } + inline bool store_lex_cstring(const LEX_CSTRING &s, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs) + { + return store_str(s.str, (uint) s.length, fromcs, from_repertoire, tocs); + } + inline bool store_binary_string(Binary_string *str, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire) + { + return store_str(str->ptr(), (uint) str->length(), fromcs, from_repertoire, + &my_charset_bin); + } + bool store_ident(const LEX_CSTRING &s, + my_repertoire_t repertoire= MY_REPERTOIRE_UNICODE30) + { + return store_lex_cstring(s, system_charset_info, repertoire, + character_set_results()); + } + // End of wrappers + virtual bool send_out_parameters(List<Item_param> *sp_params)=0; #ifdef EMBEDDED_LIBRARY bool begin_dataset(); @@ -178,9 +220,10 @@ public: virtual bool store_long(longlong from); virtual bool store_longlong(longlong from, bool unsigned_flag); virtual bool store_decimal(const my_decimal *); - virtual bool store(const char *from, size_t length, CHARSET_INFO *cs); - virtual bool store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + virtual bool store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs); virtual bool store(MYSQL_TIME *time, int decimals); virtual bool store_date(MYSQL_TIME *time); virtual bool store_time(MYSQL_TIME *time, int decimals); @@ -223,9 +266,10 @@ public: virtual bool store_long(longlong from); virtual bool store_longlong(longlong from, bool unsigned_flag); virtual bool store_decimal(const my_decimal *); - virtual bool store(const char *from, size_t length, CHARSET_INFO *cs); - virtual bool store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + virtual bool store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs); virtual bool store(MYSQL_TIME *time, int decimals); virtual bool store_date(MYSQL_TIME *time); virtual bool store_time(MYSQL_TIME *time, int decimals); @@ -272,8 +316,11 @@ public: bool store_long(longlong) { return false; } bool store_longlong(longlong, bool) { return false; } bool store_decimal(const my_decimal *) { return false; } - bool store(const char *, size_t, CHARSET_INFO *) { return false; } - bool store(const char *, size_t, CHARSET_INFO *, CHARSET_INFO *) { return false; } + bool store_str(const char *, size_t, CHARSET_INFO *, my_repertoire_t, + CHARSET_INFO *) + { + return false; + } bool store(MYSQL_TIME *, int) { return false; } bool store_date(MYSQL_TIME *) { return false; } bool store_time(MYSQL_TIME *, int) { return false; } diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 94882230682..c12573f817f 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -1053,10 +1053,10 @@ handle_rpl_parallel_thread(void *arg) server_threads.insert(thd); set_current_thd(thd); pthread_detach_this_thread(); + thd->store_globals(); thd->init_for_queries(); thd->variables.binlog_annotate_row_events= 0; init_thr_lock(); - thd->store_globals(); thd->system_thread= SYSTEM_THREAD_SLAVE_SQL; thd->security_ctx->skip_grants(); thd->variables.max_allowed_packet= slave_max_allowed_packet; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 11eccefdde9..941616a26d5 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -268,7 +268,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name); msg= current_thd->get_stmt_da()->message(); goto err; } - if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, + if (init_io_cache(&info_file, info_fd, LOG_BIN_IO_SIZE, READ_CACHE, 0L,0, MYF(MY_WME))) { sql_print_error("Failed to create a cache on relay log info file '%s'", @@ -303,7 +303,7 @@ Failed to open the existing relay log info file '%s' (errno %d)", error= 1; } else if (init_io_cache(&info_file, info_fd, - IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME))) + LOG_BIN_IO_SIZE, READ_CACHE, 0L, 0, MYF(MY_WME))) { sql_print_error("Failed to create a cache on relay log info file '%s'", fname); diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index 6b06bddd773..f61db1e80e8 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -199,6 +199,16 @@ extern "C" void wsrep_handle_SR_rollback(THD *bf_thd, extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd, my_bool signal) { + DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort", + { + const char act[]= + "now " + "SIGNAL sync.before_wsrep_thd_abort_reached " + "WAIT_FOR signal.before_wsrep_thd_abort"; + DBUG_ASSERT(!debug_sync_set_action(bf_thd, + STRING_WITH_LEN(act))); + };); + my_bool ret= wsrep_bf_abort(bf_thd, victim_thd); /* Send awake signal if victim was BF aborted or does not @@ -210,10 +220,22 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd, mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_data); mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_kill); mysql_mutex_lock(&victim_thd->LOCK_thd_data); + + if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id) + { + WSREP_DEBUG("victim is killed already by %llu, skipping awake", + victim_thd->wsrep_aborter); + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); + return false; + } + mysql_mutex_lock(&victim_thd->LOCK_thd_kill); + victim_thd->wsrep_aborter= bf_thd->thread_id; victim_thd->awake_no_mutex(KILL_QUERY); mysql_mutex_unlock(&victim_thd->LOCK_thd_kill); mysql_mutex_unlock(&victim_thd->LOCK_thd_data); + } else { + WSREP_DEBUG("wsrep_thd_bf_abort skipped awake"); } return ret; } @@ -339,3 +361,15 @@ extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd) else return(global_system_variables.wsrep_OSU_method); } + +extern "C" bool wsrep_thd_set_wsrep_aborter(THD *bf_thd, THD *victim_thd) +{ + WSREP_DEBUG("wsrep_thd_set_wsrep_aborter called"); + mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data); + if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id) + { + return true; + } + victim_thd->wsrep_aborter = bf_thd->thread_id; + return false; +}
\ No newline at end of file diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 4cee6cb0dfa..1e5e356a5ba 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -189,7 +189,13 @@ bool sysvartrack_validate_value(THD *thd, const char *str, size_t len) char *token, *lasts= NULL; size_t rest= var_list.length; - if (!var_list.str || var_list.length == 0 || + if (!var_list.str) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), + "session_track_system_variables", "NULL"); + return false; + } + if (var_list.length == 0 || !strcmp(var_list.str, "*")) { return false; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 8b180b466f8..42b3796d03c 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7961,4 +7961,4 @@ ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS ER_NOT_ALLOWED_IN_THIS_CONTEXT eng "'%-.128s' is not allowed in this context" ER_DATA_WAS_COMMITED_UNDER_ROLLBACK - eng "Engine %s does not support rollback. Changes where commited during rollback call" + eng "Engine %s does not support rollback. Changes where committed during rollback call" diff --git a/sql/slave.cc b/sql/slave.cc index 000900efe61..fba3992a820 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3727,7 +3727,8 @@ static int request_dump(THD *thd, MYSQL* mysql, Master_info* mi, in the future, we should do a better error analysis, but for now we just fill up the error log :-) */ - if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) + if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED || + mysql_errno(mysql) == ER_NET_ERROR_ON_WRITE) *suppress_warnings= TRUE; // Suppress reconnect warning else sql_print_error("Error on COM_BINLOG_DUMP: %d %s, will retry in %d secs", diff --git a/sql/sp.cc b/sql/sp.cc index 971aa4a143f..3737bd11740 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1258,20 +1258,20 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const switch (type()) { case SP_TYPE_PACKAGE: // Drop together with its PACKAGE BODY mysql.proc record - ret= sp_handler_package_spec.sp_find_and_drop_routine(thd, table, sp); + if (sp_handler_package_spec.sp_find_and_drop_routine(thd, table, sp)) + goto done; break; case SP_TYPE_PACKAGE_BODY: case SP_TYPE_FUNCTION: case SP_TYPE_PROCEDURE: - ret= sp_drop_routine_internal(thd, sp, table); + if (sp_drop_routine_internal(thd, sp, table)) + goto done; break; case SP_TYPE_TRIGGER: case SP_TYPE_EVENT: DBUG_ASSERT(0); ret= SP_OK; } - if (ret != SP_OK) - goto done; } else if (lex->create_info.if_not_exists()) { @@ -1286,7 +1286,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const if (type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); - returns= retstr.lex_cstring(); + retstr.get_value(&returns); } goto log; } @@ -1369,7 +1369,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const if (type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); - returns= retstr.lex_cstring(); + retstr.get_value(&returns); store_failed= store_failed || table->field[MYSQL_PROC_FIELD_RETURNS]-> @@ -2061,7 +2061,7 @@ Sp_handler::sp_clone_and_link_routine(THD *thd, if (type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); - returns= retstr.lex_cstring(); + retstr.get_value(&returns); } if (sp->m_parent) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d94016b7815..9cc35d0707f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -800,6 +800,15 @@ class Grant_table_base bool init_read_record(READ_RECORD* info) const { DBUG_ASSERT(m_table); + + if (num_fields() < min_columns) + { + my_printf_error(ER_UNKNOWN_ERROR, "Fatal error: mysql.%s table is " + "damaged or in unsupported 3.20 format", + MYF(ME_ERROR_LOG), m_table->s->table_name.str); + return 1; + } + bool result= ::init_read_record(info, m_table->in_use, m_table, NULL, NULL, 1, true, false); if (!result) @@ -824,7 +833,7 @@ class Grant_table_base protected: friend class Grant_tables; - Grant_table_base() : start_priv_columns(0), end_priv_columns(0), m_table(0) + Grant_table_base() : min_columns(3), start_priv_columns(0), end_priv_columns(0), m_table(0) { } /* Compute how many privilege columns this table has. This method @@ -853,6 +862,9 @@ class Grant_table_base } } + + /* the min number of columns a table should have */ + uint min_columns; /* The index at which privilege columns start. */ uint start_priv_columns; /* The index after the last privilege column */ @@ -1266,7 +1278,7 @@ class User_table_tabular: public User_table friend class Grant_tables; /* Only Grant_tables can instantiate this class. */ - User_table_tabular() {} + User_table_tabular() { min_columns= 13; /* As in 3.20.13 */ } /* The user table is a bit different compared to the other Grant tables. Usually, we only add columns to the grant tables when adding functionality. @@ -1288,13 +1300,6 @@ class User_table_tabular: public User_table int setup_sysvars() const { - if (num_fields() < 13) // number of columns in 3.21 - { - sql_print_error("Fatal error: mysql.user table is damaged or in " - "unsupported 3.20 format."); - return 1; - } - username_char_length= MY_MIN(m_table->field[1]->char_length(), USERNAME_CHAR_LENGTH); using_global_priv_table= false; @@ -1806,7 +1811,7 @@ class Db_table: public Grant_table_base private: friend class Grant_tables; - Db_table() {} + Db_table() { min_columns= 9; /* as in 3.20.13 */ } }; class Tables_priv_table: public Grant_table_base @@ -1824,7 +1829,7 @@ class Tables_priv_table: public Grant_table_base private: friend class Grant_tables; - Tables_priv_table() {} + Tables_priv_table() { min_columns= 8; /* as in 3.22.26a */ } }; class Columns_priv_table: public Grant_table_base @@ -1841,7 +1846,7 @@ class Columns_priv_table: public Grant_table_base private: friend class Grant_tables; - Columns_priv_table() {} + Columns_priv_table() { min_columns= 7; /* as in 3.22.26a */ } }; class Host_table: public Grant_table_base @@ -1853,7 +1858,7 @@ class Host_table: public Grant_table_base private: friend class Grant_tables; - Host_table() {} + Host_table() { min_columns= 8; /* as in 3.20.13 */ } }; class Procs_priv_table: public Grant_table_base @@ -1871,7 +1876,7 @@ class Procs_priv_table: public Grant_table_base private: friend class Grant_tables; - Procs_priv_table() {} + Procs_priv_table() { min_columns=8; } }; class Proxies_priv_table: public Grant_table_base @@ -1888,7 +1893,7 @@ class Proxies_priv_table: public Grant_table_base private: friend class Grant_tables; - Proxies_priv_table() {} + Proxies_priv_table() { min_columns= 7; } }; class Roles_mapping_table: public Grant_table_base @@ -1902,7 +1907,7 @@ class Roles_mapping_table: public Grant_table_base private: friend class Grant_tables; - Roles_mapping_table() {} + Roles_mapping_table() { min_columns= 4; } }; /** diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index a1d235086db..ede30263e48 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2016, 2018, MariaDB Corporation + Copyright (c) 2016, 2020, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -129,10 +129,10 @@ const char* Alter_info::lock() const } -bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result, +bool Alter_info::supports_algorithm(THD *thd, const Alter_inplace_info *ha_alter_info) { - switch (result) { + switch (ha_alter_info->inplace_supported) { case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: case HA_ALTER_INPLACE_SHARED_LOCK: case HA_ALTER_INPLACE_NO_LOCK: @@ -173,10 +173,10 @@ bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result, } -bool Alter_info::supports_lock(THD *thd, enum_alter_inplace_result result, +bool Alter_info::supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info) { - switch (result) { + switch (ha_alter_info->inplace_supported) { case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: // If SHARED lock and no particular algorithm was requested, use COPY. if (requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED && @@ -377,7 +377,9 @@ void Alter_table_ctx::report_implicit_default_value_error(THD *thd, thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN, h->name().ptr(), h->default_value().ptr(), - s, error_field->field_name.str); + s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + error_field->field_name.str); } diff --git a/sql/sql_alter.h b/sql/sql_alter.h index ca343f36569..89eb4ebb3e9 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -1,5 +1,5 @@ /* Copyright (c) 2010, 2014, Oracle and/or its affiliates. - Copyright (c) 2013, 2018, MariaDB Corporation. + Copyright (c) 2013, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -203,29 +203,26 @@ public: with the specified user alter algorithm. @param thd Thread handle - @param result Operation supported for inplace alter @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported operation @retval true Not supported value */ - bool supports_algorithm(THD *thd, enum_alter_inplace_result result, + bool supports_algorithm(THD *thd, const Alter_inplace_info *ha_alter_info); /** Check whether the given result can be supported with the specified user lock type. - @param result Operation supported for inplace alter @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported lock type @retval true Not supported value */ - bool supports_lock(THD *thd, enum_alter_inplace_result result, - const Alter_inplace_info *ha_alter_info); + bool supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info); /** Return user requested algorithm. If user does not specify diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6d53a8ee6e3..45ce4be3eb5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5332,6 +5332,24 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list) DBUG_VOID_RETURN; } +int TABLE::fix_vcol_exprs(THD *thd) +{ + for (Field **vf= vfield; vf && *vf; vf++) + if (fix_session_vcol_expr(thd, (*vf)->vcol_info)) + return 1; + + for (Field **df= default_field; df && *df; df++) + if ((*df)->default_value && + fix_session_vcol_expr(thd, (*df)->default_value)) + return 1; + + for (Virtual_column_info **cc= check_constraints; cc && *cc; cc++) + if (fix_session_vcol_expr(thd, (*cc))) + return 1; + + return 0; +} + static bool fix_all_session_vcol_exprs(THD *thd, TABLE_LIST *tables) { @@ -5339,36 +5357,27 @@ static bool fix_all_session_vcol_exprs(THD *thd, TABLE_LIST *tables) TABLE_LIST *first_not_own= thd->lex->first_not_own_table(); DBUG_ENTER("fix_session_vcol_expr"); - for (TABLE_LIST *table= tables; table && table != first_not_own; + int error= 0; + for (TABLE_LIST *table= tables; table && table != first_not_own && !error; table= table->next_global) { TABLE *t= table->table; if (!table->placeholder() && t->s->vcols_need_refixing && table->lock_type >= TL_WRITE_ALLOW_WRITE) { + Query_arena *stmt_backup= thd->stmt_arena; + if (thd->stmt_arena->is_conventional()) + thd->stmt_arena= t->expr_arena; if (table->security_ctx) thd->security_ctx= table->security_ctx; - for (Field **vf= t->vfield; vf && *vf; vf++) - if (fix_session_vcol_expr(thd, (*vf)->vcol_info)) - goto err; - - for (Field **df= t->default_field; df && *df; df++) - if ((*df)->default_value && - fix_session_vcol_expr(thd, (*df)->default_value)) - goto err; - - for (Virtual_column_info **cc= t->check_constraints; cc && *cc; cc++) - if (fix_session_vcol_expr(thd, (*cc))) - goto err; + error= t->fix_vcol_exprs(thd); thd->security_ctx= save_security_ctx; + thd->stmt_arena= stmt_backup; } } - DBUG_RETURN(0); -err: - thd->security_ctx= save_security_ctx; - DBUG_RETURN(1); + DBUG_RETURN(error); } @@ -6328,10 +6337,11 @@ find_field_in_tables(THD *thd, Item_ident *item, for (SELECT_LEX *sl= current_sel; sl && sl!=last_select; sl=sl->outer_select()) { - Item *subs= sl->master_unit()->item; - if (subs->type() == Item::SUBSELECT_ITEM && - ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN)) + Item_in_subselect *in_subs= + sl->master_unit()->item->get_IN_subquery(); + if (in_subs && + in_subs->substype() == Item_subselect::IN_SUBS && + in_subs->test_strategy(SUBS_SEMI_JOIN)) { continue; } @@ -8230,7 +8240,7 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) */ if (embedded->sj_subq_pred) { - Item **left_expr= &embedded->sj_subq_pred->left_expr; + Item **left_expr= embedded->sj_subq_pred->left_exp_ptr(); if ((*left_expr)->fix_fields_if_needed(thd, left_expr)) return TRUE; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0b142a22f59..c507c99ddde 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -706,6 +706,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) wsrep_affected_rows(0), wsrep_has_ignored_error(false), wsrep_ignore_table(false), + wsrep_aborter(0), /* wsrep-lib */ m_wsrep_next_trx_id(WSREP_UNDEFINED_TRX_ID), @@ -1308,6 +1309,7 @@ void THD::init() wsrep_rbr_buf = NULL; wsrep_affected_rows = 0; m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID; + wsrep_aborter = 0; #endif /* WITH_WSREP */ if (variables.sql_log_bin) @@ -1394,9 +1396,11 @@ void THD::update_all_stats() void THD::init_for_queries() { - set_time(); - ha_enable_transaction(this,TRUE); + DBUG_ASSERT(transaction->on); + DBUG_ASSERT(m_transaction_psi == NULL); + /* Set time for --init-file queries */ + set_time(); reset_root_defaults(mem_root, variables.query_alloc_block_size, variables.query_prealloc_size); reset_root_defaults(&transaction->mem_root, @@ -1548,6 +1552,8 @@ void THD::cleanup(void) trans_rollback(this); DBUG_ASSERT(open_tables == NULL); + DBUG_ASSERT(m_transaction_psi == NULL); + /* If the thread was in the middle of an ongoing transaction (rolled back a few lines above) or under LOCK TABLES (unlocked the tables @@ -1648,6 +1654,7 @@ void THD::reset_for_reuse() abort_on_warning= 0; free_connection_done= 0; m_command= COM_CONNECT; + transaction->on= 1; #if defined(ENABLED_PROFILING) profiling.reset(); #endif @@ -2139,11 +2146,19 @@ void THD::reset_killed() DBUG_ENTER("reset_killed"); if (killed != NOT_KILLED) { + mysql_mutex_assert_not_owner(&LOCK_thd_kill); mysql_mutex_lock(&LOCK_thd_kill); killed= NOT_KILLED; killed_err= 0; mysql_mutex_unlock(&LOCK_thd_kill); } +#ifdef WITH_WSREP + mysql_mutex_assert_not_owner(&LOCK_thd_data); + mysql_mutex_lock(&LOCK_thd_data); + wsrep_aborter= 0; + mysql_mutex_unlock(&LOCK_thd_data); +#endif /* WITH_WSREP */ + DBUG_VOID_RETURN; } @@ -2493,7 +2508,8 @@ bool THD::to_ident_sys_alloc(Lex_ident_sys_st *to, const Lex_ident_cli_st *ident Item_basic_constant * -THD::make_string_literal(const char *str, size_t length, uint repertoire) +THD::make_string_literal(const char *str, size_t length, + my_repertoire_t repertoire) { if (!length && (variables.sql_mode & MODE_EMPTY_STRING_IS_NULL)) return new (mem_root) Item_null(this, 0, variables.collation_connection); @@ -3738,7 +3754,6 @@ void select_dumpvar::cleanup() Query_arena::Type Query_arena::type() const { - DBUG_ASSERT(0); /* Should never be called */ return STATEMENT; } @@ -5802,7 +5817,8 @@ start_new_trans::start_new_trans(THD *thd) mdl_savepoint= thd->mdl_context.mdl_savepoint(); memcpy(old_ha_data, thd->ha_data, sizeof(old_ha_data)); thd->reset_n_backup_open_tables_state(&open_tables_state_backup); - bzero(thd->ha_data, sizeof(thd->ha_data)); + for (auto &data : thd->ha_data) + data.reset(); old_transaction= thd->transaction; thd->transaction= &new_transaction; new_transaction.on= 1; diff --git a/sql/sql_class.h b/sql/sql_class.h index e13b896c820..fa64892d5a0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1099,7 +1099,7 @@ public: /* We build without RTTI, so dynamic_cast can't be used. */ enum Type { - STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE + STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE, TABLE_ARENA }; Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : @@ -2023,6 +2023,14 @@ struct Ha_data */ plugin_ref lock; Ha_data() :ha_ptr(NULL) {} + + void reset() + { + ha_ptr= nullptr; + for (auto &info : ha_info) + info.reset(); + lock= nullptr; + } }; /** @@ -3926,10 +3934,10 @@ public: @param repertoire - the repertoire of the string */ Item_basic_constant *make_string_literal(const char *str, size_t length, - uint repertoire); + my_repertoire_t repertoire); Item_basic_constant *make_string_literal(const Lex_string_with_metadata_st &str) { - uint repertoire= str.repertoire(variables.character_set_client); + my_repertoire_t repertoire= str.repertoire(variables.character_set_client); return make_string_literal(str.str, str.length, repertoire); } Item_basic_constant *make_string_literal_nchar(const Lex_string_with_metadata_st &str); @@ -4077,13 +4085,20 @@ public: return 0; } + + bool is_item_tree_change_register_required() + { + return !stmt_arena->is_conventional() + || stmt_arena->type() == Query_arena::TABLE_ARENA; + } + void change_item_tree(Item **place, Item *new_value) { DBUG_ENTER("THD::change_item_tree"); DBUG_PRINT("enter", ("Register: %p (%p) <- %p", *place, place, new_value)); /* TODO: check for OOM condition here */ - if (!stmt_arena->is_conventional()) + if (is_item_tree_change_register_required()) nocheck_register_item_tree_change(place, *place, mem_root); *place= new_value; DBUG_VOID_RETURN; @@ -4579,14 +4594,13 @@ public: void push_warning_truncated_value_for_field(Sql_condition::enum_warning_level level, const char *type_str, const char *val, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *name) { DBUG_ASSERT(name); char buff[MYSQL_ERRMSG_SIZE]; CHARSET_INFO *cs= &my_charset_latin1; - const char *db_name= s ? s->db.str : NULL; - const char *table_name= s ? s->table_name.str : NULL; if (!db_name) db_name= ""; @@ -4603,12 +4617,13 @@ public: bool totally_useless_value, const char *type_str, const char *val, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *field_name) { if (field_name) push_warning_truncated_value_for_field(level, type_str, val, - s, field_name); + db_name, table_name, field_name); else if (totally_useless_value) push_warning_wrong_value(level, type_str, val); else @@ -5004,7 +5019,8 @@ public: table updates from being replicated to other nodes via galera replication. */ bool wsrep_ignore_table; - + /* thread who has started kill for this THD protected by LOCK_thd_data*/ + my_thread_id wsrep_aborter; /* Transaction id: @@ -6437,14 +6453,14 @@ struct SORT_FIELD_ATTR */ bool maybe_null; CHARSET_INFO *cs; - uint pack_sort_string(uchar *to, const LEX_CSTRING &str, - CHARSET_INFO *cs) const; + uint pack_sort_string(uchar *to, String *str) const; int compare_packed_fixed_size_vals(uchar *a, size_t *a_len, uchar *b, size_t *b_len); int compare_packed_varstrings(uchar *a, size_t *a_len, uchar *b, size_t *b_len); bool check_if_packing_possible(THD *thd) const; bool is_variable_sized() { return type == VARIABLE_SIZE; } + void set_length_and_original_length(THD *thd, uint length_arg); }; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 420a054a1b2..83f4de1b5df 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1279,7 +1279,6 @@ void prepare_new_connection_state(THD* thd) } thd->proc_info=0; - thd->init_for_queries(); } } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 3ccab553bfe..e31e51d0316 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -671,7 +671,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, size_t mlen, RETURN VALUES FALSE Success - TRUE Error and send_error already commited + TRUE Error and send_error already committed */ static bool mysqld_help_internal(THD *thd, const char *mask) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 31badbe2aba..d25410292ef 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1717,6 +1717,10 @@ int vers_insert_history_row(TABLE *table) if (row_start->cmp(row_start->ptr, row_end->ptr) >= 0) return 0; + if (table->vfield && + table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_READ)) + return HA_ERR_GENERIC; + return table->file->ha_write_row(table->record[0]); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f39f88fe843..baec470c471 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2941,6 +2941,7 @@ void st_select_lex::init_query() n_sum_items= 0; n_child_sum_items= 0; hidden_bit_fields= 0; + fields_in_window_functions= 0; subquery_in_having= explicit_limit= 0; is_item_list_lookup= 0; changed_elements= 0; @@ -3503,7 +3504,8 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) select_n_having_items + select_n_where_fields + order_group_num + - hidden_bit_fields) * 5; + hidden_bit_fields + + fields_in_window_functions) * 5; if (!ref_pointer_array.is_null()) { /* @@ -4740,7 +4742,7 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only) } if (subquery_predicate->substype() == Item_subselect::IN_SUBS) { - Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate; + Item_in_subselect *in_subs= subquery_predicate->get_IN_subquery(); if (in_subs->is_jtbm_merged) continue; } @@ -5167,7 +5169,7 @@ void SELECT_LEX::update_used_tables() */ if (tl->jtbm_subselect) { - Item *left_expr= tl->jtbm_subselect->left_expr; + Item *left_expr= tl->jtbm_subselect->left_exp(); left_expr->walk(&Item::update_table_bitmaps_processor, FALSE, NULL); } @@ -5324,7 +5326,7 @@ void st_select_lex::set_explain_type(bool on_the_fly) if ((parent_item= master_unit()->item) && parent_item->substype() == Item_subselect::IN_SUBS) { - Item_in_subselect *in_subs= (Item_in_subselect*)parent_item; + Item_in_subselect *in_subs= parent_item->get_IN_subquery(); /* Surprisingly, in_subs->is_set_strategy() can return FALSE here, even for the last invocation of this function for the select. @@ -5613,9 +5615,10 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) sl=sl->outer_select()) { Item *subs= sl->master_unit()->item; - if (subs && subs->type() == Item::SUBSELECT_ITEM && + Item_in_subselect *in_subs= (subs ? subs->get_IN_subquery() : NULL); + if (in_subs && ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN)) + in_subs->test_strategy(SUBS_SEMI_JOIN)) { continue; } @@ -6784,6 +6787,7 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd, LEX_CSTRING name; uint coffs, param_count= 0; const sp_pcursor *pcursor; + DBUG_ENTER("LEX::sp_for_loop_cursor_declarations"); if ((item_splocal= item->get_item_splocal())) name= item_splocal->m_name; @@ -6815,23 +6819,23 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd, else { thd->parse_error(); - return true; + DBUG_RETURN(true); } if (unlikely(!(pcursor= spcont->find_cursor_with_error(&name, &coffs, false)) || pcursor->check_param_count_with_error(param_count))) - return true; + DBUG_RETURN(true); if (!(loop->m_index= sp_add_for_loop_cursor_variable(thd, index, pcursor, coffs, bounds.m_index, item_func_sp))) - return true; + DBUG_RETURN(true); loop->m_target_bound= NULL; loop->m_direction= bounds.m_direction; loop->m_cursor_offset= coffs; loop->m_implicit_cursor= bounds.m_implicit_cursor; - return false; + DBUG_RETURN(false); } @@ -8185,6 +8189,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, const Sp_rcontext_handler *rh; sp_variable *spv; + uint unused_off; DBUG_ASSERT(spcont); DBUG_ASSERT(sphead); if ((spv= find_variable(name, &rh))) @@ -8223,6 +8228,15 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, return new (thd->mem_root) Item_func_sqlerrm(thd); } + if (!select_stack_head() && + (current_select->parsing_place != FOR_LOOP_BOUND || + spcont->find_cursor(name, &unused_off, false) == NULL)) + { + // we are out of SELECT or FOR so it is syntax error + my_error(ER_SP_UNDECLARED_VAR, MYF(0), name->str); + return NULL; + } + if (current_select->parsing_place == FOR_LOOP_BOUND) return create_item_for_loop_bound(thd, &null_clex_str, &null_clex_str, name); @@ -9712,7 +9726,8 @@ Item *LEX::create_item_query_expression(THD *thd, // Add the subtree of subquery to the current SELECT_LEX SELECT_LEX *curr_sel= select_stack_head(); - DBUG_ASSERT(current_select == curr_sel); + DBUG_ASSERT(current_select == curr_sel || + (curr_sel == NULL && current_select == &builtin_select)); if (!curr_sel) { curr_sel= &builtin_select; @@ -9955,7 +9970,8 @@ SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit) // Add the subtree of subquery to the current SELECT_LEX SELECT_LEX *curr_sel= select_stack_head(); - DBUG_ASSERT(current_select == curr_sel); + DBUG_ASSERT(current_select == curr_sel || + (curr_sel == NULL && current_select == &builtin_select)); if (curr_sel) { curr_sel->register_unit(unit, &curr_sel->context); @@ -10031,7 +10047,8 @@ TABLE_LIST *LEX::parsed_derived_table(SELECT_LEX_UNIT *unit, // Add the subtree of subquery to the current SELECT_LEX SELECT_LEX *curr_sel= select_stack_head(); - DBUG_ASSERT(current_select == curr_sel); + DBUG_ASSERT(current_select == curr_sel || + (curr_sel == NULL && current_select == &builtin_select)); Table_ident *ti= new (thd->mem_root) Table_ident(unit); if (ti == NULL) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b6dcb49ed08..92d4ec42c8f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -85,13 +85,13 @@ public: bool is_quoted() const { return m_quote != '\0'; } char quote() const { return m_quote; } // Get string repertoire by the 8-bit flag and the character set - uint repertoire(CHARSET_INFO *cs) const + my_repertoire_t repertoire(CHARSET_INFO *cs) const { return !m_is_8bit && my_charset_is_ascii_based(cs) ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; } // Get string repertoire by the 8-bit flag, for ASCII-based character sets - uint repertoire() const + my_repertoire_t repertoire() const { return !m_is_8bit ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; } @@ -1215,6 +1215,14 @@ public: converted to a GROUP BY involving BIT fields. */ uint hidden_bit_fields; + /* + Number of fields used in the definition of all the windows functions. + This includes: + 1) Fields in the arguments + 2) Fields in the PARTITION BY clause + 3) Fields in the ORDER BY clause + */ + uint fields_in_window_functions; enum_parsing_place parsing_place; /* where we are parsing expression */ enum_parsing_place save_parsing_place; enum_parsing_place context_analysis_place; /* where we are in prepare */ @@ -1548,10 +1556,7 @@ public: SQL_I_List<ORDER> win_order_list, Window_frame *win_frame); List<Item_window_func> window_funcs; - bool add_window_func(Item_window_func *win_func) - { - return window_funcs.push_back(win_func); - } + bool add_window_func(Item_window_func *win_func); bool have_window_funcs() const { return (window_funcs.elements !=0); } ORDER *find_common_window_func_partition_fields(THD *thd); @@ -3693,8 +3698,9 @@ public: if (unlikely(!select_stack_top)) { - current_select= NULL; - DBUG_PRINT("info", ("Top Select is empty")); + current_select= &builtin_select; + DBUG_PRINT("info", ("Top Select is empty -> sel builtin: %p", + current_select)); } else current_select= select_stack[select_stack_top - 1]; diff --git a/sql/sql_locale.h b/sql/sql_locale.h index feeb7a44bdf..b7ce9f7ba1d 100644 --- a/sql/sql_locale.h +++ b/sql/sql_locale.h @@ -60,7 +60,7 @@ public: grouping(grouping_par), errmsgs(errmsgs_par) {} - uint repertoire() const + my_repertoire_t repertoire() const { return is_ascii ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_EXTENDED; } }; /* Exported variables */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1d830f60da0..144b86e8fc9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1271,6 +1271,7 @@ bool do_command(THD *thd) command= fetch_command(thd, packet); #ifdef WITH_WSREP + DEBUG_SYNC(thd, "wsrep_before_before_command"); /* Aborted by background rollbacker thread. Handle error here and jump straight to out @@ -7852,8 +7853,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, sp_cache_enforce_limit(thd->sp_package_spec_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size); thd->end_statement(); + thd->Item_change_list::rollback_item_tree_changes(); thd->cleanup_after_query(); - DBUG_ASSERT(thd->Item_change_list::is_empty()); } else { @@ -8664,6 +8665,11 @@ bool st_select_lex::add_window_def(THD *thd, win_frame); group_list= thd->lex->save_group_list; order_list= thd->lex->save_order_list; + if (parsing_place != SELECT_LIST) + { + fields_in_window_functions+= win_part_list_ptr->elements + + win_order_list_ptr->elements; + } return (win_def == NULL || window_specs.push_back(win_def)); } @@ -8685,6 +8691,11 @@ bool st_select_lex::add_window_spec(THD *thd, win_frame); group_list= thd->lex->save_group_list; order_list= thd->lex->save_order_list; + if (parsing_place != SELECT_LIST) + { + fields_in_window_functions+= win_part_list_ptr->elements + + win_order_list_ptr->elements; + } thd->lex->win_spec= win_spec; return (win_spec == NULL || window_specs.push_back(win_spec)); } @@ -8916,6 +8927,8 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, SELECT_LEX *lex) { b->natural_join= a; + a->part_of_natural_join= TRUE; + b->part_of_natural_join= TRUE; lex->prev_join_using= using_fields; } @@ -8945,7 +8958,6 @@ my_bool find_thread_callback(THD *thd, find_thread_callback_arg *arg) if (thd->get_command() != COM_DAEMON && arg->id == (arg->query_id ? thd->query_id : (longlong) thd->thread_id)) { - if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data); mysql_mutex_lock(&thd->LOCK_thd_kill); // Lock from delete arg->thd= thd; return 1; @@ -8961,6 +8973,26 @@ THD *find_thread_by_id(longlong id, bool query_id) return arg.thd; } +#ifdef WITH_WSREP +my_bool find_thread_with_thd_data_lock_callback(THD *thd, find_thread_callback_arg *arg) +{ + if (thd->get_command() != COM_DAEMON && + arg->id == (arg->query_id ? thd->query_id : (longlong) thd->thread_id)) + { + if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data); + mysql_mutex_lock(&thd->LOCK_thd_kill); // Lock from delete + arg->thd= thd; + return 1; + } + return 0; +} +THD *find_thread_by_id_with_thd_data_lock(longlong id, bool query_id) +{ + find_thread_callback_arg arg(id, query_id); + server_threads.iterate(find_thread_with_thd_data_lock_callback, &arg); + return arg.thd; +} +#endif /** kill one thread. @@ -8978,8 +9010,11 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ uint error= (type == KILL_TYPE_QUERY ? ER_NO_SUCH_QUERY : ER_NO_SUCH_THREAD); DBUG_ENTER("kill_one_thread"); DBUG_PRINT("enter", ("id: %lld signal: %u", id, (uint) kill_signal)); - WSREP_DEBUG("kill_one_thread %llu", thd->thread_id); +#ifdef WITH_WSREP + if (id && (tmp= find_thread_by_id_with_thd_data_lock(id, type == KILL_TYPE_QUERY))) +#else if (id && (tmp= find_thread_by_id(id, type == KILL_TYPE_QUERY))) +#endif { /* If we're SUPER, we can KILL anything, including system-threads. @@ -9011,13 +9046,31 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ thd->security_ctx->user_matches(tmp->security_ctx)) #endif /* WITH_WSREP */ { - tmp->awake_no_mutex(kill_signal); - error=0; +#ifdef WITH_WSREP + DEBUG_SYNC(thd, "before_awake_no_mutex"); + if (tmp->wsrep_aborter && tmp->wsrep_aborter != thd->thread_id) + { + /* victim is in hit list already, bail out */ + WSREP_DEBUG("victim has wsrep aborter: %lu, skipping awake()", + tmp->wsrep_aborter); + error= 0; + } + else +#endif /* WITH_WSREP */ + { + WSREP_DEBUG("kill_one_thread %llu, victim: %llu wsrep_aborter %llu by signal %d", + thd->thread_id, id, tmp->wsrep_aborter, kill_signal); + tmp->awake_no_mutex(kill_signal); + WSREP_DEBUG("victim: %llu taken care of", id); + error= 0; + } } else error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR : ER_KILL_DENIED_ERROR); +#ifdef WITH_WSREP if (WSREP(tmp)) mysql_mutex_unlock(&tmp->LOCK_thd_data); +#endif mysql_mutex_unlock(&tmp->LOCK_thd_kill); } DBUG_PRINT("exit", ("%d", error)); diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 7822cab5ff0..55abee72a52 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -563,12 +563,12 @@ bool Sql_cmd_alter_table_exchange_partition:: part_table= table_list->table; swap_table= swap_table_list->table; - if (part_table->file->check_if_updates_are_ignored("ALTER")) - DBUG_RETURN(return_with_logging(thd)); - if (unlikely(check_exchange_partition(swap_table, part_table))) DBUG_RETURN(TRUE); + if (part_table->file->check_if_updates_are_ignored("ALTER")) + DBUG_RETURN(return_with_logging(thd)); + /* Add IF EXISTS to binlog if shared table */ if (part_table->file->partition_ht()->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 4526cac5af1..633d969b3de 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2018, Oracle and/or its affiliates. - Copyright (c) 2010, 2020, MariaDB Corporation + Copyright (c) 2010, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1831,6 +1831,8 @@ static void plugin_load(MEM_ROOT *tmp_root) int error; THD *new_thd= new THD(0); bool result; + unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] = + { MYSQL_AUDIT_GENERAL_CLASSMASK }; DBUG_ENTER("plugin_load"); if (global_system_variables.log_warnings >= 9) @@ -1882,6 +1884,31 @@ static void plugin_load(MEM_ROOT *tmp_root) continue; /* + Pre-acquire audit plugins for events that may potentially occur + during [UN]INSTALL PLUGIN. + + When audit event is triggered, audit subsystem acquires interested + plugins by walking through plugin list. Evidently plugin list + iterator protects plugin list by acquiring LOCK_plugin, see + plugin_foreach_with_mask(). + + On the other hand plugin_load is acquiring LOCK_plugin + rather for a long time. + + When audit event is triggered during plugin_load plugin + list iterator acquires the same lock (within the same thread) + second time. + + This hack should be removed when LOCK_plugin is fixed so it + protects only what it supposed to protect. + + See also mysql_install_plugin(), mysql_uninstall_plugin() and + initialize_audit_plugin() + */ + if (mysql_audit_general_enabled()) + mysql_audit_acquire_plugins(new_thd, event_class_mask); + + /* there're no other threads running yet, so we don't need a mutex. but plugin_add() before is designed to work in multi-threaded environment, and it uses mysql_mutex_assert_owner(), so we lock @@ -2281,27 +2308,30 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name) if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)) || plugin->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_DYING)) { - myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0; - my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "PLUGIN", name->str); - return !MyFlags; - } - if (!plugin->plugin_dl) - { - my_error(ER_PLUGIN_DELETE_BUILTIN, MYF(0)); - return 1; + // maybe plugin is present in mysql.plugin; postpone the error + plugin= nullptr; } - if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) + + if (plugin) { - my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); - return 1; - } + if (!plugin->plugin_dl) + { + my_error(ER_PLUGIN_DELETE_BUILTIN, MYF(0)); + return 1; + } + if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) + { + my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); + return 1; + } - plugin->state= PLUGIN_IS_DELETED; - if (plugin->ref_count) - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, - WARN_PLUGIN_BUSY, ER_THD(thd, WARN_PLUGIN_BUSY)); - else - reap_needed= true; + plugin->state= PLUGIN_IS_DELETED; + if (plugin->ref_count) + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, + WARN_PLUGIN_BUSY, ER_THD(thd, WARN_PLUGIN_BUSY)); + else + reap_needed= true; + } uchar user_key[MAX_KEY_LENGTH]; table->use_all_columns(); @@ -2325,6 +2355,12 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name) return 1; } } + else if (!plugin) + { + const myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0; + my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "PLUGIN", name->str); + return !MyFlags; + } return 0; } diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 2db426e7b57..e4f9f3c0d13 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -177,7 +177,8 @@ static struct wsrep_service_st wsrep_handler = { wsrep_thd_is_applying, wsrep_OSU_method_get, wsrep_thd_has_ignored_error, - wsrep_thd_set_ignored_error + wsrep_thd_set_ignored_error, + wsrep_thd_set_wsrep_aborter }; static struct thd_specifics_service_st thd_specifics_handler= diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 75c3bcd2083..f6920e7420f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -262,9 +262,10 @@ protected: virtual bool store_long(longlong from); virtual bool store_longlong(longlong from, bool unsigned_flag); virtual bool store_decimal(const my_decimal *); - virtual bool store(const char *from, size_t length, CHARSET_INFO *cs); - virtual bool store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + virtual bool store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, + my_repertoire_t from_repertoire, + CHARSET_INFO *tocs); virtual bool store(MYSQL_TIME *time, int decimals); virtual bool store_date(MYSQL_TIME *time); virtual bool store_time(MYSQL_TIME *time, int decimals); @@ -287,7 +288,9 @@ protected: virtual bool send_error(uint sql_errno, const char *err_msg, const char* sqlstate); private: bool store_string(const char *str, size_t length, - CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs); + CHARSET_INFO *src_cs, + my_repertoire_t src_repertoire, + CHARSET_INFO *dst_cs); bool store_column(const void *data, size_t length); void opt_add_row_to_rset(); @@ -5270,14 +5273,14 @@ bool Protocol_local::store_column(const void *data, size_t length) bool Protocol_local::store_string(const char *str, size_t length, - CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs) + CHARSET_INFO *src_cs, + my_repertoire_t src_repertoire, + CHARSET_INFO *dst_cs) { /* Store with conversion */ uint error_unused; - if (dst_cs && !my_charset_same(src_cs, dst_cs) && - src_cs != &my_charset_bin && - dst_cs != &my_charset_bin) + if (needs_conversion(src_cs, src_repertoire, dst_cs)) { if (unlikely(convert->copy(str, length, src_cs, dst_cs, &error_unused))) return TRUE; @@ -5334,24 +5337,14 @@ bool Protocol_local::store_decimal(const my_decimal *value) } -/** Convert to cs_results and store a string. */ - -bool Protocol_local::store(const char *str, size_t length, - CHARSET_INFO *src_cs) -{ - CHARSET_INFO *dst_cs; - - dst_cs= m_connection->m_thd->variables.character_set_results; - return store_string(str, length, src_cs, dst_cs); -} - - /** Store a string. */ -bool Protocol_local::store(const char *str, size_t length, - CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs) +bool Protocol_local::store_str(const char *str, size_t length, + CHARSET_INFO *src_cs, + my_repertoire_t from_repertoire, + CHARSET_INFO *dst_cs) { - return store_string(str, length, src_cs, dst_cs); + return store_string(str, length, src_cs, from_repertoire, dst_cs); } @@ -5360,7 +5353,7 @@ bool Protocol_local::store(const char *str, size_t length, bool Protocol_local::store(MYSQL_TIME *time, int decimals) { if (decimals != AUTO_SEC_PART_DIGITS) - my_time_trunc(time, decimals); + my_datetime_trunc(time, decimals); return store_column(time, sizeof(MYSQL_TIME)); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cef61ece5d8..7992ced036d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1425,7 +1425,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num, if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list && !(select_lex->master_unit()->item && select_lex->master_unit()->item->is_in_predicate() && - ((Item_in_subselect*)select_lex->master_unit()->item)-> + select_lex->master_unit()->item->get_IN_subquery()-> test_set_strategy(SUBS_MAXMIN_INJECTED)) && select_lex->non_agg_field_used() && select_lex->agg_func_used()) @@ -5056,7 +5056,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, */ bool skip_unprefixed_keyparts= !(join->is_in_subquery() && - ((Item_in_subselect*)join->unit->item)->test_strategy(SUBS_IN_TO_EXISTS)); + join->unit->item->get_IN_subquery()->test_strategy(SUBS_IN_TO_EXISTS)); if (keyuse_array->elements && sort_and_filter_keyuse(thd, keyuse_array, @@ -5809,7 +5809,8 @@ static uint get_semi_join_select_list_index(Field *field) { Item_in_subselect *subq_pred= emb_sj_nest->sj_subq_pred; st_select_lex *subq_lex= subq_pred->unit->first_select(); - if (subq_pred->left_expr->cols() == 1) + uint ncols= subq_pred->left_exp()->cols(); + if (ncols == 1) { Item *sel_item= subq_lex->ref_pointer_array[0]; if (sel_item->type() == Item::FIELD_ITEM && @@ -5820,7 +5821,7 @@ static uint get_semi_join_select_list_index(Field *field) } else { - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + for (uint i= 0; i < ncols; i++) { Item *sel_item= subq_lex->ref_pointer_array[i]; if (sel_item->type() == Item::FIELD_ITEM && @@ -21258,7 +21259,7 @@ int join_read_key2(THD *thd, JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref) if (tab && tab->bush_children) { TABLE_LIST *emb_sj_nest= tab->bush_children->start->emb_sj_nest; - emb_sj_nest->sj_subq_pred->left_expr->bring_value(); + emb_sj_nest->sj_subq_pred->left_exp()->bring_value(); } /* TODO: Why don't we do "Late NULLs Filtering" here? */ @@ -24470,10 +24471,13 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List<Item> &fields, List<Item> &all_fields, ORDER *order, bool from_window_spec) { + SELECT_LEX *select = thd->lex->current_select; enum_parsing_place context_analysis_place= thd->lex->current_select->context_analysis_place; thd->where="order clause"; - for (; order; order=order->next) + const bool for_union= select->master_unit()->is_unit_op() && + select == select->master_unit()->fake_select_lex; + for (uint number = 1; order; order=order->next, number++) { if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, all_fields, false, true, from_window_spec)) @@ -24484,8 +24488,22 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0)); return 1; } - if (from_window_spec && (*order->item)->with_sum_func() && - (*order->item)->type() != Item::SUM_FUNC_ITEM) + + if (!(*order->item)->with_sum_func()) + continue; + + /* + UNION queries cannot be used with an aggregate function in + an ORDER BY clause + */ + + if (for_union) + { + my_error(ER_AGGREGATE_ORDER_FOR_UNION, MYF(0), number); + return 1; + } + + if (from_window_spec && (*order->item)->type() != Item::SUM_FUNC_ITEM) (*order->item)->split_sum_func(thd, ref_pointer_array, all_fields, SPLIT_SUM_SELECT); } diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index c0925da59e1..b9d500d463c 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2017, MariaDB Corporation, Alibaba Corporation + Copyrgiht (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -483,6 +484,10 @@ int SEQUENCE::read_initial_values(TABLE *table) if (mdl_lock_used) thd->mdl_context.release_lock(mdl_request.ticket); write_unlock(table); + + if (!has_active_transaction && !thd->transaction->stmt.is_empty() && + !thd->in_sub_stmt) + trans_commit_stmt(thd); DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT); } DBUG_ASSERT(table->reginfo.lock_type == TL_READ); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 64076197cf8..77ebc58bc02 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8126,7 +8126,10 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) else all_items= thd->free_list; - mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items); + if (table_list->part_of_natural_join) + bitmap_set_all(&bitmap); + else + mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items); TMP_TABLE_PARAM *tmp_table_param = new (thd->mem_root) TMP_TABLE_PARAM; tmp_table_param->init(); @@ -8215,7 +8218,7 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(lex->wild->ptr()); buffer.append(')'); } - field->set_name(thd, buffer.lex_cstring()); + field->set_name(thd, &buffer); } return 0; } @@ -8224,7 +8227,7 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { char tmp[128]; - String buffer(tmp,sizeof(tmp), thd->charset()); + String buffer(tmp, sizeof(tmp), system_charset_info); LEX *lex= thd->lex; Name_resolution_context *context= &lex->first_select_lex()->context; ST_FIELD_INFO *field_info= &schema_table->fields_info[2]; @@ -8242,7 +8245,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) Item_field *field= new (thd->mem_root) Item_field(thd, context, field_name); if (add_item_to_list(thd, field)) return 1; - field->set_name(thd, buffer.lex_cstring()); + field->set_name(thd, &buffer); if (thd->lex->verbose) { field_info= &schema_table->fields_info[3]; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 879955af723..2636299e330 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -2123,8 +2123,8 @@ int alloc_statistics_for_table(THD* thd, TABLE *table) sizeof(Index_statistics) * keys); uint key_parts= table->s->ext_key_parts; - ulong *idx_avg_frequency= (ulong*) alloc_root(&table->mem_root, - sizeof(ulong) * key_parts); + ulonglong *idx_avg_frequency= (ulonglong*) alloc_root(&table->mem_root, + sizeof(ulonglong) * key_parts); uint columns= 0; for (field_ptr= table->field; *field_ptr; field_ptr++) @@ -2169,7 +2169,7 @@ int alloc_statistics_for_table(THD* thd, TABLE *table) } } - memset(idx_avg_frequency, 0, sizeof(ulong) * key_parts); + memset(idx_avg_frequency, 0, sizeof(ulonglong) * key_parts); KEY *key_info, *end; for (key_info= table->key_info, end= key_info + table->s->keys; @@ -2285,14 +2285,14 @@ static int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share) } uint key_parts= table_share->ext_key_parts; - ulong *idx_avg_frequency= table_stats->idx_avg_frequency; + ulonglong *idx_avg_frequency= table_stats->idx_avg_frequency; if (!idx_avg_frequency) { - idx_avg_frequency= (ulong*) alloc_root(&stats_cb->mem_root, - sizeof(ulong) * key_parts); + idx_avg_frequency= (ulonglong*) alloc_root(&stats_cb->mem_root, + sizeof(ulonglong) * key_parts); if (idx_avg_frequency) { - memset(idx_avg_frequency, 0, sizeof(ulong) * key_parts); + memset(idx_avg_frequency, 0, sizeof(ulonglong) * key_parts); table_stats->idx_avg_frequency= idx_avg_frequency; for (key_info= table_share->key_info, end= key_info + keys; key_info < end; diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index b90c614b74f..20ecf06bfee 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -294,7 +294,9 @@ public: uchar *min_max_record_buffers; /* Record buffers for min/max values */ Column_statistics *column_stats; /* Array of statistical data for columns */ Index_statistics *index_stats; /* Array of statistical data for indexes */ - ulong *idx_avg_frequency; /* Array of records per key for index prefixes */ + + /* Array of records per key for index prefixes */ + ulonglong *idx_avg_frequency; uchar *histograms; /* Sequence of histograms */ }; @@ -346,7 +348,7 @@ private: CHAR values are stripped of trailing spaces. Flexible values are stripped of their length prefixes. */ - ulong avg_length; + ulonglong avg_length; /* The ratio N/D multiplied by the scale factor Scale_factor_avg_frequency, @@ -354,7 +356,7 @@ private: N is the number of rows with not null value in the column, D the number of distinct values among them */ - ulong avg_frequency; + ulonglong avg_frequency; public: @@ -404,12 +406,12 @@ public: void set_avg_length (double val) { - avg_length= (ulong) (val * Scale_factor_avg_length); + avg_length= (ulonglong) (val * Scale_factor_avg_length); } void set_avg_frequency (double val) { - avg_frequency= (ulong) (val * Scale_factor_avg_frequency); + avg_frequency= (ulonglong) (val * Scale_factor_avg_frequency); } bool min_max_values_are_provided() @@ -448,11 +450,11 @@ private: in the first k components, and D is the number of distinct k-component prefixes among them */ - ulong *avg_frequency; + ulonglong *avg_frequency; public: - void init_avg_frequency(ulong *ptr) { avg_frequency= ptr; } + void init_avg_frequency(ulonglong *ptr) { avg_frequency= ptr; } bool avg_frequency_is_inited() { return avg_frequency != NULL; } @@ -463,7 +465,7 @@ public: void set_avg_frequency(uint i, double val) { - avg_frequency[i]= (ulong) (val * Scale_factor_avg_frequency); + avg_frequency[i]= (ulonglong) (val * Scale_factor_avg_frequency); } }; diff --git a/sql/sql_string.h b/sql/sql_string.h index 2d38f6d5d13..274b1d9a5df 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -222,18 +222,6 @@ public: inline bool is_empty() const { return (str_length == 0); } inline const char *ptr() const { return Ptr; } inline const char *end() const { return Ptr + str_length; } - - LEX_STRING lex_string() const - { - LEX_STRING str = { (char*) ptr(), length() }; - return str; - } - LEX_CSTRING lex_cstring() const - { - LEX_CSTRING skr = { ptr(), length() }; - return skr; - } - bool has_8bit_bytes() const { for (const char *c= ptr(), *c_end= end(); c < c_end; c++) @@ -488,6 +476,12 @@ public: if (str.Alloced_length) Alloced_length= (uint32) (str.Alloced_length - offset); } + inline LEX_CSTRING *get_value(LEX_CSTRING *res) + { + res->str= Ptr; + res->length= str_length; + return res; + } /* Take over handling of buffer from some other object */ void reset(char *ptr_arg, size_t length_arg, size_t alloced_length_arg) @@ -888,13 +882,13 @@ public: { return Binary_string::append_hex((const char*)src, srclen); } - bool append_introducer_and_hex(CHARSET_INFO *cs, const LEX_CSTRING &str) + bool append_introducer_and_hex(String *str) { return append(STRING_WITH_LEN("_")) || - append(cs->csname) || + append(str->charset()->csname) || append(STRING_WITH_LEN(" 0x")) || - append_hex(str.str, (uint32) str.length); + append_hex(str->ptr(), (uint32) str->length()); } bool append(IO_CACHE* file, uint32 arg_length) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 87257bc9ab4..8834c4d26e9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7804,7 +7804,6 @@ static bool is_inplace_alter_impossible(TABLE *table, @param ha_alter_info Structure describing ALTER TABLE to be carried out and serving as a storage place for data used during different phases. - @param inplace_supported Enum describing the locking requirements. @param target_mdl_request Metadata request/lock on the target table name. @param alter_ctx ALTER TABLE runtime context. @@ -7829,7 +7828,6 @@ static bool mysql_inplace_alter_table(THD *thd, TABLE *table, TABLE *altered_table, Alter_inplace_info *ha_alter_info, - enum_alter_inplace_result inplace_supported, MDL_request *target_mdl_request, Alter_table_ctx *alter_ctx) { @@ -7839,6 +7837,10 @@ static bool mysql_inplace_alter_table(THD *thd, bool reopen_tables= false; bool res; handlerton *hton; + + const enum_alter_inplace_result inplace_supported= + ha_alter_info->inplace_supported; + DBUG_ENTER("mysql_inplace_alter_table"); /* Downgrade DDL lock while we are waiting for exclusive lock below */ @@ -10521,27 +10523,31 @@ do_continue:; if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) ha_alter_info.online= true; // Ask storage engine whether to use copy or in-place - enum_alter_inplace_result inplace_supported= + ha_alter_info.inplace_supported= table->file->check_if_supported_inplace_alter(&altered_table, &ha_alter_info); - - Key *k; - for (List_iterator<Key> it(alter_info->key_list); - (k= it++) && inplace_supported != HA_ALTER_INPLACE_NOT_SUPPORTED;) + if (ha_alter_info.inplace_supported != HA_ALTER_INPLACE_NOT_SUPPORTED) { - if(k->without_overlaps) - inplace_supported= HA_ALTER_INPLACE_NOT_SUPPORTED; + List_iterator<Key> it(alter_info->key_list); + while (Key *k= it++) + { + if (k->without_overlaps) + { + ha_alter_info.inplace_supported= HA_ALTER_INPLACE_NOT_SUPPORTED; + break; + } + } } - if (alter_info->supports_algorithm(thd, inplace_supported, &ha_alter_info) || - alter_info->supports_lock(thd, inplace_supported, &ha_alter_info)) + if (alter_info->supports_algorithm(thd, &ha_alter_info) || + alter_info->supports_lock(thd, &ha_alter_info)) { cleanup_table_after_inplace_alter(&altered_table); goto err_new_table_cleanup; } // If SHARED lock and no particular algorithm was requested, use COPY. - if (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK && + if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK && alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED && alter_info->algorithm(thd) == Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT && @@ -10549,7 +10555,7 @@ do_continue:; Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT) use_inplace= false; - if (inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED) + if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED) use_inplace= false; if (use_inplace) @@ -10562,7 +10568,7 @@ do_continue:; */ thd->count_cuted_fields = CHECK_FIELD_WARN; int res= mysql_inplace_alter_table(thd, table_list, table, &altered_table, - &ha_alter_info, inplace_supported, + &ha_alter_info, &target_mdl_request, &alter_ctx); thd->count_cuted_fields= save_count_cuted_fields; my_free(const_cast<uchar*>(frm.str)); diff --git a/sql/sql_time.cc b/sql/sql_time.cc index c08e54bed87..8bb96dfa776 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -18,7 +18,6 @@ /* Functions to handle date and time */ #include "mariadb.h" -#include "sql_priv.h" #include "sql_time.h" #include "tztime.h" // struct Time_zone #include "sql_class.h" // THD @@ -297,7 +296,7 @@ check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, { ErrConvTime str(ltime); make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, - &str, ts_type, 0, 0); + &str, ts_type, nullptr, nullptr, nullptr); return true; } return false; @@ -431,7 +430,7 @@ str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs, const char *str, size_t length, MYSQL_TIME *to, date_mode_t mode) { - Temporal::Warn_push warn(thd, NULL, NullS, to, mode); + Temporal::Warn_push warn(thd, nullptr, nullptr, nullptr, to, mode); Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, str, length, cs, mode); return !t->is_valid_temporal(); } @@ -441,7 +440,9 @@ bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime, date_mode_t fuzzydate, const TABLE_SHARE *s, const char *field_name) { - Temporal::Warn_push warn(thd, s, field_name, ltime, fuzzydate); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name, ltime, fuzzydate); Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate); return !t->is_valid_temporal(); } @@ -452,7 +453,9 @@ bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value, date_mode_t fuzzydate, const TABLE_SHARE *s, const char *field_name) { - Temporal::Warn_push warn(thd, s, field_name, ltime, fuzzydate); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name, ltime, fuzzydate); Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate); return !t->is_valid_temporal(); } @@ -467,7 +470,9 @@ bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr, Note: conversion from an integer to TIME can overflow to '838:59:59.999999', so the conversion result can have fractional digits. */ - Temporal::Warn_push warn(thd, s, field_name, ltime, fuzzydate); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name, ltime, fuzzydate); Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, nr, fuzzydate); return !t->is_valid_temporal(); } @@ -896,12 +901,13 @@ void make_truncated_value_warning(THD *thd, Sql_condition::enum_warning_level level, const ErrConv *sval, timestamp_type time_type, - const TABLE_SHARE *s, const char *field_name) + const char *db_name, const char *table_name, + const char *field_name) { const char *type_str= Temporal::type_name_by_timestamp_type(time_type); return thd->push_warning_wrong_or_truncated_value (level, time_type <= MYSQL_TIMESTAMP_ERROR, type_str, sval->ptr(), - s, field_name); + db_name, table_name, field_name); } diff --git a/sql/sql_time.h b/sql/sql_time.h index fe9697adf67..c918eb6d807 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -1,5 +1,5 @@ /* Copyright (c) 2006, 2010, Oracle and/or its affiliates. - Copyright (c) 2011, 2016, MariaDB + Copyright (c) 2011, 2020, 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 @@ -78,7 +78,7 @@ void make_truncated_value_warning(THD *thd, Sql_condition::enum_warning_level level, const ErrConv *str_val, timestamp_type time_type, - const TABLE_SHARE *s, + const char *db_name, const char *table_name, const char *field_name); extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type, diff --git a/sql/sql_type.cc b/sql/sql_type.cc index aee9b4c165c..bce65e494d3 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -507,17 +507,21 @@ bool Sec6::convert_to_mysql_time(THD *thd, int *warn, MYSQL_TIME *ltime, void Temporal::push_conversion_warnings(THD *thd, bool totally_useless_value, int warn, const char *typestr, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *field_name, const char *value) { if (MYSQL_TIME_WARN_HAVE_WARNINGS(warn)) thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN, totally_useless_value, - typestr, value, s, field_name); + typestr, value, + db_name, table_name, + field_name); else if (MYSQL_TIME_WARN_HAVE_NOTES(warn)) thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_NOTE, - false, typestr, value, s, + false, typestr, value, + db_name, table_name, field_name); } @@ -1092,7 +1096,7 @@ bool Temporal::datetime_round_or_invalidate(THD *thd, uint dec, int *warn, ulong DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); if (datetime_add_nanoseconds_or_invalidate(thd, warn, nsec)) return true; - my_time_trunc(this, dec); + my_datetime_trunc(this, dec); return false; } @@ -4069,7 +4073,7 @@ uint32 Type_handler_bit::Item_decimal_notation_int_digits(const Item *item) const { - return Bit_decimal_notation_int_digits(item); + return Bit_decimal_notation_int_digits_by_nbits(item->max_length); } @@ -4087,9 +4091,23 @@ Type_handler_general_purpose_int::Item_decimal_notation_int_digits( a divisor. */ uint32 -Type_handler_bit::Bit_decimal_notation_int_digits(const Item *item) -{ - return item->max_length/3+1; +Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(uint nbits) +{ + DBUG_ASSERT(nbits > 0); + DBUG_ASSERT(nbits <= 64); + set_if_smaller(nbits, 64); // Safety + static uint ndigits[65]= + {0, + 1,1,1,2,2,2,3,3, // 1..8 bits + 3,4,4,4,4,5,5,5, // 9..16 bits + 6,6,6,7,7,7,7,8, // 17..24 bits + 8,8,9,9,9,10,10,10, // 25..32 bits + 10,11,11,11,12,12,12,13, // 33..40 bits + 13,13,13,14,14,14,15,15, // 41..48 bits + 15,16,16,16,16,17,17,17, // 49..56 bits + 18,18,18,19,19,19,19,20 // 57..64 bits + }; + return ndigits[nbits]; } /*************************************************************************/ @@ -4933,7 +4951,9 @@ bool Type_handler::Item_get_date_with_warn(THD *thd, Item *item, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - Temporal::Warn_push warn(thd, item->field_table_or_null(), + const TABLE_SHARE *s= item->field_table_or_null(); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, item->field_name_or_null(), ltime, fuzzydate); Item_get_date(thd, item, &warn, ltime, fuzzydate); return ltime->time_type < 0; @@ -4945,7 +4965,9 @@ bool Type_handler::Item_func_hybrid_field_type_get_date_with_warn(THD *thd, MYSQL_TIME *ltime, date_mode_t mode) const { - Temporal::Warn_push warn(thd, item->field_table_or_null(), + const TABLE_SHARE *s= item->field_table_or_null(); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, item->field_name_or_null(), ltime, mode); Item_func_hybrid_field_type_get_date(thd, item, &warn, ltime, mode); return ltime->time_type < 0; @@ -6143,7 +6165,40 @@ bool Type_handler_row:: bool Type_handler_int_result:: Item_func_round_fix_length_and_dec(Item_func_round *item) const { - item->fix_arg_int(); + item->fix_arg_int(this, item->arguments()[0]); + return false; +} + + +bool Type_handler_year:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + item->fix_arg_int(&type_handler_ulong, item->arguments()[0]); + return false; +} + + +bool Type_handler_hex_hybrid:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + item->fix_arg_int(nullptr, nullptr); + return false; +} + + +bool Type_handler_bit:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + uint nbits= item->arguments()[0]->max_length; + item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits); + return false; +} + + +bool Type_handler_typelib:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + item->fix_length_and_dec_long_or_longlong(5, true); return false; } @@ -6164,10 +6219,12 @@ bool Type_handler_decimal_result:: } -bool Type_handler_temporal_result:: +bool Type_handler_date_common:: Item_func_round_fix_length_and_dec(Item_func_round *item) const { - item->fix_arg_double(); + static const Type_std_attributes attr(Type_numeric_attributes(8, 0, true), + DTCollation_numeric()); + item->fix_arg_int(&type_handler_ulong, &attr); return false; } @@ -6217,7 +6274,43 @@ bool Type_handler_row:: bool Type_handler_int_result:: Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const { - item->fix_length_and_dec_int_or_decimal(); + item->Type_std_attributes::set(item->arguments()[0]); + item->set_handler(this); + return false; +} + + +bool Type_handler_year:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->Type_std_attributes::set(item->arguments()[0]); + item->set_handler(&type_handler_ulong); + return false; +} + + +bool Type_handler_bit:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + uint nbits= item->arguments()[0]->max_length; + item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits); + return false; +} + + +bool Type_handler_typelib:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_long_or_longlong(5, true); + return false; +} + + +bool Type_handler_hex_hybrid:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + uint nchars= item->arguments()[0]->decimal_precision(); + item->fix_length_and_dec_long_or_longlong(nchars, true); return false; } @@ -6238,10 +6331,36 @@ bool Type_handler_decimal_result:: } -bool Type_handler_temporal_result:: +bool Type_handler_date_common:: Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const { - item->fix_length_and_dec_int_or_decimal(); + static const Type_numeric_attributes attr(8, 0/*dec*/, true/*unsigned*/); + item->Type_std_attributes::set(attr, DTCollation_numeric()); + item->set_handler(&type_handler_ulong); + return false; +} + + +bool Type_handler_time_common:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_time(); + return false; +} + + +bool Type_handler_datetime_common:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_datetime(); + return false; +} + + +bool Type_handler_timestamp_common:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_datetime(); return false; } @@ -8589,7 +8708,8 @@ static void literal_warn(THD *thd, const Item *item, ErrConvString err(str, length, cs); thd->push_warning_wrong_or_truncated_value( Sql_condition::time_warn_level(st->warnings), - false, typestr, err.ptr(), NULL, NullS); + false, typestr, err.ptr(), + nullptr, nullptr, nullptr); } } else if (send_error) @@ -8981,8 +9101,8 @@ bool Type_handler::partition_field_append_value( uint cnverr2= 0; buf2.copy(res->ptr(), res->length(), res->charset(), field_cs, &cnverr2); if (!cnverr2) - return str->append_introducer_and_hex(buf2.charset(), buf2.lex_cstring()); - return str->append_introducer_and_hex(res->charset(), res->lex_cstring()); + return str->append_introducer_and_hex(&buf2); + return str->append_introducer_and_hex(res); } StringBuffer<64> val(system_charset_info); diff --git a/sql/sql_type.h b/sql/sql_type.h index 0850d08c5ae..ed0aaaea400 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -807,34 +807,39 @@ public: public: void push_conversion_warnings(THD *thd, bool totally_useless_value, date_mode_t mode, timestamp_type tstype, - const TABLE_SHARE* s, const char *name) + const char *db_name, const char *table_name, + const char *name) { const char *typestr= tstype >= 0 ? type_name_by_timestamp_type(tstype) : mode & (TIME_INTERVAL_hhmmssff | TIME_INTERVAL_DAY) ? "interval" : mode & TIME_TIME_ONLY ? "time" : "datetime"; Temporal::push_conversion_warnings(thd, totally_useless_value, warnings, - typestr, s, name, ptr()); + typestr, db_name, table_name, name, + ptr()); } }; class Warn_push: public Warn { - THD *m_thd; - const TABLE_SHARE *m_s; - const char *m_name; - const MYSQL_TIME *m_ltime; - date_mode_t m_mode; + THD * const m_thd; + const char * const m_db_name; + const char * const m_table_name; + const char * const m_name; + const MYSQL_TIME * const m_ltime; + const date_mode_t m_mode; public: - Warn_push(THD *thd, const TABLE_SHARE *s, const char *name, - const MYSQL_TIME *ltime, date_mode_t mode) - :m_thd(thd), m_s(s), m_name(name), m_ltime(ltime), m_mode(mode) + Warn_push(THD *thd, const char *db_name, const char *table_name, + const char *name, const MYSQL_TIME *ltime, date_mode_t mode) + : m_thd(thd), m_db_name(db_name), m_table_name(table_name), m_name(name), + m_ltime(ltime), m_mode(mode) { } ~Warn_push() { if (warnings) push_conversion_warnings(m_thd, m_ltime->time_type < 0, - m_mode, m_ltime->time_type, m_s, m_name); + m_mode, m_ltime->time_type, + m_db_name, m_table_name, m_name); } }; @@ -875,7 +880,8 @@ public: } static void push_conversion_warnings(THD *thd, bool totally_useless_value, int warn, const char *type_name, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *field_name, const char *value); /* @@ -1503,6 +1509,14 @@ public: { } }; + class Options_for_round: public Options + { + public: + Options_for_round(time_round_mode_t round_mode= TIME_FRAC_TRUNCATE) + :Options(Time::default_flags_for_get_date(), round_mode, + Time::DATETIME_TO_TIME_DISALLOW) + { } + }; class Options_cmp: public Options { public: @@ -1854,6 +1868,40 @@ public: DBUG_ASSERT(is_valid_value_slow()); return *this; } + Time &ceiling(int *warn) + { + if (is_valid_time()) + { + if (neg) + my_time_trunc(this, 0); + else if (second_part) + round_or_set_max(0, warn, 999999999); + } + DBUG_ASSERT(is_valid_value_slow()); + return *this; + } + Time &ceiling() + { + int warn= 0; + return ceiling(&warn); + } + Time &floor(int *warn) + { + if (is_valid_time()) + { + if (!neg) + my_time_trunc(this, 0); + else if (second_part) + round_or_set_max(0, warn, 999999999); + } + DBUG_ASSERT(is_valid_value_slow()); + return *this; + } + Time &floor() + { + int warn= 0; + return floor(&warn); + } Time &round(uint dec, int *warn) { if (is_valid_time()) @@ -2421,10 +2469,22 @@ public: Datetime &trunc(uint dec) { if (is_valid_datetime()) - my_time_trunc(this, dec); + my_datetime_trunc(this, dec); + DBUG_ASSERT(is_valid_value_slow()); + return *this; + } + Datetime &ceiling(THD *thd, int *warn) + { + if (is_valid_datetime() && second_part) + round_or_invalidate(thd, 0, warn, 999999999); DBUG_ASSERT(is_valid_value_slow()); return *this; } + Datetime &ceiling(THD *thd) + { + int warn= 0; + return ceiling(thd, &warn); + } Datetime &round(THD *thd, uint dec, int *warn) { if (is_valid_datetime()) @@ -2712,6 +2772,19 @@ public: #define MY_REPERTOIRE_NUMERIC MY_REPERTOIRE_ASCII +static inline my_repertoire_t operator|(const my_repertoire_t a, + const my_repertoire_t b) +{ + return (my_repertoire_t) ((uint) a | (uint) b); +} + +static inline my_repertoire_t &operator|=(my_repertoire_t &a, + const my_repertoire_t b) +{ + return a= (my_repertoire_t) ((uint) a | (uint) b); +} + + enum Derivation { DERIVATION_IGNORABLE= 6, @@ -2733,7 +2806,7 @@ class DTCollation { public: CHARSET_INFO *collation; enum Derivation derivation; - uint repertoire; + my_repertoire_t repertoire; void set_repertoire_from_charset(CHARSET_INFO *cs) { @@ -2769,7 +2842,7 @@ public: } DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg, - uint repertoire_arg) + my_repertoire_t repertoire_arg) :collation(collation_arg), derivation(derivation_arg), repertoire(repertoire_arg) @@ -2786,7 +2859,7 @@ public: } void set(CHARSET_INFO *collation_arg, Derivation derivation_arg, - uint repertoire_arg) + my_repertoire_t repertoire_arg) { collation= collation_arg; derivation= derivation_arg; @@ -5089,8 +5162,6 @@ public: bool Item_func_between_fix_length_and_dec(Item_func_between *)const override; bool Item_func_in_fix_comparator_compatible_types(THD *, Item_func_in *) const override; - bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; - bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *)const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; @@ -5616,6 +5687,8 @@ public: const Column_definition_attributes *attr, uint32 flags) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *)const override; void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; void Item_func_hybrid_field_type_get_date(THD *, @@ -5640,7 +5713,7 @@ public: } uint32 max_display_length(const Item *item) const override; uint32 Item_decimal_notation_int_digits(const Item *item) const override; - static uint32 Bit_decimal_notation_int_digits(const Item *item); + static uint32 Bit_decimal_notation_int_digits_by_nbits(uint nbits); uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override { return length / 8; } uint calc_key_length(const Column_definition &def) const override; @@ -5657,6 +5730,8 @@ public: } void show_binlog_type(const Conv_source &src, const Field &, String *str) const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; @@ -5899,6 +5974,7 @@ public: const override; longlong Item_func_between_val_int(Item_func_between *func) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; bool set_comparator_func(Arg_comparator *cmp) const override; @@ -6060,6 +6136,8 @@ public: longlong Item_func_min_max_val_int(Item_func_min_max *) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -6195,6 +6273,7 @@ public: String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; @@ -6324,6 +6403,7 @@ public: int cmp_native(const Native &a, const Native &b) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const override; @@ -6749,6 +6829,8 @@ class Type_handler_hex_hybrid: public Type_handler_varchar public: virtual ~Type_handler_hex_hybrid() {} const Type_handler *cast_to_int_type_handler() const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; }; @@ -6967,6 +7049,8 @@ public: enum_field_types field_type() const override { return MYSQL_TYPE_STRING; } const Type_handler *type_handler_for_item_field() const override; const Type_handler *cast_to_int_type_handler() const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; uint32 max_display_length_for_field(const Conv_source &src) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 68a783341f3..af6a73006a8 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -3167,6 +3167,14 @@ Window_funcs_computation::save_explain_plan(MEM_ROOT *mem_root, return xpl; } + +bool st_select_lex::add_window_func(Item_window_func *win_func) +{ + if (parsing_place != SELECT_LIST) + fields_in_window_functions+= win_func->window_func()->argument_count(); + return window_funcs.push_back(win_func); +} + ///////////////////////////////////////////////////////////////////////////// // Unneeded comments (will be removed when we develop a replacement for // the feature that was attempted here diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d8ad3aef7c3..b42d68c26e1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -14698,13 +14698,15 @@ literal: | UNDERSCORE_CHARSET hex_or_bin_String { Item_string_with_introducer *item_str; + LEX_CSTRING tmp; + $2->get_value(&tmp); /* Pass NULL as name. Name will be set in the "select_item" rule and will include the introducer and the original hex/bin notation. */ item_str= new (thd->mem_root) Item_string_with_introducer(thd, null_clex_str, - $2->lex_cstring(), $1); + tmp, $1); if (unlikely(!item_str || !item_str->check_well_formed_result(true))) MYSQL_YYABORT; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 1badca024fd..4bda42b2ffa 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2015, Oracle and/or its affiliates. - Copyright (c) 2012, 2018, MariaDB Corporation. + Copyright (c) 2012, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2728,12 +2728,23 @@ static bool fix_optimizer_switch(sys_var *self, THD *thd, "engine_condition_pushdown=on"); // since 10.1.1 return false; } +static bool check_legal_optimizer_switch(sys_var *self, THD *thd, + set_var *var) +{ + if (var->save_result.ulonglong_value & (OPTIMIZER_SWITCH_MATERIALIZATION | + OPTIMIZER_SWITCH_IN_TO_EXISTS)) + { + return false; + } + my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0)); + return true; +} static Sys_var_flagset Sys_optimizer_switch( "optimizer_switch", "Fine-tune the optimizer behavior", SESSION_VAR(optimizer_switch), CMD_LINE(REQUIRED_ARG), optimizer_switch_names, DEFAULT(OPTIMIZER_SWITCH_DEFAULT), - NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_legal_optimizer_switch), ON_UPDATE(fix_optimizer_switch)); static Sys_var_flagset Sys_optimizer_trace( @@ -3852,6 +3863,12 @@ static bool fix_tp_min_threads(sys_var *, THD *, enum_var_type) static bool check_threadpool_size(sys_var *self, THD *thd, set_var *var) { + +#ifdef _WIN32 + if (threadpool_mode != TP_MODE_GENERIC) + return false; +#endif + ulonglong v= var->save_result.ulonglong_value; if (v > threadpool_max_size) { diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index ed2aaf49b9f..ba56a7b4bfb 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -534,7 +534,10 @@ public: String str2(buff2, sizeof(buff2), charset), *res; if (!(res=var->value->val_str(&str))) + { var->save_result.string_value.str= 0; + var->save_result.string_value.length= 0; // safety + } else { uint32 unused; @@ -939,9 +942,16 @@ public: String str(buff, sizeof(buff), system_charset_info), *res; if (!(res=var->value->val_str(&str))) + { var->save_result.string_value.str= const_cast<char*>(""); + var->save_result.string_value.length= 0; + } else - var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); + { + size_t len= res->length(); + var->save_result.string_value.str= thd->strmake(res->ptr(), len); + var->save_result.string_value.length= len; + } return false; } bool session_update(THD *thd, set_var *var) @@ -965,6 +975,7 @@ public: { char *ptr= (char*)(intptr)option.def_value; var->save_result.string_value.str= ptr; + var->save_result.string_value.length= safe_strlen(ptr); } uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) { diff --git a/sql/table.cc b/sql/table.cc index 32d0ee6f538..e4ed862f41b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -50,6 +50,17 @@ #define MYSQL57_GENERATED_FIELD 128 #define MYSQL57_GCOL_HEADER_SIZE 4 +class Table_arena: public Query_arena +{ +public: + Table_arena(MEM_ROOT *mem_root, enum enum_state state_arg) : + Query_arena(mem_root, state_arg){} + virtual Type type() const + { + return TABLE_ARENA; + } +}; + struct extra2_fields { LEX_CUSTRING version; @@ -1145,8 +1156,9 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, We need to use CONVENTIONAL_EXECUTION here to ensure that any new items created by fix_fields() are not reverted. */ - table->expr_arena= new (alloc_root(mem_root, sizeof(Query_arena))) - Query_arena(mem_root, Query_arena::STMT_CONVENTIONAL_EXECUTION); + table->expr_arena= new (alloc_root(mem_root, sizeof(Table_arena))) + Table_arena(mem_root, + Query_arena::STMT_CONVENTIONAL_EXECUTION); if (!table->expr_arena) DBUG_RETURN(1); @@ -8809,29 +8821,24 @@ void TABLE::vers_update_fields() bitmap_set_bit(write_set, vers_start_field()->field_index); bitmap_set_bit(write_set, vers_end_field()->field_index); - if (versioned(VERS_TIMESTAMP)) + if (!vers_write) { - if (!vers_write) - { - file->column_bitmaps_signal(); - return; - } - if (vers_start_field()->store_timestamp(in_use->query_start(), - in_use->query_start_sec_part())) - DBUG_ASSERT(0); + file->column_bitmaps_signal(); + return; } - else + + if (versioned(VERS_TIMESTAMP) && + vers_start_field()->store_timestamp(in_use->query_start(), + in_use->query_start_sec_part())) { - if (!vers_write) - { - file->column_bitmaps_signal(); - return; - } + DBUG_ASSERT(0); } vers_end_field()->set_max(); bitmap_set_bit(read_set, vers_end_field()->field_index); file->column_bitmaps_signal(); + if (vfield) + update_virtual_fields(file, VCOL_UPDATE_FOR_READ); } diff --git a/sql/table.h b/sql/table.h index 4db27270509..efac9558450 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1667,6 +1667,7 @@ public: TABLE *tmp_table, TMP_TABLE_PARAM *tmp_table_param, bool with_cleanup); + int fix_vcol_exprs(THD *thd); Field *find_field_by_name(LEX_CSTRING *str) const; bool export_structure(THD *thd, class Row_definition_list *defs); bool is_splittable() { return spl_opt_info != NULL; } @@ -2236,6 +2237,7 @@ struct TABLE_LIST parsing 'this' is a NATURAL/USING join iff (natural_join != NULL). */ TABLE_LIST *natural_join; + bool part_of_natural_join; /* True if 'this' represents a nested join that is a NATURAL JOIN. For one of the operands of 'this', the member 'natural_join' points diff --git a/sql/threadpool.h b/sql/threadpool.h index 285b46e3b27..11132b3bf95 100644 --- a/sql/threadpool.h +++ b/sql/threadpool.h @@ -76,6 +76,7 @@ enum TP_STATE { TP_STATE_IDLE, TP_STATE_RUNNING, + TP_STATE_PENDING }; /* diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index c27f42b3d62..b26f41c6e9a 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -459,11 +459,25 @@ void tp_timeout_handler(TP_connection *c) { if (c->state != TP_STATE_IDLE) return; - THD *thd=c->thd; + THD *thd= c->thd; mysql_mutex_lock(&thd->LOCK_thd_kill); - thd->set_killed_no_mutex(KILL_WAIT_TIMEOUT); - c->priority= TP_PRIORITY_HIGH; - post_kill_notification(thd); + Vio *vio= thd->net.vio; + if (vio && (vio_pending(vio) > 0 || vio->has_data(vio)) && + c->state == TP_STATE_IDLE) + { + /* + There is some data on that connection, i.e + i.e there was no inactivity timeout. + Don't kill. + */ + c->state= TP_STATE_PENDING; + } + else if (c->state == TP_STATE_IDLE) + { + thd->set_killed_no_mutex(KILL_WAIT_TIMEOUT); + c->priority= TP_PRIORITY_HIGH; + post_kill_notification(thd); + } mysql_mutex_unlock(&thd->LOCK_thd_kill); } diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index 2a5587fa04a..7895431bc13 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Monty Program Ab +/* Copyright (C) 2012, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -505,11 +505,21 @@ static my_bool timeout_check(THD *thd, pool_timer_t *timer) DBUG_ENTER("timeout_check"); if (thd->net.reading_or_writing == 1) { - /* - Check if connection does not have scheduler data. This happens for example - if THD belongs to a different scheduler, that is listening to extra_port. - */ - if (auto connection= (TP_connection_generic *) thd->event_scheduler.data) + TP_connection_generic *connection= (TP_connection_generic *)thd->event_scheduler.data; + if (!connection || connection->state != TP_STATE_IDLE) + { + /* + Connection does not have scheduler data. This happens for example + if THD belongs to a different scheduler, that is listening to extra_port. + */ + DBUG_RETURN(0); + } + + if(connection->abs_wait_timeout < timer->current_microtime) + { + tp_timeout_handler(connection); + } + else { if (connection->abs_wait_timeout < timer->current_microtime) tp_timeout_handler(connection); diff --git a/sql/unireg.cc b/sql/unireg.cc index 525e7a8a56a..ae860f0143b 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -86,6 +86,13 @@ static uchar* extra2_write_str(uchar *pos, const LEX_CSTRING &str) return pos + str.length; } +static uchar* extra2_write_str(uchar *pos, Binary_string *str) +{ + pos= extra2_write_len(pos, str->length()); + memcpy(pos, str->ptr(), str->length()); + return pos + str->length(); +} + static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type, const LEX_CSTRING &str) { @@ -178,11 +185,11 @@ class Field_data_type_info_image: public BinaryStringBuffer<512> { return net_store_length(pos, length); } - static uchar *store_string(uchar *pos, const LEX_CSTRING &str) + static uchar *store_string(uchar *pos, Binary_string *str) { - pos= store_length(pos, str.length); - memcpy(pos, str.str, str.length); - return pos + str.length; + pos= store_length(pos, str->length()); + memcpy(pos, str->ptr(), str->length()); + return pos + str->length(); } static uint store_length_required_length(ulonglong length) { @@ -206,7 +213,7 @@ public: return true; // Error uchar *pos= (uchar *) end(); pos= store_length(pos, fieldnr); - pos= store_string(pos, type_info.lex_cstring()); + pos= store_string(pos, &type_info); size_t new_length= (const char *) pos - ptr(); DBUG_ASSERT(new_length < alloced_length()); length((uint32) new_length); @@ -471,7 +478,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table, goto err; } *pos= EXTRA2_FIELD_DATA_TYPE_INFO; - pos= extra2_write_str(pos + 1, field_data_type_info_image.lex_cstring()); + pos= extra2_write_str(pos + 1, &field_data_type_info_image); } // PERIOD diff --git a/sql/winservice.c b/sql/winservice.c index 44e9302e3d3..a11087e5cd5 100644 --- a/sql/winservice.c +++ b/sql/winservice.c @@ -116,6 +116,24 @@ BOOL exclude_service(mysqld_service_properties *props) } +static void get_datadir_from_ini(const char *ini, char *service_name, char *datadir, size_t sz) +{ + *datadir= 0; + const char *sections[]= {service_name, "mysqld", "server", "mariadb", + "mariadbd"}; + for (int i= 0; i < sizeof(sections) / sizeof(sections[0]); i++) + { + if (sections[i]) + { + GetPrivateProfileStringA(sections[i], "datadir", NULL, datadir, + (DWORD) sz, ini); + if (*datadir) + return; + } + } +} + + /* Retrieve some properties from windows mysqld service binary path. We're interested in ini file location and datadir, and also in version of @@ -135,6 +153,7 @@ int get_mysql_service_properties(const wchar_t *bin_path, wchar_t **args= NULL; int retval= 1; BOOL have_inifile; + char service_name[MAX_PATH]; props->datadir[0]= 0; props->inifile[0]= 0; @@ -163,6 +182,9 @@ int get_mysql_service_properties(const wchar_t *bin_path, goto end; } + /* Last parameter is the service name*/ + wcstombs(service_name, args[numargs-1], MAX_PATH); + if(have_inifile && wcsncmp(args[1], L"--defaults-file=", 16) != 0) goto end; @@ -195,8 +217,8 @@ int get_mysql_service_properties(const wchar_t *bin_path, normalize_path(props->inifile, MAX_PATH); if (GetFileAttributes(props->inifile) != INVALID_FILE_ATTRIBUTES) { - GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, MAX_PATH, - props->inifile); + get_datadir_from_ini(props->inifile, service_name, props->datadir, + sizeof(props->datadir)); } else { @@ -245,8 +267,8 @@ int get_mysql_service_properties(const wchar_t *bin_path, if (GetFileAttributes(props->inifile) != INVALID_FILE_ATTRIBUTES) { /* Ini file found, get datadir from there */ - GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, - MAX_PATH, props->inifile); + get_datadir_from_ini(props->inifile, service_name, props->datadir, + sizeof(props->datadir)); } else { diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 6405a5d2cb7..139cd5cd7ae 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -149,4 +149,6 @@ my_bool wsrep_thd_has_ignored_error(const THD*) void wsrep_thd_set_ignored_error(THD*, my_bool) { } ulong wsrep_OSU_method_get(const THD*) +{ return 0;} +bool wsrep_thd_set_wsrep_aborter(THD*, THD*) { return 0;}
\ No newline at end of file diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index de0aab4b81a..8f52938f9ed 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -292,6 +292,8 @@ int Wsrep_high_priority_service::append_fragment_and_commit( ret= ret || (m_thd->wsrep_cs().after_applying(), 0); m_thd->mdl_context.release_transactional_locks(); + free_root(m_thd->mem_root, MYF(MY_KEEP_PREALLOC)); + thd_proc_info(m_thd, "wsrep applier committed"); DBUG_RETURN(ret); @@ -350,6 +352,8 @@ int Wsrep_high_priority_service::commit(const wsrep::ws_handle& ws_handle, thd->lex->sql_command= SQLCOM_END; + free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC)); + must_exit_= check_exit_status(); DBUG_RETURN(ret); } @@ -370,6 +374,9 @@ int Wsrep_high_priority_service::rollback(const wsrep::ws_handle& ws_handle, int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd)); m_thd->mdl_context.release_transactional_locks(); m_thd->mdl_context.release_explicit_locks(); + + free_root(m_thd->mem_root, MYF(MY_KEEP_PREALLOC)); + DBUG_RETURN(ret); } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 0c31631d19b..9a2d5e635a5 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1968,7 +1968,7 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) if (sp->m_handler->type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); - returns= retstr.lex_cstring(); + retstr.get_value(&returns); } if (sp->m_handler-> show_create_sp(thd, &log_query, diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index 08c90e488bd..643f0072ebf 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -492,12 +492,11 @@ static int scan(TABLE* table, uint field, INTTYPE& val) static int scan(TABLE* table, uint field, char* strbuf, uint strbuf_len) { - String str; - (void)table->field[field]->val_str(&str); - LEX_CSTRING tmp= str.lex_cstring(); - uint len = tmp.length; - strncpy(strbuf, tmp.str, std::min(len, strbuf_len)); - strbuf[strbuf_len - 1]= '\0'; + uint len; + StringBuffer<STRING_BUFFER_USUAL_SIZE> str; + (void) table->field[field]->val_str(&str); + len= str.length(); + strmake(strbuf, str.ptr(), MY_MIN(len, strbuf_len-1)); return 0; } diff --git a/sql/xa.cc b/sql/xa.cc index 68e6e67fa0b..e8e6dc43c56 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -689,7 +689,8 @@ bool trans_xa_commit(THD *thd) { DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock"); - if ((res= MY_TEST(ha_commit_one_phase(thd, 1)))) + res= MY_TEST(ha_commit_one_phase(thd, 1, 1)); + if (res) my_error(ER_XAER_RMERR, MYF(0)); else { @@ -842,6 +843,7 @@ bool trans_xa_detach(THD *thd) thd->transaction->all.ha_list= 0; thd->transaction->all.no_2pc= 0; + thd->m_transaction_psi= 0; return false; } |