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