summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-08-04 07:55:16 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-08-04 07:55:16 +0300
commit9a7948e3f6d3fd7528e49f43eb4d41f8f55c8a35 (patch)
tree68f8e54f6c2484dc7791bee8c594d3d07c611d29 /sql
parent56990b18d914b8150c9f777d134724d2b3390360 (diff)
parentbbd70fcc43cc889e4593594ee5ca436fe1433aac (diff)
downloadmariadb-git-9a7948e3f6d3fd7528e49f43eb4d41f8f55c8a35.tar.gz
Merge 10.5 into 10.6
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc21
-rw-r--r--sql/filesort.cc35
-rw-r--r--sql/filesort_utils.cc9
-rw-r--r--sql/ha_partition.cc7
-rw-r--r--sql/handler.cc100
-rw-r--r--sql/handler.h5
-rw-r--r--sql/item.cc68
-rw-r--r--sql/item.h38
-rw-r--r--sql/item_cmpfunc.cc28
-rw-r--r--sql/item_cmpfunc.h80
-rw-r--r--sql/item_create.cc2
-rw-r--r--sql/item_func.cc112
-rw-r--r--sql/item_func.h55
-rw-r--r--sql/item_strfunc.cc4
-rw-r--r--sql/item_subselect.cc53
-rw-r--r--sql/item_subselect.h180
-rw-r--r--sql/item_timefunc.cc14
-rw-r--r--sql/item_windowfunc.cc6
-rw-r--r--sql/item_windowfunc.h12
-rw-r--r--sql/log.cc4
-rw-r--r--sql/log.h6
-rw-r--r--sql/log_event_client.cc9
-rw-r--r--sql/log_event_server.cc14
-rw-r--r--sql/mdl.cc4
-rw-r--r--sql/mdl.h5
-rw-r--r--sql/mysqld.cc8
-rw-r--r--sql/net_serv.cc12
-rw-r--r--sql/opt_subselect.cc112
-rw-r--r--sql/partition_info.cc5
-rw-r--r--sql/protocol.cc86
-rw-r--r--sql/protocol.h79
-rw-r--r--sql/rpl_parallel.cc2
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/service_wsrep.cc34
-rw-r--r--sql/session_tracker.cc8
-rw-r--r--sql/share/errmsg-utf8.txt2
-rw-r--r--sql/slave.cc3
-rw-r--r--sql/sp.cc14
-rw-r--r--sql/sql_acl.cc37
-rw-r--r--sql/sql_alter.cc14
-rw-r--r--sql/sql_alter.h9
-rw-r--r--sql/sql_base.cc54
-rw-r--r--sql/sql_class.cc26
-rw-r--r--sql/sql_class.h40
-rw-r--r--sql/sql_connect.cc1
-rw-r--r--sql/sql_help.cc2
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_lex.cc43
-rw-r--r--sql/sql_lex.h22
-rw-r--r--sql/sql_locale.h2
-rw-r--r--sql/sql_parse.cc63
-rw-r--r--sql/sql_partition_admin.cc6
-rw-r--r--sql/sql_plugin.cc74
-rw-r--r--sql/sql_plugin_services.ic3
-rw-r--r--sql/sql_prepare.cc41
-rw-r--r--sql/sql_select.cc34
-rw-r--r--sql/sql_sequence.cc5
-rw-r--r--sql/sql_show.cc11
-rw-r--r--sql/sql_statistics.cc14
-rw-r--r--sql/sql_statistics.h18
-rw-r--r--sql/sql_string.h24
-rw-r--r--sql/sql_table.cc34
-rw-r--r--sql/sql_time.cc22
-rw-r--r--sql/sql_time.h4
-rw-r--r--sql/sql_type.cc158
-rw-r--r--sql/sql_type.h122
-rw-r--r--sql/sql_window.cc8
-rw-r--r--sql/sql_yacc.yy4
-rw-r--r--sql/sys_vars.cc21
-rw-r--r--sql/sys_vars.ic13
-rw-r--r--sql/table.cc41
-rw-r--r--sql/table.h2
-rw-r--r--sql/threadpool.h1
-rw-r--r--sql/threadpool_common.cc22
-rw-r--r--sql/threadpool_generic.cc22
-rw-r--r--sql/unireg.cc19
-rw-r--r--sql/winservice.c30
-rw-r--r--sql/wsrep_dummy.cc2
-rw-r--r--sql/wsrep_high_priority_service.cc7
-rw-r--r--sql/wsrep_mysqld.cc2
-rw-r--r--sql/wsrep_schema.cc11
-rw-r--r--sql/xa.cc4
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> &parameters);
- 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> &parameters) 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> &parameters);
- 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> &parameters) 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;
}