summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-05-25 09:15:08 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2022-05-25 09:15:08 +0300
commit3cc8539d84f569f4829874bf36f4b44b0ceb030c (patch)
treecc4cf6561f81b4d6b33af1dc5da888e6baff59af /sql
parent956d93b581b704fa56b0b6469ae35a2e79850ef4 (diff)
parent1ace1075dc6bb02fe19802334f9d47446a17a79a (diff)
downloadmariadb-git-3cc8539d84f569f4829874bf36f4b44b0ceb030c.tar.gz
Merge 10.9 into 10.10
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc7
-rw-r--r--sql/field.h18
-rw-r--r--sql/gcalc_tools.cc2
-rw-r--r--sql/gcalc_tools.h16
-rw-r--r--sql/ha_partition.cc15
-rw-r--r--sql/ha_partition.h4
-rw-r--r--sql/handler.cc22
-rw-r--r--sql/handler.h91
-rw-r--r--sql/item.cc42
-rw-r--r--sql/item.h32
-rw-r--r--sql/item_cmpfunc.cc12
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_func.h2
-rw-r--r--sql/item_subselect.cc26
-rw-r--r--sql/item_sum.cc12
-rw-r--r--sql/json_table.cc2
-rw-r--r--sql/json_table.h2
-rw-r--r--sql/lex_charset.cc708
-rw-r--r--sql/lex_charset.h558
-rw-r--r--sql/mysql_install_db.cc2
-rw-r--r--sql/mysqld.cc47
-rw-r--r--sql/partition_info.cc52
-rw-r--r--sql/partition_info.h6
-rw-r--r--sql/rpl_gtid.cc6
-rw-r--r--sql/rpl_gtid.h1
-rw-r--r--sql/semisync_master.cc65
-rw-r--r--sql/semisync_master.h39
-rw-r--r--sql/semisync_slave.cc40
-rw-r--r--sql/semisync_slave.h1
-rw-r--r--sql/share/CMakeLists.txt30
-rw-r--r--sql/share/errmsg-utf8.txt27
-rw-r--r--sql/slave.cc143
-rw-r--r--sql/sp_cache.cc9
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_alter.cc2
-rw-r--r--sql/sql_base.cc12
-rw-r--r--sql/sql_class.cc136
-rw-r--r--sql/sql_class.h91
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_handler.cc4
-rw-r--r--sql/sql_i_s.h4
-rw-r--r--sql/sql_insert.cc9
-rw-r--r--sql/sql_lex.cc44
-rw-r--r--sql/sql_lex.h72
-rw-r--r--sql/sql_manager.cc1
-rw-r--r--sql/sql_parse.cc75
-rw-r--r--sql/sql_parse.h1
-rw-r--r--sql/sql_partition.cc5
-rw-r--r--sql/sql_partition_admin.cc12
-rw-r--r--sql/sql_plugin.cc3
-rw-r--r--sql/sql_select.cc213
-rw-r--r--sql/sql_select.h6
-rw-r--r--sql/sql_show.cc92
-rw-r--r--sql/sql_table.cc151
-rw-r--r--sql/sql_table.h11
-rw-r--r--sql/sql_tvc.cc1
-rw-r--r--sql/sql_type.cc3
-rw-r--r--sql/sql_update.cc3
-rw-r--r--sql/sql_window.cc68
-rw-r--r--sql/sql_window.h15
-rw-r--r--sql/sql_yacc.yy157
-rw-r--r--sql/structs.h17
-rw-r--r--sql/table.cc55
-rw-r--r--sql/wsrep_trans_observer.h4
64 files changed, 2420 insertions, 892 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 2fe66a96b15..4435e8c7f38 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -3345,11 +3345,12 @@ Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
decimal_digits_t dec_arg,bool zero_arg,
bool unsigned_arg)
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
+ unireg_check_arg, field_name_arg,
+ MY_MIN(dec_arg, DECIMAL_MAX_SCALE), zero_arg, unsigned_arg)
{
precision= get_decimal_precision(len_arg, dec_arg, unsigned_arg);
- DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
- (dec <= DECIMAL_MAX_SCALE));
+ DBUG_ASSERT(precision <= DECIMAL_MAX_PRECISION);
+ DBUG_ASSERT(dec <= DECIMAL_MAX_SCALE);
bin_size= my_decimal_get_binary_size(precision, dec);
}
diff --git a/sql/field.h b/sql/field.h
index 7b279ffb41e..cb78bdccd4b 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -5501,22 +5501,22 @@ public:
bool check_vcol_for_key(THD *thd) const;
- void set_lex_charset_collation(const Lex_charset_collation_st &lc)
+ void set_charset_collation_attrs(const
+ Lex_column_charset_collation_attrs_st &lc)
{
- charset= lc.charset_collation();
+ charset= lc.charset_info();
if (lc.is_contextually_typed_collation())
flags|= CONTEXT_COLLATION_FLAG;
else
flags&= ~CONTEXT_COLLATION_FLAG;
}
- Lex_charset_collation lex_charset_collation() const
+ Lex_column_charset_collation_attrs charset_collation_attrs() const
{
- return Lex_charset_collation(
- charset,
- !charset ? Lex_charset_collation_st::TYPE_EMPTY :
- flags & CONTEXT_COLLATION_FLAG ?
- Lex_charset_collation_st::TYPE_COLLATE_CONTEXTUALLY_TYPED :
- Lex_charset_collation_st::TYPE_CHARACTER_SET);
+ if (!charset)
+ return Lex_column_charset_collation_attrs();
+ if (flags & CONTEXT_COLLATION_FLAG)
+ return Lex_column_charset_collation_attrs(Lex_context_collation(charset));
+ return Lex_column_charset_collation_attrs(Lex_exact_collation(charset));
}
};
diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc
index 307f063fb43..25c80a7a796 100644
--- a/sql/gcalc_tools.cc
+++ b/sql/gcalc_tools.cc
@@ -132,7 +132,7 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
int mask= (c_op & op_not) ? 1:0;
uint n_ops= c_op & ~(op_any | op_not | v_mask);
uint n_shape= c_op & ~(op_any | op_not | v_mask); /* same as n_ops */
- value v_state= (value) (c_op & v_mask);
+ op_type v_state= (op_type) (c_op & v_mask);
int result= 0;
const char *sav_cur_func= cur_func;
diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h
index e625b355d95..bb1f473e180 100644
--- a/sql/gcalc_tools.h
+++ b/sql/gcalc_tools.h
@@ -52,17 +52,15 @@ private:
int count_internal(const char *cur_func, uint set_type,
const char **end);
public:
- enum value
- {
- v_empty= 0x0000000,
- v_find_t= 0x1000000,
- v_find_f= 0x2000000,
- v_t_found= 0x3000000,
- v_f_found= 0x4000000,
- v_mask= 0x7000000
- };
enum op_type
{
+ v_empty= 0x00000000,
+ v_find_t= 0x01000000,
+ v_find_f= 0x02000000,
+ v_t_found= 0x03000000,
+ v_f_found= 0x04000000,
+ v_mask= 0x07000000,
+
op_not= 0x80000000,
op_shape= 0x00000000,
op_union= 0x10000000,
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 34c65f2e45d..e85ce02b7e6 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2005, 2019, Oracle and/or its affiliates.
- Copyright (c) 2009, 2021, MariaDB
+ Copyright (c) 2009, 2022, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -4177,6 +4177,8 @@ int ha_partition::external_lock(THD *thd, int lock_type)
if (lock_type == F_UNLCK)
{
bitmap_clear_all(used_partitions);
+ if (m_lock_type == F_WRLCK && m_part_info->vers_require_hist_part(thd))
+ m_part_info->vers_check_limit(thd);
}
else
{
@@ -10576,7 +10578,16 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table,
Loop over all other partitions as to follow the protocol!
*/
uint i;
- DBUG_ASSERT(0);
+ /*
+ InnoDB does not set ha_alter_info->group_commit_ctx to NULL in the
+ case if autoincrement attribute is necessary to reset for all
+ partitions for INNOBASE_INPLACE_IGNORE handler flags. It does not
+ affect durability, because it is solely about updating the InnoDB data
+ dictionary caches (one InnoDB dict_table_t per partition or
+ sub-partition).
+ */
+ DBUG_ASSERT(table->found_next_number_field
+ && !altered_table->found_next_number_field);
for (i= 1; i < m_tot_parts; i++)
{
ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i];
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index fbf34efe39f..9cbb6c928ee 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1608,9 +1608,6 @@ public:
/**
Get the number of records in part_elem and its subpartitions, if any.
- Also sets read_partitions bit for each partition id it uses (that is needed
- for vers_set_hist_part() because it is called before read_partitions bitmap
- is initialized).
*/
ha_rows part_records(partition_element *part_elem)
{
@@ -1623,7 +1620,6 @@ public:
for (; part_id < part_id_end; ++part_id)
{
handler *file= m_file[part_id];
- bitmap_set_bit(&(m_part_info->read_partitions), part_id);
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_OPEN);
part_recs+= file->stats.records;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index fb1f9ba8a76..2f2c7064e6a 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -4365,6 +4365,7 @@ void handler::print_error(int error, myf errflag)
if ((int) key_nr >= 0 && key_nr < table->s->keys)
{
print_keydup_error(table, &table->key_info[key_nr], errflag);
+ table->file->lookup_errkey= -1;
DBUG_VOID_RETURN;
}
}
@@ -5810,6 +5811,9 @@ int handler::calculate_checksum()
for (uint i= 0; i < table->s->fields; i++ )
{
Field *f= table->field[i];
+ if (!f->stored_in_db())
+ continue;
+
if (! (thd->variables.old_behavior & OLD_MODE_COMPAT_5_1_CHECKSUM) &&
f->is_real_null(0))
@@ -7917,24 +7921,6 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
#endif /* WITH_WSREP */
-bool HA_CREATE_INFO::check_conflicting_charset_declarations(CHARSET_INFO *cs)
-{
- if ((used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
- /* DEFAULT vs explicit, or explicit vs DEFAULT */
- (((default_table_charset == NULL) != (cs == NULL)) ||
- /* Two different explicit character sets */
- (default_table_charset && cs &&
- !my_charset_same(default_table_charset, cs))))
- {
- my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
- "CHARACTER SET ", default_table_charset ?
- default_table_charset->cs_name.str : "DEFAULT",
- "CHARACTER SET ", cs ? cs->cs_name.str : "DEFAULT");
- return true;
- }
- return false;
-}
-
/* Remove all indexes for a given table from global index statistics */
static
diff --git a/sql/handler.h b/sql/handler.h
index cdab18cecbc..60c6195e68e 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -967,6 +967,7 @@ typedef struct xid_t XID;
*/
typedef uint Binlog_file_id;
const Binlog_file_id MAX_binlog_id= UINT_MAX;
+const my_off_t MAX_off_t = (~(my_off_t) 0);
/*
Compound binlog-id and byte offset of transaction's first event
in a sequence (e.g the recovery sequence) of binlog files.
@@ -981,14 +982,22 @@ struct xid_recovery_member
my_xid xid;
uint in_engine_prepare; // number of engines that have xid prepared
bool decided_to_commit;
- Binlog_offset binlog_coord; // semisync recovery binlog offset
+ /*
+ Semisync recovery binlog offset. It's initialized with the maximum
+ unreachable offset. The max value will remain for any transaction
+ not found in binlog to yield its rollback decision as it's guaranteed
+ to be within a truncated tail part of the binlog.
+ */
+ Binlog_offset binlog_coord;
XID *full_xid; // needed by wsrep or past it recovery
decltype(::server_id) server_id; // server id of orginal server
xid_recovery_member(my_xid xid_arg, uint prepare_arg, bool decided_arg,
XID *full_xid_arg, decltype(::server_id) server_id_arg)
: xid(xid_arg), in_engine_prepare(prepare_arg),
- decided_to_commit(decided_arg), full_xid(full_xid_arg) , server_id(server_id_arg) {};
+ decided_to_commit(decided_arg),
+ binlog_coord(Binlog_offset(MAX_binlog_id, MAX_off_t)),
+ full_xid(full_xid_arg), server_id(server_id_arg) {};
};
/* for recover() handlerton call */
@@ -2280,33 +2289,6 @@ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
Schema_specification_st::init();
alter_info= NULL;
}
- bool check_conflicting_charset_declarations(CHARSET_INFO *cs);
- bool add_table_option_default_charset(CHARSET_INFO *cs)
- {
- // cs can be NULL, e.g.: CREATE TABLE t1 (..) CHARACTER SET DEFAULT;
- if (check_conflicting_charset_declarations(cs))
- return true;
- default_table_charset= cs;
- used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- return false;
- }
- bool add_alter_list_item_convert_to_charset(CHARSET_INFO *cs)
- {
- /*
- cs cannot be NULL, as sql_yacc.yy translates
- CONVERT TO CHARACTER SET DEFAULT
- to
- CONVERT TO CHARACTER SET <character-set-of-the-current-database>
- TODO: Shouldn't we postpone resolution of DEFAULT until the
- character set of the table owner database is loaded from its db.opt?
- */
- DBUG_ASSERT(cs);
- if (check_conflicting_charset_declarations(cs))
- return true;
- alter_table_convert_to_charset= default_table_charset= cs;
- used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET);
- return false;
- }
ulong table_options_with_row_type()
{
if (row_type == ROW_TYPE_DYNAMIC || row_type == ROW_TYPE_PAGE)
@@ -2314,6 +2296,10 @@ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
else
return table_options;
}
+ bool resolve_to_charset_collation_context(THD *thd,
+ const Lex_table_charset_collation_attrs_st &default_cscl,
+ const Lex_table_charset_collation_attrs_st &convert_cscl,
+ const Charset_collation_context &ctx);
};
@@ -2324,16 +2310,23 @@ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
struct Table_specification_st: public HA_CREATE_INFO,
public DDL_options_st
{
+ Lex_table_charset_collation_attrs_st default_charset_collation;
+ Lex_table_charset_collation_attrs_st convert_charset_collation;
+
// Deep initialization
void init()
{
HA_CREATE_INFO::init();
DDL_options_st::init();
+ default_charset_collation.init();
+ convert_charset_collation.init();
}
void init(DDL_options_st::Options options_arg)
{
HA_CREATE_INFO::init();
DDL_options_st::init(options_arg);
+ default_charset_collation.init();
+ convert_charset_collation.init();
}
/*
Quick initialization, for parser.
@@ -2345,6 +2338,46 @@ struct Table_specification_st: public HA_CREATE_INFO,
{
HA_CREATE_INFO::options= 0;
DDL_options_st::init();
+ default_charset_collation.init();
+ convert_charset_collation.init();
+ }
+
+ bool add_table_option_convert_charset(CHARSET_INFO *cs)
+ {
+ // cs can be NULL, e.g.: ALTER TABLE t1 CONVERT TO CHARACTER SET DEFAULT;
+ used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET);
+ return cs ?
+ convert_charset_collation.merge_exact_charset(Lex_exact_charset(cs)) :
+ convert_charset_collation.merge_charset_default();
+ }
+ bool add_table_option_convert_collation(const Lex_extended_collation_st &cl)
+ {
+ used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET);
+ return convert_charset_collation.merge_collation(cl);
+ }
+
+ bool add_table_option_default_charset(CHARSET_INFO *cs)
+ {
+ // cs can be NULL, e.g.: CREATE TABLE t1 (..) CHARACTER SET DEFAULT;
+ used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ return cs ?
+ default_charset_collation.merge_exact_charset(Lex_exact_charset(cs)) :
+ default_charset_collation.merge_charset_default();
+ }
+ bool add_table_option_default_collation(const Lex_extended_collation_st &cl)
+ {
+ used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ return default_charset_collation.merge_collation(cl);
+ }
+
+ bool resolve_to_charset_collation_context(THD *thd,
+ const Charset_collation_context &ctx)
+ {
+ return HA_CREATE_INFO::
+ resolve_to_charset_collation_context(thd,
+ default_charset_collation,
+ convert_charset_collation,
+ ctx);
}
};
diff --git a/sql/item.cc b/sql/item.cc
index 3b8345f4416..6c5a892fc96 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -959,8 +959,7 @@ bool Item_field::check_field_expression_processor(void *arg)
(!field->vcol_info && !org_field->vcol_info)) &&
field->field_index >= org_field->field_index))
{
- my_error(ER_EXPRESSION_REFERS_TO_UNINIT_FIELD,
- MYF(0),
+ my_error(ER_EXPRESSION_REFERS_TO_UNINIT_FIELD, MYF(0),
org_field->field_name.str, field->field_name.str);
return 1;
}
@@ -7998,8 +7997,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
else if (!ref || ref == not_found_item)
{
DBUG_ASSERT(reference_trough_name != 0);
- if (!(ref= resolve_ref_in_select_and_group(thd, this,
- context->select_lex)))
+ if (!(ref= resolve_ref_in_select_and_group(thd, this, context->select_lex)))
goto error; /* Some error occurred (e.g. ambiguous names). */
if (ref == not_found_item) /* This reference was not resolved. */
@@ -8012,8 +8010,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (unlikely(!outer_context))
{
/* The current reference cannot be resolved in this query. */
- my_error(ER_BAD_FIELD_ERROR,MYF(0),
- this->full_name(), thd->where);
+ my_error(ER_BAD_FIELD_ERROR,MYF(0), full_name(), thd->where);
goto error;
}
@@ -9505,6 +9502,12 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const
}
+bool Item_default_value::check_field_expression_processor(void *)
+{
+ field->default_value= ((Item_field *)(arg->real_item()))->field->default_value;
+ return 0;
+}
+
bool Item_default_value::fix_fields(THD *thd, Item **items)
{
Item *real_arg;
@@ -9546,7 +9549,6 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
}
if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of())))
goto error;
- cached_field= def_field;
memcpy((void *)def_field, (void *)field_arg->field,
field_arg->field->size_of());
def_field->reset_fields();
@@ -9575,8 +9577,7 @@ error:
void Item_default_value::cleanup()
{
- delete cached_field; // Free cached blob data
- cached_field= 0;
+ delete field; // Free cached blob data
Item_field::cleanup();
}
@@ -9651,6 +9652,12 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
return Item_field::save_in_field(field_arg, no_conversions);
}
+void Item_default_value::save_in_result_field(bool no_conversions)
+{
+ calculate();
+ Item_field::save_in_result_field(no_conversions);
+}
+
double Item_default_value::val_result()
{
calculate();
@@ -9710,6 +9717,23 @@ table_map Item_default_value::used_tables() const
return field->default_value->expr->used_tables();
}
+bool Item_default_value::register_field_in_read_map(void *arg)
+{
+ TABLE *table= (TABLE *) arg;
+ int res= 0;
+ if (!table || (table && table == field->table))
+ {
+ if (field->default_value && field->default_value->expr)
+ res= field->default_value->expr->walk(&Item::register_field_in_read_map,1,arg);
+ }
+ else if (result_field && table == result_field->table)
+ {
+ bitmap_set_bit(table->read_set, result_field->field_index);
+ }
+
+ return res;
+}
+
/**
This method like the walk method traverses the item tree, but at the
same time it can replace some nodes in the tree.
diff --git a/sql/item.h b/sql/item.h
index 4ef0e1b93b2..d1d19157b83 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2177,6 +2177,12 @@ public:
return 0;
}
+ virtual bool set_extraction_flag_processor(void *arg)
+ {
+ set_extraction_flag(*(int16*)arg);
+ return 0;
+ }
+
/**
Check db/table_name if they defined in item and match arg values
@@ -6613,7 +6619,6 @@ class Item_default_value : public Item_field
void calculate();
public:
Item *arg= nullptr;
- Field *cached_field= nullptr;
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a,
bool vcol_assignment_arg)
: Item_field(thd, context_arg),
@@ -6630,6 +6635,10 @@ public:
bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate) override;
bool val_native(THD *thd, Native *to) override;
bool val_native_result(THD *thd, Native *to) override;
+ longlong val_datetime_packed(THD *thd) override
+ { return Item::val_datetime_packed(thd); }
+ longlong val_time_packed(THD *thd) override
+ { return Item::val_time_packed(thd); }
/* Result variants */
double val_result() override;
@@ -6643,6 +6652,7 @@ public:
bool send(Protocol *protocol, st_value *buffer) override;
int save_in_field(Field *field_arg, bool no_conversions) override;
+ void save_in_result_field(bool no_conversions) override;
bool save_in_param(THD *, Item_param *param) override
{
// It should not be possible to have "EXECUTE .. USING DEFAULT(a)"
@@ -6658,11 +6668,12 @@ public:
}
bool vcol_assignment_allowed_value() const override
{ return vcol_assignment_ok; }
- Field *get_tmp_table_field() override { return nullptr; }
Item *get_tmp_table_item(THD *) override { return this; }
Item_field *field_for_view_update() override { return nullptr; }
bool update_vcol_processor(void *) override { return false; }
+ bool check_field_expression_processor(void *arg) override;
bool check_func_default_processor(void *) override { return true; }
+ bool register_field_in_read_map(void *arg) override;
bool walk(Item_processor processor, bool walk_subquery, void *args) override
{
return (arg && arg->walk(processor, walk_subquery, args)) ||
@@ -6941,7 +6952,7 @@ public:
for any value.
*/
-class Item_cache: public Item,
+class Item_cache: public Item_fixed_hybrid,
public Type_handler_hybrid_field_type
{
protected:
@@ -6972,7 +6983,7 @@ public:
bool null_value_inside;
Item_cache(THD *thd):
- Item(thd),
+ Item_fixed_hybrid(thd),
Type_handler_hybrid_field_type(&type_handler_string),
example(0), cached_field(0),
value_cached(0),
@@ -6981,10 +6992,11 @@ public:
set_maybe_null();
null_value= 1;
null_value_inside= true;
+ quick_fix_field();
}
protected:
Item_cache(THD *thd, const Type_handler *handler):
- Item(thd),
+ Item_fixed_hybrid(thd),
Type_handler_hybrid_field_type(handler),
example(0), cached_field(0),
value_cached(0),
@@ -6993,6 +7005,7 @@ protected:
set_maybe_null();
null_value= 1;
null_value_inside= true;
+ quick_fix_field();
}
public:
@@ -7045,10 +7058,17 @@ public:
}
return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE);
}
+ bool fix_fields(THD *thd, Item **ref) override
+ {
+ quick_fix_field();
+ if (example && !example->fixed())
+ return example->fix_fields(thd, ref);
+ return 0;
+ }
void cleanup() override
{
clear();
- Item::cleanup();
+ Item_fixed_hybrid::cleanup();
}
/**
Check if saved item has a non-NULL value.
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index dbfbc07a600..a53bb2e53b6 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -7663,7 +7663,17 @@ bool Item_equal::create_pushable_equalities(THD *thd,
if (!eq || equalities->push_back(eq, thd->mem_root))
return true;
if (!clone_const)
- right_item->set_extraction_flag(MARKER_IMMUTABLE);
+ {
+ /*
+ Also set IMMUTABLE_FL for any sub-items of the right_item.
+ This is needed to prevent Item::cleanup_excluding_immutables_processor
+ from peforming cleanup of the sub-items and so creating an item tree
+ where a fixed item has non-fixed items inside it.
+ */
+ int16 new_flag= MARKER_IMMUTABLE;
+ right_item->walk(&Item::set_extraction_flag_processor, false,
+ (void*)&new_flag);
+ }
}
while ((item=it++))
diff --git a/sql/item_func.cc b/sql/item_func.cc
index f25dffdfd02..e53b89a9291 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2501,7 +2501,7 @@ void Item_func_round::fix_arg_decimal()
set_handler(&type_handler_newdecimal);
unsigned_flag= args[0]->unsigned_flag;
decimals= args[0]->decimals;
- max_length= float_length(args[0]->decimals) + 1;
+ max_length= args[0]->max_length;
}
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 185242b7901..a4122f78e87 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -3773,7 +3773,7 @@ public:
}
bool set(const Type_handler *handler,
const Lex_length_and_dec_st & length_and_dec,
- const Lex_charset_collation_st &cscl,
+ const Lex_column_charset_collation_attrs_st &cscl,
CHARSET_INFO *defcs)
{
CHARSET_INFO *tmp= cscl.resolved_to_character_set(defcs);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index de31c82abf4..2169ac874e5 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -826,6 +826,7 @@ bool Item_subselect::exec()
DBUG_ENTER("Item_subselect::exec");
DBUG_ASSERT(fixed());
DBUG_ASSERT(thd);
+ DBUG_ASSERT(!eliminated);
DBUG_EXECUTE_IF("Item_subselect",
Item::Print print(this,
@@ -1361,11 +1362,18 @@ bool Item_singlerow_subselect::fix_length_and_dec()
}
unsigned_flag= value->unsigned_flag;
/*
- If there are not tables in subquery then ability to have NULL value
- depends on SELECT list (if single row subquery have tables then it
- always can be NULL if there are not records fetched).
+ If the subquery has no tables (1) and is not a UNION (2), like:
+
+ (SELECT subq_value)
+
+ then its NULLability is the same as subq_value's NULLability.
+
+ (1): A subquery that uses a table will return NULL when the table is empty.
+ (2): A UNION subquery will return NULL if it produces a "Subquery returns
+ more than one row" error.
*/
- if (engine->no_tables())
+ if (engine->no_tables() &&
+ engine->engine_type() != subselect_engine::UNION_ENGINE)
set_maybe_null(engine->may_be_null());
else
{
@@ -1401,6 +1409,16 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(THD *tmp_thd,
DBUG_ASSERT(thd == tmp_thd);
+ /*
+ Do not create subquery cache if the subquery was eliminated.
+ The optimizer may eliminate subquery items (see
+ eliminate_subselect_processor). However it does not update
+ all query's data structures, so the eliminated item may be
+ still reachable.
+ */
+ if (eliminated)
+ DBUG_RETURN(this);
+
if (expr_cache)
DBUG_RETURN(expr_cache);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 109a0f883e8..4f79c8f647d 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1559,6 +1559,8 @@ void Item_sum_sum::fix_length_and_dec_decimal()
decimals= args[0]->decimals;
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS;
+ decimals= MY_MIN(decimals, DECIMAL_MAX_SCALE);
+ precision= MY_MIN(precision, DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
@@ -1970,12 +1972,12 @@ void Item_sum_avg::fix_length_and_dec_decimal()
{
Item_sum_sum::fix_length_and_dec_decimal();
int precision= args[0]->decimal_precision() + prec_increment;
- decimals= MY_MIN(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
+ decimals= MY_MIN(args[0]->decimal_scale() + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
f_precision= MY_MIN(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
- f_scale= args[0]->decimals;
+ f_scale= args[0]->decimal_scale();
dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
}
@@ -4261,9 +4263,9 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
result.set_charset(collation.collation);
result_field= 0;
null_value= 1;
- max_length= (uint32)MY_MIN(thd->variables.group_concat_max_len
- / collation.collation->mbminlen
- * collation.collation->mbmaxlen, UINT_MAX32);
+ max_length= (uint32) MY_MIN((ulonglong) thd->variables.group_concat_max_len
+ / collation.collation->mbminlen
+ * collation.collation->mbmaxlen, UINT_MAX32);
uint32 offset;
if (separator->needs_conversion(separator->length(), separator->charset(),
diff --git a/sql/json_table.cc b/sql/json_table.cc
index e2f90aa2a9a..a9e882291b6 100644
--- a/sql/json_table.cc
+++ b/sql/json_table.cc
@@ -874,7 +874,7 @@ int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
- const Lex_charset_collation_st &cl)
+ const Lex_column_charset_collation_attrs_st &cl)
{
if (cl.is_empty() || cl.is_contextually_typed_collate_default())
return set(thd, ctype, path, nullptr);
diff --git a/sql/json_table.h b/sql/json_table.h
index 2cadb07961e..6398b061889 100644
--- a/sql/json_table.h
+++ b/sql/json_table.h
@@ -161,7 +161,7 @@ public:
}
int set(THD *thd, enum_type ctype, const LEX_CSTRING &path, CHARSET_INFO *cs);
int set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
- const Lex_charset_collation_st &cl);
+ const Lex_column_charset_collation_attrs_st &cl);
Json_table_column(Create_field *f, Json_table_nested_path *nest) :
m_field(f), m_nest(nest), m_explicit_cs(NULL)
{
diff --git a/sql/lex_charset.cc b/sql/lex_charset.cc
index 7570abbdfb9..c36e01498c5 100644
--- a/sql/lex_charset.cc
+++ b/sql/lex_charset.cc
@@ -21,47 +21,333 @@
#include "mysqld_error.h"
+static void
+raise_ER_CONFLICTING_DECLARATIONS(const char *clause1,
+ const char *name1,
+ const char *clause2,
+ const char *name2,
+ bool reverse_order)
+{
+ if (!reverse_order)
+ my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
+ clause1, name1, clause2, name2);
+ else
+ my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
+ clause2, name2, clause1, name1);
+}
+
+
+static void
+raise_ER_CONFLICTING_DECLARATIONS(const char *clause1,
+ const char *name1,
+ const char *name1_part2,
+ const char *clause2,
+ const char *name2,
+ bool reverse_order)
+{
+ char def[MY_CS_NAME_SIZE * 2];
+ my_snprintf(def, sizeof(def), "%s (%s)", name1, name1_part2);
+ raise_ER_CONFLICTING_DECLARATIONS(clause1, def,
+ clause2, name2,
+ reverse_order);
+}
+
+
+bool Lex_exact_charset::raise_if_not_equal(const Lex_exact_charset &rhs) const
+{
+ if (m_ci == rhs.m_ci)
+ return false;
+ my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
+ "CHARACTER SET ", m_ci->cs_name.str,
+ "CHARACTER SET ", rhs.m_ci->cs_name.str);
+ return true;
+}
+
+
+bool Lex_exact_charset::
+ raise_if_not_applicable(const Lex_exact_collation &cl) const
+{
+ return Lex_exact_charset_opt_extended_collate(m_ci, false).
+ raise_if_not_applicable(cl);
+}
+
+
+bool Lex_exact_charset_opt_extended_collate::
+ raise_if_not_applicable(const Lex_exact_collation &cl) const
+{
+ if (!my_charset_same(m_ci, cl.charset_info()))
+ {
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ cl.charset_info()->coll_name.str, m_ci->cs_name.str);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+Lex_exact_collation::raise_if_not_equal(const Lex_exact_collation &cl) const
+{
+ if (m_ci != cl.m_ci)
+ {
+ my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
+ "COLLATE ", m_ci->coll_name.str,
+ "COLLATE ", cl.m_ci->coll_name.str);
+ return true;
+ }
+ return false;
+}
+
+
+/*
+ Merge an exact collation and a contexual collation.
+ @param cl - The contextual collation to merge to "this".
+ @param reverse_order - If the contextual collation is on the left side
+
+ Use reverse_order as follows:
+ false: COLLATE latin1_swedish_ci COLLATE DEFAULT
+ true: COLLATE DEFAULT COLLATE latin1_swedish_ci
+*/
+bool
+Lex_exact_collation::
+ raise_if_conflicts_with_context_collation(const Lex_context_collation &cl,
+ bool reverse_order) const
+{
+ if (cl.is_contextually_typed_collate_default() &&
+ !(m_ci->state & MY_CS_PRIMARY))
+ {
+ raise_ER_CONFLICTING_DECLARATIONS("COLLATE ", m_ci->coll_name.str,
+ "COLLATE ", "DEFAULT", reverse_order);
+ return true;
+ }
+
+ if (cl.is_contextually_typed_binary_style() &&
+ !(m_ci->state & MY_CS_BINSORT))
+ {
+ raise_ER_CONFLICTING_DECLARATIONS("COLLATE ", m_ci->coll_name.str,
+ "", "BINARY", reverse_order);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+Lex_context_collation::raise_if_not_equal(const Lex_context_collation &cl) const
+{
+ /*
+ Only equal context collations are possible here so far:
+ - Column grammar only supports BINARY, but does not support COLLATE DEFAULT
+ - DB/Table grammar only support COLLATE DEFAULT
+ But we'll have different collations here - uca140 is coming soon.
+ */
+ DBUG_ASSERT(m_ci == cl.m_ci);
+ return false;
+}
+
+
+/*
+ Resolve a context collation to the character set (when the former gets known):
+ CREATE TABLE t1 (a CHAR(10) BINARY) CHARACTER SET latin1;
+ CREATE DATABASE db1 COLLATE DEFAULT CHARACTER SET latin1;
+*/
+bool Lex_exact_charset_opt_extended_collate::
+ merge_context_collation_override(const Lex_context_collation &cl)
+{
+ DBUG_ASSERT(m_ci);
+
+ // CHAR(10) BINARY
+ if (cl.is_contextually_typed_binary_style())
+ {
+ CHARSET_INFO *ci= find_bin_collation();
+ if (!ci)
+ return true;
+ m_ci= ci;
+ m_with_collate= true;
+ return false;
+ }
+
+ // COLLATE DEFAULT
+ if (cl.is_contextually_typed_collate_default())
+ {
+ CHARSET_INFO *ci= find_default_collation();
+ DBUG_ASSERT(ci);
+ if (!ci)
+ return true;
+ m_ci= ci;
+ m_with_collate= true;
+ return false;
+ }
+
+ /*
+ A non-binary and non-default contextually typed collation.
+ We don't have such yet - the parser cannot produce this.
+ But we have "uca1400_as_ci" coming soon.
+ */
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Lex_extended_collation_st::merge_exact_charset(const Lex_exact_charset &cs)
+{
+ switch (m_type) {
+ case TYPE_EXACT:
+ {
+ // COLLATE latin1_swedish_ci .. CHARACTER SET latin1
+ return cs.raise_if_not_applicable(Lex_exact_collation(m_ci));
+ }
+ case TYPE_CONTEXTUALLY_TYPED:
+ {
+ // COLLATE DEFAULT .. CHARACTER SET latin1
+ Lex_exact_charset_opt_extended_collate tmp(cs);
+ if (tmp.merge_context_collation(Lex_context_collation(m_ci)))
+ return true;
+ *this= Lex_extended_collation(tmp.collation());
+ return false;
+ }
+ }
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Lex_extended_collation_st::
+ merge_exact_collation(const Lex_exact_collation &rhs)
+{
+ switch (m_type) {
+
+ case TYPE_EXACT:
+ /*
+ EXACT + EXACT
+ COLLATE latin1_bin .. COLLATE latin1_bin
+ */
+ return Lex_exact_collation(m_ci).raise_if_not_equal(rhs);
+
+ case TYPE_CONTEXTUALLY_TYPED:
+ {
+ /*
+ CONTEXT + EXACT
+ CHAR(10) COLLATE DEFAULT .. COLLATE latin1_swedish_ci
+ CHAR(10) BINARY .. COLLATE latin1_bin
+ CHAR(10) COLLATE uca1400_as_ci .. COLLATE latin1_bin - coming soon
+ */
+ if (rhs.raise_if_conflicts_with_context_collation(
+ Lex_context_collation(m_ci), true))
+ return true;
+ *this= Lex_extended_collation(rhs);
+ return false;
+ }
+ }
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Lex_extended_collation_st::
+ raise_if_conflicts_with_context_collation(const Lex_context_collation &rhs)
+ const
+{
+ switch (m_type) {
+
+ case TYPE_EXACT:
+ /*
+ EXACT + CONTEXT
+ COLLATE latin1_swedish_ci .. COLLATE DEFAULT
+ */
+ return Lex_exact_collation(m_ci).
+ raise_if_conflicts_with_context_collation(rhs, false);
+
+ case TYPE_CONTEXTUALLY_TYPED:
+ {
+ /*
+ CONTEXT + CONTEXT:
+ CHAR(10) BINARY .. COLLATE DEFAULT - not supported by the parser
+ CREATE DATABASE db1 COLLATE DEFAULT COLLATE DEFAULT;
+ */
+ return Lex_context_collation(m_ci).raise_if_not_equal(rhs);
+ }
+ }
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+/*
+ Merge two non-empty COLLATE clauses.
+*/
+bool Lex_extended_collation_st::merge(const Lex_extended_collation_st &rhs)
+{
+ switch (rhs.type()) {
+ case TYPE_EXACT:
+ /*
+ EXACT + EXACT
+ COLLATE latin1_swedish_ci .. COLLATE latin1_swedish_ci
+
+ CONTEXT + EXACT
+ COLLATE DEFAULT .. COLLATE latin1_swedish_ci
+ CHAR(10) BINARY .. COLLATE latin1_bin
+ */
+ return merge_exact_collation(Lex_exact_collation(rhs.m_ci));
+ case TYPE_CONTEXTUALLY_TYPED:
+ /*
+ EXACT + CONTEXT
+ COLLATE latin1_swedish_ci .. COLLATE DEFAULT
+
+ CONTEXT + CONTEXT
+ COLLATE DEFAULT .. COLLATE DEFAULT
+ CHAR(10) BINARY .. COLLATE DEFAULT
+ */
+ return raise_if_conflicts_with_context_collation(
+ Lex_context_collation(rhs.m_ci));
+ }
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
/** find a collation with binary comparison rules
*/
-CHARSET_INFO *Lex_charset_collation_st::find_bin_collation(CHARSET_INFO *cs)
+CHARSET_INFO *Lex_exact_charset_opt_extended_collate::find_bin_collation() const
{
/*
We don't need to handle old_mode=UTF8_IS_UTF8MB3 here,
- because "cs" points to a real character set name.
+ because "m_ci" points to a real character set name.
It can be either "utf8mb3" or "utf8mb4". It cannot be "utf8".
No thd->get_utf8_flag() flag passed to get_charset_by_csname().
*/
- DBUG_ASSERT(cs->cs_name.length !=4 || memcmp(cs->cs_name.str, "utf8", 4));
+ DBUG_ASSERT(m_ci->cs_name.length !=4 || memcmp(m_ci->cs_name.str, "utf8", 4));
/*
CREATE TABLE t1 (a CHAR(10) BINARY)
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
Nothing to do, we have the binary collation already.
*/
- if (cs->state & MY_CS_BINSORT)
- return cs;
+ if (m_ci->state & MY_CS_BINSORT)
+ return m_ci;
// CREATE TABLE t1 (a CHAR(10) BINARY) CHARACTER SET utf8mb4;
- const LEX_CSTRING &cs_name= cs->cs_name;
- if (!(cs= get_charset_by_csname(cs->cs_name.str, MY_CS_BINSORT, MYF(0))))
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset_by_csname(m_ci->cs_name.str, MY_CS_BINSORT, MYF(0))))
{
char tmp[65];
- strxnmov(tmp, sizeof(tmp)-1, cs_name.str, "_bin", NULL);
+ strxnmov(tmp, sizeof(tmp)-1, m_ci->cs_name.str, "_bin", NULL);
my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
}
return cs;
}
-CHARSET_INFO *Lex_charset_collation_st::find_default_collation(CHARSET_INFO *cs)
+CHARSET_INFO *
+Lex_exact_charset_opt_extended_collate::find_default_collation() const
{
// See comments in find_bin_collation()
- DBUG_ASSERT(cs->cs_name.length !=4 || memcmp(cs->cs_name.str, "utf8", 4));
+ DBUG_ASSERT(m_ci->cs_name.length !=4 || memcmp(m_ci->cs_name.str, "utf8", 4));
/*
CREATE TABLE t1 (a CHAR(10) COLLATE DEFAULT) CHARACTER SET utf8mb4;
Nothing to do, we have the default collation already.
*/
- if (cs->state & MY_CS_PRIMARY)
- return cs;
+ if (m_ci->state & MY_CS_PRIMARY)
+ return m_ci;
/*
CREATE TABLE t1 (a CHAR(10) COLLATE DEFAULT)
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
@@ -69,7 +355,8 @@ CHARSET_INFO *Lex_charset_collation_st::find_default_collation(CHARSET_INFO *cs)
Don't need to handle old_mode=UTF8_IS_UTF8MB3 here.
See comments in find_bin_collation.
*/
- cs= get_charset_by_csname(cs->cs_name.str, MY_CS_PRIMARY, MYF(MY_WME));
+ CHARSET_INFO *cs= get_charset_by_csname(m_ci->cs_name.str,
+ MY_CS_PRIMARY, MYF(MY_WME));
/*
The above should never fail, as we have default collations for
all character sets.
@@ -79,21 +366,6 @@ CHARSET_INFO *Lex_charset_collation_st::find_default_collation(CHARSET_INFO *cs)
}
-bool Lex_charset_collation_st::set_charset_collate_exact(CHARSET_INFO *cs,
- CHARSET_INFO *cl)
-{
- DBUG_ASSERT(cs != nullptr && cl != nullptr);
- if (!my_charset_same(cl, cs))
- {
- my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- cl->coll_name.str, cs->cs_name.str);
- return true;
- }
- set_collate_exact(cl);
- return false;
-}
-
-
/*
Resolve an empty or a contextually typed collation according to the
upper level default character set (and optionally a collation), e.g.:
@@ -105,8 +377,8 @@ bool Lex_charset_collation_st::set_charset_collate_exact(CHARSET_INFO *cs,
"this" is the COLLATE clause (e.g. of a column)
"def" is the upper level CHARACTER SET clause (e.g. of a table)
*/
-CHARSET_INFO *
-Lex_charset_collation_st::resolved_to_character_set(CHARSET_INFO *def) const
+CHARSET_INFO *Lex_exact_charset_extended_collation_attrs_st::
+ resolved_to_character_set(CHARSET_INFO *def) const
{
DBUG_ASSERT(def);
@@ -120,103 +392,84 @@ Lex_charset_collation_st::resolved_to_character_set(CHARSET_INFO *def) const
DBUG_ASSERT(m_ci);
return m_ci;
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
- break;
+ {
+ Lex_exact_charset_opt_extended_collate tmp(def, true);
+ if (tmp.merge_context_collation_override(Lex_context_collation(m_ci)))
+ return NULL;
+ return tmp.collation().charset_info();
+ }
}
-
- // Contextually typed
- DBUG_ASSERT(m_ci);
-
- if (is_contextually_typed_binary_style()) // CHAR(10) BINARY
- return find_bin_collation(def);
-
- if (is_contextually_typed_collate_default()) // CHAR(10) COLLATE DEFAULT
- return find_default_collation(def);
-
- /*
- Non-binary and non-default contextually typed collation.
- We don't have such yet - the parser cannot produce this.
- But will have soon, e.g. "uca1400_as_ci".
- */
DBUG_ASSERT(0);
return NULL;
}
-/*
- Merge the CHARACTER SET clause to:
- - an empty COLLATE clause
- - an explicitly typed collation name
- - a contextually typed collation
-
- "this" corresponds to `CHARACTER SET xxx [BINARY]`
- "cl" corresponds to the COLLATE clause
-*/
-bool
-Lex_charset_collation_st::
- merge_charset_clause_and_collate_clause(const Lex_charset_collation_st &cl)
+bool Lex_exact_charset_extended_collation_attrs_st::
+ merge_exact_collation(const Lex_exact_collation &cl)
{
- if (cl.is_empty()) // No COLLATE clause
- return false;
-
switch (m_type) {
case TYPE_EMPTY:
/*
No CHARACTER SET clause
CHAR(10) NOT NULL COLLATE latin1_bin
- CHAR(10) NOT NULL COLLATE DEFAULT
*/
- *this= cl;
+ *this= Lex_exact_charset_extended_collation_attrs(cl);
return false;
case TYPE_CHARACTER_SET:
- case TYPE_COLLATE_EXACT:
{
- Lex_explicit_charset_opt_collate ecs(m_ci, m_type == TYPE_COLLATE_EXACT);
- if (ecs.merge_collate_or_error(cl))
+ // CHARACTER SET latin1 .. COLLATE latin1_swedish_ci
+ if (Lex_exact_charset(m_ci).raise_if_not_applicable(cl))
return true;
- set_collate_exact(ecs.charset_and_collation());
+ *this= Lex_exact_charset_extended_collation_attrs(cl);
return false;
}
+ case TYPE_COLLATE_EXACT:
+ {
+ // [CHARACTER SET latin1] COLLATE latin1_bin .. COLLATE latin1_bin
+ return Lex_exact_collation(m_ci).raise_if_not_equal(cl);
+ }
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
- break;
- }
-
- if (is_contextually_typed_collation())
- {
- if (cl.is_contextually_typed_collation())
{
- /*
- CONTEXT + CONTEXT:
- CHAR(10) BINARY .. COLLATE DEFAULT - not supported by the parser
- CHAR(10) BINARY .. COLLATE uca1400_as_ci - not supported yet
- */
- DBUG_ASSERT(0); // Not possible yet
+ // COLLATE DEFAULT .. COLLATE latin1_swedish_ci
+ if (cl.raise_if_conflicts_with_context_collation(
+ Lex_context_collation(m_ci), true))
+ return true;
+ *this= Lex_exact_charset_extended_collation_attrs(cl);
return false;
}
+ }
+ DBUG_ASSERT(0);
+ return false;
+}
+
+bool Lex_exact_charset_extended_collation_attrs_st::
+ merge_context_collation(const Lex_context_collation &cl)
+{
+ switch (m_type) {
+ case TYPE_EMPTY:
/*
- CONTEXT + EXPLICIT
- CHAR(10) COLLATE DEFAULT .. COLLATE latin1_swedish_ci
- CHAR(10) BINARY .. COLLATE latin1_bin
- CHAR(10) COLLATE uca1400_as_ci .. COLLATE latin1_bin
+ No CHARACTER SET clause
+ CHAR(10) NOT NULL .. COLLATE DEFAULT
*/
- if (is_contextually_typed_collate_default() &&
- !(cl.charset_collation()->state & MY_CS_PRIMARY))
- {
- my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
- "COLLATE ", "DEFAULT", "COLLATE ",
- cl.charset_collation()->coll_name.str);
- return true;
- }
-
- if (is_contextually_typed_binary_style() &&
- !(cl.charset_collation()->state & MY_CS_BINSORT))
+ *this= Lex_exact_charset_extended_collation_attrs(cl);
+ return false;
+ case TYPE_CHARACTER_SET:
{
- my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
- "", "BINARY", "COLLATE ", cl.charset_collation()->coll_name.str);
- return true;
+ // CHARACTER SET latin1 .. COLLATE DEFAULT
+ Lex_exact_charset_opt_extended_collate tmp(m_ci, false);
+ if (tmp.merge_context_collation(cl))
+ return true;
+ *this= Lex_exact_charset_extended_collation_attrs(tmp.collation());
+ return false;
}
- *this= cl;
- return false;
+ case TYPE_COLLATE_EXACT:
+ // [CHARACTER SET latin1] COLLATE latin1_swedish_ci .. COLLATE DEFAULT
+ return Lex_exact_collation(m_ci).
+ raise_if_conflicts_with_context_collation(cl, false);
+ case TYPE_COLLATE_CONTEXTUALLY_TYPED:
+ // COLLATE DEFAULT .. COLLATE DEFAULT
+ return Lex_context_collation(m_ci).raise_if_not_equal(cl);
}
DBUG_ASSERT(0);
@@ -224,69 +477,38 @@ Lex_charset_collation_st::
}
-bool
-Lex_explicit_charset_opt_collate::
- merge_collate_or_error(const Lex_charset_collation_st &cl)
+bool Lex_exact_charset_opt_extended_collate::
+ merge_exact_collation(const Lex_exact_collation &cl)
{
- DBUG_ASSERT(cl.type() != Lex_charset_collation_st::TYPE_CHARACTER_SET);
+ // CHARACTER SET latin1 [COLLATE latin1_bin] .. COLLATE latin1_bin
+ if (m_with_collate)
+ return Lex_exact_collation(m_ci).raise_if_not_equal(cl);
+ if (raise_if_not_applicable(cl))
+ return true;
+ *this= Lex_exact_charset_opt_extended_collate(cl);
+ return false;
+}
- switch (cl.type()) {
- case Lex_charset_collation_st::TYPE_EMPTY:
- return false;
- case Lex_charset_collation_st::TYPE_CHARACTER_SET:
- DBUG_ASSERT(0);
- return false;
- case Lex_charset_collation_st::TYPE_COLLATE_EXACT:
- /*
- EXPLICIT + EXPLICIT
- CHAR(10) CHARACTER SET latin1 .. COLLATE latin1_bin
- CHAR(10) CHARACTER SET latin1 COLLATE latin1_bin .. COLLATE latin1_bin
- CHAR(10) COLLATE latin1_bin .. COLLATE latin1_bin
- CHAR(10) COLLATE latin1_bin .. COLLATE latin1_bin
- CHAR(10) CHARACTER SET latin1 BINARY .. COLLATE latin1_bin
- */
- if (m_with_collate && m_ci != cl.charset_collation())
- {
- my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
- "COLLATE ", m_ci->coll_name.str,
- "COLLATE ", cl.charset_collation()->coll_name.str);
- return true;
- }
- if (!my_charset_same(m_ci, cl.charset_collation()))
- {
- my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- cl.charset_collation()->coll_name.str, m_ci->cs_name.str);
- return true;
- }
- m_ci= cl.charset_collation();
- m_with_collate= true;
- return false;
- case Lex_charset_collation_st::TYPE_COLLATE_CONTEXTUALLY_TYPED:
- if (cl.is_contextually_typed_collate_default())
- {
- /*
- SET NAMES latin1 COLLATE DEFAULT;
- ALTER TABLE t1 CONVERT TO CHARACTER SET latin1 COLLATE DEFAULT;
- */
- CHARSET_INFO *tmp= Lex_charset_collation_st::find_default_collation(m_ci);
- if (!tmp)
- return true;
- m_ci= tmp;
- m_with_collate= true;
- return false;
- }
- else
- {
- /*
- EXPLICIT + CONTEXT
- CHAR(10) COLLATE latin1_bin .. COLLATE DEFAULT not possible yet
- CHAR(10) COLLATE latin1_bin .. COLLATE uca1400_as_ci
- */
+bool Lex_exact_charset_opt_extended_collate::
+ merge_context_collation(const Lex_context_collation &cl)
+{
+ // CHARACTER SET latin1 [COLLATE latin1_bin] .. COLLATE DEFAULT
+ if (m_with_collate)
+ return Lex_exact_collation(m_ci).
+ raise_if_conflicts_with_context_collation(cl, false);
+ return merge_context_collation_override(cl);
+}
- DBUG_ASSERT(0); // Not possible yet
- return false;
- }
+
+bool Lex_exact_charset_extended_collation_attrs_st::
+ merge_collation(const Lex_extended_collation_st &cl)
+{
+ switch (cl.type()) {
+ case Lex_extended_collation_st::TYPE_EXACT:
+ return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
+ case Lex_extended_collation_st::TYPE_CONTEXTUALLY_TYPED:
+ return merge_context_collation(Lex_context_collation(cl.charset_info()));
}
DBUG_ASSERT(0);
return false;
@@ -294,47 +516,161 @@ Lex_explicit_charset_opt_collate::
/*
- This method is used in the "attribute_list" rule to merge two independent
- COLLATE clauses (not belonging to a CHARACTER SET clause).
+ Mix an unordered combination of CHARACTER SET and COLLATE clauses
+ (i.e. COLLATE can come before CHARACTER SET).
+ Merge a CHARACTER SET clause.
+ @param cs - The "CHARACTER SET exact_charset_name".
*/
-bool
-Lex_charset_collation_st::
- merge_collate_clause_and_collate_clause(const Lex_charset_collation_st &cl)
+bool Lex_exact_charset_extended_collation_attrs_st::
+ merge_exact_charset(const Lex_exact_charset &cs)
{
- /*
- "BINARY" and "COLLATE DEFAULT" are not possible
- in an independent COLLATE clause in a column attribute.
- */
- DBUG_ASSERT(!is_contextually_typed_collation());
- DBUG_ASSERT(!cl.is_contextually_typed_collation());
-
- if (cl.is_empty())
- return false;
+ DBUG_ASSERT(cs.charset_info());
switch (m_type) {
case TYPE_EMPTY:
- *this= cl;
+ // CHARACTER SET cs
+ *this= Lex_exact_charset_extended_collation_attrs(cs);
return false;
+
case TYPE_CHARACTER_SET:
- DBUG_ASSERT(0);
- return false;
+ // CHARACTER SET cs1 .. CHARACTER SET cs2
+ return Lex_exact_charset(m_ci).raise_if_not_equal(cs);
+
case TYPE_COLLATE_EXACT:
+ // COLLATE latin1_bin .. CHARACTER SET cs
+ return cs.raise_if_not_applicable(Lex_exact_collation(m_ci));
+
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
- break;
+ // COLLATE DEFAULT .. CHARACTER SET cs
+ {
+ Lex_exact_charset_opt_extended_collate tmp(cs);
+ if (tmp.merge_context_collation(Lex_context_collation(m_ci)))
+ return true;
+ *this= Lex_exact_charset_extended_collation_attrs(tmp.collation());
+ return false;
+ }
}
+ DBUG_ASSERT(0);
+ return false;
+}
- /*
- Two independent explicit collations:
- CHAR(10) NOT NULL COLLATE latin1_bin DEFAULT 'a' COLLATE latin1_bin
- Note, we should perhaps eventually disallow double COLLATE clauses.
- But for now let's just disallow only conflicting ones.
- */
- if (charset_collation() != cl.charset_collation())
+
+bool Lex_extended_charset_extended_collation_attrs_st::merge_charset_default()
+{
+ if (m_charset_order == CHARSET_TYPE_EMPTY)
+ m_charset_order= CHARSET_TYPE_CONTEXT;
+ Lex_opt_context_charset_st::merge_charset_default();
+ return false;
+}
+
+
+bool Lex_extended_charset_extended_collation_attrs_st::
+ merge_exact_charset(const Lex_exact_charset &cs)
+{
+ m_had_charset_exact= true;
+ if (m_charset_order == CHARSET_TYPE_EMPTY)
+ m_charset_order= CHARSET_TYPE_EXACT;
+ return Lex_exact_charset_extended_collation_attrs_st::merge_exact_charset(cs);
+}
+
+
+bool Lex_extended_charset_extended_collation_attrs_st::
+ raise_if_charset_conflicts_with_default(
+ const Lex_exact_charset_opt_extended_collate &def) const
+{
+ DBUG_ASSERT(m_charset_order != CHARSET_TYPE_EMPTY || is_empty());
+ if (!my_charset_same(def.collation().charset_info(), m_ci))
{
- my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
- "COLLATE ", charset_collation()->coll_name.str,
- "COLLATE ", cl.charset_collation()->coll_name.str);
+ raise_ER_CONFLICTING_DECLARATIONS("CHARACTER SET ", "DEFAULT",
+ def.collation().charset_info()->cs_name.str,
+ "CHARACTER SET ", m_ci->cs_name.str,
+ m_charset_order == CHARSET_TYPE_EXACT);
return true;
}
return false;
}
+
+
+CHARSET_INFO *
+Lex_extended_charset_extended_collation_attrs_st::
+ resolved_to_context(const Charset_collation_context &ctx) const
+{
+ if (Lex_opt_context_charset_st::is_empty())
+ {
+ // Without CHARACTER SET DEFAULT
+ return Lex_exact_charset_extended_collation_attrs_st::
+ resolved_to_character_set(ctx.collate_default().charset_info());
+ }
+
+ // With CHARACTER SET DEFAULT
+ switch (type()) {
+ case TYPE_EMPTY:
+ // CHARACTER SET DEFAULT;
+ return ctx.charset_default().charset().charset_info();
+
+ case TYPE_CHARACTER_SET:
+ // CHARACTER SET DEFAULT CHARACTER SET cs_exact
+ if (raise_if_charset_conflicts_with_default(ctx.charset_default()))
+ {
+ /*
+ A possible scenario:
+ SET character_set_server=utf8mb4;
+ CREATE DATABASE db1 CHARACTER SET latin1 CHARACTER SET DEFAULT;
+ */
+ return NULL;
+ }
+ return m_ci;
+
+ case TYPE_COLLATE_EXACT:
+ {
+ /*
+ CREATE DATABASE db1
+ COLLATE cl_exact
+ [ CHARACTER SET cs_exact ]
+ CHARACTER SET DEFAULT;
+ */
+ if (m_had_charset_exact &&
+ raise_if_charset_conflicts_with_default(ctx.charset_default()))
+ {
+ /*
+ A possible scenario:
+ SET character_set_server=utf8mb4;
+ CREATE DATABASE db1
+ COLLATE latin1_bin
+ CHARACTER SET latin1
+ CHARACTER SET DEFAULT;
+ */
+ return NULL;
+ }
+ /*
+ Now check that "COLLATE cl_exact" does not conflict with
+ CHARACTER SET DEFAULT.
+ */
+ if (ctx.charset_default().
+ raise_if_not_applicable(Lex_exact_collation(m_ci)))
+ {
+ /*
+ A possible scenario:
+ SET character_set_server=utf8mb4;
+ CREATE DATABASE db1
+ COLLATE latin1_bin
+ CHARACTER SET DEFAULT;
+ */
+ return NULL;
+ }
+ return m_ci;
+ }
+
+ case TYPE_COLLATE_CONTEXTUALLY_TYPED:
+ /*
+ Both CHARACTER SET and COLLATE are contextual:
+ ALTER DATABASE db1 CHARACTER SET DEFAULT COLLATE DEFAULT;
+ ALTER DATABASE db1 COLLATE DEFAULT CHARACTER SET DEFAULT;
+ */
+ return Lex_exact_charset_extended_collation_attrs_st::
+ resolved_to_character_set(ctx.charset_default().
+ collation().charset_info());
+ }
+ DBUG_ASSERT(0);
+ return NULL;
+}
diff --git a/sql/lex_charset.h b/sql/lex_charset.h
index abbe761df36..d195b405569 100644
--- a/sql/lex_charset.h
+++ b/sql/lex_charset.h
@@ -16,8 +16,237 @@
#ifndef LEX_CHARSET_INCLUDED
#define LEX_CHARSET_INCLUDED
+
+/*
+ An exact character set, e.g:
+ CHARACTER SET latin1
+*/
+class Lex_exact_charset
+{
+ CHARSET_INFO *m_ci;
+public:
+ explicit Lex_exact_charset(CHARSET_INFO *ci)
+ :m_ci(ci)
+ {
+ DBUG_ASSERT(m_ci);
+ DBUG_ASSERT(m_ci->state & MY_CS_PRIMARY);
+ }
+ CHARSET_INFO *charset_info() const { return m_ci; }
+ bool raise_if_not_equal(const Lex_exact_charset &rhs) const;
+ bool raise_if_not_applicable(const class Lex_exact_collation &cl) const;
+};
+
+
+/*
+ An optional contextually typed character set:
+ [ CHARACTER SET DEFAULT ]
+*/
+class Lex_opt_context_charset_st
+{
+ /*
+ Currently we support only DEFAULT as a possible value.
+ So "bool" is enough.
+ */
+ bool m_had_charset_default;
+public:
+ void init()
+ {
+ m_had_charset_default= false;
+ }
+ void merge_charset_default()
+ {
+ /*
+ Ok to specify CHARACTER SET DEFAULT multiple times.
+ No error raised here.
+ */
+ m_had_charset_default= true;
+ }
+ bool is_empty() const
+ {
+ return !m_had_charset_default;
+ }
+ bool is_contextually_typed_charset_default() const
+ {
+ return m_had_charset_default;
+ }
+};
+
+
+/*
+ A contextually typed collation, e.g.:
+ COLLATE DEFAULT
+ CHAR(10) BINARY
+*/
+class Lex_context_collation
+{
+ CHARSET_INFO *m_ci;
+public:
+ explicit Lex_context_collation(CHARSET_INFO *ci)
+ :m_ci(ci)
+ {
+ DBUG_ASSERT(ci);
+ }
+ CHARSET_INFO *charset_info() const { return m_ci; }
+ bool is_contextually_typed_collate_default() const
+ {
+ return m_ci == &my_collation_contextually_typed_default;
+ }
+ bool is_contextually_typed_binary_style() const
+ {
+ return m_ci == &my_collation_contextually_typed_binary;
+ }
+ bool raise_if_not_equal(const Lex_context_collation &cl) const;
+};
+
+
+/*
+ An exact collation, e.g.
+ COLLATE latin1_swedish_ci
+*/
+class Lex_exact_collation
+{
+ CHARSET_INFO *m_ci;
+public:
+ explicit Lex_exact_collation(CHARSET_INFO *ci)
+ :m_ci(ci)
+ {
+ DBUG_ASSERT(ci);
+ }
+ CHARSET_INFO *charset_info() const { return m_ci; }
+ // EXACT + EXACT
+ bool raise_if_not_equal(const Lex_exact_collation &cl) const;
+ // EXACT + CONTEXT
+ // CONTEXT + EXACT
+ bool raise_if_conflicts_with_context_collation(const Lex_context_collation &,
+ bool reverse_order) const;
+};
+
+
+/*
+ Parse time COLLATE clause:
+ COLLATE colation_name
+ The collation can be either exact or contextual:
+ COLLATE latin1_bin
+ COLLATE DEFAULT
+*/
+class Lex_extended_collation_st
+{
+public:
+ enum Type
+ {
+ TYPE_EXACT,
+ TYPE_CONTEXTUALLY_TYPED
+ };
+protected:
+ CHARSET_INFO *m_ci;
+ Type m_type;
+public:
+ void init(CHARSET_INFO *ci, Type type)
+ {
+ m_ci= ci;
+ m_type= type;
+ }
+ CHARSET_INFO *charset_info() const { return m_ci; }
+ Type type() const { return m_type; }
+ void set_collate_default()
+ {
+ m_ci= &my_collation_contextually_typed_default;
+ m_type= TYPE_CONTEXTUALLY_TYPED;
+ }
+ bool raise_if_conflicts_with_context_collation(const Lex_context_collation &)
+ const;
+ bool merge_exact_charset(const Lex_exact_charset &rhs);
+ bool merge_exact_collation(const Lex_exact_collation &rhs);
+ bool merge(const Lex_extended_collation_st &rhs);
+};
+
+
+class Lex_extended_collation: public Lex_extended_collation_st
+{
+public:
+ Lex_extended_collation(CHARSET_INFO *ci, Type type)
+ {
+ init(ci, type);
+ }
+ Lex_extended_collation(const Lex_exact_collation &rhs)
+ {
+ init(rhs.charset_info(), TYPE_EXACT);
+ }
+};
+
+
+/*
+ CHARACTER SET cs_exact [COLLATE cl_exact_or_context]
+*/
+class Lex_exact_charset_opt_extended_collate
+{
+ CHARSET_INFO *m_ci;
+ bool m_with_collate;
+public:
+ Lex_exact_charset_opt_extended_collate(CHARSET_INFO *ci, bool with_collate)
+ :m_ci(ci), m_with_collate(with_collate)
+ {
+ DBUG_ASSERT(m_ci);
+ DBUG_ASSERT((m_ci->state & MY_CS_PRIMARY) || m_with_collate);
+ }
+ Lex_exact_charset_opt_extended_collate(const Lex_exact_charset &cs)
+ :m_ci(cs.charset_info()), m_with_collate(false)
+ {
+ DBUG_ASSERT(m_ci);
+ DBUG_ASSERT(m_ci->state & MY_CS_PRIMARY);
+ }
+ Lex_exact_charset_opt_extended_collate(const Lex_exact_collation &cl)
+ :m_ci(cl.charset_info()), m_with_collate(true)
+ {
+ DBUG_ASSERT(m_ci);
+ }
+ bool with_collate() const { return m_with_collate; }
+ CHARSET_INFO *find_bin_collation() const;
+ CHARSET_INFO *find_default_collation() const;
+ bool raise_if_not_applicable(const Lex_exact_collation &cl) const;
+ /*
+ Add another COLLATE clause (exact or context).
+ So the full syntax looks like:
+ CHARACTER SET cs [COLLATE cl] ... COLLATE cl2
+ */
+ bool merge_collation(const Lex_extended_collation_st &cl)
+ {
+ switch (cl.type()) {
+ case Lex_extended_collation_st::TYPE_EXACT:
+ return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
+ case Lex_extended_collation_st::TYPE_CONTEXTUALLY_TYPED:
+ return merge_context_collation(Lex_context_collation(cl.charset_info()));
+ }
+ DBUG_ASSERT(0);
+ return false;
+ }
+ /*
+ Add a context collation:
+ CHARACTER SET cs [COLLATE cl] ... COLLATE DEFAULT
+ */
+ bool merge_context_collation(const Lex_context_collation &cl);
+ bool merge_context_collation_override(const Lex_context_collation &cl);
+ /*
+ Add an exact collation:
+ CHARACTER SET cs [COLLATE cl] ... COLLATE latin1_bin
+ */
+ bool merge_exact_collation(const Lex_exact_collation &cl);
+ Lex_exact_collation collation() const
+ {
+ return Lex_exact_collation(m_ci);
+ }
+ Lex_exact_charset charset() const
+ {
+ if ((m_ci->state & MY_CS_PRIMARY))
+ return Lex_exact_charset(m_ci);
+ return Lex_exact_charset(find_default_collation());
+ }
+};
+
+
/*
- Parse time character set and collation.
+ Parse time character set and collation for:
+ [CHARACTER SET cs_exact] [COLLATE cl_exact_or_context]
Can be:
@@ -44,7 +273,7 @@
Resolution happens in Type_handler::Column_definition_prepare_stage1().
*/
-struct Lex_charset_collation_st
+struct Lex_exact_charset_extended_collation_attrs_st
{
public:
enum Type
@@ -60,20 +289,50 @@ public:
#define LEX_CHARSET_COLLATION_TYPE_BITS 2
static_assert(((1<<LEX_CHARSET_COLLATION_TYPE_BITS)-1) >=
TYPE_COLLATE_CONTEXTUALLY_TYPED,
- "Lex_charset_collation_st::Type bits check");
+ "Lex_exact_charset_extended_collation_attrs_st::Type bits");
protected:
CHARSET_INFO *m_ci;
Type m_type;
-public:
- static CHARSET_INFO *find_bin_collation(CHARSET_INFO *cs);
- static CHARSET_INFO *find_default_collation(CHARSET_INFO *cs);
+protected:
+ static Type type_from_lex_collation_type(Lex_extended_collation_st::Type type)
+ {
+ switch (type) {
+ case Lex_extended_collation_st::TYPE_EXACT:
+ return TYPE_COLLATE_EXACT;
+ case Lex_extended_collation_st::TYPE_CONTEXTUALLY_TYPED:
+ return TYPE_COLLATE_CONTEXTUALLY_TYPED;
+ }
+ DBUG_ASSERT(0);
+ return TYPE_COLLATE_EXACT;
+ }
public:
void init()
{
m_ci= NULL;
m_type= TYPE_EMPTY;
}
+ void init(CHARSET_INFO *cs, Type type)
+ {
+ DBUG_ASSERT(cs || type == TYPE_EMPTY);
+ m_ci= cs;
+ m_type= type;
+ }
+ void init(const Lex_exact_charset &cs)
+ {
+ m_ci= cs.charset_info();
+ m_type= TYPE_CHARACTER_SET;
+ }
+ void init(const Lex_exact_collation &cs)
+ {
+ m_ci= cs.charset_info();
+ m_type= TYPE_COLLATE_EXACT;
+ }
+ void init(const Lex_exact_charset_opt_extended_collate &cscl)
+ {
+ cscl.with_collate() ? init(cscl.collation()) :
+ init(cscl.charset());
+ }
bool is_empty() const
{
return m_type == TYPE_EMPTY;
@@ -84,23 +343,26 @@ public:
m_ci= cs;
m_type= TYPE_CHARACTER_SET;
}
- void set_charset_collate_default(CHARSET_INFO *cs)
+ bool set_charset_collate_default(CHARSET_INFO *cs)
{
DBUG_ASSERT(cs);
+ if (!(cs= Lex_exact_charset_opt_extended_collate(cs, true).
+ find_default_collation()))
+ return true;
m_ci= cs;
m_type= TYPE_COLLATE_EXACT;
+ return false;
}
bool set_charset_collate_binary(CHARSET_INFO *cs)
{
DBUG_ASSERT(cs);
- if (!(cs= find_bin_collation(cs)))
+ if (!(cs= Lex_exact_charset_opt_extended_collate(cs, true).
+ find_bin_collation()))
return true;
m_ci= cs;
m_type= TYPE_COLLATE_EXACT;
return false;
}
- bool set_charset_collate_exact(CHARSET_INFO *cs,
- CHARSET_INFO *cl);
void set_collate_default()
{
m_ci= &my_collation_contextually_typed_default;
@@ -113,19 +375,9 @@ public:
}
bool is_contextually_typed_collate_default() const
{
- return m_ci == &my_collation_contextually_typed_default;
+ return Lex_context_collation(m_ci).is_contextually_typed_collate_default();
}
- bool is_contextually_typed_binary_style() const
- {
- return m_ci == &my_collation_contextually_typed_binary;
- }
- void set_collate_exact(CHARSET_INFO *cl)
- {
- DBUG_ASSERT(cl);
- m_ci= cl;
- m_type= TYPE_COLLATE_EXACT;
- }
- CHARSET_INFO *charset_collation() const
+ CHARSET_INFO *charset_info() const
{
return m_ci;
}
@@ -138,62 +390,262 @@ public:
return m_type == TYPE_COLLATE_CONTEXTUALLY_TYPED;
}
CHARSET_INFO *resolved_to_character_set(CHARSET_INFO *cs) const;
- bool merge_charset_clause_and_collate_clause(const Lex_charset_collation_st &cl);
- bool merge_collate_clause_and_collate_clause(const Lex_charset_collation_st &cl);
+ /*
+ Merge the column CHARACTER SET clause to:
+ - an exact collation name
+ - a contextually typed collation
+ "this" corresponds to `CHARACTER SET xxx [BINARY]`
+ "cl" corresponds to the COLLATE clause
+ */
+ bool merge_column_charset_clause_and_collate_clause(
+ const Lex_exact_charset_extended_collation_attrs_st &cl)
+ {
+ switch (cl.type()) {
+ case TYPE_EMPTY:
+ return false;
+ case TYPE_COLLATE_EXACT:
+ return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
+ case TYPE_COLLATE_CONTEXTUALLY_TYPED:
+ case TYPE_CHARACTER_SET:
+ break;
+ }
+ DBUG_ASSERT(0);
+ return false;
+ }
+ /*
+ This method is used in the "attribute_list" rule to merge two independent
+ COLLATE clauses (not belonging to a CHARACTER SET clause).
+ "BINARY" and "COLLATE DEFAULT" are not possible
+ in an independent COLLATE clause in a column attribute.
+ */
+ bool merge_column_collate_clause_and_collate_clause(
+ const Lex_exact_charset_extended_collation_attrs_st &cl)
+ {
+ DBUG_ASSERT(m_type != TYPE_COLLATE_CONTEXTUALLY_TYPED);
+ DBUG_ASSERT(m_type != TYPE_CHARACTER_SET);
+ switch (cl.type()) {
+ case TYPE_EMPTY:
+ return false;
+ case TYPE_COLLATE_EXACT:
+ return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
+ case TYPE_COLLATE_CONTEXTUALLY_TYPED:
+ case TYPE_CHARACTER_SET:
+ break;
+ }
+ DBUG_ASSERT(0);
+ return false;
+ }
+ bool merge_exact_charset(const Lex_exact_charset &cs);
+ bool merge_exact_collation(const Lex_exact_collation &cl);
+ bool merge_context_collation(const Lex_context_collation &cl);
+ bool merge_collation(const Lex_extended_collation_st &cl);
};
-/*
- CHARACTER SET cs [COLLATE cl]
-*/
-class Lex_explicit_charset_opt_collate
+class Charset_collation_context
{
- CHARSET_INFO *m_ci;
- bool m_with_collate;
+ /*
+ Although the goal of m_charset_default is to store the meaning
+ of CHARACTER SET DEFAULT, it does not necessarily point to a
+ default collation of CHARACTER SET DEFAULT. It can point to its any
+ arbitrary collation.
+ For performance purposes we don't need to find the default
+ collation at the instantiation time of "this", because:
+ - m_charset_default may not be even needed during the resolution
+ - when it's needed, in many cases it's passed to my_charset_same(),
+ which does not need the default collation again.
+
+ Note, m_charset_default and m_collate_default are not necessarily equal.
+
+ - The default value for CHARACTER SET is taken from the upper level:
+ CREATE DATABASE db1 CHARACTER SET DEFAULT; <-- @@character_set_server
+ ALTER DATABASE db1 CHARACTER SET DEFAULT; <-- @@character_set_server
+
+ - The default value for COLLATE is taken from the upper level for CREATE:
+ CREATE DATABASE db1 COLLATE DEFAULT; <-- @@collation_server
+ CREATE TABLE db1.t1 COLLATE DEFAULT; <-- character set of "db1"
+
+ - The default value for COLLATE is taken from the same level for ALTER:
+ ALTER DATABASE db1 COLLATE DEFAULT; <-- the default collation of the
+ current db1 character set
+ ALTER TABLE db1.t1 COLLATE DEFAULT; <-- the default collation of the
+ current db1.t1 character set
+ */
+
+ // comes from the upper level
+ Lex_exact_charset_opt_extended_collate m_charset_default;
+
+ // comes from the upper or the current level
+ Lex_exact_collation m_collate_default;
public:
- Lex_explicit_charset_opt_collate(CHARSET_INFO *ci, bool with_collate)
- :m_ci(ci), m_with_collate(with_collate)
+ Charset_collation_context(CHARSET_INFO *charset_default,
+ CHARSET_INFO *collate_default)
+ :m_charset_default(charset_default,
+ !(charset_default->state & MY_CS_PRIMARY)),
+ m_collate_default(collate_default)
+ { }
+ const Lex_exact_charset_opt_extended_collate charset_default() const
{
- DBUG_ASSERT(m_ci);
- // Item_func_set_collation uses non-default collations in "ci"
- //DBUG_ASSERT(m_ci->default_flag() || m_with_collate);
+ return m_charset_default;
+ }
+ const Lex_exact_collation collate_default() const
+ {
+ return m_collate_default;
}
+};
+
+
+/*
+ A universal container. It can store at the same time:
+ - CHARACTER SET DEFAULT
+ - CHARACTER SET cs_exact
+ - COLLATE {cl_exact|cl_context}
+ All three parts can co-exist.
+ All three parts are optional.
+ Parts can come in any arbitrary order, e.g:
+
+ CHARACTER SET DEFAULT [CHARACTER SET latin1] COLLATE latin1_bin
+ CHARACTER SET latin1 CHARACTER SET DEFAULT COLLATE latin1_bin
+ COLLATE latin1_bin [CHARACTER SET latin1] CHARACTER SET DEFAULT
+ COLLATE latin1_bin CHARACTER SET DEFAULT [CHARACTER SET latin1]
+*/
+class Lex_extended_charset_extended_collation_attrs_st:
+ public Lex_opt_context_charset_st,
+ public Lex_exact_charset_extended_collation_attrs_st
+{
+ enum charset_type_t
+ {
+ CHARSET_TYPE_EMPTY,
+ CHARSET_TYPE_CONTEXT,
+ CHARSET_TYPE_EXACT
+ };
/*
- Merge to another COLLATE clause. So the full syntax looks like:
- CHARACTER SET cs [COLLATE cl] ... COLLATE cl2
+ Which part came first:
+ - CHARACTER SET DEFAULT or
+ - CHARACTER SET cs_exact
+ e.g. to produce error messages preserving the user typed
+ order of CHARACTER SET clauses in case of conflicts.
*/
- bool merge_collate_or_error(const Lex_charset_collation_st &cl);
- bool merge_opt_collate_or_error(const Lex_charset_collation_st &cl)
+ charset_type_t m_charset_order;
+ /*
+ The parent class Lex_exact_charset_extended_collation_attrs_st
+ does not let know if a "COLLATE cl_exact" was used in combination with
+ "CHARACTER SET cs_exact" or just alone.
+ Here we need to distinguish:
+ - CHARACTER SET cs_exact COLLATE cl_exact, or
+ - COLLATE cl_exact CHARACTER SET cs_exact
+ versus just:
+ - COLLATE cl_exact
+ to produce better error messages in case of conflicts.
+ So let's add a flag member:
+ */
+ bool m_had_charset_exact;
+public:
+ void init()
{
- if (cl.is_empty())
- return false;
- return merge_collate_or_error(cl);
+ Lex_opt_context_charset_st::init();
+ Lex_exact_charset_extended_collation_attrs_st::init();
+ m_charset_order= CHARSET_TYPE_EMPTY;
+ m_had_charset_exact= false;
}
- CHARSET_INFO *charset_and_collation() const { return m_ci; }
- bool with_collate() const { return m_with_collate; }
+ void init(const Lex_exact_charset_opt_extended_collate &c)
+ {
+ Lex_opt_context_charset_st::init();
+ Lex_exact_charset_extended_collation_attrs_st::init(c);
+ m_charset_order= CHARSET_TYPE_EXACT;
+ m_had_charset_exact= true;
+ }
+ bool is_empty() const
+ {
+ return Lex_opt_context_charset_st::is_empty() &&
+ Lex_exact_charset_extended_collation_attrs_st::is_empty();
+ }
+ bool raise_if_charset_conflicts_with_default(
+ const Lex_exact_charset_opt_extended_collate &def) const;
+ CHARSET_INFO *resolved_to_context(const Charset_collation_context &ctx) const;
+ bool merge_charset_default();
+ bool merge_exact_charset(const Lex_exact_charset &cs);
};
-class Lex_charset_collation: public Lex_charset_collation_st
+class Lex_exact_charset_extended_collation_attrs:
+ public Lex_exact_charset_extended_collation_attrs_st
{
public:
- Lex_charset_collation()
+ Lex_exact_charset_extended_collation_attrs()
{
init();
}
- Lex_charset_collation(CHARSET_INFO *collation, Type type)
+ Lex_exact_charset_extended_collation_attrs(CHARSET_INFO *collation, Type type)
{
- DBUG_ASSERT(collation || type == TYPE_EMPTY);
- m_ci= collation;
- m_type= type;
+ init(collation, type);
+ }
+ explicit
+ Lex_exact_charset_extended_collation_attrs(const Lex_exact_charset &cs)
+ {
+ init(cs.charset_info(), TYPE_CHARACTER_SET);
+ }
+ explicit
+ Lex_exact_charset_extended_collation_attrs(const Lex_exact_collation &cl)
+ {
+ init(cl.charset_info(), TYPE_COLLATE_EXACT);
+ }
+ explicit
+ Lex_exact_charset_extended_collation_attrs(const Lex_context_collation &cl)
+ {
+ init(cl.charset_info(), TYPE_COLLATE_CONTEXTUALLY_TYPED);
}
- static Lex_charset_collation national(bool bin_mod)
+ explicit
+ Lex_exact_charset_extended_collation_attrs(
+ const Lex_exact_charset_opt_extended_collate &cscl)
+ {
+ init(cscl);
+ }
+ explicit
+ Lex_exact_charset_extended_collation_attrs(const Lex_extended_collation_st &cl)
+ {
+ init(cl.charset_info(), type_from_lex_collation_type(cl.type()));
+ }
+ static Lex_exact_charset_extended_collation_attrs national(bool bin_mod)
{
return bin_mod ?
- Lex_charset_collation(&my_charset_utf8mb3_bin, TYPE_COLLATE_EXACT) :
- Lex_charset_collation(&my_charset_utf8mb3_general_ci, TYPE_CHARACTER_SET);
+ Lex_exact_charset_extended_collation_attrs(&my_charset_utf8mb3_bin,
+ TYPE_COLLATE_EXACT) :
+ Lex_exact_charset_extended_collation_attrs(&my_charset_utf8mb3_general_ci,
+ TYPE_CHARACTER_SET);
+ }
+};
+
+
+class Lex_extended_charset_extended_collation_attrs:
+ public Lex_extended_charset_extended_collation_attrs_st
+{
+public:
+ Lex_extended_charset_extended_collation_attrs()
+ {
+ init();
+ }
+ explicit Lex_extended_charset_extended_collation_attrs(
+ const Lex_exact_charset_opt_extended_collate &c)
+ {
+ init(c);
}
};
+
+using Lex_column_charset_collation_attrs_st =
+ Lex_exact_charset_extended_collation_attrs_st;
+
+using Lex_column_charset_collation_attrs =
+ Lex_exact_charset_extended_collation_attrs;
+
+
+using Lex_table_charset_collation_attrs_st =
+ Lex_extended_charset_extended_collation_attrs_st;
+
+using Lex_table_charset_collation_attrs =
+ Lex_extended_charset_extended_collation_attrs;
+
+
#endif // LEX_CHARSET_INCLUDED
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index 710f05784d1..934226685a9 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -335,7 +335,7 @@ static char *init_bootstrap_command_line(char *cmdline, size_t size)
" %s"
" --bootstrap"
" --datadir=."
- " --loose-innodb-buffer-pool-size=10M"
+ " --loose-innodb-buffer-pool-size=20M"
"\""
, mysqld_path, opt_verbose_bootstrap ? "--console" : "");
return cmdline;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 00a7b23b085..9a64fbf2c52 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1559,11 +1559,15 @@ static void kill_thread(THD *thd)
/**
First shutdown everything but slave threads and binlog dump connections
*/
-static my_bool kill_thread_phase_1(THD *thd, void *)
+static my_bool kill_thread_phase_1(THD *thd, int *n_threads_awaiting_ack)
{
DBUG_PRINT("quit", ("Informing thread %ld that it's time to die",
(ulong) thd->thread_id));
- if (thd->slave_thread || thd->is_binlog_dump_thread())
+
+ if (thd->slave_thread || thd->is_binlog_dump_thread() ||
+ (shutdown_wait_for_slaves &&
+ repl_semisync_master.is_thd_awaiting_semisync_ack(thd) &&
+ ++(*n_threads_awaiting_ack)))
return 0;
if (DBUG_IF("only_kill_system_threads") ? !thd->system_thread : 0)
@@ -1578,7 +1582,7 @@ static my_bool kill_thread_phase_1(THD *thd, void *)
*/
static my_bool kill_thread_phase_2(THD *thd, void *)
{
- if (shutdown_wait_for_slaves)
+ if (shutdown_wait_for_slaves && thd->is_binlog_dump_thread())
{
thd->set_killed(KILL_SERVER);
}
@@ -1751,7 +1755,29 @@ static void close_connections(void)
This will give the threads some time to gracefully abort their
statements and inform their clients that the server is about to die.
*/
- server_threads.iterate(kill_thread_phase_1);
+ DBUG_EXECUTE_IF("mysqld_delay_kill_threads_phase_1", my_sleep(200000););
+ int n_threads_awaiting_ack= 0;
+ server_threads.iterate(kill_thread_phase_1, &n_threads_awaiting_ack);
+
+ /*
+ If we are waiting on any ACKs, delay killing the thread until either an ACK
+ is received or the timeout is hit.
+
+ Allow at max the number of sessions to await a timeout; however, if all
+ ACKs have been received in less iterations, then quit early
+ */
+ if (shutdown_wait_for_slaves && repl_semisync_master.get_master_enabled())
+ {
+ int waiting_threads= repl_semisync_master.sync_get_master_wait_sessions();
+ if (waiting_threads)
+ sql_print_information("Delaying shutdown to await semi-sync ACK");
+
+ while (waiting_threads-- > 0)
+ repl_semisync_master.await_slave_reply();
+ }
+
+ DBUG_EXECUTE_IF("delay_shutdown_phase_2_after_semisync_wait",
+ my_sleep(500000););
Events::deinit();
slave_prepare_for_shutdown();
@@ -1774,7 +1800,8 @@ static void close_connections(void)
*/
DBUG_PRINT("info", ("THD_count: %u", THD_count::value()));
- for (int i= 0; (THD_count::connection_thd_count()) && i < 1000; i++)
+ for (int i= 0; THD_count::connection_thd_count() - n_threads_awaiting_ack
+ && i < 1000; i++)
my_sleep(20000);
if (global_system_variables.log_warnings)
@@ -1788,9 +1815,10 @@ static void close_connections(void)
wsrep_sst_auth_free();
#endif
/* All threads has now been aborted */
- DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)", THD_count::value()));
+ DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)",
+ THD_count::connection_thd_count() - n_threads_awaiting_ack));
- while (THD_count::connection_thd_count())
+ while (THD_count::connection_thd_count() - n_threads_awaiting_ack)
my_sleep(1000);
/* Kill phase 2 */
@@ -5353,6 +5381,9 @@ static int init_server_components()
if (ha_recover(0))
unireg_abort(1);
+#ifndef EMBEDDED_LIBRARY
+ start_handle_manager();
+#endif
if (opt_bin_log)
{
int error;
@@ -5810,8 +5841,6 @@ int mysqld_main(int argc, char **argv)
}
}
- start_handle_manager();
-
/* Copy default global rpl_filter to global_rpl_filter */
copy_filter_setting(global_rpl_filter, get_or_create_rpl_filter("", 0));
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 5c2237fb3d2..19f077136cb 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -829,12 +829,10 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
{
DBUG_ASSERT(!vers_info->interval.is_set());
ha_partition *hp= (ha_partition*)(table->file);
- partition_element *next= NULL;
+ partition_element *next;
List_iterator<partition_element> it(partitions);
- while (next != vers_info->hist_part)
- next= it++;
- DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id));
- ha_rows records= hp->part_records(next);
+ ha_rows records= 0;
+ vers_info->hist_part= partitions.head();
while ((next= it++) != vers_info->now_part)
{
DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id));
@@ -850,14 +848,11 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
{
if (auto_hist)
*create_count= 1;
- else
- 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, "LIMIT");
}
else
vers_info->hist_part= next;
}
+ return 0;
}
else if (vers_info->interval.is_set() &&
vers_info->hist_part->range_value <= thd->query_start())
@@ -927,7 +922,7 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
bool vers_create_partitions(THD *thd, TABLE_LIST* tl, uint num_parts)
{
bool result= true;
- HA_CREATE_INFO create_info;
+ Table_specification_st create_info;
Alter_info alter_info;
partition_info *save_part_info= thd->work_part_info;
Query_tables_list save_query_tables;
@@ -1039,6 +1034,43 @@ exit:
}
+/**
+ Warn at the end of DML command if the last history partition is out of LIMIT.
+*/
+void partition_info::vers_check_limit(THD *thd)
+{
+ if (vers_info->auto_hist || !vers_info->limit ||
+ vers_info->hist_part->id + 1 < vers_info->now_part->id)
+ return;
+
+ /*
+ NOTE: at this point read_partitions bitmap is already pruned by DML code,
+ we have to set read bits for working history partition. We could use
+ bitmap_set_all(), but this is not optimal since there can be quite a number
+ of partitions.
+ */
+ const uint32 sub_factor= num_subparts ? num_subparts : 1;
+ uint32 part_id= vers_info->hist_part->id * sub_factor;
+ const uint32 part_id_end= part_id + sub_factor;
+ DBUG_ASSERT(part_id_end <= num_parts * sub_factor);
+
+ ha_partition *hp= (ha_partition*)(table->file);
+ ha_rows hist_rows= hp->part_records(vers_info->hist_part);
+ if (hist_rows >= vers_info->limit)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ WARN_VERS_PART_FULL,
+ ER_THD(thd, WARN_VERS_PART_FULL),
+ table->s->db.str, table->s->table_name.str,
+ vers_info->hist_part->partition_name, "LIMIT");
+
+ sql_print_warning(ER_THD(thd, WARN_VERS_PART_FULL),
+ table->s->db.str, table->s->table_name.str,
+ vers_info->hist_part->partition_name, "LIMIT");
+ }
+}
+
+
/*
Check that the partition/subpartition is setup to use the correct
storage engine
diff --git a/sql/partition_info.h b/sql/partition_info.h
index a3e36a64ffa..93247b939e4 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -407,6 +407,12 @@ public:
bool auto_part, const char *table_name);
bool vers_set_limit(ulonglong limit, bool auto_part, const char *table_name);
bool vers_set_hist_part(THD* thd, uint *create_count);
+ bool vers_require_hist_part(THD *thd) const
+ {
+ return part_type == VERSIONING_PARTITION &&
+ thd->lex->vers_history_generating();
+ }
+ void vers_check_limit(THD *thd);
bool vers_fix_field_list(THD *thd);
void vers_update_el_ids();
partition_element *get_partition(uint part_id)
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index eb9c0758d02..516c9da31d9 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -3677,9 +3677,9 @@ int Id_delegating_gtid_event_filter<T>::set_id_restrictions(
{
DBUG_ASSERT(map_element->filter->get_filter_type() ==
(mode ==
- Gtid_event_filter::id_restriction_mode::WHITELIST_MODE)
- ? Gtid_event_filter::ACCEPT_ALL_GTID_FILTER_TYPE
- : Gtid_event_filter::REJECT_ALL_GTID_FILTER_TYPE);
+ Gtid_event_filter::id_restriction_mode::WHITELIST_MODE
+ ? Gtid_event_filter::ACCEPT_ALL_GTID_FILTER_TYPE
+ : Gtid_event_filter::REJECT_ALL_GTID_FILTER_TYPE));
}
}
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index 8bbb87c0e81..925e271e68a 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -26,6 +26,7 @@
extern const LEX_CSTRING rpl_gtid_slave_state_table_name;
class String;
+#define PARAM_GTID(G) G.domain_id, G.server_id, G.seq_no
#define GTID_MAX_STR_LENGTH (10+1+10+1+20)
#define PARAM_GTID(G) G.domain_id, G.server_id, G.seq_no
diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc
index cfe29824328..0e72ff441c4 100644
--- a/sql/semisync_master.cc
+++ b/sql/semisync_master.cc
@@ -463,6 +463,37 @@ void Repl_semi_sync_master::cleanup()
delete m_active_tranxs;
}
+int Repl_semi_sync_master::sync_get_master_wait_sessions()
+{
+ int wait_sessions;
+ lock();
+ wait_sessions= rpl_semi_sync_master_wait_sessions;
+ unlock();
+ return wait_sessions;
+}
+
+void Repl_semi_sync_master::create_timeout(struct timespec *out,
+ struct timespec *start_arg)
+{
+ struct timespec *start_ts;
+ struct timespec now_ts;
+ if (!start_arg)
+ {
+ set_timespec(now_ts, 0);
+ start_ts= &now_ts;
+ }
+ else
+ {
+ start_ts= start_arg;
+ }
+
+ long diff_secs= (long) (m_wait_timeout / TIME_THOUSAND);
+ long diff_nsecs= (long) ((m_wait_timeout % TIME_THOUSAND) * TIME_MILLION);
+ long nsecs= start_ts->tv_nsec + diff_nsecs;
+ out->tv_sec= start_ts->tv_sec + diff_secs + nsecs / TIME_BILLION;
+ out->tv_nsec= nsecs % TIME_BILLION;
+}
+
void Repl_semi_sync_master::lock()
{
mysql_mutex_lock(&LOCK_binlog);
@@ -862,13 +893,6 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
m_wait_file_name, (ulong)m_wait_file_pos));
}
- /* Calcuate the waiting period. */
- long diff_secs = (long) (m_wait_timeout / TIME_THOUSAND);
- long diff_nsecs = (long) ((m_wait_timeout % TIME_THOUSAND) * TIME_MILLION);
- long nsecs = start_ts.tv_nsec + diff_nsecs;
- abstime.tv_sec = start_ts.tv_sec + diff_secs + nsecs/TIME_BILLION;
- abstime.tv_nsec = nsecs % TIME_BILLION;
-
/* In semi-synchronous replication, we wait until the binlog-dump
* thread has received the reply on the relevant binlog segment from the
* replication slave.
@@ -879,12 +903,20 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
*/
rpl_semi_sync_master_wait_sessions++;
+ /* We keep track of when this thread is awaiting an ack to ensure it is
+ * not killed while awaiting an ACK if a shutdown is issued.
+ */
+ set_thd_awaiting_semisync_ack(thd, TRUE);
+
DBUG_PRINT("semisync", ("%s: wait %lu ms for binlog sent (%s, %lu)",
"Repl_semi_sync_master::commit_trx",
m_wait_timeout,
m_wait_file_name, (ulong)m_wait_file_pos));
+ create_timeout(&abstime, &start_ts);
wait_result = cond_timewait(&abstime);
+
+ set_thd_awaiting_semisync_ack(thd, FALSE);
rpl_semi_sync_master_wait_sessions--;
if (wait_result != 0)
@@ -1320,6 +1352,25 @@ void Repl_semi_sync_master::set_export_stats()
unlock();
}
+void Repl_semi_sync_master::await_slave_reply()
+{
+ struct timespec abstime;
+
+ DBUG_ENTER("Repl_semi_sync_master::::await_slave_reply");
+ lock();
+
+ /* Just return if there is nothing to wait for */
+ if (!rpl_semi_sync_master_wait_sessions)
+ goto end;
+
+ create_timeout(&abstime, NULL);
+ cond_timewait(&abstime);
+
+end:
+ unlock();
+ DBUG_VOID_RETURN;
+}
+
/* Get the waiting time given the wait's staring time.
*
* Return:
diff --git a/sql/semisync_master.h b/sql/semisync_master.h
index 9f0acf57a60..04fc0e5ce50 100644
--- a/sql/semisync_master.h
+++ b/sql/semisync_master.h
@@ -472,6 +472,21 @@ class Repl_semi_sync_master
m_wait_timeout = wait_timeout;
}
+ int sync_get_master_wait_sessions();
+
+ /*
+ Calculates a timeout that is m_wait_timeout after start_arg and saves it
+ in out. If start_arg is NULL, the timeout is m_wait_timeout after the
+ current system time.
+ */
+ void create_timeout(struct timespec *out, struct timespec *start_arg);
+
+ /*
+ Blocks the calling thread until the ack_receiver either receives an ACK
+ or times out (from rpl_semi_sync_master_timeout)
+ */
+ void await_slave_reply();
+
/*set the ACK point, after binlog sync or after transaction commit*/
void set_wait_point(unsigned long ack_point)
{
@@ -620,6 +635,30 @@ class Repl_semi_sync_master
void check_and_switch();
+ /*
+ Determines if the given thread is currently awaiting a semisync_ack. Note
+ that the thread's value is protected by this class's LOCK_binlog, so this
+ function (indirectly) provides safe access.
+ */
+ my_bool is_thd_awaiting_semisync_ack(THD *thd)
+ {
+ lock();
+ my_bool ret= thd->is_awaiting_semisync_ack;
+ unlock();
+ return ret;
+ }
+
+ /*
+ Update the thread's value for is_awaiting_semisync_ack. LOCK_binlog (from
+ this class) should be acquired before calling this function.
+ */
+ void set_thd_awaiting_semisync_ack(THD *thd,
+ my_bool _is_awaiting_semisync_ack)
+ {
+ mysql_mutex_assert_owner(&LOCK_binlog);
+ thd->is_awaiting_semisync_ack= _is_awaiting_semisync_ack;
+ }
+
mysql_mutex_t LOCK_rpl_semi_sync_master_enabled;
};
diff --git a/sql/semisync_slave.cc b/sql/semisync_slave.cc
index 684199031ee..788aab78911 100644
--- a/sql/semisync_slave.cc
+++ b/sql/semisync_slave.cc
@@ -114,10 +114,12 @@ int Repl_semi_sync_slave::slave_start(Master_info *mi)
int Repl_semi_sync_slave::slave_stop(Master_info *mi)
{
- if (rpl_semi_sync_slave_status)
- rpl_semi_sync_slave_status= 0;
if (get_slave_enabled())
kill_connection(mi->mysql);
+
+ if (rpl_semi_sync_slave_status)
+ rpl_semi_sync_slave_status= 0;
+
return 0;
}
@@ -133,6 +135,8 @@ void Repl_semi_sync_slave::kill_connection(MYSQL *mysql)
char kill_buffer[30];
MYSQL *kill_mysql = NULL;
+ size_t kill_buffer_length;
+
kill_mysql = mysql_init(kill_mysql);
mysql_options(kill_mysql, MYSQL_OPT_CONNECT_TIMEOUT, &m_kill_conn_timeout);
mysql_options(kill_mysql, MYSQL_OPT_READ_TIMEOUT, &m_kill_conn_timeout);
@@ -144,13 +148,35 @@ void Repl_semi_sync_slave::kill_connection(MYSQL *mysql)
{
sql_print_information("cannot connect to master to kill slave io_thread's "
"connection");
- mysql_close(kill_mysql);
- return;
+ goto failed_graceful_kill;
}
- size_t kill_buffer_length = my_snprintf(kill_buffer, 30, "KILL %lu",
- mysql->thread_id);
- mysql_real_query(kill_mysql, kill_buffer, (ulong)kill_buffer_length);
+
+ DBUG_EXECUTE_IF("slave_delay_killing_semisync_connection", my_sleep(400000););
+
+ kill_buffer_length= my_snprintf(kill_buffer, 30, "KILL %lu",
+ mysql->thread_id);
+ if (mysql_real_query(kill_mysql, kill_buffer, (ulong)kill_buffer_length))
+ {
+ sql_print_information(
+ "Failed to gracefully kill our active semi-sync connection with "
+ "primary. Silently closing the connection.");
+ goto failed_graceful_kill;
+ }
+
+end:
mysql_close(kill_mysql);
+ return;
+
+failed_graceful_kill:
+ /*
+ If we fail to issue `KILL` on the primary to kill the active semi-sync
+ connection; we need to locally clean up our side of the connection. This
+ is because mysql_close will send COM_QUIT on the active semi-sync
+ connection, causing the primary to error.
+ */
+ net_clear(&(mysql->net), 0);
+ end_server(mysql);
+ goto end;
}
int Repl_semi_sync_slave::request_transmit(Master_info *mi)
diff --git a/sql/semisync_slave.h b/sql/semisync_slave.h
index e7ccd952130..f0b8eceeebf 100644
--- a/sql/semisync_slave.h
+++ b/sql/semisync_slave.h
@@ -23,6 +23,7 @@
#include "sql_priv.h"
#include "rpl_mi.h"
#include "mysql.h"
+#include <sql_common.h>
class Master_info;
diff --git a/sql/share/CMakeLists.txt b/sql/share/CMakeLists.txt
index 55f39e5e22b..ddb813057ab 100644
--- a/sql/share/CMakeLists.txt
+++ b/sql/share/CMakeLists.txt
@@ -15,30 +15,32 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
SET (dirs
+bulgarian
+chinese
+czech
danish
-german
-slovak
dutch
-greek
-norwegian
-spanish
english
+estonian
+french
+german
+greek
+hindi
hungarian
-norwegian-ny
-swedish
italian
-polish
-ukrainian
japanese
+korean
+norwegian-ny
+norwegian
+polish
portuguese
romanian
-estonian
-korean
russian
-czech
-french
serbian
-hindi
+slovak
+spanish
+swedish
+ukrainian
)
SET(files
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 388a3aa74c1..e2cacdae420 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -1,4 +1,4 @@
-languages chinese=chi gbk, czech=cze latin2, danish=dan latin1, dutch=nla latin1, english=eng latin1, estonian=est latin7, french=fre latin1, german=ger latin1, greek=greek greek, hungarian=hun latin2, italian=ita latin1, japanese=jpn ujis, korean=kor euckr, norwegian-ny=norwegian-ny latin1, norwegian=nor latin1, polish=pol latin2, portuguese=por latin1, romanian=rum latin2, russian=rus koi8r, serbian=serbian cp1250, slovak=slo latin2, spanish=spa latin1, swedish=swe latin1, ukrainian=ukr koi8u, bulgarian=bgn cp1251, hindi=hindi utf8mb3;
+languages bulgarian=bgn cp1251, chinese=chi gbk, czech=cze latin2, danish=dan latin1, dutch=nla latin1, english=eng latin1, estonian=est latin7, french=fre latin1, german=ger latin1, greek=greek greek, hindi=hindi utf8mb3, hungarian=hun latin2, italian=ita latin1, japanese=jpn ujis, korean=kor euckr, norwegian-ny=norwegian-ny latin1, norwegian=nor latin1, polish=pol latin2, portuguese=por latin1, romanian=rum latin2, russian=rus koi8r, serbian=serbian cp1250, slovak=slo latin2, spanish=spa latin1, swedish=swe latin1, ukrainian=ukr koi8u;
default-language eng
@@ -6450,10 +6450,21 @@ ER_AMBIGUOUS_FIELD_TERM
ger "Das erste Zeichen der Zeichenkette FIELDS TERMINATED ist mehrdeutig; bitte benutzen Sie nicht optionale und nicht leere FIELDS ENCLOSED BY"
spa "El primer carácter de la cadena de los FIELDS TERMINATED es ambiguo; por favor, use FIELDS ENCLOSED BY no opcionales y no vacíos"
ER_FOREIGN_SERVER_EXISTS
- chi "您正在尝试创建的外来服务器%s已存在"
- eng "The foreign server, %s, you are trying to create already exists"
- ger "Der entfernte Server %s, den Sie versuchen zu erzeugen, existiert schon"
- spa "El servidor foráneo %s que intenta crear ya existe"
+ chi "无法创建外部服务器'%s',因为它已经存在"
+ eng "Cannot create foreign server '%s' as it already exists"
+ fin "Vieraata palvelinta '%s' ei voida luoda, koska se on jo olemassa"
+ fre "Impossible de créer le serveur étranger '%s' car il existe déjà"
+ ger "Der auswärtige Server '%s' kann nicht erstellt werden, da er bereits vorhanden ist"
+ greek "Δεν είναι δυνατή η δημιουργία ξένου διακομιστή '%s' επειδή υπάρχει ήδη"
+ ita "Impossibile creare il server esterno '%s' poiché esiste già"
+ jpn "外部サーバー '%s'は既に存在するため、作成できません"
+ nla "Kan geen externe server '%s' maken omdat deze al bestaat"
+ nor "Kan ikke opprette utenlandsk server '%s' fordi den allerede eksisterer"
+ pol "Nie można utworzyć obcego serwera '%s', ponieważ już istnieje"
+ por "Não foi possível criar o servidor externo '%s' porque ele já existe"
+ rus "Невозможно создать сторонний сервер '%s', так как он уже существует"
+ spa "No se puede crear el servidor externo '%s' porque ya existe"
+ swe "Det gick inte att skapa främmande server '%s' eftersom den redan finns"
ER_FOREIGN_SERVER_DOESNT_EXIST
chi "您尝试引用的外部服务器名称不存在。数据源错误:%-.64s"
eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s"
@@ -8200,12 +8211,12 @@ ER_TABLE_IN_SYSTEM_TABLESPACE
spa "Tabla %-.192s en espacio de tablas del sitema"
ER_IO_READ_ERROR
- chi "IO读取错误:(%lu,%s)%s"
+ chi "IO读取错误:(%lu,%s)%s"
eng "IO Read error: (%lu, %s) %s"
spa "Error de Lectura de E/S: (%lu, %s) %s"
ER_IO_WRITE_ERROR
- chi "IO写错错误:(%lu,%s)%s"
+ chi "IO写错错误:(%lu,%s)%s"
eng "IO Write error: (%lu, %s) %s"
spa "Error de Escritura de E/S: (%lu, %s) %s"
@@ -9300,7 +9311,7 @@ ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED
eng "Reference to recursive WITH table '%s' in materialized derived"
spa "Referencia recursiva con WITH tabla '%s' en derivada materializada"
ER_NOT_STANDARD_COMPLIANT_RECURSIVE
- chi "表'%s'违反了递归定义的限制"
+ chi "表'%s'R_WRONG_WINDOW_SPEC_NAME违反了递归定义的限制"
eng "Restrictions imposed on recursive definitions are violated for table '%s'"
ER_WRONG_WINDOW_SPEC_NAME
chi "没有定义名称'%s'的窗口规范"
diff --git a/sql/slave.cc b/sql/slave.cc
index f6f243d7f03..19037525422 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3307,9 +3307,9 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
protocol->store((uint32) mi->master_id);
// SQL_Delay
// Master_Ssl_Crl
- protocol->store_string_or_null(mi->ssl_ca, &my_charset_bin);
+ protocol->store_string_or_null(mi->ssl_crl, &my_charset_bin);
// Master_Ssl_Crlpath
- protocol->store_string_or_null(mi->ssl_capath, &my_charset_bin);
+ protocol->store_string_or_null(mi->ssl_crlpath, &my_charset_bin);
// Using_Gtid
protocol->store_string_or_null(mi->using_gtid_astext(mi->using_gtid),
&my_charset_bin);
@@ -3402,7 +3402,7 @@ bool show_all_master_info(THD* thd)
String gtid_pos;
Master_info **tmp;
List<Item> field_list;
- DBUG_ENTER("show_master_info");
+ DBUG_ENTER("show_all_master_info");
mysql_mutex_assert_owner(&LOCK_active_mi);
gtid_pos.length(0);
@@ -4991,6 +4991,7 @@ Stopping slave I/O thread due to out-of-memory error from master");
not cause the slave IO thread to stop, and the error messages are
already reported.
*/
+ DBUG_EXECUTE_IF("simulate_delay_semisync_slave_reply", my_sleep(800000););
(void)repl_semisync_slave.slave_reply(mi);
}
@@ -6777,17 +6778,75 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
mi->gtid_event_seen= true;
/*
- We have successfully queued to relay log everything before this GTID, so
+ Unless the previous group is malformed,
+ we have successfully queued to relay log everything before this GTID, so
in case of reconnect we can start from after any previous GTID.
- (Normally we would have updated gtid_current_pos earlier at the end of
- the previous event group, but better leave an extra check here for
- safety).
+ (We must have updated gtid_current_pos earlier at the end of
+ the previous event group. Unless ...)
*/
- if (mi->events_queued_since_last_gtid)
+ if (unlikely(mi->events_queued_since_last_gtid > 0))
{
- mi->gtid_current_pos.update(&mi->last_queued_gtid);
- mi->events_queued_since_last_gtid= 0;
+ /*
+ ...unless the last group has not been completed. An assert below
+ can be satisfied only with the strict mode that ensures
+ against "genuine" gtid duplicates.
+ */
+ rpl_gtid *gtid_in_slave_state=
+ mi->gtid_current_pos.find(mi->last_queued_gtid.domain_id);
+
+ // Slave gtid state must not have updated yet to the last received gtid.
+ DBUG_ASSERT((mi->using_gtid == Master_info::USE_GTID_NO ||
+ !opt_gtid_strict_mode) ||
+ (!gtid_in_slave_state ||
+ !(*gtid_in_slave_state == mi->last_queued_gtid)));
+
+ DBUG_EXECUTE_IF("slave_discard_xid_for_gtid_0_x_1000",
+ {
+ /* Inject an event group that is missing its XID commit event. */
+ if ((mi->last_queued_gtid.domain_id == 0 &&
+ mi->last_queued_gtid.seq_no == 1000) ||
+ (mi->last_queued_gtid.domain_id == 1 &&
+ mi->last_queued_gtid.seq_no == 32))
+ {
+ sql_print_warning(
+ "Unexpected break of being relay-logged GTID %u-%u-%llu "
+ "event group by the current GTID event %u-%u-%llu",
+ PARAM_GTID(mi->last_queued_gtid),PARAM_GTID(event_gtid));
+ DBUG_SET("-d,slave_discard_xid_for_gtid_0_x_1000");
+ goto dbug_gtid_accept;
+ }
+ });
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ sql_print_error("Unexpected break of being relay-logged GTID %u-%u-%llu "
+ "event group by the current GTID event %u-%u-%llu",
+ PARAM_GTID(mi->last_queued_gtid),PARAM_GTID(event_gtid));
+ goto err;
}
+ else if (unlikely(mi->gtid_reconnect_event_skip_count > 0))
+ {
+ if (mi->gtid_reconnect_event_skip_count ==
+ mi->events_queued_since_last_gtid)
+ {
+ DBUG_ASSERT(event_gtid == mi->last_queued_gtid);
+
+ goto default_action;
+ }
+
+ DBUG_ASSERT(0);
+ }
+ // else_likely{...
+#ifndef DBUG_OFF
+dbug_gtid_accept:
+ DBUG_EXECUTE_IF("slave_discard_gtid_0_x_1002",
+ {
+ if (mi->last_queued_gtid.server_id == 27697 &&
+ mi->last_queued_gtid.seq_no == 1002)
+ {
+ DBUG_SET("-d,slave_discard_gtid_0_x_1002");
+ goto skip_relay_logging;
+ }
+ });
+#endif
mi->last_queued_gtid= event_gtid;
mi->last_queued_gtid_standalone=
(gtid_flag & Gtid_log_event::FL_STANDALONE) != 0;
@@ -6797,7 +6856,7 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
++mi->events_queued_since_last_gtid;
inc_pos= event_len;
-
+ // ...} eof else_likely
}
break;
/*
@@ -6877,6 +6936,12 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
case XID_EVENT:
DBUG_EXECUTE_IF("slave_discard_xid_for_gtid_0_x_1000",
{
+ if (mi->last_queued_gtid.server_id == 27697 &&
+ mi->last_queued_gtid.seq_no == 1000)
+ {
+ DBUG_SET("-d,slave_discard_xid_for_gtid_0_x_1000");
+ goto skip_relay_logging;
+ }
/* Inject an event group that is missing its XID commit event. */
if (mi->last_queued_gtid.domain_id == 0 &&
mi->last_queued_gtid.seq_no == 1000)
@@ -6923,15 +6988,48 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
}
};);
- if (mi->using_gtid != Master_info::USE_GTID_NO && mi->gtid_event_seen)
+ if (mi->using_gtid != Master_info::USE_GTID_NO)
{
- if (unlikely(mi->gtid_reconnect_event_skip_count))
+ if (likely(mi->gtid_event_seen))
{
- --mi->gtid_reconnect_event_skip_count;
- gtid_skip_enqueue= true;
+ if (unlikely(mi->gtid_reconnect_event_skip_count))
+ {
+ if (!got_gtid_event &&
+ mi->gtid_reconnect_event_skip_count ==
+ mi->events_queued_since_last_gtid)
+ goto gtid_not_start; // the 1st re-sent must be gtid
+
+ --mi->gtid_reconnect_event_skip_count;
+ gtid_skip_enqueue= true;
+ }
+ else if (likely(mi->events_queued_since_last_gtid))
+ {
+ DBUG_ASSERT(!got_gtid_event);
+
+ ++mi->events_queued_since_last_gtid;
+ }
+ else if (Log_event::is_group_event((Log_event_type) (uchar)
+ buf[EVENT_TYPE_OFFSET]))
+ {
+ goto gtid_not_start; // no first gtid event in this group
+ }
+ }
+ else if (Log_event::is_group_event((Log_event_type) (uchar)
+ buf[EVENT_TYPE_OFFSET]))
+ {
+ gtid_not_start:
+
+ DBUG_ASSERT(!got_gtid_event);
+
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ sql_print_error("The current group of events starts with "
+ "a non-GTID %s event; "
+ "the last seen GTID is %u-%u-%llu",
+ Log_event::get_type_str((Log_event_type) (uchar)
+ buf[EVENT_TYPE_OFFSET]),
+ mi->last_queued_gtid);
+ goto err;
}
- else if (mi->events_queued_since_last_gtid)
- ++mi->events_queued_since_last_gtid;
}
if (!is_compress_event)
@@ -7129,8 +7227,9 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
mi->using_gtid != Master_info::USE_GTID_NO &&
mi->events_queued_since_last_gtid > 0 &&
( (mi->last_queued_gtid_standalone &&
- !Log_event::is_part_of_group((Log_event_type)(uchar)
- buf[EVENT_TYPE_OFFSET])) ||
+ (LOG_EVENT_IS_QUERY((Log_event_type)(uchar)
+ buf[EVENT_TYPE_OFFSET]) ||
+ (uchar)buf[EVENT_TYPE_OFFSET] == INCIDENT_EVENT)) ||
(!mi->last_queued_gtid_standalone &&
((uchar)buf[EVENT_TYPE_OFFSET] == XID_EVENT ||
(uchar)buf[EVENT_TYPE_OFFSET] == XA_PREPARE_LOG_EVENT ||
@@ -7142,11 +7241,13 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
The whole of the current event group is queued. So in case of
reconnect we can start from after the current GTID.
*/
- if (mi->gtid_reconnect_event_skip_count)
+ if (gtid_skip_enqueue)
{
bool first= true;
StringBuffer<1024> gtid_text;
+ DBUG_ASSERT(mi->events_queued_since_last_gtid > 1);
+
rpl_slave_state_tostring_helper(&gtid_text, &mi->last_queued_gtid,
&first);
sql_print_error("Slave IO thread received a terminal event from "
@@ -7156,6 +7257,8 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
gtid_text.ptr(),
mi->gtid_reconnect_event_skip_count,
mi->events_queued_since_last_gtid);
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ goto err;
}
mi->gtid_current_pos.update(&mi->last_queued_gtid);
mi->events_queued_since_last_gtid= 0;
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index b3949a94751..36ad37104bd 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -312,3 +312,12 @@ sp_cache::cleanup()
{
my_hash_free(&m_hashtable);
}
+
+
+void Sp_caches::sp_caches_clear()
+{
+ sp_cache_clear(&sp_proc_cache);
+ sp_cache_clear(&sp_func_cache);
+ sp_cache_clear(&sp_package_spec_cache);
+ sp_cache_clear(&sp_package_body_cache);
+}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index fab72fd0c6f..bdd94fd6d0e 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -830,7 +830,7 @@ void
sp_head::set_stmt_end(THD *thd)
{
Lex_input_stream *lip= & thd->m_parser_state->m_lip; /* shortcut */
- const char *end_ptr= lip->get_cpp_ptr(); /* shortcut */
+ const char *end_ptr= lip->get_cpp_tok_start(); /* shortcut */
/* Make the string of parameters. */
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 86c6e9a27f8..1d5875733ac 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -411,7 +411,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
referenced from this structure will be modified.
@todo move these into constructor...
*/
- HA_CREATE_INFO create_info(lex->create_info);
+ Table_specification_st create_info(lex->create_info);
Alter_info alter_info(lex->alter_info, thd->mem_root);
create_info.alter_info= &alter_info;
privilege_t priv(NO_ACL);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 50371b3e722..18ffdc9e174 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -819,7 +819,14 @@ int close_thread_tables(THD *thd)
table->s->table_name.str, (ulong) table->query_id));
if (thd->locked_tables_mode)
+ {
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (table->part_info && table->part_info->vers_require_hist_part(thd) &&
+ !thd->stmt_arena->is_stmt_prepare())
+ table->part_info->vers_check_limit(thd);
+#endif
table->vcol_cleanup_expr(thd);
+ }
/* Detach MERGE children after every statement. Even under LOCK TABLES. */
if (thd->locked_tables_mode <= LTM_LOCK_TABLES ||
@@ -8664,9 +8671,11 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
thd->lex->which_check_option_applicable();
bool save_is_item_list_lookup= select_lex->is_item_list_lookup;
TABLE_LIST *derived= select_lex->master_unit()->derived;
+ bool save_resolve_in_select_list= select_lex->context.resolve_in_select_list;
DBUG_ENTER("setup_conds");
select_lex->is_item_list_lookup= 0;
+ select_lex->context.resolve_in_select_list= false;
thd->column_usage= MARK_COLUMNS_READ;
DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage));
@@ -8719,7 +8728,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
select_lex->where= *conds;
}
thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
- DBUG_RETURN(MY_TEST(thd->is_error()));
+ select_lex->context.resolve_in_select_list= save_resolve_in_select_list;
+ DBUG_RETURN(thd->is_error());
err_no_arena:
select_lex->is_item_list_lookup= save_is_item_list_lookup;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index f902f12481e..a0ba1d7e5a3 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2021, MariaDB Corporation.
+ Copyright (c) 2008, 2022, 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
@@ -56,6 +56,7 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "sql_show.h" // append_identifier
+#include "sql_db.h" // get_default_db_collation
#include "transaction.h"
#include "sql_select.h" /* declares create_tmp_table() */
#include "debug_sync.h"
@@ -679,7 +680,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
#ifdef HAVE_REPLICATION
,
current_linfo(0),
- slave_info(0)
+ slave_info(0),
+ is_awaiting_semisync_ack(0)
#endif
#ifdef WITH_WSREP
,
@@ -861,11 +863,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
get_sequence_last_key, (my_hash_free_key) free_sequence_last,
HASH_THREAD_SPECIFIC);
- sp_proc_cache= NULL;
- sp_func_cache= NULL;
- sp_package_spec_cache= NULL;
- sp_package_body_cache= NULL;
-
/* For user vars replication*/
if (opt_bin_log)
my_init_dynamic_array(key_memory_user_var_entry, &user_var_events,
@@ -1439,10 +1436,7 @@ void THD::change_user(void)
SEQUENCES_HASH_SIZE, 0, 0, (my_hash_get_key)
get_sequence_last_key, (my_hash_free_key) free_sequence_last,
HASH_THREAD_SPECIFIC);
- sp_cache_clear(&sp_proc_cache);
- sp_cache_clear(&sp_func_cache);
- sp_cache_clear(&sp_package_spec_cache);
- sp_cache_clear(&sp_package_body_cache);
+ sp_caches_clear();
opt_trace.delete_traces();
}
@@ -1569,10 +1563,7 @@ void THD::cleanup(void)
my_hash_free(&user_vars);
my_hash_free(&sequences);
- sp_cache_clear(&sp_proc_cache);
- sp_cache_clear(&sp_func_cache);
- sp_cache_clear(&sp_package_spec_cache);
- sp_cache_clear(&sp_package_body_cache);
+ sp_caches_clear();
auto_inc_intervals_forced.empty();
auto_inc_intervals_in_cur_stmt_for_binlog.empty();
@@ -6741,49 +6732,86 @@ int THD::decide_logging_format(TABLE_LIST *tables)
DBUG_RETURN(0);
}
-int THD::decide_logging_format_low(TABLE *table)
+
+/*
+ Reconsider logging format in case of INSERT...ON DUPLICATE KEY UPDATE
+ for tables with more than one unique keys in case of MIXED binlog format.
+
+ Unsafe means that a master could execute the statement differently than
+ the slave.
+ This could can happen in the following cases:
+ - The unique check are done in different order on master or slave
+ (different engine or different key order).
+ - There is a conflict on another key than the first and before the
+ statement is committed, another connection commits a row that conflicts
+ on an earlier unique key. Example follows:
+
+ Below a and b are unique keys, the table has a row (1,1,0)
+ connection 1:
+ INSERT INTO t1 set a=2,b=1,c=0 ON DUPLICATE KEY UPDATE c=1;
+ connection 2:
+ INSERT INTO t1 set a=2,b=2,c=0;
+
+ If 2 commits after 1 has been executed but before 1 has committed
+ (and are thus put before the other in the binary log), one will
+ get different data on the slave:
+ (1,1,1),(2,2,1) instead of (1,1,1),(2,2,0)
+*/
+
+void THD::reconsider_logging_format_for_iodup(TABLE *table)
{
- DBUG_ENTER("decide_logging_format_low");
- /*
- INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys
- can be unsafe.
- */
- if (wsrep_binlog_format() <= BINLOG_FORMAT_STMT &&
- !is_current_stmt_binlog_format_row() &&
- !lex->is_stmt_unsafe() &&
- lex->duplicates == DUP_UPDATE)
+ DBUG_ENTER("reconsider_logging_format_for_iodup");
+ enum_binlog_format bf= (enum_binlog_format) wsrep_binlog_format();
+
+ DBUG_ASSERT(lex->duplicates == DUP_UPDATE);
+
+ if (bf <= BINLOG_FORMAT_STMT &&
+ !is_current_stmt_binlog_format_row())
{
+ KEY *end= table->s->key_info + table->s->keys;
uint unique_keys= 0;
- uint keys= table->s->keys, i= 0;
- Field *field;
- for (KEY* keyinfo= table->s->key_info;
- i < keys && unique_keys <= 1; i++, keyinfo++)
- if (keyinfo->flags & HA_NOSAME &&
- !(keyinfo->key_part->field->flags & AUTO_INCREMENT_FLAG &&
- //User given auto inc can be unsafe
- !keyinfo->key_part->field->val_int()))
+
+ for (KEY *keyinfo= table->s->key_info; keyinfo < end ; keyinfo++)
+ {
+ if (keyinfo->flags & HA_NOSAME)
{
+ /*
+ We assume that the following cases will guarantee that the
+ key is unique if a key part is not set:
+ - The key part is an autoincrement (autogenerated)
+ - The key part has a default value that is null and it not
+ a virtual field that will be calculated later.
+ */
for (uint j= 0; j < keyinfo->user_defined_key_parts; j++)
{
- field= keyinfo->key_part[j].field;
- if(!bitmap_is_set(table->write_set,field->field_index))
- goto exit;
+ Field *field= keyinfo->key_part[j].field;
+ if (!bitmap_is_set(table->write_set, field->field_index))
+ {
+ /* Check auto_increment */
+ if (field == table->next_number_field)
+ goto exit;
+ if (field->is_real_null() && !field->default_value)
+ goto exit;
+ }
}
- unique_keys++;
+ if (unique_keys++)
+ break;
exit:;
}
-
+ }
if (unique_keys > 1)
{
- lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
- binlog_unsafe_warning_flags|= lex->get_stmt_unsafe_flags();
+ if (bf == BINLOG_FORMAT_STMT && !lex->is_stmt_unsafe())
+ {
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
+ binlog_unsafe_warning_flags|= lex->get_stmt_unsafe_flags();
+ }
set_current_stmt_binlog_format_row_if_mixed();
if (is_current_stmt_binlog_format_row())
binlog_prepare_for_row_logging();
- DBUG_RETURN(1);
}
}
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
#ifndef MYSQL_CLIENT
@@ -8269,3 +8297,27 @@ THD_list_iterator *THD_list_iterator::iterator()
{
return &server_threads;
}
+
+
+Charset_collation_context
+THD::charset_collation_context_alter_db(const char *db)
+{
+ return Charset_collation_context(variables.collation_server,
+ get_default_db_collation(this, db));
+}
+
+
+Charset_collation_context
+THD::charset_collation_context_create_table_in_db(const char *db)
+{
+ CHARSET_INFO *cs= get_default_db_collation(this, db);
+ return Charset_collation_context(cs, cs);
+}
+
+
+Charset_collation_context
+THD::charset_collation_context_alter_table(const TABLE_SHARE *s)
+{
+ return Charset_collation_context(get_default_db_collation(this, s->db.str),
+ s->table_charset);
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 47d4f9fee6a..806f77c1ba2 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2021, MariaDB Corporation.
+ Copyright (c) 2009, 2022, 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
@@ -1185,7 +1185,7 @@ public:
/* We build without RTTI, so dynamic_cast can't be used. */
enum Type
{
- STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE, TABLE_ARENA
+ STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
};
Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) :
@@ -2367,6 +2367,39 @@ struct wait_for_commit
void reinit();
};
+
+class Sp_caches
+{
+public:
+ sp_cache *sp_proc_cache;
+ sp_cache *sp_func_cache;
+ sp_cache *sp_package_spec_cache;
+ sp_cache *sp_package_body_cache;
+ Sp_caches()
+ :sp_proc_cache(NULL),
+ sp_func_cache(NULL),
+ sp_package_spec_cache(NULL),
+ sp_package_body_cache(NULL)
+ { }
+ ~Sp_caches()
+ {
+ // All caches must be freed by the caller explicitly
+ DBUG_ASSERT(sp_proc_cache == NULL);
+ DBUG_ASSERT(sp_func_cache == NULL);
+ DBUG_ASSERT(sp_package_spec_cache == NULL);
+ DBUG_ASSERT(sp_package_body_cache == NULL);
+ }
+ void sp_caches_swap(Sp_caches &rhs)
+ {
+ swap_variables(sp_cache*, sp_proc_cache, rhs.sp_proc_cache);
+ swap_variables(sp_cache*, sp_func_cache, rhs.sp_func_cache);
+ swap_variables(sp_cache*, sp_package_spec_cache, rhs.sp_package_spec_cache);
+ swap_variables(sp_cache*, sp_package_body_cache, rhs.sp_package_body_cache);
+ }
+ void sp_caches_clear();
+};
+
+
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
@@ -2562,7 +2595,8 @@ class THD: public THD_count, /* this must be first */
*/
public Item_change_list,
public MDL_context_owner,
- public Open_tables_state
+ public Open_tables_state,
+ public Sp_caches
{
private:
inline bool is_stmt_prepare() const
@@ -3606,10 +3640,6 @@ public:
enum_sql_command last_sql_command; // Last sql_command exceuted in mysql_execute_command()
sp_rcontext *spcont; // SP runtime context
- sp_cache *sp_proc_cache;
- sp_cache *sp_func_cache;
- sp_cache *sp_package_spec_cache;
- sp_cache *sp_package_body_cache;
/** number of name_const() substitutions, see sp_head.cc:subst_spvars() */
uint query_name_consts;
@@ -4407,8 +4437,7 @@ public:
bool is_item_tree_change_register_required()
{
- return !stmt_arena->is_conventional()
- || stmt_arena->type() == Query_arena::TABLE_ARENA;
+ return !stmt_arena->is_conventional();
}
void change_item_tree(Item **place, Item *new_value)
@@ -4998,18 +5027,18 @@ public:
mdl_context.release_transactional_locks(this);
}
int decide_logging_format(TABLE_LIST *tables);
+
/*
- In Some cases when decide_logging_format is called it does not have all
- information to decide the logging format. So that cases we call decide_logging_format_2
- at later stages in execution.
- One example would be binlog format for IODKU but column with unique key is not inserted.
- We don't have inserted columns info when we call decide_logging_format so on later stage we call
- decide_logging_format_low
+ In Some cases when decide_logging_format is called it does not have
+ all information to decide the logging format. So that cases we call
+ decide_logging_format_2 at later stages in execution.
- @returns 0 if no format is changed
- 1 if there is change in binlog format
+ One example would be binlog format for insert on duplicate key
+ (IODKU) but column with unique key is not inserted. We do not have
+ inserted columns info when we call decide_logging_format so on
+ later stage we call reconsider_logging_format_for_iodup()
*/
- int decide_logging_format_low(TABLE *table);
+ void reconsider_logging_format_for_iodup(TABLE *table);
enum need_invoker { INVOKER_NONE=0, INVOKER_USER, INVOKER_ROLE};
void binlog_invoker(bool role) { m_binlog_invoker= role ? INVOKER_ROLE : INVOKER_USER; }
@@ -5259,6 +5288,14 @@ public:
bool is_binlog_dump_thread();
#endif
+ /*
+ Indicates if this thread is suspended due to awaiting an ACK from a
+ replica. True if suspended, false otherwise.
+
+ Note that this variable is protected by Repl_semi_sync_master::LOCK_binlog
+ */
+ bool is_awaiting_semisync_ack;
+
inline ulong wsrep_binlog_format() const
{
return WSREP_BINLOG_FORMAT(variables.binlog_format);
@@ -5484,6 +5521,19 @@ public:
MY_UTF8_IS_UTF8MB3 : 0);
}
+ Charset_collation_context
+ charset_collation_context_create_db() const
+ {
+ return Charset_collation_context(variables.collation_server,
+ variables.collation_server);
+ }
+ Charset_collation_context
+ charset_collation_context_alter_db(const char *db);
+ Charset_collation_context
+ charset_collation_context_create_table_in_db(const char *db);
+ Charset_collation_context
+ charset_collation_context_alter_table(const TABLE_SHARE *s);
+
/**
Save current lex to the output parameter and reset it to point to
main_lex. This method is called from mysql_client_binlog_statement()
@@ -5581,8 +5631,8 @@ my_eof(THD *thd)
inline date_conv_mode_t sql_mode_for_dates(THD *thd)
{
- static_assert((date_conv_mode_t::KNOWN_MODES &
- time_round_mode_t::KNOWN_MODES) == 0,
+ static_assert((ulonglong(date_conv_mode_t::KNOWN_MODES) &
+ ulonglong(time_round_mode_t::KNOWN_MODES)) == 0,
"date_conv_mode_t and time_round_mode_t must use different "
"bit values");
static_assert(MODE_NO_ZERO_DATE == date_mode_t::NO_ZERO_DATE &&
@@ -6103,6 +6153,7 @@ public:
m_plock(NULL), exit_done(0),
saved_tmp_table_share(0)
{
+ DBUG_ASSERT(create_info->default_table_charset);
bzero(&ddl_log_state_create, sizeof(ddl_log_state_create));
bzero(&ddl_log_state_rm, sizeof(ddl_log_state_rm));
}
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index c5defc1959c..9da1ac5ca77 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -943,6 +943,7 @@ exit:
int mysql_create_db(THD *thd, const LEX_CSTRING *db, DDL_options_st options,
const Schema_specification_st *create_info)
{
+ DBUG_ASSERT(create_info->default_table_charset);
/*
As mysql_create_db_internal() may modify Db_create_info structure passed
to it, we need to use a copy to make execution prepared statement- safe.
@@ -958,6 +959,7 @@ int mysql_create_db(THD *thd, const LEX_CSTRING *db, DDL_options_st options,
bool mysql_alter_db(THD *thd, const LEX_CSTRING *db,
const Schema_specification_st *create_info)
{
+ DBUG_ASSERT(create_info->default_table_charset);
/*
As mysql_alter_db_internal() may modify Db_create_info structure passed
to it, we need to use a copy to make execution prepared statement- safe.
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 833492d3d9f..7235dc6472d 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -712,8 +712,10 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler,
if (!in_prepare)
{
MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set);
- (void) item->save_in_field(key_part->field, 1);
+ int res= item->save_in_field(key_part->field, 1);
dbug_tmp_restore_column_map(&table->write_set, old_map);
+ if (res)
+ return 1;
}
key_len+= key_part->store_length;
keypart_map= (keypart_map << 1) | 1;
diff --git a/sql/sql_i_s.h b/sql/sql_i_s.h
index bed2e886718..a3614d889c9 100644
--- a/sql/sql_i_s.h
+++ b/sql/sql_i_s.h
@@ -158,10 +158,10 @@ public:
};
-class Yesno: public Varchar
+class Yes_or_empty: public Varchar
{
public:
- Yesno(): Varchar(3) { }
+ Yes_or_empty(): Varchar(3) { }
};
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index e498daca83c..d9d22dbe514 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2021, MariaDB
+ Copyright (c) 2010, 2022, 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
@@ -995,7 +995,12 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
goto values_loop_end;
THD_STAGE_INFO(thd, stage_update);
- thd->decide_logging_format_low(table);
+
+ if (duplic == DUP_UPDATE)
+ {
+ restore_record(table,s->default_values); // Get empty record
+ thd->reconsider_logging_format_for_iodup(table);
+ }
fix_rownum_pointers(thd, thd->lex->current_select, &info.accepted_rows);
if (returning)
fix_rownum_pointers(thd, thd->lex->returning(), &info.accepted_rows);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 18d54bf0d69..5f2f072b348 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -719,7 +719,6 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
return TRUE;
context->resolve_in_table_list_only(table_list);
lex->use_only_table_context= TRUE;
- lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VCOL_EXPR;
select_lex->cur_pos_in_select_list= UNDEF_POS;
table->map= 1; //To ensure correct calculation of const item
table_list->table= table;
@@ -1212,6 +1211,7 @@ void LEX::start(THD *thd_arg)
context_stack.empty();
//empty select_stack
select_stack_top= 0;
+ select_stack_outer_barrier= 0;
unit.init_query();
current_select_number= 0;
curr_with_clause= 0;
@@ -5296,17 +5296,21 @@ void SELECT_LEX::update_used_tables()
while ((tl= ti++))
{
TABLE_LIST *embedding= tl;
- do
+ if (!is_eliminated_table(join->eliminated_tables, tl))
{
- bool maybe_null;
- if ((maybe_null= MY_TEST(embedding->outer_join)))
+ do
{
- tl->table->maybe_null= maybe_null;
- break;
+ bool maybe_null;
+ if ((maybe_null= MY_TEST(embedding->outer_join)))
+ {
+ tl->table->maybe_null= maybe_null;
+ break;
+ }
}
+ while ((embedding= embedding->embedding));
}
- while ((embedding= embedding->embedding));
- if (tl->on_expr)
+
+ if (tl->on_expr && !is_eliminated_table(join->eliminated_tables, tl))
{
tl->on_expr->update_used_tables();
tl->on_expr->walk(&Item::eval_not_null_tables, 0, NULL);
@@ -5333,8 +5337,11 @@ void SELECT_LEX::update_used_tables()
if (embedding->on_expr &&
embedding->nested_join->join_list.head() == tl)
{
- embedding->on_expr->update_used_tables();
- embedding->on_expr->walk(&Item::eval_not_null_tables, 0, NULL);
+ if (!is_eliminated_table(join->eliminated_tables, embedding))
+ {
+ embedding->on_expr->update_used_tables();
+ embedding->on_expr->walk(&Item::eval_not_null_tables, 0, NULL);
+ }
}
tl= embedding;
embedding= tl->embedding;
@@ -7800,7 +7807,7 @@ bool LEX::maybe_start_compound_statement(THD *thd)
if (!make_sp_head(thd, NULL, &sp_handler_procedure, DEFAULT_AGGREGATE))
return true;
sphead->set_suid(SP_IS_NOT_SUID);
- sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_ptr());
+ sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_tok_start());
}
return false;
}
@@ -11867,6 +11874,21 @@ bool LEX::sp_create_set_password_instr(THD *thd,
}
+bool LEX::set_names(const char *pos,
+ const Lex_exact_charset_opt_extended_collate &cscl,
+ bool no_lookahead)
+{
+ if (sp_create_assignment_lex(thd, pos))
+ return true;
+ CHARSET_INFO *ci= cscl.collation().charset_info();
+ set_var_collation_client *var;
+ var= new (thd->mem_root) set_var_collation_client(ci, ci, ci);
+ return unlikely(var == NULL) ||
+ unlikely(thd->lex->var_list.push_back(var, thd->mem_root)) ||
+ unlikely(sp_create_assignment_instr(thd, no_lookahead));
+}
+
+
bool LEX::map_data_type(const Lex_ident_sys_st &schema_name,
Lex_field_type_st *type) const
{
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a6e7546d38c..4f2e775a7fc 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2047,8 +2047,7 @@ public:
@retval nonzero if the statement is a row injection
*/
inline bool is_stmt_row_injection() const {
- return binlog_stmt_flags &
- (1U << (BINLOG_STMT_UNSAFE_COUNT + BINLOG_STMT_TYPE_ROW_INJECTION));
+ return binlog_stmt_flags & (1U << BINLOG_STMT_TYPE_ROW_INJECTION);
}
/**
@@ -2058,8 +2057,7 @@ public:
*/
inline void set_stmt_row_injection() {
DBUG_ENTER("set_stmt_row_injection");
- binlog_stmt_flags|=
- (1U << (BINLOG_STMT_UNSAFE_COUNT + BINLOG_STMT_TYPE_ROW_INJECTION));
+ binlog_stmt_flags|= (1U << BINLOG_STMT_TYPE_ROW_INJECTION);
DBUG_VOID_RETURN;
}
@@ -2335,7 +2333,7 @@ private:
The statement is a row injection (i.e., either a BINLOG
statement or a row event executed by the slave SQL thread).
*/
- BINLOG_STMT_TYPE_ROW_INJECTION = 0,
+ BINLOG_STMT_TYPE_ROW_INJECTION = BINLOG_STMT_UNSAFE_COUNT,
/** The last element of this enumeration type. */
BINLOG_STMT_TYPE_COUNT
@@ -2349,8 +2347,8 @@ private:
- The low BINLOG_STMT_UNSAFE_COUNT bits indicate the types of
unsafeness that the current statement has.
- - The next BINLOG_STMT_TYPE_COUNT bits indicate if the statement
- is of some special type.
+ - The next BINLOG_STMT_TYPE_COUNT-BINLOG_STMT_TYPE_COUNT bits indicate if
+ the statement is of some special type.
This must be a member of LEX, not of THD: each stored procedure
needs to remember its unsafeness state between calls and each
@@ -3309,6 +3307,12 @@ public:
List<Name_resolution_context> context_stack;
SELECT_LEX *select_stack[MAX_SELECT_NESTING + 1];
uint select_stack_top;
+ /*
+ Usually this is set to 0, but for INSERT/REPLACE SELECT it is set to 1.
+ When parsing such statements the pointer to the most outer select is placed
+ into the second element of select_stack rather than into the first.
+ */
+ uint select_stack_outer_barrier;
SQL_I_List<ORDER> proc_list;
SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list;
@@ -3752,6 +3756,17 @@ public:
bool copy_db_to(LEX_CSTRING *to);
+ void inc_select_stack_outer_barrier()
+ {
+ select_stack_outer_barrier++;
+ }
+
+ SELECT_LEX *parser_current_outer_select()
+ {
+ return select_stack_top - 1 == select_stack_outer_barrier ?
+ 0 : select_stack[select_stack_top - 2];
+ }
+
Name_resolution_context *current_context()
{
return context_stack.head();
@@ -3818,6 +3833,9 @@ public:
int case_stmt_action_then();
bool setup_select_in_parentheses();
+ bool set_names(const char *pos,
+ const Lex_exact_charset_opt_extended_collate &cs,
+ bool no_lookahead);
bool set_trigger_new_row(const LEX_CSTRING *name, Item *val);
bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
Item *val);
@@ -4390,6 +4408,23 @@ public:
bool add_alter_list(LEX_CSTRING par_name, Virtual_column_info *expr,
bool par_exists);
bool add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name, bool exists);
+ bool add_alter_list_item_convert_to_charset(CHARSET_INFO *cs)
+ {
+ if (create_info.add_table_option_convert_charset(cs))
+ return true;
+ alter_info.flags|= ALTER_CONVERT_TO;
+ return false;
+ }
+ bool
+ add_alter_list_item_convert_to_charset(CHARSET_INFO *cs,
+ const Lex_extended_collation_st &cl)
+ {
+ if (create_info.add_table_option_convert_charset(cs) ||
+ create_info.add_table_option_convert_collation(cl))
+ return true;
+ alter_info.flags|= ALTER_CONVERT_TO;
+ return false;
+ }
void set_command(enum_sql_command command,
DDL_options_st options)
{
@@ -4529,6 +4564,29 @@ public:
return create_info.vers_info;
}
+ /* The list of history-generating DML commands */
+ bool vers_history_generating() const
+ {
+ switch (sql_command)
+ {
+ case SQLCOM_DELETE:
+ return !vers_conditions.delete_history;
+ case SQLCOM_UPDATE:
+ case SQLCOM_UPDATE_MULTI:
+ case SQLCOM_DELETE_MULTI:
+ case SQLCOM_REPLACE:
+ case SQLCOM_REPLACE_SELECT:
+ return true;
+ case SQLCOM_INSERT:
+ case SQLCOM_INSERT_SELECT:
+ return duplicates == DUP_UPDATE;
+ case SQLCOM_LOAD:
+ return duplicates == DUP_REPLACE;
+ default:
+ return false;
+ }
+ }
+
int add_period(Lex_ident name, Lex_ident_sys_st start, Lex_ident_sys_st end)
{
if (lex_string_cmp(system_charset_info, &start, &end) == 0)
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index df6847f2ba1..3d3728b9e00 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -134,6 +134,7 @@ void start_handle_manager()
{
pthread_t hThread;
int err;
+ DBUG_EXECUTE_IF("delay_start_handle_manager", my_sleep(1000););
manager_thread_in_use = 1;
mysql_cond_init(key_COND_manager, &COND_manager,NULL);
mysql_mutex_init(key_LOCK_manager, &LOCK_manager, NULL);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0ac082b1812..0597b086b7b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -43,9 +43,7 @@
// mysql_alter_db,
// check_db_dir_existence,
// my_dbopt_cleanup
-#include "sql_table.h" // mysql_create_like_table,
- // mysql_create_table,
- // mysql_alter_table,
+#include "sql_table.h" // mysql_alter_table,
// mysql_backup_table,
// mysql_restore_table
#include "sql_reload.h" // reload_acl_and_cache
@@ -1507,22 +1505,6 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
}
#ifdef WITH_WSREP
-static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables)
-{
- int opt_readonly_saved = opt_readonly;
- privilege_t flag_saved= thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY;
-
- opt_readonly = 0;
- thd->security_ctx->master_access &= ~PRIV_IGNORE_READ_ONLY;
-
- my_bool ret = !deny_updates_if_read_only_option(thd, all_tables);
-
- opt_readonly = opt_readonly_saved;
- thd->security_ctx->master_access |= flag_saved;
-
- return ret;
-}
-
static void wsrep_copy_query(THD *thd)
{
thd->wsrep_retry_command = thd->get_command();
@@ -4206,7 +4188,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
*/
{
/* Prepare stack copies to be re-execution safe */
- HA_CREATE_INFO create_info;
+ Table_specification_st create_info;
Alter_info alter_info(lex->alter_info, thd->mem_root);
if (unlikely(thd->is_fatal_error)) /* out of memory creating alter_info */
@@ -4216,10 +4198,9 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
- bzero((char*) &create_info, sizeof(create_info));
+ create_info.init();
create_info.db_type= 0;
create_info.row_type= ROW_TYPE_NOT_USED;
- create_info.default_table_charset= thd->variables.collation_database;
create_info.alter_info= &alter_info;
WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL);
@@ -5178,6 +5159,10 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
&lex->name))
break;
+ if ((res= lex->create_info.resolve_to_charset_collation_context(thd,
+ thd->charset_collation_context_create_db())))
+ break;
+
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL);
res= mysql_create_db(thd, &lex->name,
@@ -5239,6 +5224,10 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
if (prepare_db_action(thd, ALTER_ACL, db))
break;
+ if ((res= lex->create_info.resolve_to_charset_collation_context(thd,
+ thd->charset_collation_context_alter_db(lex->name.str))))
+ break;
+
WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL);
res= mysql_alter_db(thd, db, &lex->create_info);
@@ -7852,7 +7841,7 @@ static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
{
bool is_autocommit=
!thd->in_multi_stmt_transaction_mode() &&
- wsrep_read_only_option(thd, thd->lex->query_tables);
+ !thd->wsrep_applier;
bool retry_autocommit;
do
{
@@ -8890,6 +8879,7 @@ bool st_select_lex::add_window_def(THD *thd,
fields_in_window_functions+= win_part_list_ptr->elements +
win_order_list_ptr->elements;
}
+ win_def->win_spec_number= window_specs.elements;
return (win_def == NULL || window_specs.push_back(win_def));
}
@@ -8917,6 +8907,7 @@ bool st_select_lex::add_window_spec(THD *thd,
win_order_list_ptr->elements;
}
thd->lex->win_spec= win_spec;
+ win_spec->win_spec_number= window_specs.elements;
return (win_spec == NULL || window_specs.push_back(win_spec));
}
@@ -9060,9 +9051,7 @@ push_new_name_resolution_context(THD *thd,
right_op->last_leaf_for_name_resolution();
LEX *lex= thd->lex;
on_context->select_lex = lex->current_select;
- st_select_lex *curr_select= lex->pop_select();
- st_select_lex *outer_sel= lex->select_stack_head();
- lex->push_select(curr_select);
+ st_select_lex *outer_sel= lex->parser_current_outer_select();
on_context->outer_context = outer_sel ? &outer_sel->context : 0;
return lex->push_context(on_context);
}
@@ -10488,40 +10477,6 @@ bool parse_sql(THD *thd, Parser_state *parser_state,
*/
-
-/**
- Check and merge "CHARACTER SET cs [ COLLATE cl ]" clause
-
- @param cs character set pointer.
- @param cl collation pointer.
-
- Check if collation "cl" is applicable to character set "cs".
-
- If "cl" is NULL (e.g. when COLLATE clause is not specified),
- then simply "cs" is returned.
-
- @return Error status.
- @retval NULL, if "cl" is not applicable to "cs".
- @retval pointer to merged CHARSET_INFO on success.
-*/
-
-
-CHARSET_INFO*
-merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl)
-{
- if (cl)
- {
- if (!my_charset_same(cs, cl))
- {
- my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl->coll_name.str,
- cs->cs_name.str);
- return NULL;
- }
- return cl;
- }
- return cs;
-}
-
void LEX::mark_first_table_as_inserting()
{
TABLE_LIST *t= first_select_lex()->table_list.first;
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index 9e1ec6fabbc..d3cf83b6e08 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -78,7 +78,6 @@ bool check_string_char_length(const LEX_CSTRING *str, uint err_msg,
size_t max_char_length, CHARSET_INFO *cs,
bool no_error);
bool check_ident_length(const LEX_CSTRING *ident);
-CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl);
bool check_host_name(LEX_CSTRING *str);
bool check_identifier_name(LEX_CSTRING *str, uint max_char_length,
uint err_code, const char *param_for_err_msg);
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index d2cdbdaf122..f42b9955b90 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -5984,11 +5984,12 @@ the generated partition syntax in a correct manner.
tab_part_info != part_info && part_info->part_type == VERSIONING_PARTITION &&
part_info->num_parts == 0)
{
- if (part_info->vers_info->interval.is_set() &&
+ if (part_info->vers_info->interval.is_set() && (
+ !tab_part_info->vers_info->interval.is_set() ||
/* TODO: equivalent intervals like 1 hour and 60 mins should be considered equal */
memcmp(&part_info->vers_info->interval,
&tab_part_info->vers_info->interval,
- sizeof(Vers_part_info::interval)))
+ sizeof(Vers_part_info::interval))))
{
/* If interval is changed we can not do fast alter */
tab_part_info= tab_part_info->get_clone(thd);
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index fb1ae0d5fc7..4edd6e7f9a0 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -195,7 +195,8 @@ static bool check_exchange_partition(TABLE *table, TABLE *part_table)
bool compare_table_with_partition(THD *thd, TABLE *table, TABLE *part_table,
partition_element *part_elem, uint part_id)
{
- HA_CREATE_INFO table_create_info, part_create_info;
+ HA_CREATE_INFO table_create_info;
+ Table_specification_st part_create_info;
Alter_info part_alter_info;
Alter_table_ctx part_alter_ctx; // Not used
DBUG_ENTER("compare_table_with_partition");
@@ -258,8 +259,13 @@ bool compare_table_with_partition(THD *thd, TABLE *table, TABLE *part_table,
my_error(ER_TABLES_DIFFERENT_METADATA, MYF(0));
DBUG_RETURN(TRUE);
}
- DBUG_ASSERT(table->s->db_create_options ==
- part_table->s->db_create_options);
+
+ if (table->s->db_create_options != part_table->s->db_create_options)
+ {
+ my_error(ER_TABLES_DIFFERENT_METADATA, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
DBUG_ASSERT(table->s->db_options_in_use ==
part_table->s->db_options_in_use);
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 2e647712e64..66781caac3e 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -374,7 +374,8 @@ bool check_valid_path(const char *path, size_t len)
static void fix_dl_name(MEM_ROOT *root, LEX_CSTRING *dl)
{
const size_t so_ext_len= sizeof(SO_EXT) - 1;
- if (my_strcasecmp(&my_charset_latin1, dl->str + dl->length - so_ext_len,
+ if (dl->length < so_ext_len ||
+ my_strcasecmp(&my_charset_latin1, dl->str + dl->length - so_ext_len,
SO_EXT))
{
char *s= (char*)alloc_root(root, dl->length + so_ext_len + 1);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 766cb28dfd1..019adceacc5 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -111,12 +111,19 @@ static void optimize_straight_join(JOIN *join, table_map join_tables);
static bool greedy_search(JOIN *join, table_map remaining_tables,
uint depth, uint prune_level,
uint use_cond_selectivity);
-static bool best_extension_by_limited_search(JOIN *join,
- table_map remaining_tables,
- uint idx, double record_count,
- double read_time, uint depth,
- uint prune_level,
- uint use_cond_selectivity);
+enum enum_best_search {
+ SEARCH_ABORT= -2,
+ SEARCH_ERROR= -1,
+ SEARCH_OK= 0,
+ SEARCH_FOUND_EDGE=1
+};
+static enum_best_search
+best_extension_by_limited_search(JOIN *join,
+ table_map remaining_tables,
+ uint idx, double record_count,
+ double read_time, uint depth,
+ uint prune_level,
+ uint use_cond_selectivity);
static uint determine_search_depth(JOIN* join);
C_MODE_START
static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
@@ -409,6 +416,7 @@ POSITION::POSITION()
range_rowid_filter_info= 0;
ref_depend_map= dups_producing_tables= 0;
inner_tables_handled_with_other_sjs= 0;
+ type= JT_UNKNOWN;
dups_weedout_picker.set_empty();
firstmatch_picker.set_empty();
loosescan_picker.set_empty();
@@ -8468,6 +8476,7 @@ best_access_path(JOIN *join,
pos->records_read= records;
pos->read_time= best;
pos->key= best_key;
+ pos->type= best_type;
pos->table= s;
pos->ref_depend_map= best_ref_depends_map;
pos->loosescan_picker.loosescan_key= MAX_KEY;
@@ -9123,9 +9132,12 @@ greedy_search(JOIN *join,
do {
/* Find the extension of the current QEP with the lowest cost */
join->best_read= DBL_MAX;
- if (best_extension_by_limited_search(join, remaining_tables, idx, record_count,
- read_time, search_depth, prune_level,
- use_cond_selectivity))
+ if ((int) best_extension_by_limited_search(join, remaining_tables, idx,
+ record_count,
+ read_time, search_depth,
+ prune_level,
+ use_cond_selectivity) <
+ (int) SEARCH_OK)
DBUG_RETURN(TRUE);
/*
'best_read < DBL_MAX' means that optimizer managed to find
@@ -9761,6 +9773,28 @@ exit:
}
+/*
+ Check if the table is an EQ_REF or similar table and there is no cost
+ to gain by moveing it to a later stage.
+ We call such a table a edge table (or hanging leaf) as it will read at
+ most one row and will not add to the number of row combinations in the join.
+*/
+
+static inline enum_best_search
+check_if_edge_table(POSITION *pos,
+ double pushdown_cond_selectivity)
+{
+
+ if ((pos->type == JT_EQ_REF ||
+ (pos->type == JT_REF &&
+ pos->records_read == 1 &&
+ !pos->range_rowid_filter_info)) &&
+ pushdown_cond_selectivity >= 0.999)
+ return SEARCH_FOUND_EDGE;
+ return SEARCH_OK;
+}
+
+
/**
Find a good, possibly optimal, query execution plan (QEP) by a possibly
exhaustive search.
@@ -9875,12 +9909,17 @@ exit:
pushed to a table should be taken into account
@retval
- FALSE ok
+ enum_best_search::SEARCH_OK All fine
@retval
- TRUE Fatal error
+ enum_best_search::SEARCH_FOUND_EDGE All remaning tables are edge tables
+ @retval
+ enum_best_search::SEARCH_ABORT Killed by user
+ @retval
+ enum_best_search::SEARCH_ERROR Fatal error
*/
-static bool
+
+static enum_best_search
best_extension_by_limited_search(JOIN *join,
table_map remaining_tables,
uint idx,
@@ -9890,9 +9929,17 @@ best_extension_by_limited_search(JOIN *join,
uint prune_level,
uint use_cond_selectivity)
{
- DBUG_ENTER("best_extension_by_limited_search");
-
THD *thd= join->thd;
+ /*
+ 'join' is a partial plan with lower cost than the best plan so far,
+ so continue expanding it further with the tables in 'remaining_tables'.
+ */
+ JOIN_TAB *s;
+ double best_record_count= DBL_MAX;
+ double best_read_time= DBL_MAX;
+ bool disable_jbuf= join->thd->variables.join_cache_level == 0;
+ enum_best_search best_res;
+ DBUG_ENTER("best_extension_by_limited_search");
DBUG_EXECUTE_IF("show_explain_probe_best_ext_lim_search",
if (dbug_user_var_equals_int(thd,
@@ -9902,19 +9949,7 @@ best_extension_by_limited_search(JOIN *join,
);
if (unlikely(thd->check_killed())) // Abort
- DBUG_RETURN(TRUE);
-
- DBUG_EXECUTE("opt", print_plan(join, idx, read_time, record_count, idx,
- "SOFAR:"););
-
- /*
- 'join' is a partial plan with lower cost than the best plan so far,
- so continue expanding it further with the tables in 'remaining_tables'.
- */
- JOIN_TAB *s;
- double best_record_count= DBL_MAX;
- double best_read_time= DBL_MAX;
- bool disable_jbuf= join->thd->variables.join_cache_level == 0;
+ DBUG_RETURN(SEARCH_ABORT);
DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time,
"part_plan"););
@@ -9930,15 +9965,18 @@ best_extension_by_limited_search(JOIN *join,
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{
table_map real_table_bit= s->table->map;
- if ((remaining_tables & real_table_bit) &&
- (allowed_tables & real_table_bit) &&
+ DBUG_ASSERT(remaining_tables & real_table_bit);
+
+ if ((allowed_tables & real_table_bit) &&
!(remaining_tables & s->dependent) &&
- (!idx || !check_interleaving_with_nj(s)))
+ !check_interleaving_with_nj(s))
{
double current_record_count, current_read_time;
+ double partial_join_cardinality;
POSITION *position= join->positions + idx;
-
+ POSITION loose_scan_pos;
Json_writer_object trace_one_table(thd);
+
if (unlikely(thd->trace_started()))
{
trace_plan_prefix(join, idx, remaining_tables);
@@ -9946,7 +9984,6 @@ best_extension_by_limited_search(JOIN *join,
}
/* Find the best access method from 's' to the current partial plan */
- POSITION loose_scan_pos;
best_access_path(join, s, remaining_tables, join->positions, idx,
disable_jbuf, record_count, position, &loose_scan_pos);
@@ -10021,32 +10058,51 @@ best_extension_by_limited_search(JOIN *join,
double pushdown_cond_selectivity= 1.0;
if (use_cond_selectivity > 1)
pushdown_cond_selectivity= table_cond_selectivity(join, idx, s,
- remaining_tables &
+ remaining_tables &
~real_table_bit);
join->positions[idx].cond_selectivity= pushdown_cond_selectivity;
- if (unlikely(thd->trace_started()) && pushdown_cond_selectivity < 1.0)
- trace_one_table.add("selectivity", pushdown_cond_selectivity);
+ partial_join_cardinality= (current_record_count *
+ pushdown_cond_selectivity);
- double partial_join_cardinality= current_record_count *
- pushdown_cond_selectivity;
- if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) & allowed_tables )
- { /* Recursively expand the current partial plan */
+ if (unlikely(thd->trace_started()))
+ {
+ if (pushdown_cond_selectivity < 1.0)
+ {
+ trace_one_table.add("selectivity", pushdown_cond_selectivity);
+ trace_one_table.add("estimated_join_cardinality",
+ partial_join_cardinality);
+ }
+ }
+
+ if ((search_depth > 1) && (remaining_tables & ~real_table_bit) &
+ allowed_tables)
+ {
+ /* Recursively expand the current partial plan */
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
Json_writer_array trace_rest(thd, "rest_of_plan");
- if (best_extension_by_limited_search(join,
- remaining_tables & ~real_table_bit,
- idx + 1,
- partial_join_cardinality,
- current_read_time,
- search_depth - 1,
- prune_level,
- use_cond_selectivity))
- DBUG_RETURN(TRUE);
+ best_res=
+ best_extension_by_limited_search(join,
+ remaining_tables &
+ ~real_table_bit,
+ idx + 1,
+ partial_join_cardinality,
+ current_read_time,
+ search_depth - 1,
+ prune_level,
+ use_cond_selectivity);
+ if ((int) best_res < (int) SEARCH_OK)
+ DBUG_RETURN(best_res); // Abort
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
+ if (best_res == SEARCH_FOUND_EDGE &&
+ check_if_edge_table(join->positions+ idx,
+ pushdown_cond_selectivity) !=
+ SEARCH_FOUND_EDGE)
+ best_res= SEARCH_OK;
}
else
- { /*
+ {
+ /*
'join' is either the best partial QEP with 'search_depth' relations,
or the best complete QEP so far, whichever is smaller.
*/
@@ -10055,15 +10111,13 @@ best_extension_by_limited_search(JOIN *join,
join->positions[join->const_tables].table->table)
{
/*
- We may have to make a temp table, note that this is only a
- heuristic since we cannot know for sure at this point.
- Hence it may be wrong.
+ We may have to make a temp table, note that this is only a
+ heuristic since we cannot know for sure at this point.
+ Hence it may be wrong.
*/
trace_one_table.add("cost_for_sorting", current_record_count);
current_read_time= COST_ADD(current_read_time, current_record_count);
}
- trace_one_table.add("estimated_join_cardinality",
- partial_join_cardinality);
if (current_read_time < join->best_read)
{
memcpy((uchar*) join->best_positions, (uchar*) join->positions,
@@ -10076,12 +10130,19 @@ best_extension_by_limited_search(JOIN *join,
read_time,
current_read_time,
"full_plan"););
+ best_res= check_if_edge_table(join->positions + idx,
+ pushdown_cond_selectivity);
}
restore_prev_nj_state(s);
restore_prev_sj_state(remaining_tables, s, idx);
+ if (best_res == SEARCH_FOUND_EDGE)
+ {
+ trace_one_table.add("pruned_by_hanging_leaf", true);
+ DBUG_RETURN(best_res);
+ }
}
}
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(SEARCH_OK);
}
@@ -17233,7 +17294,6 @@ static uint reset_nj_counters(JOIN *join, List<TABLE_LIST> *join_list)
static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
{
- TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding;
JOIN *join= next_tab->join;
if (join->cur_embedding_map & ~next_tab->embedding_map)
@@ -17245,6 +17305,7 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
return TRUE;
}
+ TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding;
/*
Do update counters for "pairs of brackets" that we've left (marked as
X,Y,Z in the above picture)
@@ -18430,14 +18491,17 @@ Field *Item_default_value::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
- if (field->default_value && (field->flags & BLOB_FLAG))
+ if (field->default_value || (field->flags & BLOB_FLAG))
{
/*
We have to use a copy function when using a blob with default value
as the we have to calculate the default value before we can use it.
*/
get_tmp_field_src(src, param);
- return tmp_table_field_from_field_type(root, table);
+ Field *result= tmp_table_field_from_field_type(root, table);
+ if (result && param->modify_item())
+ result_field= result;
+ return result;
}
/*
Same code as in Item_field::create_tmp_field_ex, except no default field
@@ -18874,6 +18938,7 @@ TABLE *Create_tmp_table::start(THD *thd,
table->copy_blobs= 1;
table->in_use= thd;
table->no_rows_with_nulls= param->force_not_null_cols;
+ table->expr_arena= thd;
table->s= share;
init_tmp_table_share(thd, share, "", 0, "(temporary)", tmpname);
@@ -25087,8 +25152,8 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
all_fields, false, true, from_window_spec))
return 1;
- if ((*order->item)->with_window_func() &&
- context_analysis_place != IN_ORDER_BY)
+ Item * const item= *order->item;
+ if (item->with_window_func() && context_analysis_place != IN_ORDER_BY)
{
my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0));
return 1;
@@ -25099,20 +25164,18 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
an ORDER BY clause
*/
- if (for_union &&
- ((*order->item)->with_sum_func() ||
- (*order->item)->with_window_func()))
+ if (for_union && (item->with_sum_func() || item->with_window_func()))
{
my_error(ER_AGGREGATE_ORDER_FOR_UNION, MYF(0), number);
return 1;
}
- if (!(*order->item)->with_sum_func())
- continue;
-
- 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);
+ if ((from_window_spec && item->with_sum_func() &&
+ item->type() != Item::SUM_FUNC_ITEM) || item->with_window_func())
+ {
+ item->split_sum_func(thd, ref_pointer_array,
+ all_fields, SPLIT_SUM_SELECT);
+ }
}
return 0;
}
@@ -26062,15 +26125,17 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
for (uint i= 0; (item= it++); i++)
{
Field *field;
- if ((item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) ||
- item->with_window_func())
+ enum Item::Type item_type= item->type();
+ if ((item->with_sum_func() && item_type != Item::SUM_FUNC_ITEM) ||
+ item->with_window_func())
item_field= item;
- else if (item->type() == Item::FIELD_ITEM)
+ else if (item_type == Item::FIELD_ITEM ||
+ item_type == Item::DEFAULT_VALUE_ITEM)
{
if (!(item_field= item->get_tmp_table_item(thd)))
DBUG_RETURN(true);
}
- else if (item->type() == Item::FUNC_ITEM &&
+ else if (item_type == Item::FUNC_ITEM &&
((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)
{
field= item->get_tmp_table_field();
@@ -27929,7 +27994,7 @@ static void print_table_array(THD *thd,
too)
*/
-static bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl)
+bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl)
{
return eliminated_tables &&
((tbl->table && (tbl->table->map & eliminated_tables)) ||
diff --git a/sql/sql_select.h b/sql/sql_select.h
index e6f63b465f6..34d689cf698 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -2,7 +2,7 @@
#define SQL_SELECT_INCLUDED
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2020, MariaDB Corporation.
+ Copyright (c) 2008, 2022, 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
@@ -989,6 +989,8 @@ public:
*/
enum sj_strategy_enum sj_strategy;
+ /* Type of join (EQ_REF, REF etc) */
+ enum join_type type;
/*
Valid only after fix_semijoin_strategies_for_picked_join_order() call:
if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that
@@ -2469,6 +2471,8 @@ int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort);
JOIN_TAB *first_explain_order_tab(JOIN* join);
JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab);
+bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl);
+
bool check_simple_equality(THD *thd, const Item::Context &ctx,
Item *left_item, Item *right_item,
COND_EQUAL *cond_equal);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 2134bb04f6e..04bec87ca13 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -5193,6 +5193,7 @@ public:
int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
+ DBUG_ENTER("get_all_tables");
LEX *lex= thd->lex;
TABLE *table= tables->table;
TABLE_LIST table_acl_check;
@@ -5210,7 +5211,29 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
uint table_open_method= tables->table_open_method;
bool can_deadlock;
MEM_ROOT tmp_mem_root;
- DBUG_ENTER("get_all_tables");
+ /*
+ We're going to open FRM files for tables.
+ In case of VIEWs that contain stored function calls,
+ these stored functions will be parsed and put to the SP cache.
+
+ Suppose we have a view containing a stored function call:
+ CREATE VIEW v1 AS SELECT f1() AS c1;
+ and now we're running:
+ SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=f1();
+ If a parallel thread invalidates the cache,
+ e.g. by creating or dropping some stored routine,
+ the SELECT query will re-parse f1() when processing "v1"
+ and replace the outdated cached version of f1() to a new one.
+ But the old version of f1() is referenced from the m_sp member
+ of the Item_func_sp instances used in the WHERE condition.
+ We cannot destroy it. To avoid such clashes, let's remember
+ all old routines into a temporary SP cache collection
+ and process tables with a new empty temporary SP cache collection.
+ Then restore to the old SP cache collection at the end.
+ */
+ Sp_caches old_sp_caches;
+
+ old_sp_caches.sp_caches_swap(*thd);
bzero(&tmp_mem_root, sizeof(tmp_mem_root));
@@ -5386,6 +5409,13 @@ err:
thd->restore_backup_open_tables_state(&open_tables_state_backup);
free_root(&tmp_mem_root, 0);
+ /*
+ Now restore to the saved SP cache collection
+ and clear the temporary SP cache collection.
+ */
+ old_sp_caches.sp_caches_swap(*thd);
+ old_sp_caches.sp_caches_clear();
+
DBUG_RETURN(error);
}
@@ -9093,7 +9123,7 @@ ST_FIELD_INFO columns_fields_info[]=
Column("ORDINAL_POSITION", ULonglong(), NOT_NULL, OPEN_FRM_ONLY),
Column("COLUMN_DEFAULT", Longtext(MAX_FIELD_VARCHARLENGTH),
NULLABLE, "Default",OPEN_FRM_ONLY),
- Column("IS_NULLABLE", Yesno(), NOT_NULL, "Null", OPEN_FRM_ONLY),
+ Column("IS_NULLABLE", Yes_or_empty(), NOT_NULL, "Null", OPEN_FRM_ONLY),
Column("DATA_TYPE", Name(), NOT_NULL, OPEN_FRM_ONLY),
Column("CHARACTER_MAXIMUM_LENGTH",ULonglong(), NULLABLE, OPEN_FRM_ONLY),
Column("CHARACTER_OCTET_LENGTH", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
@@ -9130,8 +9160,8 @@ ST_FIELD_INFO collation_fields_info[]=
Column("COLLATION_NAME", CSName(), NOT_NULL, "Collation"),
Column("CHARACTER_SET_NAME", CSName(), NOT_NULL, "Charset"),
Column("ID", SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL, "Id"),
- Column("IS_DEFAULT", Yesno(), NOT_NULL, "Default"),
- Column("IS_COMPILED", Yesno(), NOT_NULL, "Compiled"),
+ Column("IS_DEFAULT", Yes_or_empty(), NOT_NULL, "Default"),
+ Column("IS_COMPILED", Yes_or_empty(), NOT_NULL, "Compiled"),
Column("SORTLEN", SLonglong(3), NOT_NULL, "Sortlen"),
CEnd()
};
@@ -9139,10 +9169,10 @@ ST_FIELD_INFO collation_fields_info[]=
ST_FIELD_INFO applicable_roles_fields_info[]=
{
- Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("GRANTEE", Userhost(), NOT_NULL),
Column("ROLE_NAME", Varchar(USERNAME_CHAR_LENGTH), NOT_NULL),
- Column("IS_GRANTABLE", Yesno(), NOT_NULL),
- Column("IS_DEFAULT", Yesno(), NULLABLE),
+ Column("IS_GRANTABLE", Yes_or_empty(), NOT_NULL),
+ Column("IS_DEFAULT", Yes_or_empty(), NULLABLE),
CEnd()
};
@@ -9286,7 +9316,7 @@ ST_FIELD_INFO view_fields_info[]=
Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FRM_ONLY),
Column("VIEW_DEFINITION", Longtext(65535), NOT_NULL, OPEN_FRM_ONLY),
Column("CHECK_OPTION", Varchar(8), NOT_NULL, OPEN_FRM_ONLY),
- Column("IS_UPDATABLE", Yesno(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("IS_UPDATABLE", Yes_or_empty(), NOT_NULL, OPEN_FULL_TABLE),
Column("DEFINER", Definer(), NOT_NULL, OPEN_FRM_ONLY),
Column("SECURITY_TYPE", Varchar(7), NOT_NULL, OPEN_FRM_ONLY),
Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, OPEN_FRM_ONLY),
@@ -9298,46 +9328,46 @@ ST_FIELD_INFO view_fields_info[]=
ST_FIELD_INFO user_privileges_fields_info[]=
{
- Column("GRANTEE", Userhost(), NOT_NULL),
- Column("TABLE_CATALOG", Catalog(), NOT_NULL),
- Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
- Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yes_or_empty(), NOT_NULL),
CEnd()
};
ST_FIELD_INFO schema_privileges_fields_info[]=
{
- Column("GRANTEE", Userhost(), NOT_NULL),
- Column("TABLE_CATALOG", Catalog(), NOT_NULL),
- Column("TABLE_SCHEMA", Name(), NOT_NULL),
- Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
- Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yes_or_empty(), NOT_NULL),
CEnd()
};
ST_FIELD_INFO table_privileges_fields_info[]=
{
- Column("GRANTEE", Userhost(), NOT_NULL),
- Column("TABLE_CATALOG", Catalog(), NOT_NULL),
- Column("TABLE_SCHEMA", Name(), NOT_NULL),
- Column("TABLE_NAME", Name(), NOT_NULL),
- Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
- Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yes_or_empty(), NOT_NULL),
CEnd()
};
ST_FIELD_INFO column_privileges_fields_info[]=
{
- Column("GRANTEE", Userhost(), NOT_NULL),
- Column("TABLE_CATALOG", Catalog(), NOT_NULL),
- Column("TABLE_SCHEMA", Name(), NOT_NULL),
- Column("TABLE_NAME", Name(), NOT_NULL),
- Column("COLUMN_NAME", Name(), NOT_NULL),
- Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
- Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL),
+ Column("COLUMN_NAME", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yes_or_empty(), NOT_NULL),
CEnd()
};
@@ -9478,7 +9508,7 @@ ST_FIELD_INFO sysvars_fields_info[]=
Column("NUMERIC_MAX_VALUE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
Column("NUMERIC_BLOCK_SIZE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
Column("ENUM_VALUE_LIST", Longtext(65535), NULLABLE),
- Column("READ_ONLY", Yesno(), NOT_NULL),
+ Column("READ_ONLY", Yes_or_empty(), NOT_NULL),
Column("COMMAND_LINE_ARGUMENT",Name(), NULLABLE),
Column("GLOBAL_VALUE_PATH", Varchar(2048), NULLABLE),
CEnd()
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 43fa10fab3c..449478a7fa4 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2202,7 +2202,7 @@ bool check_duplicates_in_interval(const char *set_or_name,
bool Column_definition::
prepare_charset_for_string(const Column_derived_attributes *dattr)
{
- CHARSET_INFO *tmp= lex_charset_collation().
+ CHARSET_INFO *tmp= charset_collation_attrs().
resolved_to_character_set(dattr->charset());
if (!tmp)
return true;
@@ -3875,38 +3875,6 @@ bool validate_comment_length(THD *thd, LEX_CSTRING *comment, size_t max_len,
/*
- Set table default charset, if not set
-
- SYNOPSIS
- set_table_default_charset()
- create_info Table create information
-
- DESCRIPTION
- If the table character set was not given explicitly,
- let's fetch the database default character set and
- apply it to the table.
-*/
-
-static void set_table_default_charset(THD *thd, HA_CREATE_INFO *create_info,
- const LEX_CSTRING &db)
-{
- /*
- If the table character set was not given explicitly,
- let's fetch the database default character set and
- apply it to the table.
- */
- if (!create_info->default_table_charset)
- {
- Schema_specification_st db_info;
-
- load_db_opt_by_name(thd, db.str, &db_info);
-
- create_info->default_table_charset= db_info.default_table_charset;
- }
-}
-
-
-/*
Extend long VARCHAR fields to blob & prepare field if it's a blob
SYNOPSIS
@@ -4064,14 +4032,14 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db,
handler *file;
DBUG_ENTER("mysql_create_frm_image");
+ DBUG_ASSERT(create_info->default_table_charset);
+
if (!alter_info->create_list.elements)
{
my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
DBUG_RETURN(NULL);
}
- set_table_default_charset(thd, create_info, db);
-
db_options= create_info->table_options_with_row_type();
if (unlikely(!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
@@ -4345,6 +4313,7 @@ err:
@retval -1 table existed but IF NOT EXISTS was used
*/
+static
int create_table_impl(THD *thd,
DDL_LOG_STATE *ddl_log_state_create,
DDL_LOG_STATE *ddl_log_state_rm,
@@ -4365,6 +4334,8 @@ int create_table_impl(THD *thd,
DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d path: %s",
db.str, table_name.str, internal_tmp_table, path.str));
+ DBUG_ASSERT(create_info->default_table_charset);
+
/* Easy check for ddl logging if we are creating a temporary table */
if (create_info->tmp_table())
{
@@ -4703,6 +4674,8 @@ int mysql_create_table_no_lock(THD *thd,
LEX_CSTRING cpath;
LEX_CUSTRING frm= {0,0};
+ DBUG_ASSERT(create_info->default_table_charset);
+
if (create_info->tmp_table())
path_length= build_tmptable_filename(thd, path, sizeof(path));
else
@@ -4771,6 +4744,8 @@ int mysql_create_table_no_lock(THD *thd,
close of thread tables.
*/
+
+static
bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
Table_specification_st *create_info,
Alter_info *alter_info)
@@ -4784,6 +4759,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
bool result;
DBUG_ENTER("mysql_create_table");
+ DBUG_ASSERT(create_info->default_table_charset);
+
DBUG_ASSERT(create_table == thd->lex->query_tables);
bzero(&ddl_log_state_create, sizeof(ddl_log_state_create));
@@ -5222,6 +5199,7 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
TRUE error
*/
+static
bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
TABLE_LIST* src_table,
Table_specification_st *create_info)
@@ -5296,6 +5274,14 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
local_create_info.db_type= src_table->table->s->db_type();
local_create_info.row_type= src_table->table->s->row_type;
local_create_info.alter_info= &local_alter_info;
+ /*
+ This statement:
+ CREATE TABLE t1 LIKE t2
+ does not support table charset/collation clauses.
+ No needs to copy. Assert they are empty.
+ */
+ DBUG_ASSERT(create_info->default_charset_collation.is_empty());
+ DBUG_ASSERT(create_info->convert_charset_collation.is_empty());
if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
&local_alter_info, &local_alter_ctx))
goto err;
@@ -7949,12 +7935,14 @@ void append_drop_column(THD *thd, String *str, Field *field)
bool
mysql_prepare_alter_table(THD *thd, TABLE *table,
- HA_CREATE_INFO *create_info,
+ Table_specification_st *create_info,
Alter_info *alter_info,
Alter_table_ctx *alter_ctx)
{
/* New column definitions are added here */
List<Create_field> new_create_list;
+ /* System-invisible fields must be added last */
+ List<Create_field> new_create_tail;
/* New key definitions are added here */
List<Key> new_key_list;
List<Alter_rename_key> rename_key_list(alter_info->alter_rename_key_list);
@@ -8013,8 +8001,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
create_info->max_rows= table->s->max_rows;
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
create_info->avg_row_length= table->s->avg_row_length;
- if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
- create_info->default_table_charset= table->s->table_charset;
+
+ if (create_info->resolve_to_charset_collation_context(thd,
+ thd->charset_collation_context_alter_table(table->s)))
+ DBUG_RETURN(true);
+
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
{
/* Table has an autoincrement, copy value to new table */
@@ -8181,7 +8172,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
dropped_sys_vers_fields|= field->flags;
drop_it.remove();
}
- else
+ else if (field->invisible < INVISIBLE_SYSTEM)
{
/*
This field was not dropped and not changed, add it to the list
@@ -8232,6 +8223,12 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
alter_it.remove();
}
}
+ else
+ {
+ DBUG_ASSERT(field->invisible == INVISIBLE_SYSTEM);
+ def= new (thd->mem_root) Create_field(thd, field, field);
+ new_create_tail.push_back(def, thd->mem_root);
+ }
}
/*
@@ -8394,6 +8391,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
alter_it.remove();
}
}
+
+ new_create_list.append(&new_create_tail);
+
if (unlikely(alter_info->alter_list.elements))
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
@@ -9763,7 +9763,7 @@ static uint64 get_start_alter_id(THD *thd)
bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_name,
- HA_CREATE_INFO *create_info,
+ Table_specification_st *create_info,
TABLE_LIST *table_list,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore,
@@ -10356,7 +10356,7 @@ do_continue:;
DBUG_RETURN(true);
}
- set_table_default_charset(thd, create_info, alter_ctx.db);
+ DBUG_ASSERT(create_info->default_table_charset);
if (create_info->check_fields(thd, alter_info,
table_list->table_name, table_list->db) ||
@@ -11776,7 +11776,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
{
- HA_CREATE_INFO create_info;
+ Table_specification_st create_info;
Alter_info alter_info;
TABLE_LIST *next_table= table_list->next_global;
DBUG_ENTER("mysql_recreate_table");
@@ -11788,9 +11788,8 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
/* hide following tables from open_tables() */
table_list->next_global= NULL;
- bzero((char*) &create_info, sizeof(create_info));
+ create_info.init();
create_info.row_type=ROW_TYPE_NOT_USED;
- create_info.default_table_charset=default_charset_info;
create_info.alter_info= &alter_info;
/* Force alter table to recreate table */
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
@@ -12047,6 +12046,11 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
const bool used_engine= lex->create_info.used_fields & HA_CREATE_USED_ENGINE;
DBUG_ASSERT((m_storage_engine_name.str != NULL) == used_engine);
+
+ if (lex->create_info.resolve_to_charset_collation_context(thd,
+ thd->charset_collation_context_create_table_in_db(first_table->db.str)))
+ DBUG_RETURN(true);
+
if (used_engine)
{
if (resolve_storage_engine_with_error(thd, &lex->create_info.db_type,
@@ -12119,19 +12123,9 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
*/
if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
create_info.use_default_db_type(thd);
- /*
- If we are using SET CHARSET without DEFAULT, add an implicit
- DEFAULT to not confuse old users. (This may change).
- */
- if ((create_info.used_fields &
- (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
- HA_CREATE_USED_CHARSET)
- {
- create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
- create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- create_info.default_table_charset= create_info.alter_table_convert_to_charset;
- create_info.alter_table_convert_to_charset= 0;
- }
+
+ DBUG_ASSERT(!(create_info.used_fields & HA_CREATE_USED_CHARSET));
+ DBUG_ASSERT(create_info.convert_charset_collation.is_empty());
/*
If we are a slave, we should add OR REPLACE if we don't have
@@ -12357,3 +12351,46 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
end_with_restore_list:
DBUG_RETURN(res);
}
+
+
+bool HA_CREATE_INFO::
+ resolve_to_charset_collation_context(THD *thd,
+ const Lex_table_charset_collation_attrs_st &default_cscl_arg,
+ const Lex_table_charset_collation_attrs_st &convert_cscl,
+ const Charset_collation_context &ctx)
+{
+ /*
+ If CONVERT TO clauses are specified only (without table default clauses),
+ then we copy CONVERT TO clauses to default clauses, so e.g:
+ CONVERT TO CHARACTER SET utf8mb4
+ means
+ CONVERT TO CHARACTER SET utf8mb4, DEFAULT CHARACTER SET utf8mb4
+ */
+ Lex_table_charset_collation_attrs_st default_cscl=
+ !convert_cscl.is_empty() && default_cscl_arg.is_empty() ?
+ convert_cscl : default_cscl_arg;
+
+ if (default_cscl.is_empty())
+ default_table_charset= ctx.collate_default().charset_info();
+ else
+ {
+ // Make sure we don't do double resolution in direct SQL execution
+ DBUG_ASSERT(!default_table_charset || thd->stmt_arena->is_stmt_execute());
+ if (!(default_table_charset=
+ default_cscl.resolved_to_context(ctx)))
+ return true;
+ }
+
+ if (convert_cscl.is_empty())
+ alter_table_convert_to_charset= NULL;
+ else
+ {
+ // Make sure we don't do double resolution in direct SQL execution
+ DBUG_ASSERT(!alter_table_convert_to_charset ||
+ thd->stmt_arena->is_stmt_execute());
+ if (!(alter_table_convert_to_charset=
+ convert_cscl.resolved_to_context(ctx)))
+ return true;
+ }
+ return false;
+}
diff --git a/sql/sql_table.h b/sql/sql_table.h
index e3cfec9ca93..c9e4d969482 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -19,6 +19,7 @@
#include <my_sys.h> // pthread_mutex_t
#include "m_string.h" // LEX_CUSTRING
+#include "lex_charset.h"
#define ERROR_INJECT(code) \
((DBUG_IF("crash_" code) && (DBUG_SUICIDE(), 0)) || \
@@ -90,9 +91,6 @@ void build_lower_case_table_filename(char *buff, size_t bufflen,
const LEX_CSTRING *table,
uint flags);
uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen);
-bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
- Table_specification_st *create_info,
- Alter_info *alter_info);
bool add_keyword_to_query(THD *thd, String *result, const LEX_CSTRING *keyword,
const LEX_CSTRING *add);
@@ -156,14 +154,14 @@ int mysql_discard_or_import_tablespace(THD *thd,
bool discard);
bool mysql_prepare_alter_table(THD *thd, TABLE *table,
- HA_CREATE_INFO *create_info,
+ Table_specification_st *create_info,
Alter_info *alter_info,
Alter_table_ctx *alter_ctx);
bool mysql_trans_prepare_alter_copy_data(THD *thd);
bool mysql_trans_commit_alter_copy_data(THD *thd);
bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_name,
- HA_CREATE_INFO *create_info,
+ Table_specification_st *create_info,
TABLE_LIST *table_list,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore,
@@ -173,9 +171,6 @@ bool mysql_compare_tables(TABLE *table,
HA_CREATE_INFO *create_info,
bool *metadata_equal);
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy);
-bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
- TABLE_LIST *src_table,
- Table_specification_st *create_info);
bool mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
const LEX_CSTRING *old_name, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_name, LEX_CUSTRING *id,
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index be6e120716d..d80342a8395 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -1209,4 +1209,3 @@ bool JOIN::transform_in_predicates_into_in_subq(THD *thd)
thd->lex->current_select= save_current_select;
DBUG_RETURN(false);
}
-
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 69ca474eee1..0ede2b3fee2 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -2295,7 +2295,6 @@ Type_handler_decimal_result::make_num_distinct_aggregator_field(
const Item *item)
const
{
- DBUG_ASSERT(item->decimals <= DECIMAL_MAX_SCALE);
return new (mem_root)
Field_new_decimal(NULL, item->max_length,
(uchar *) (item->maybe_null() ? "" : 0),
@@ -2716,7 +2715,7 @@ Type_handler::Column_definition_set_attributes(THD *thd,
column_definition_type_t type)
const
{
- def->set_lex_charset_collation(attr.lex_charset_collation());
+ def->set_charset_collation_attrs(attr.charset_collation_attrs());
def->set_length_and_dec(attr);
return false;
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 82ef47608b9..74ed078e936 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -2130,10 +2130,9 @@ int multi_update::prepare(List<Item> &not_used_values,
if (!tl)
DBUG_RETURN(1);
update.link_in_list(tl, &tl->next_local);
- tl->shared= table_count++;
+ table_ref->shared= tl->shared= table_count++;
table->no_keyread=1;
table->covering_keys.clear_all();
- table->pos_in_table_list= tl;
table->prepare_triggers_for_update_stmt_or_event();
table->reset_default_fields();
}
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index e50a17333e8..c0acecd138f 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2016, 2017 MariaDB
+ Copyright (c) 2016, 2022 MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -424,16 +424,49 @@ ORDER *st_select_lex::find_common_window_func_partition_fields(THD *thd)
#define CMP_GT 2 // Greater then
static
-int compare_order_elements(ORDER *ord1, ORDER *ord2)
+int compare_order_elements(ORDER *ord1, int weight1,
+ ORDER *ord2, int weight2)
{
if (*ord1->item == *ord2->item && ord1->direction == ord2->direction)
return CMP_EQ;
Item *item1= (*ord1->item)->real_item();
Item *item2= (*ord2->item)->real_item();
- DBUG_ASSERT(item1->type() == Item::FIELD_ITEM &&
- item2->type() == Item::FIELD_ITEM);
- int cmp= ((Item_field *) item1)->field->field_index -
- ((Item_field *) item2)->field->field_index;
+
+ bool item1_field= (item1->type() == Item::FIELD_ITEM);
+ bool item2_field= (item2->type() == Item::FIELD_ITEM);
+
+ ptrdiff_t cmp;
+ if (item1_field && item2_field)
+ {
+ DBUG_ASSERT(((Item_field *) item1)->field->table ==
+ ((Item_field *) item2)->field->table);
+ cmp= ((Item_field *) item1)->field->field_index -
+ ((Item_field *) item2)->field->field_index;
+ }
+ else if (item1_field && !item2_field)
+ return CMP_LT;
+ else if (!item1_field && item2_field)
+ return CMP_LT;
+ else
+ {
+ /*
+ Ok, item1_field==NULL and item2_field==NULL.
+ We're not able to compare Item expressions. Order them according to
+ their passed "weight" (which comes from Window_spec::win_spec_number):
+ */
+ if (weight1 != weight2)
+ cmp= weight1 - weight2;
+ else
+ {
+ /*
+ The weight is the same. That is, the elements come from the same
+ window specification... This shouldn't happen.
+ */
+ DBUG_ASSERT(0);
+ cmp= item1 - item2;
+ }
+ }
+
if (cmp == 0)
{
if (ord1->direction == ord2->direction)
@@ -446,7 +479,9 @@ int compare_order_elements(ORDER *ord1, ORDER *ord2)
static
int compare_order_lists(SQL_I_List<ORDER> *part_list1,
- SQL_I_List<ORDER> *part_list2)
+ int spec_number1,
+ SQL_I_List<ORDER> *part_list2,
+ int spec_number2)
{
if (part_list1 == part_list2)
return CMP_EQ;
@@ -471,7 +506,8 @@ int compare_order_lists(SQL_I_List<ORDER> *part_list1,
if (!elem1 || !elem2)
break;
- if ((cmp= compare_order_elements(elem1, elem2)))
+ if ((cmp= compare_order_elements(elem1, spec_number1,
+ elem2, spec_number2)))
return cmp;
}
if (elem1)
@@ -566,7 +602,9 @@ int compare_window_spec_joined_lists(Window_spec *win_spec1,
win_spec1->join_partition_and_order_lists();
win_spec2->join_partition_and_order_lists();
int cmp= compare_order_lists(win_spec1->partition_list,
- win_spec2->partition_list);
+ win_spec1->win_spec_number,
+ win_spec2->partition_list,
+ win_spec2->win_spec_number);
win_spec1->disjoin_partition_and_order_lists();
win_spec2->disjoin_partition_and_order_lists();
return cmp;
@@ -584,7 +622,9 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
if (win_spec1 == win_spec2)
return CMP_EQ;
cmp= compare_order_lists(win_spec1->partition_list,
- win_spec2->partition_list);
+ win_spec1->win_spec_number,
+ win_spec2->partition_list,
+ win_spec2->win_spec_number);
if (cmp == CMP_EQ)
{
/*
@@ -603,7 +643,9 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
}
cmp= compare_order_lists(win_spec1->order_list,
- win_spec2->order_list);
+ win_spec1->win_spec_number,
+ win_spec2->order_list,
+ win_spec2->win_spec_number);
if (cmp != CMP_EQ)
return cmp;
@@ -696,7 +738,9 @@ void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list)
int cmp;
if (win_spec_prev->partition_list == win_spec_curr->partition_list)
cmp= compare_order_lists(win_spec_prev->order_list,
- win_spec_curr->order_list);
+ win_spec_prev->win_spec_number,
+ win_spec_curr->order_list,
+ win_spec_curr->win_spec_number);
else
cmp= compare_window_spec_joined_lists(win_spec_prev, win_spec_curr);
if (!(CMP_LT_C <= cmp && cmp <= CMP_GT_C))
diff --git a/sql/sql_window.h b/sql/sql_window.h
index 5e76a33dcd0..66ea8c7dd4d 100644
--- a/sql/sql_window.h
+++ b/sql/sql_window.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2016, 2017 MariaDB
+ Copyright (c) 2016, 2022 MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -120,10 +120,15 @@ class Window_spec : public Sql_alloc
Window_spec *referenced_win_spec;
- Window_spec(LEX_CSTRING *win_ref,
- SQL_I_List<ORDER> *part_list,
- SQL_I_List<ORDER> *ord_list,
- Window_frame *win_frame)
+ /*
+ Window_spec objects are numbered by the number of their appearance in the
+ query. This is used by compare_order_elements() to provide a predictable
+ ordering of PARTITION/ORDER BY clauses.
+ */
+ int win_spec_number;
+
+ Window_spec(LEX_CSTRING *win_ref, SQL_I_List<ORDER> *part_list,
+ SQL_I_List<ORDER> *ord_list, Window_frame *win_frame)
: window_names_are_checked(false), window_ref(win_ref),
partition_list(part_list), save_partition_list(NULL),
order_list(ord_list), save_order_list(NULL),
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 826c470511f..80d6c12e4e5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -213,7 +213,9 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)()
Lex_length_and_dec_st Lex_length_and_dec;
Lex_cast_type_st Lex_cast_type;
Lex_field_type_st Lex_field_type;
- Lex_charset_collation_st Lex_charset_collation;
+ Lex_exact_charset_extended_collation_attrs_st
+ Lex_exact_charset_extended_collation_attrs;
+ Lex_extended_collation_st Lex_extended_collation;
Lex_dyncol_type_st Lex_dyncol_type;
Lex_for_loop_st for_loop;
Lex_for_loop_bounds_st for_loop_bounds;
@@ -343,12 +345,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/
%ifdef MARIADB
-%expect 67
+%expect 71
%else
-%expect 69
+%expect 72
%endif
-
/*
Comments for TOKENS.
For each token, please include in the same line a comment that contains
@@ -376,6 +377,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/
%token <NONE> ABORT_SYM /* INTERNAL (used in lex) */
%token <NONE> IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */
+%token <NONE> FORCE_LOOKAHEAD /* INTERNAL never returned by the lexer */
%token <NONE> END_OF_INPUT /* INTERNAL */
%token <kwd> COLON_ORACLE_SYM /* INTERNAL */
%token <kwd> PARAM_MARKER /* INTERNAL */
@@ -389,7 +391,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <NONE> WITH_ROLLUP_SYM /* INTERNAL */
%token <NONE> WITH_SYSTEM_SYM /* INTERNAL */
-
/*
Identifiers
*/
@@ -1379,7 +1380,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
field_type_misc
json_table_field_type
-%type <Lex_charset_collation>
+%type <Lex_exact_charset_extended_collation_attrs>
binary
opt_binary
opt_binary_and_compression
@@ -1387,6 +1388,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
attribute_list
field_def
+%type <Lex_extended_collation>
+ collation_name
+ collation_name_or_default
+
%type <Lex_dyncol_type> opt_dyncol_type dyncol_type
numeric_dyncol_type temporal_dyncol_type string_dyncol_type
@@ -1579,14 +1584,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
text_or_password
%type <charset>
- opt_collate_or_default
charset_name
charset_or_alias
charset_name_or_default
old_or_new_charset_name
old_or_new_charset_name_or_default
- collation_name
- collation_name_or_default
opt_load_data_charset
UNDERSCORE_CHARSET
@@ -2367,9 +2369,9 @@ create:
If the table exists, we should either not create it or replace it
*/
lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
- lex->create_info.default_table_charset= NULL;
lex->name= null_clex_str;
lex->create_last_non_select_table= lex->last_table();
+ lex->inc_select_stack_outer_barrier();
}
create_body
{
@@ -2509,9 +2511,7 @@ create:
}
| create_or_replace DATABASE opt_if_not_exists ident
{
- Lex->create_info.default_table_charset= NULL;
- Lex->create_info.schema_comment= NULL;
- Lex->create_info.used_fields= 0;
+ Lex->create_info.init();
}
opt_create_database_options
{
@@ -2709,6 +2709,9 @@ sequence_def:
}
;
+/* this rule is used to force look-ahead in the parser */
+force_lookahead: {} | FORCE_LOOKAHEAD {} ;
+
server_def:
SERVER_SYM opt_if_not_exists ident_or_text
{
@@ -2910,7 +2913,7 @@ ev_sql_stmt:
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
}
- sp_proc_stmt
+ sp_proc_stmt force_lookahead
{
/* return back to the original memory root ASAP */
if (Lex->sp_body_finalize_event(thd))
@@ -5527,15 +5530,9 @@ default_charset:
default_collation:
opt_default COLLATE_SYM opt_equal collation_name_or_default
{
- HA_CREATE_INFO *cinfo= &Lex->create_info;
- if (unlikely((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
- cinfo->default_table_charset && $4 &&
- !($4= merge_charset_and_collation(cinfo->default_table_charset,
- $4))))
+ Table_specification_st *cinfo= &Lex->create_info;
+ if (unlikely(cinfo->add_table_option_default_collation($4)))
MYSQL_YYABORT;
-
- Lex->create_info.default_table_charset= $4;
- Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
}
;
@@ -5786,10 +5783,10 @@ field_type_or_serial:
}
field_def
{
- Lex_charset_collation tmp= $1.lex_charset_collation();
- if (tmp.merge_charset_clause_and_collate_clause($3))
+ auto tmp= $1.charset_collation_attrs();
+ if (tmp.merge_column_charset_clause_and_collate_clause($3))
MYSQL_YYABORT;
- Lex->last_field->set_lex_charset_collation(tmp);
+ Lex->last_field->set_charset_collation_attrs(tmp);
}
| SERIAL_SYM
{
@@ -5827,7 +5824,7 @@ field_def:
| attribute_list compressed_deprecated_column_attribute { $$= $1; }
| attribute_list compressed_deprecated_column_attribute attribute_list
{
- if (($$= $1).merge_collate_clause_and_collate_clause($3))
+ if (($$= $1).merge_column_collate_clause_and_collate_clause($3))
MYSQL_YYABORT;
}
| opt_generated_always AS virtual_column_func
@@ -6076,7 +6073,7 @@ field_type_string:
| nchar opt_field_length opt_bin_mod
{
$$.set(&type_handler_string, $2,
- Lex_charset_collation::national($3));
+ Lex_exact_charset_extended_collation_attrs::national($3));
}
| BINARY opt_field_length
{
@@ -6093,7 +6090,7 @@ field_type_string:
| nvarchar opt_field_length opt_compressed opt_bin_mod
{
$$.set(&type_handler_varchar, $2,
- Lex_charset_collation::national($4));
+ Lex_exact_charset_extended_collation_attrs::national($4));
}
| VARBINARY opt_field_length opt_compressed
{
@@ -6308,7 +6305,7 @@ opt_precision:
attribute_list:
attribute_list attribute
{
- if (($$= $1).merge_collate_clause_and_collate_clause($2))
+ if (($$= $1).merge_column_collate_clause_and_collate_clause($2))
MYSQL_YYABORT;
}
| attribute
@@ -6335,7 +6332,7 @@ attribute:
}
| COLLATE_SYM collation_name
{
- $$.set_collate_exact($2);
+ $$= Lex_exact_charset_extended_collation_attrs($2);
}
| serial_attribute { $$.init(); }
;
@@ -6475,20 +6472,17 @@ old_or_new_charset_name_or_default:
collation_name:
ident_or_text
{
- if (unlikely(!($$= mysqld_collation_get_by_name($1.str,
+ CHARSET_INFO *cs;
+ if (unlikely(!(cs= mysqld_collation_get_by_name($1.str,
thd->get_utf8_flag()))))
MYSQL_YYABORT;
+ $$= Lex_extended_collation(Lex_exact_collation(cs));
}
;
-opt_collate_or_default:
- /* empty */ { $$=NULL; }
- | COLLATE_SYM collation_name_or_default { $$=$2; }
- ;
-
collation_name_or_default:
collation_name { $$=$1; }
- | DEFAULT { $$=NULL; }
+ | DEFAULT { $$.set_collate_default(); }
;
opt_default:
@@ -6531,11 +6525,18 @@ binary:
}
| charset_or_alias COLLATE_SYM collation_name
{
- if ($$.set_charset_collate_exact($1, $3))
+ if ($3.merge_exact_charset(Lex_exact_charset($1)))
MYSQL_YYABORT;
+ $$= Lex_exact_charset_extended_collation_attrs($3);
+ }
+ | COLLATE_SYM collation_name
+ {
+ $$= Lex_exact_charset_extended_collation_attrs($2);
+ }
+ | COLLATE_SYM DEFAULT
+ {
+ $$.set_collate_default();
}
- | COLLATE_SYM collation_name { $$.set_collate_exact($2); }
- | COLLATE_SYM DEFAULT { $$.set_collate_default(); }
;
opt_bin_mod:
@@ -6943,9 +6944,7 @@ alter:
}
| ALTER DATABASE ident_or_empty
{
- Lex->create_info.default_table_charset= NULL;
- Lex->create_info.schema_comment= NULL;
- Lex->create_info.used_fields= 0;
+ Lex->create_info.init();
if (Lex->main_select_push(true))
MYSQL_YYABORT;
}
@@ -6961,8 +6960,7 @@ alter:
}
| ALTER DATABASE COMMENT_SYM opt_equal TEXT_STRING_sys
{
- Lex->create_info.default_table_charset= NULL;
- Lex->create_info.used_fields= 0;
+ Lex->create_info.init();
Lex->create_info.schema_comment= thd->make_clex_string($5);
Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
}
@@ -7606,19 +7604,15 @@ alter_list_item:
lex->alter_info.flags|= ALTER_RENAME_INDEX;
}
| CONVERT_SYM TO_SYM charset charset_name_or_default
- opt_collate_or_default
{
- if (!$4)
- {
- $4= thd->variables.collation_database;
- }
- $5= $5 ? $5 : $4;
- if (unlikely(!my_charset_same($4,$5)))
- my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- $5->coll_name.str, $4->cs_name.str));
- if (unlikely(Lex->create_info.add_alter_list_item_convert_to_charset($5)))
+ if (Lex->add_alter_list_item_convert_to_charset($4))
+ MYSQL_YYABORT;
+ }
+ | CONVERT_SYM TO_SYM charset charset_name_or_default
+ COLLATE_SYM collation_name_or_default
+ {
+ if (Lex->add_alter_list_item_convert_to_charset($4, $6))
MYSQL_YYABORT;
- Lex->alter_info.flags|= ALTER_CONVERT_TO;
}
| create_table_options_space_separated
{
@@ -9735,7 +9729,9 @@ string_factor_expr:
primary_expr
| string_factor_expr COLLATE_SYM collation_name
{
- if (unlikely(!($$= new (thd->mem_root) Item_func_set_collation(thd, $1, $3))))
+ if (unlikely(!($$= new (thd->mem_root)
+ Item_func_set_collation(thd, $1,
+ $3.charset_info()))))
MYSQL_YYABORT;
}
;
@@ -11355,7 +11351,7 @@ json_table_column_type:
COLUMN_DEFINITION_TABLE_FIELD);
if (Lex->json_table->m_cur_json_table_column->
set(thd, Json_table_column::PATH, $3,
- $1.lex_charset_collation()))
+ $1.charset_collation_attrs()))
{
MYSQL_YYABORT;
}
@@ -11366,7 +11362,7 @@ json_table_column_type:
COLUMN_DEFINITION_TABLE_FIELD);
if (Lex->json_table->m_cur_json_table_column->
set(thd, Json_table_column::EXISTS_PATH, $4,
- $1.lex_charset_collation()))
+ $1.charset_collation_attrs()))
MYSQL_YYABORT;
}
;
@@ -12946,6 +12942,7 @@ insert_start: {
if (Lex->main_select_push())
MYSQL_YYABORT;
mysql_init_select(Lex);
+ Lex->inc_select_stack_outer_barrier();
Lex->current_select->parsing_place= BEFORE_OPT_LIST;
}
;
@@ -16576,26 +16573,20 @@ option_value_no_option_type:
thd->parse_error();
MYSQL_YYABORT;
}
- | NAMES_SYM charset_name_or_default opt_collate_or_default
+ | NAMES_SYM charset_name_or_default
{
- if (sp_create_assignment_lex(thd, $1.pos()))
+ CHARSET_INFO *def= global_system_variables.character_set_client;
+ Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false);
+ if (Lex->set_names($1.pos(), tmp, yychar == YYEMPTY))
MYSQL_YYABORT;
- LEX *lex= Lex;
- CHARSET_INFO *cs2;
- CHARSET_INFO *cs3;
- cs2= $2 ? $2 : global_system_variables.character_set_client;
- cs3= $3 ? $3 : cs2;
- if (unlikely(!my_charset_same(cs2, cs3)))
- {
- my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- cs3->coll_name.str, cs2->cs_name.str);
- MYSQL_YYABORT;
- }
- set_var_collation_client *var;
- var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3);
- if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
- unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ }
+ | NAMES_SYM charset_name_or_default
+ COLLATE_SYM collation_name_or_default
+ {
+ CHARSET_INFO *def= global_system_variables.character_set_client;
+ Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false);
+ if (tmp.merge_collation($4) ||
+ Lex->set_names($1.pos(), tmp, yychar == YYEMPTY))
MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role
@@ -17776,8 +17767,8 @@ trigger_tail:
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
}
- sp_proc_stmt /* $19 */
- { /* $20 */
+ sp_proc_stmt /* $19 */ force_lookahead /* $20 */
+ { /* $21 */
LEX *lex= Lex;
lex->sql_command= SQLCOM_CREATE_TRIGGER;
@@ -17817,7 +17808,6 @@ sf_return_type:
}
;
-
/*************************************************************************/
xa:
@@ -18155,7 +18145,7 @@ sf_c_chistics_and_body_standalone:
lex->sphead->set_c_chistics(lex->sp_chistics);
lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
- sp_proc_stmt_in_returns_clause
+ sp_proc_stmt_in_returns_clause force_lookahead
{
if (unlikely(Lex->sp_body_finalize_function(thd)))
MYSQL_YYABORT;
@@ -18176,7 +18166,7 @@ sp_tail_standalone:
Lex->sphead->set_c_chistics(Lex->sp_chistics);
Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
- sp_proc_stmt
+ sp_proc_stmt force_lookahead
{
if (unlikely(Lex->sp_body_finalize_procedure(thd)))
MYSQL_YYABORT;
@@ -19027,8 +19017,7 @@ sf_c_chistics_and_body_standalone:
lex->sphead->set_c_chistics(lex->sp_chistics);
lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
- sp_tail_is
- sp_body
+ sp_tail_is sp_body force_lookahead
{
if (unlikely(Lex->sp_body_finalize_function(thd)))
MYSQL_YYABORT;
diff --git a/sql/structs.h b/sql/structs.h
index eab15c4d92b..52e47d5d7ee 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -699,17 +699,18 @@ public:
}
void set(const Type_handler *handler,
const Lex_length_and_dec_st &length_and_dec,
- const Lex_charset_collation_st &coll)
+ const Lex_column_charset_collation_attrs_st &coll)
{
m_handler= handler;
- m_ci= coll.charset_collation();
+ m_ci= coll.charset_info();
Lex_length_and_dec_st::operator=(length_and_dec);
m_collation_type= ((uint8) coll.type()) & 0x3;
}
- void set(const Type_handler *handler, const Lex_charset_collation_st &coll)
+ void set(const Type_handler *handler,
+ const Lex_column_charset_collation_attrs_st &coll)
{
m_handler= handler;
- m_ci= coll.charset_collation();
+ m_ci= coll.charset_info();
Lex_length_and_dec_st::reset();
m_collation_type= ((uint8) coll.type()) & 0x3;
}
@@ -734,10 +735,10 @@ public:
}
const Type_handler *type_handler() const { return m_handler; }
CHARSET_INFO *charset_collation() const { return m_ci; }
- Lex_charset_collation lex_charset_collation() const
+ Lex_column_charset_collation_attrs charset_collation_attrs() const
{
- return Lex_charset_collation(m_ci,
- (Lex_charset_collation_st::Type)
+ return Lex_column_charset_collation_attrs(m_ci,
+ (Lex_column_charset_collation_attrs_st::Type)
m_collation_type);
}
};
@@ -768,7 +769,7 @@ public:
m_ci= cs;
Lex_length_and_dec_st::reset();
}
- bool set(int type, const Lex_charset_collation_st &collation,
+ bool set(int type, const Lex_column_charset_collation_attrs_st &collation,
CHARSET_INFO *charset)
{
CHARSET_INFO *tmp= collation.resolved_to_character_set(charset);
diff --git a/sql/table.cc b/sql/table.cc
index efa7ae3a5b6..f0d51495953 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -45,30 +45,20 @@
#include "ha_sequence.h"
#include "sql_show.h"
#include "opt_trace.h"
+#include "sql_db.h" // get_default_db_collation
/* For MySQL 5.7 virtual fields */
#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;
- }
-};
-
bool TABLE::init_expr_arena(MEM_ROOT *mem_root)
{
/*
We need to use CONVENTIONAL_EXECUTION here to ensure that
any new items created by fix_fields() are not reverted.
*/
- expr_arena= new (alloc_root(mem_root, sizeof(Table_arena)))
- Table_arena(mem_root, Query_arena::STMT_CONVENTIONAL_EXECUTION);
+ expr_arena= new (alloc_root(mem_root, sizeof(Query_arena)))
+ Query_arena(mem_root, Query_arena::STMT_CONVENTIONAL_EXECUTION);
return expr_arena == NULL;
}
@@ -3514,6 +3504,19 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
else
thd->set_n_backup_active_arena(arena, &backup);
+ /*
+ THD::reset_db() does not set THD::db_charset,
+ so it keeps pointing to the character set and collation
+ of the current database, rather than the database of the
+ new initialized table. After reset_db() the result of
+ get_default_db_collation() can be wrong. The latter is
+ used inside charset_collation_context_create_table_in_db().
+ Let's initialize ctx before calling reset_db().
+ This makes sure the db.opt file to be loaded properly when needed.
+ */
+ Charset_collation_context
+ ctx(thd->charset_collation_context_create_table_in_db(db.str));
+
thd->reset_db(&db);
lex_start(thd);
@@ -3521,6 +3524,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
sql_unusable_for_discovery(thd, hton, sql_copy))))
goto ret;
+ if (thd->lex->create_info.resolve_to_charset_collation_context(thd, ctx))
+ DBUG_RETURN(true);
+
thd->lex->create_info.db_type= hton;
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0; // For partitioning
@@ -3659,8 +3665,7 @@ class Vcol_expr_context
bool inited;
THD *thd;
TABLE *table;
- LEX *old_lex;
- LEX lex;
+ Query_arena backup_arena;
table_map old_map;
Security_context *save_security_ctx;
sql_mode_t save_sql_mode;
@@ -3670,7 +3675,6 @@ public:
inited(false),
thd(_thd),
table(_table),
- old_lex(thd->lex),
old_map(table->map),
save_security_ctx(thd->security_ctx),
save_sql_mode(thd->variables.sql_mode) {}
@@ -3682,18 +3686,6 @@ public:
bool Vcol_expr_context::init()
{
- /*
- As this is vcol expression we must narrow down name resolution to
- single table.
- */
- if (init_lex_with_single_table(thd, table, &lex))
- {
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- table->map= old_map;
- return true;
- }
-
- lex.sql_command= old_lex->sql_command;
thd->variables.sql_mode= 0;
TABLE_LIST const *tl= table->pos_in_table_list;
@@ -3702,6 +3694,8 @@ bool Vcol_expr_context::init()
if (table->pos_in_table_list->security_ctx)
thd->security_ctx= tl->security_ctx;
+ thd->set_n_backup_active_arena(table->expr_arena, &backup_arena);
+
inited= true;
return false;
}
@@ -3710,9 +3704,9 @@ Vcol_expr_context::~Vcol_expr_context()
{
if (!inited)
return;
- end_lex_with_single_table(thd, table, old_lex);
table->map= old_map;
thd->security_ctx= save_security_ctx;
+ thd->restore_active_arena(table->expr_arena, &backup_arena);
thd->variables.sql_mode= save_sql_mode;
}
@@ -4111,6 +4105,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
outparam->s= share;
outparam->db_stat= db_stat;
outparam->write_row_record= NULL;
+ outparam->status= STATUS_NO_RECORD;
if (share->incompatible_version &&
!(ha_open_flags & (HA_OPEN_FOR_ALTER | HA_OPEN_FOR_REPAIR |
@@ -6960,7 +6955,7 @@ Item *Field_iterator_view::create_item(THD *thd)
Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
LEX_CSTRING *name)
{
- bool save_wrapper= thd->lex->first_select_lex()->no_wrap_view_item;
+ bool save_wrapper= thd->lex->current_select->no_wrap_view_item;
Item *field= *field_ref;
DBUG_ENTER("create_view_field");
diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h
index 70759e381a5..f99d33094df 100644
--- a/sql/wsrep_trans_observer.h
+++ b/sql/wsrep_trans_observer.h
@@ -232,6 +232,10 @@ static inline int wsrep_before_prepare(THD* thd, bool all)
WSREP_DEBUG("wsrep_before_prepare: %d", wsrep_is_real(thd, all));
int ret= 0;
DBUG_ASSERT(wsrep_run_commit_hook(thd, all));
+ if ((ret= thd->wsrep_parallel_slave_wait_for_prior_commit()))
+ {
+ DBUG_RETURN(ret);
+ }
if ((ret= thd->wsrep_cs().before_prepare()) == 0)
{
DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined());