summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h13
-rw-r--r--sql/create_options.cc5
-rw-r--r--sql/field.cc14
-rw-r--r--sql/field.h3
-rw-r--r--sql/filesort.cc14
-rw-r--r--sql/ha_partition.cc6
-rw-r--r--sql/handler.cc9
-rw-r--r--sql/handler.h14
-rw-r--r--sql/item.cc47
-rw-r--r--sql/item.h35
-rw-r--r--sql/item_cmpfunc.cc33
-rw-r--r--sql/item_cmpfunc.h7
-rw-r--r--sql/item_create.cc36
-rw-r--r--sql/item_func.cc3
-rw-r--r--sql/item_geofunc.cc146
-rw-r--r--sql/item_geofunc.h14
-rw-r--r--sql/item_subselect.cc71
-rw-r--r--sql/item_subselect.h7
-rw-r--r--sql/item_sum.cc25
-rw-r--r--sql/key.cc9
-rw-r--r--sql/log.cc4
-rw-r--r--sql/log.h4
-rw-r--r--sql/log_event.cc48
-rw-r--r--sql/mdl.cc11
-rw-r--r--sql/mf_iocache_encr.cc15
-rw-r--r--sql/mysqld.cc47
-rw-r--r--sql/mysqld.h4
-rw-r--r--sql/opt_range.cc159
-rw-r--r--sql/opt_sum.cc3
-rw-r--r--sql/partition_info.cc4
-rw-r--r--sql/protocol.cc6
-rw-r--r--sql/rpl_gtid.cc4
-rw-r--r--sql/rpl_injector.cc56
-rw-r--r--sql/rpl_parallel.cc5
-rw-r--r--sql/rpl_rli.cc22
-rw-r--r--sql/signal_handler.cc14
-rw-r--r--sql/slave.cc196
-rw-r--r--sql/sp_head.cc8
-rw-r--r--sql/spatial.cc189
-rw-r--r--sql/spatial.h22
-rw-r--r--sql/sql_acl.cc9
-rw-r--r--sql/sql_admin.cc20
-rw-r--r--sql/sql_base.cc156
-rw-r--r--sql/sql_cache.cc4
-rw-r--r--sql/sql_cache.h2
-rw-r--r--sql/sql_class.cc28
-rw-r--r--sql/sql_class.h75
-rw-r--r--sql/sql_connect.cc4
-rw-r--r--sql/sql_cte.cc27
-rw-r--r--sql/sql_derived.cc33
-rw-r--r--sql/sql_handler.cc5
-rw-r--r--sql/sql_help.cc3
-rw-r--r--sql/sql_insert.cc7
-rw-r--r--sql/sql_join_cache.cc93
-rw-r--r--sql/sql_join_cache.h11
-rw-r--r--sql/sql_lex.cc11
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_manager.cc87
-rw-r--r--sql/sql_manager.h2
-rw-r--r--sql/sql_parse.cc323
-rw-r--r--sql/sql_parse.h1
-rw-r--r--sql/sql_plugin.h5
-rw-r--r--sql/sql_plugin_services.ic1
-rw-r--r--sql/sql_prepare.cc36
-rw-r--r--sql/sql_repl.cc17
-rw-r--r--sql/sql_repl.h1
-rw-r--r--sql/sql_select.cc56
-rw-r--r--sql/sql_select.h18
-rw-r--r--sql/sql_show.cc33
-rw-r--r--sql/sql_statistics.cc108
-rw-r--r--sql/sql_statistics.h11
-rw-r--r--sql/sql_string.cc11
-rw-r--r--sql/sql_table.cc13
-rw-r--r--sql/sql_test.cc7
-rw-r--r--sql/sql_truncate.cc9
-rw-r--r--sql/sql_type.h2
-rw-r--r--sql/sql_union.cc107
-rw-r--r--sql/sql_update.cc10
-rw-r--r--sql/sql_view.cc2
-rw-r--r--sql/sql_yacc.yy72
-rw-r--r--sql/structs.h2
-rw-r--r--sql/sys_vars.cc12
-rw-r--r--sql/table.cc10
-rw-r--r--sql/table.h49
-rw-r--r--sql/transaction.cc7
-rw-r--r--sql/unireg.cc12
-rw-r--r--sql/unireg.h3
-rw-r--r--sql/wsrep_applier.cc4
-rw-r--r--sql/wsrep_dummy.cc8
-rw-r--r--sql/wsrep_mysqld.cc24
-rw-r--r--sql/wsrep_notify.cc10
-rw-r--r--sql/wsrep_sst.cc68
-rw-r--r--sql/wsrep_thd.cc52
93 files changed, 2029 insertions, 986 deletions
diff --git a/sql/contributors.h b/sql/contributors.h
index 34f06087c8c..e16448ee985 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -37,22 +37,17 @@ struct show_table_contributors_st {
struct show_table_contributors_st show_table_contributors[]= {
/* MariaDB foundation sponsors, in contribution, size , time order */
- {"Booking.com", "https://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
{"Alibaba Cloud", "https://www.alibabacloud.com/", "Platinum Sponsor of the MariaDB Foundation"},
{"Tencent Cloud", "https://cloud.tencent.com", "Platinum Sponsor of the MariaDB Foundation"},
{"Microsoft", "https://microsoft.com/", "Platinum Sponsor of the MariaDB Foundation"},
{"MariaDB Corporation", "https://mariadb.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
+ {"ServiceNow", "https://servicenow.com", "Platinum Sponsor of the MariaDB Foundation"},
{"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
{"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
{"IBM", "https://www.ibm.com", "Gold Sponsor of the MariaDB Foundation"},
- {"Tencent Games", "http://game.qq.com/", "Gold Sponsor of the MariaDB Foundation"},
- {"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"},
- {"Acronis", "https://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"},
- {"Verkkokauppa.com", "https://www.verkkokauppa.com", "Bronze Sponsor of the MariaDB Foundation"},
- {"Virtuozzo", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"},
- {"Tencent Game DBA", "http://tencentdba.com/about", "Bronze Sponsor of the MariaDB Foundation"},
- {"Tencent TDSQL", "http://tdsql.org", "Bronze Sponsor of the MariaDB Foundation"},
- {"Percona", "https://www.percona.com/", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Automattic", "https://automattic.com", "Silver Sponsor of the MariaDB Foundation"},
+ {"Percona", "https://www.percona.com/", "Sponsor of the MariaDB Foundation"},
+ {"Galera Cluster", "https://galeracluster.com", "Sponsor of the MariaDB Foundation"},
/* Sponsors of important features */
{"Google", "USA", "Sponsoring encryption, parallel replication and GTID"},
diff --git a/sql/create_options.cc b/sql/create_options.cc
index 4049443de2a..63552e60c4b 100644
--- a/sql/create_options.cc
+++ b/sql/create_options.cc
@@ -97,14 +97,13 @@ static bool report_unknown_option(THD *thd, engine_option_value *val,
{
DBUG_ENTER("report_unknown_option");
- if (val->parsed || suppress_warning)
+ if (val->parsed || suppress_warning || thd->slave_thread)
{
DBUG_PRINT("info", ("parsed => exiting"));
DBUG_RETURN(FALSE);
}
- if (!(thd->variables.sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS) &&
- !thd->slave_thread)
+ if (!(thd->variables.sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS))
{
my_error(ER_UNKNOWN_OPTION, MYF(0), val->name.str);
DBUG_RETURN(TRUE);
diff --git a/sql/field.cc b/sql/field.cc
index bdaaecc2026..652228beceb 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -8255,7 +8255,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
DBUG_ASSERT(length <= max_data_length());
new_length= length;
- copy_length= (uint)MY_MIN(UINT_MAX,table->in_use->variables.group_concat_max_len);
+ copy_length= table->in_use->variables.group_concat_max_len;
if (new_length > copy_length)
{
new_length= Well_formed_prefix(cs,
@@ -8446,7 +8446,10 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
b_length=get_length(b_ptr);
if (b_length > max_length)
b_length=max_length;
- diff=memcmp(a,b,MY_MIN(a_length,b_length));
+ if (uint32 len= MY_MIN(a_length,b_length))
+ diff= memcmp(a,b,len);
+ else
+ diff= 0;
return diff ? diff : (int) (a_length - b_length);
}
@@ -8503,7 +8506,8 @@ uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
length=(uint) blob_length;
}
int2store(buff,length);
- memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
+ if (length)
+ memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
return HA_KEY_BLOB_LENGTH+length;
}
@@ -11162,7 +11166,7 @@ key_map Field::get_possible_keys()
bool Field::validate_value_in_record_with_warn(THD *thd, const uchar *record)
{
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set);
bool rc;
if ((rc= validate_value_in_record(thd, record)))
{
@@ -11174,7 +11178,7 @@ bool Field::validate_value_in_record_with_warn(THD *thd, const uchar *record)
ER_THD(thd, ER_INVALID_DEFAULT_VALUE_FOR_FIELD),
ErrConvString(&tmp).ptr(), field_name);
}
- dbug_tmp_restore_column_map(table->read_set, old_map);
+ dbug_tmp_restore_column_map(&table->read_set, old_map);
return rc;
}
diff --git a/sql/field.h b/sql/field.h
index fea40251587..18e44f1d9d4 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1339,8 +1339,6 @@ public:
virtual uint max_packed_col_length(uint max_length)
{ return max_length;}
- virtual bool is_packable() const { return false; }
-
uint offset(uchar *record) const
{
return (uint) (ptr - record);
@@ -1829,7 +1827,6 @@ public:
bool can_optimize_range(const Item_bool_func *cond,
const Item *item,
bool is_eq_func) const;
- bool is_packable() const { return true; }
};
/* base class for float and double and decimal (old one) */
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 96f9aa874da..d76c39c3bd4 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1971,14 +1971,7 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
if (sortorder->field)
{
CHARSET_INFO *cs= sortorder->field->sort_charset();
- sortorder->type= sortorder->field->is_packable() ?
- SORT_FIELD_ATTR::VARIABLE_SIZE :
- SORT_FIELD_ATTR::FIXED_SIZE;
-
sortorder->length= sortorder->field->sort_length();
- if (sortorder->is_variable_sized())
- set_if_smaller(sortorder->length, thd->variables.max_sort_length);
-
if (use_strnxfrm((cs=sortorder->field->sort_charset())))
{
*multi_byte_charset= true;
@@ -1989,10 +1982,6 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
}
else
{
- sortorder->type= sortorder->item->type_handler()->is_packable() ?
- SORT_FIELD_ATTR::VARIABLE_SIZE :
- SORT_FIELD_ATTR::FIXED_SIZE;
-
sortorder->item->sortlength(thd, sortorder->item, sortorder);
if (use_strnxfrm(sortorder->item->collation.collation))
{
@@ -2001,8 +1990,7 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
if (sortorder->item->maybe_null)
length++; // Place for NULL marker
}
- if (sortorder->is_variable_sized())
- set_if_smaller(sortorder->length, thd->variables.max_sort_length);
+ set_if_smaller(sortorder->length, thd->variables.max_sort_length);
length+=sortorder->length;
}
sortorder->field= (Field*) 0; // end marker
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index daac3f6a86d..523e76e511e 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -4124,7 +4124,7 @@ int ha_partition::write_row(uchar * buf)
int error;
longlong func_value;
bool have_auto_increment= table->next_number_field && buf == table->record[0];
- my_bitmap_map *old_map;
+ MY_BITMAP *old_map;
THD *thd= ha_thd();
sql_mode_t saved_sql_mode= thd->variables.sql_mode;
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
@@ -4173,9 +4173,9 @@ int ha_partition::write_row(uchar * buf)
}
}
- old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ old_map= dbug_tmp_use_all_columns(table, &table->read_set);
error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value);
- dbug_tmp_restore_column_map(table->read_set, old_map);
+ dbug_tmp_restore_column_map(&table->read_set, old_map);
if (unlikely(error))
{
m_part_info->err_value= func_value;
diff --git a/sql/handler.cc b/sql/handler.cc
index d2408767530..87592beb5d3 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -838,6 +838,7 @@ static my_bool kill_handlerton(THD *thd, plugin_ref plugin,
{
handlerton *hton= plugin_hton(plugin);
+ mysql_mutex_assert_owner(&thd->LOCK_thd_data);
if (hton->state == SHOW_OPTION_YES && hton->kill_query &&
thd_get_ha_data(thd, hton))
hton->kill_query(hton, thd, *(enum thd_kill_levels *) level);
@@ -3118,6 +3119,13 @@ int handler::update_auto_increment()
(table->auto_increment_field_not_null &&
thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO))
{
+
+ /*
+ There could be an error reported because value was truncated
+ when strict mode is enabled.
+ */
+ if (thd->is_error())
+ DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
/*
Update next_insert_id if we had already generated a value in this
statement (case of INSERT VALUES(null),(3763),(null):
@@ -4839,6 +4847,7 @@ int ha_create_table(THD *thd, const char *path,
char name_buff[FN_REFLEN];
const char *name;
TABLE_SHARE share;
+ Abort_on_warning_instant_set old_abort_on_warning(thd, 0);
bool temp_table __attribute__((unused)) =
create_info->options & (HA_LEX_CREATE_TMP_TABLE | HA_CREATE_TMP_ALTER);
diff --git a/sql/handler.h b/sql/handler.h
index 0aa56afe1a5..e0e0604176d 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -584,8 +584,10 @@ struct xid_t {
void set(long f, const char *g, long gl, const char *b, long bl)
{
formatID= f;
- memcpy(data, g, gtrid_length= gl);
- memcpy(data+gl, b, bqual_length= bl);
+ if ((gtrid_length= gl))
+ memcpy(data, g, gl);
+ if ((bqual_length= bl))
+ memcpy(data+gl, b, bl);
}
void set(ulonglong xid)
{
@@ -1235,7 +1237,7 @@ struct handlerton
enum handler_create_iterator_result
(*create_iterator)(handlerton *hton, enum handler_iterator_type type,
struct handler_iterator *fill_this_in);
- int (*abort_transaction)(handlerton *hton, THD *bf_thd,
+ void (*abort_transaction)(handlerton *hton, THD *bf_thd,
THD *victim_thd, my_bool signal);
int (*set_checkpoint)(handlerton *hton, const XID* xid);
int (*get_checkpoint)(handlerton *hton, XID* xid);
@@ -1417,6 +1419,12 @@ handlerton *ha_default_tmp_handlerton(THD *thd);
// MySQL compatibility. Unused.
#define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported.
+/*
+ Table requires and close and reopen after truncate
+ If the handler has HTON_CAN_RECREATE, this flag is not used
+*/
+#define HTON_REQUIRES_CLOSE_AFTER_TRUNCATE (1 << 18)
+
class Ha_trx_info;
struct THD_TRANS
diff --git a/sql/item.cc b/sql/item.cc
index 994d45a9dc3..45f40874ddb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1486,7 +1486,7 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
TABLE *table= field->table;
THD *thd= table->in_use;
enum_check_fields tmp= thd->count_cuted_fields;
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set);
sql_mode_t sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
thd->variables.sql_mode|= MODE_INVALID_DATES;
@@ -1495,7 +1495,7 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
res= save_in_field(field, no_conversions);
thd->count_cuted_fields= tmp;
- dbug_tmp_restore_column_map(table->write_set, old_map);
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
thd->variables.sql_mode= sql_mode;
return res;
}
@@ -8160,6 +8160,22 @@ bool Item_direct_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
}
+longlong Item_direct_ref::val_time_packed()
+{
+ longlong tmp = (*ref)->val_time_packed();
+ null_value= (*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_direct_ref::val_datetime_packed()
+{
+ longlong tmp = (*ref)->val_datetime_packed();
+ null_value= (*ref)->null_value;
+ return tmp;
+}
+
+
Item_cache_wrapper::~Item_cache_wrapper()
{
DBUG_ASSERT(expr_cache == 0);
@@ -9674,7 +9690,7 @@ bool Item_cache_int::cache_value()
return FALSE;
value_cached= TRUE;
value= example->val_int_result();
- null_value= example->null_value;
+ null_value_inside= null_value= example->null_value;
unsigned_flag= example->unsigned_flag;
return TRUE;
}
@@ -9844,7 +9860,7 @@ bool Item_cache_temporal::cache_value()
return true;
value= pack_time(&ltime);
}
- null_value= example->null_value;
+ null_value_inside= null_value= example->null_value;
return true;
}
@@ -9939,7 +9955,7 @@ bool Item_cache_real::cache_value()
return FALSE;
value_cached= TRUE;
value= example->val_result();
- null_value= example->null_value;
+ null_value_inside= null_value= example->null_value;
return TRUE;
}
@@ -10001,7 +10017,8 @@ bool Item_cache_decimal::cache_value()
return FALSE;
value_cached= TRUE;
my_decimal *val= example->val_decimal_result(&decimal_value);
- if (!(null_value= example->null_value) && val != &decimal_value)
+ if (!(null_value_inside= null_value= example->null_value) &&
+ val != &decimal_value)
my_decimal2decimal(val, &decimal_value);
return TRUE;
}
@@ -10067,11 +10084,14 @@ Item *Item_cache_decimal::convert_to_basic_const_item(THD *thd)
bool Item_cache_str::cache_value()
{
if (!example)
+ {
+ DBUG_ASSERT(value_cached == FALSE);
return FALSE;
+ }
value_cached= TRUE;
value_buff.set(buffer, sizeof(buffer), example->collation.collation);
value= example->str_result(&value_buff);
- if ((null_value= example->null_value))
+ if ((null_value= null_value_inside= example->null_value))
value= 0;
else if (value != &value_buff)
{
@@ -10170,6 +10190,8 @@ Item *Item_cache_str::convert_to_basic_const_item(THD *thd)
bool Item_cache_row::setup(THD *thd, Item *item)
{
example= item;
+ null_value= true;
+
if (!values && allocate(thd, item->cols()))
return 1;
for (uint i= 0; i < item_count; i++)
@@ -10202,12 +10224,19 @@ bool Item_cache_row::cache_value()
if (!example)
return FALSE;
value_cached= TRUE;
- null_value= 0;
+ null_value= TRUE;
+ null_value_inside= false;
example->bring_value();
+
+ /*
+ For Item_cache_row null_value is set to TRUE only when ALL the values
+ inside the cache are NULL
+ */
for (uint i= 0; i < item_count; i++)
{
values[i]->cache_value();
- null_value|= values[i]->null_value;
+ null_value&= values[i]->null_value;
+ null_value_inside|= values[i]->null_value;
}
return TRUE;
}
diff --git a/sql/item.h b/sql/item.h
index a49f9e8e5e4..cb1e8519b27 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -818,6 +818,12 @@ public:
void set_name_for_rollback(THD *thd, const char *str, uint length,
CHARSET_INFO *cs);
void rename(char *new_name);
+ void share_name_with(Item *item)
+ {
+ name= item->name;
+ name_length= item->name_length;
+ is_autogenerated_name= item->is_autogenerated_name;
+ }
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup();
virtual void make_field(THD *thd, Send_field *field);
@@ -4665,13 +4671,16 @@ public:
return Item_ref::fix_fields(thd, it);
}
void save_val(Field *to);
+ /* Below we should have all val() methods as in Item_ref */
double val_real();
longlong val_int();
- String *val_str(String* tmp);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
+ String *val_str(String* tmp);
bool is_null();
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ longlong val_datetime_packed();
+ longlong val_time_packed();
virtual Ref_Type ref_type() { return DIRECT_REF; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_direct_ref>(thd, mem_root, this); }
@@ -4986,6 +4995,20 @@ public:
}
return Item_direct_ref::get_date(ltime, fuzzydate);
}
+ longlong val_time_packed()
+ {
+ if (check_null_ref())
+ return 0;
+ else
+ return Item_direct_ref::val_time_packed();
+ }
+ longlong val_datetime_packed()
+ {
+ if (check_null_ref())
+ return 0;
+ else
+ return Item_direct_ref::val_datetime_packed();
+ }
bool send(Protocol *protocol, String *buffer);
void save_org_in_field(Field *field,
fast_field_copier data __attribute__ ((__unused__)))
@@ -5635,6 +5658,14 @@ protected:
*/
bool value_cached;
public:
+ /*
+ This is set if at least one of the values of a sub query is NULL
+ Item_cache_row returns this with null_inside().
+ For not row items, it's set to the value of null_value
+ It is set after cache_value() is called.
+ */
+ bool null_value_inside;
+
Item_cache(THD *thd):
Item_basic_constant(thd),
Type_handler_hybrid_field_type(MYSQL_TYPE_STRING),
@@ -5644,6 +5675,7 @@ public:
fixed= 1;
maybe_null= 1;
null_value= 1;
+ null_value_inside= true;
}
protected:
Item_cache(THD *thd, enum_field_types field_type_arg):
@@ -5655,6 +5687,7 @@ protected:
fixed= 1;
maybe_null= 1;
null_value= 1;
+ null_value_inside= true;
}
public:
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 2a0972216f8..7b7604053e3 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -428,13 +428,13 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item,
TABLE *table= field->table;
sql_mode_t orig_sql_mode= thd->variables.sql_mode;
enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields;
- my_bitmap_map *old_maps[2] = { NULL, NULL };
+ MY_BITMAP *old_maps[2] = { NULL, NULL };
ulonglong UNINIT_VAR(orig_field_val); /* original field value if valid */
/* table->read_set may not be set if we come here from a CREATE TABLE */
if (table && table->read_set)
dbug_tmp_use_all_columns(table, old_maps,
- table->read_set, table->write_set);
+ &table->read_set, &table->write_set);
/* For comparison purposes allow invalid dates like 2000-01-32 */
thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) |
MODE_INVALID_DATES;
@@ -478,7 +478,7 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item,
thd->variables.sql_mode= orig_sql_mode;
thd->count_cuted_fields= orig_count_cuted_fields;
if (table && table->read_set)
- dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_maps);
+ dbug_tmp_restore_column_maps(&table->read_set, &table->write_set, old_maps);
}
return result;
}
@@ -1234,7 +1234,9 @@ longlong Item_func_truth::val_int()
bool Item_in_optimizer::is_top_level_item()
{
- return ((Item_in_subselect *)args[1])->is_top_level_item();
+ if (!invisible_mode())
+ return ((Item_in_subselect *)args[1])->is_top_level_item();
+ return false;
}
@@ -1596,7 +1598,7 @@ longlong Item_in_optimizer::val_int()
DBUG_RETURN(res);
}
- if (cache->null_value)
+ if (cache->null_value_inside)
{
DBUG_PRINT("info", ("Left NULL..."));
/*
@@ -5261,6 +5263,7 @@ void Item_func_like::print(String *str, enum_query_type query_type)
longlong Item_func_like::val_int()
{
DBUG_ASSERT(fixed == 1);
+ DBUG_ASSERT(escape != -1);
String* res= args[0]->val_str(&cmp_value1);
if (args[0]->null_value)
{
@@ -5347,15 +5350,29 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str,
bool escape_used_in_parsing, CHARSET_INFO *cmp_cs,
int *escape)
{
- if (!escape_item->const_during_execution())
+ /*
+ ESCAPE clause accepts only constant arguments and Item_param.
+
+ Subqueries during context_analysis_only might decide they're
+ const_during_execution, but not quite const yet, not evaluate-able.
+ This is fine, as most of context_analysis_only modes will never
+ reach val_int(), so we won't need the value.
+ CONTEXT_ANALYSIS_ONLY_DERIVED being a notable exception here.
+ */
+ if (!escape_item->const_during_execution() ||
+ (!escape_item->const_item() &&
+ !(thd->lex->context_analysis_only & ~CONTEXT_ANALYSIS_ONLY_DERIVED)))
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE");
return TRUE;
}
-
+
+ IF_DBUG(*escape= -1,);
+
if (escape_item->const_item())
{
/* If we are on execution stage */
+ /* XXX is it safe to evaluate is_expensive() items here? */
String *escape_str= escape_item->val_str(tmp_str);
if (escape_str)
{
@@ -5413,7 +5430,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
if (Item_bool_func2::fix_fields(thd, ref) ||
- escape_item->fix_fields(thd, &escape_item) ||
+ (!escape_item->fixed && escape_item->fix_fields(thd, &escape_item)) ||
fix_escape_item(thd, escape_item, &cmp_value1, escape_used_in_parsing,
cmp_collation.collation, &escape))
return TRUE;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 22736339bf6..26469d88929 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -2013,6 +2013,13 @@ public:
return this;
}
+ bool walk(Item_processor processor, bool walk_subquery, void *arg)
+ {
+ return walk_args(processor, walk_subquery, arg)
+ || escape_item->walk(processor, walk_subquery, arg)
+ || (this->*processor)(arg);
+ }
+
bool find_selective_predicates_list_processor(void *arg);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 1cf5a06a3a4..4bfb2615fbe 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -202,7 +202,6 @@ public:
@return An item representing the function call
*/
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
-
protected:
/** Constructor. */
Create_func_arg2() {}
@@ -229,7 +228,6 @@ public:
@return An item representing the function call
*/
virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
-
protected:
/** Constructor. */
Create_func_arg3() {}
@@ -975,6 +973,19 @@ class Create_func_distance : public Create_func_arg2
Create_func_distance() {}
virtual ~Create_func_distance() {}
};
+
+
+class Create_func_distance_sphere: public Create_native_func
+{
+ public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+ static Create_func_distance_sphere s_singleton;
+
+ protected:
+ Create_func_distance_sphere() {}
+ virtual ~Create_func_distance_sphere() {}
+};
+
#endif
@@ -4761,6 +4772,26 @@ Create_func_glength::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_glength(thd, arg1);
}
+
+
+Create_func_distance_sphere Create_func_distance_sphere::s_singleton;
+
+Item*
+Create_func_distance_sphere::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ if (arg_count < 2)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ return NULL;
+ }
+ return new (thd->mem_root) Item_func_sphere_distance(thd, *item_list);
+}
#endif
@@ -7051,6 +7082,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
{ { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
{ { C_STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
+ { { C_STRING_WITH_LEN("ST_DISTANCE_SPHERE") }, GEOM_BUILDER(Create_func_distance_sphere)},
{ { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
{ { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)},
{ { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)},
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 4d03e209eab..7b39b7710fb 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -4882,7 +4882,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
length--; // Fix length change above
entry->value[length]= 0; // Store end \0
}
- memmove(entry->value, ptr, length);
+ if (length)
+ memmove(entry->value, ptr, length);
if (type == DECIMAL_RESULT)
((my_decimal*)entry->value)->fix_buffer_pointer();
entry->length= length;
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 1c3fafc0582..0daf9da4a81 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -145,7 +145,7 @@ String *Item_func_geometry_from_json::val_str(String *str)
{
String *sv= args[1]->val_str(&tmp_js);
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0),
- "option", sv->c_ptr_safe(), "ST_GeometryFromJSON");
+ "option", sv->c_ptr_safe(), "ST_GeomFromGeoJSON");
null_value= 1;
return 0;
}
@@ -182,7 +182,7 @@ String *Item_func_geometry_from_json::val_str(String *str)
code= ER_GEOJSON_NOT_CLOSED;
break;
case Geometry::GEOJ_DIMENSION_NOT_SUPPORTED:
- my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_GeometryFromJSON");
+ my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_GeomFromGeoJSON");
break;
default:
report_json_error_ex(js, &je, func_name(), 0, Sql_condition::WARN_LEVEL_WARN);
@@ -2537,11 +2537,151 @@ mem_error:
}
+double Item_func_sphere_distance::val_real()
+{
+ /* To test null_value of item, first get well-known bytes as a backups */
+ String bak1, bak2;
+ String *arg1= args[0]->val_str(&bak1);
+ String *arg2= args[1]->val_str(&bak2);
+ double distance= 0.0;
+ double sphere_radius= 6370986.0; // Default radius equals Earth radius
+
+ null_value= (args[0]->null_value || args[1]->null_value);
+ if (null_value)
+ {
+ return 0;
+ }
+
+ if (arg_count == 3)
+ {
+ sphere_radius= args[2]->val_real();
+ // Radius cannot be Null
+ if (args[2]->null_value)
+ {
+ null_value= true;
+ return 0;
+ }
+ if (sphere_radius <= 0)
+ {
+ my_error(ER_INTERNAL_ERROR, MYF(0), "Radius must be greater than zero.");
+ return 1;
+ }
+ }
+ Geometry_buffer buffer1, buffer2;
+ Geometry *g1, *g2;
+ if (!(g1= Geometry::construct(&buffer1, arg1->ptr(), arg1->length())) ||
+ !(g2= Geometry::construct(&buffer2, arg2->ptr(), arg2->length())))
+ {
+ my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_Distance_Sphere");
+ goto handle_errors;
+ }
+// Method allowed for points and multipoints
+ if (!(g1->get_class_info()->m_type_id == Geometry::wkb_point ||
+ g1->get_class_info()->m_type_id == Geometry::wkb_multipoint) ||
+ !(g2->get_class_info()->m_type_id == Geometry::wkb_point ||
+ g2->get_class_info()->m_type_id == Geometry::wkb_multipoint))
+ {
+ // Generate error message in case different geometry is used?
+ my_error(ER_INTERNAL_ERROR, MYF(0), func_name());
+ return 0;
+ }
+ distance= spherical_distance_points(g1, g2, sphere_radius);
+ if (distance < 0)
+ {
+ my_error(ER_INTERNAL_ERROR, MYF(0), "Returned distance cannot be negative.");
+ return 1;
+ }
+ return distance;
+
+ handle_errors:
+ return 0;
+}
+
+
+double Item_func_sphere_distance::spherical_distance_points(Geometry *g1,
+ Geometry *g2,
+ const double r)
+{
+ double res= 0.0;
+ // Length for the single point (25 Bytes)
+ uint32 len= SRID_SIZE + POINT_DATA_SIZE + WKB_HEADER_SIZE;
+ int error= 0;
+
+ switch (g2->get_class_info()->m_type_id)
+ {
+ case Geometry::wkb_point:
+ // Optimization for point-point case
+ if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
+ {
+ res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error);
+ }
+ else
+ {
+ // Optimization for single point in Multipoint
+ if (g1->get_data_size() == len)
+ {
+ res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error);
+ }
+ else
+ {
+ // There are multipoints in g1
+ // g1 is MultiPoint and calculate MP.sphericaldistance from g2 Point
+ if (g1->get_data_size() != GET_SIZE_ERROR)
+ static_cast<Gis_point *>(g2)->spherical_distance_multipoints(
+ (Gis_multi_point *)g1, r, &res, &error);
+ }
+ }
+ break;
+
+ case Geometry::wkb_multipoint:
+ // Optimization for point-point case
+ if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
+ {
+ // Optimization for single point in Multipoint g2
+ if (g2->get_data_size() == len)
+ {
+ res= static_cast<Gis_point *>(g1)->calculate_haversine(g2, r, &error);
+ }
+ else
+ {
+ if (g2->get_data_size() != GET_SIZE_ERROR)
+ // g1 is a point (casted to multi_point) and g2 multipoint
+ static_cast<Gis_point *>(g1)->spherical_distance_multipoints(
+ (Gis_multi_point *)g2, r, &res, &error);
+ }
+ }
+ else
+ {
+ // Multipoints in g1 and g2 - no optimization
+ static_cast<Gis_multi_point *>(g1)->spherical_distance_multipoints(
+ (Gis_multi_point *)g2, r, &res, &error);
+ }
+ break;
+
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+
+ if (res < 0)
+ goto handle_error;
+
+ handle_error:
+ if (error > 0)
+ my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0),
+ "Longitude should be [-180,180]", "ST_Distance_Sphere");
+ else if(error < 0)
+ my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0),
+ "Latitude should be [-90,90]", "ST_Distance_Sphere");
+ return res;
+}
+
+
String *Item_func_pointonsurface::val_str(String *str)
{
Gcalc_operation_transporter trn(&func, &collector);
- DBUG_ENTER("Item_func_pointonsurface::val_real");
+ DBUG_ENTER("Item_func_pointonsurface::val_str");
DBUG_ASSERT(fixed == 1);
String *res= args[0]->val_str(&tmp_value);
Geometry_buffer buffer;
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index a858a9a2d57..efff940ec4b 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -714,6 +714,20 @@ public:
};
+class Item_func_sphere_distance: public Item_real_func
+{
+ double spherical_distance_points(Geometry *g1, Geometry *g2,
+ const double sphere_r);
+public:
+ Item_func_sphere_distance(THD *thd, List<Item> &list):
+ Item_real_func(thd, list) {}
+ double val_real();
+ const char *func_name() const { return "st_distance_sphere"; }
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_sphere_distance>(thd, mem_root, this); }
+};
+
+
class Item_func_pointonsurface: public Item_geometry_func
{
String tmp_value;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 802bfca64b7..4b8f118ca43 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -368,7 +368,7 @@ bool Item_subselect::mark_as_eliminated_processor(void *arg)
bool Item_subselect::eliminate_subselect_processor(void *arg)
{
unit->item= NULL;
- unit->exclude_from_tree();
+ unit->exclude();
eliminated= TRUE;
return FALSE;
}
@@ -437,6 +437,26 @@ bool Item_subselect::mark_as_dependent(THD *thd, st_select_lex *select,
/*
+ @brief
+ Update the table bitmaps for the outer references used within a subquery
+*/
+
+bool Item_subselect::update_table_bitmaps_processor(void *arg)
+{
+ List_iterator<Ref_to_outside> it(upper_refs);
+ Ref_to_outside *upper;
+
+ while ((upper= it++))
+ {
+ if (upper->item &&
+ upper->item->walk(&Item::update_table_bitmaps_processor, FALSE, arg))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
Adjust attributes after our parent select has been merged into grandparent
DESCRIPTION
@@ -831,7 +851,7 @@ bool Item_subselect::expr_cache_is_needed(THD *thd)
inline bool Item_in_subselect::left_expr_has_null()
{
- return (*(optimizer->get_cache()))->null_value;
+ return (*(optimizer->get_cache()))->null_value_inside;
}
@@ -1299,7 +1319,17 @@ bool Item_singlerow_subselect::null_inside()
void Item_singlerow_subselect::bring_value()
{
if (!exec() && assigned())
- null_value= 0;
+ {
+ null_value= true;
+ for (uint i= 0; i < max_columns ; i++)
+ {
+ if (!row[i]->null_value)
+ {
+ null_value= false;
+ return;
+ }
+ }
+ }
else
reset();
}
@@ -1325,7 +1355,11 @@ longlong Item_singlerow_subselect::val_int()
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_int();
+ {
+ longlong val= value->val_int();
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1334,6 +1368,7 @@ longlong Item_singlerow_subselect::val_int()
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1342,7 +1377,11 @@ String *Item_singlerow_subselect::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_str(str);
+ {
+ String *res= value->val_str(str);
+ null_value= value->null_value;
+ return res;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1351,6 +1390,7 @@ String *Item_singlerow_subselect::val_str(String *str)
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1360,7 +1400,11 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_decimal(decimal_value);
+ {
+ my_decimal *val= value->val_decimal(decimal_value);
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1369,6 +1413,7 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1378,7 +1423,11 @@ bool Item_singlerow_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_bool();
+ {
+ bool val= value->val_bool();
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1387,6 +1436,7 @@ bool Item_singlerow_subselect::val_bool()
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1396,7 +1446,11 @@ bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->get_date(ltime, fuzzydate);
+ {
+ bool val= value->get_date(ltime, fuzzydate);
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1405,6 +1459,7 @@ bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
else
{
reset();
+ DBUG_ASSERT(null_value);
return 1;
}
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 2292c22480f..130f90839e3 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -48,7 +48,11 @@ class Cached_item;
class Item_subselect :public Item_result_field,
protected Used_tables_and_const_cache
{
- bool value_assigned; /* value already assigned to subselect */
+ /*
+ Set to TRUE if the value is assigned for the subselect
+ FALSE: subquery not executed or the subquery returns an empty result
+ */
+ bool value_assigned;
bool own_engine; /* the engine was not taken from other Item_subselect */
protected:
/* thread handler, will be assigned in fix_fields only */
@@ -249,6 +253,7 @@ public:
@retval FALSE otherwise
*/
bool is_expensive_processor(void *arg) { return is_expensive(); }
+ bool update_table_bitmaps_processor(void *arg);
/**
Get the SELECT_LEX structure associated with this Item.
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index e50822e71f2..dd65f04a652 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2015, MariaDB
+ Copyright (c) 2008, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -464,7 +464,8 @@ Item_sum::Item_sum(THD *thd, Item_sum *item):
if (!(orig_args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
return;
}
- memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count);
+ if (arg_count)
+ memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count);
init_aggregator();
with_distinct= item->with_distinct;
if (item->aggr)
@@ -1136,7 +1137,8 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
check_sum_func(thd, ref))
return TRUE;
- memcpy (orig_args, args, sizeof (Item *) * arg_count);
+ if (arg_count)
+ memcpy (orig_args, args, sizeof (Item *) * arg_count);
fixed= 1;
return FALSE;
}
@@ -3169,7 +3171,7 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
{
Item_func_group_concat *item= (Item_func_group_concat *) item_arg;
TABLE *table= item->table;
- uint max_length= (uint)table->in_use->variables.group_concat_max_len;
+ uint max_length= table->in_use->variables.group_concat_max_len;
String tmp((char *)table->record[1], table->s->reclength,
default_charset_info);
String tmp2;
@@ -3312,7 +3314,8 @@ Item_func_group_concat(THD *thd, Name_resolution_context *context_arg,
/* orig_args is only used for print() */
orig_args= (Item**) (order + arg_count_order);
- memcpy(orig_args, args, sizeof(Item*) * arg_count);
+ if (arg_count)
+ memcpy(orig_args, args, sizeof(Item*) * arg_count);
}
@@ -3496,7 +3499,7 @@ bool Item_func_group_concat::repack_tree(THD *thd)
DBUG_ASSERT(tree->size_of_element == st.tree.size_of_element);
st.table= table;
st.len= 0;
- st.maxlen= (size_t)thd->variables.group_concat_max_len;
+ st.maxlen= thd->variables.group_concat_max_len;
tree_walk(tree, &copy_to_tree, &st, left_root_right);
if (st.len <= st.maxlen) // Copying aborted. Must be OOM
{
@@ -3517,7 +3520,7 @@ bool Item_func_group_concat::repack_tree(THD *thd)
decreases up to N=10 (that is, factor=1024) and then starts to increase,
again, very slowly.
*/
-#define GCONCAT_REPACK_FACTOR (1 << 10)
+#define GCONCAT_REPACK_FACTOR 10
bool Item_func_group_concat::add()
{
@@ -3563,7 +3566,7 @@ bool Item_func_group_concat::add()
{
THD *thd= table->in_use;
table->field[0]->store(row_str_len, FALSE);
- if (tree_len > thd->variables.group_concat_max_len * GCONCAT_REPACK_FACTOR
+ if ((tree_len >> GCONCAT_REPACK_FACTOR) > thd->variables.group_concat_max_len
&& tree->elements_in_tree > 1)
if (repack_tree(thd))
return 1;
@@ -3621,9 +3624,9 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
result.set_charset(collation.collation);
result_field= 0;
null_value= 1;
- max_length= (uint32)(thd->variables.group_concat_max_len
- / collation.collation->mbminlen
- * collation.collation->mbmaxlen);
+ max_length= (uint32)MY_MIN(thd->variables.group_concat_max_len
+ / collation.collation->mbminlen
+ * collation.collation->mbmaxlen, UINT_MAX32);
uint32 offset;
if (separator->needs_conversion(separator->length(), separator->charset(),
diff --git a/sql/key.cc b/sql/key.cc
index 18806efc18f..689b1e9c886 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -244,14 +244,13 @@ void key_restore(uchar *to_record, const uchar *from_key, KEY *key_info,
else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
{
Field *field= key_part->field;
- my_bitmap_map *old_map;
my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
field->move_field_offset(ptrdiff);
key_length-= HA_KEY_BLOB_LENGTH;
length= MY_MIN(key_length, key_part->length);
- old_map= dbug_tmp_use_all_columns(field->table, field->table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(field->table, &field->table->write_set);
field->set_key_image(from_key, length);
- dbug_tmp_restore_column_map(field->table->write_set, old_map);
+ dbug_tmp_restore_column_map(&field->table->write_set, old_map);
from_key+= HA_KEY_BLOB_LENGTH;
field->move_field_offset(-ptrdiff);
}
@@ -419,7 +418,7 @@ void field_unpack(String *to, Field *field, const uchar *rec, uint max_length,
void key_unpack(String *to, TABLE *table, KEY *key)
{
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set);
DBUG_ENTER("key_unpack");
to->length(0);
@@ -441,7 +440,7 @@ void key_unpack(String *to, TABLE *table, KEY *key)
field_unpack(to, key_part->field, table->record[0], key_part->length,
MY_TEST(key_part->key_part_flag & HA_PART_KEY_SEG));
}
- dbug_tmp_restore_column_map(table->read_set, old_map);
+ dbug_tmp_restore_column_map(&table->read_set, old_map);
DBUG_VOID_RETURN;
}
diff --git a/sql/log.cc b/sql/log.cc
index 54a8bd9552f..dc8df9c6fdb 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -4397,7 +4397,9 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
0, 0, &log_space_reclaimed);
mysql_mutex_lock(&rli->log_space_lock);
- rli->log_space_total-= log_space_reclaimed;
+ my_atomic_add64_explicit((volatile int64*)(&rli->log_space_total),
+ (-(int64)log_space_reclaimed),
+ MY_MEMORY_ORDER_RELAXED);
mysql_cond_broadcast(&rli->log_space_cond);
mysql_mutex_unlock(&rli->log_space_lock);
diff --git a/sql/log.h b/sql/log.h
index 0e6b2c895af..0770861fe01 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -716,7 +716,9 @@ public:
char buf1[22],buf2[22];
#endif
DBUG_ENTER("harvest_bytes_written");
- (*counter)+=bytes_written;
+
+ my_atomic_add64_explicit((volatile int64*)(counter), bytes_written,
+ MY_MEMORY_ORDER_RELAXED);
DBUG_PRINT("info",("counter: %s bytes_written: %s", llstr(*counter,buf1),
llstr(bytes_written,buf2)));
bytes_written=0;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 097cbe8da9d..c32f31db1f6 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -7150,10 +7150,10 @@ error:
if (thd->transaction_rollback_request)
{
trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
else if (! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
else
thd->mdl_context.release_statement_locks();
@@ -8554,7 +8554,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
"COMMIT /* implicit, from Xid_log_event */");
thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
res= trans_commit(thd); /* Automatically rolls back on error. */
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
#ifdef WITH_WSREP
if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data);
@@ -10718,7 +10718,7 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
There was the same problem with MERGE MYISAM tables and so here we try to
go the same way.
*/
-static void restore_empty_query_table_list(LEX *lex)
+inline void restore_empty_query_table_list(LEX *lex)
{
if (lex->first_not_own_table())
(*lex->first_not_own_table()->prev_global)= NULL;
@@ -10733,6 +10733,8 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
TABLE* table;
DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
int error= 0;
+ LEX *lex= thd->lex;
+ uint8 new_trg_event_map= get_trg_event_map();
/*
If m_table_id == ~0ULL, then we have a dummy event that does not
contain any data. In that case, we just remove all tables in the
@@ -10823,27 +10825,29 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
};);
- if (slave_run_triggers_for_rbr)
- {
- LEX *lex= thd->lex;
- uint8 new_trg_event_map= get_trg_event_map();
-
- /*
- Trigger's procedures work with global table list. So we have to add
- rgi->tables_to_lock content there to get trigger's in the list.
+ /*
+ Trigger's procedures work with global table list. So we have to add
+ rgi->tables_to_lock content there to get trigger's in the list.
- Then restore_empty_query_table_list() restore the list as it was
- */
- DBUG_ASSERT(lex->query_tables == NULL);
- if ((lex->query_tables= rgi->tables_to_lock))
- rgi->tables_to_lock->prev_global= &lex->query_tables;
+ Then restore_empty_query_table_list() restore the list as it was
+ */
+ DBUG_ASSERT(lex->query_tables == NULL);
+ if ((lex->query_tables= rgi->tables_to_lock))
+ rgi->tables_to_lock->prev_global= &lex->query_tables;
- for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
- tables= tables->next_global)
+ for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
+ tables= tables->next_global)
+ {
+ if (slave_run_triggers_for_rbr)
{
tables->trg_event_map= new_trg_event_map;
lex->query_tables_last= &tables->next_global;
}
+ else if (!WSREP_ON)
+ {
+ tables->slave_fk_event_map= new_trg_event_map;
+ lex->query_tables_last= &tables->next_global;
+ }
}
if (open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0))
{
@@ -11193,8 +11197,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
}
/* remove trigger's tables */
- if (slave_run_triggers_for_rbr)
- restore_empty_query_table_list(thd->lex);
+ restore_empty_query_table_list(thd->lex);
#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV)
@@ -11212,8 +11215,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
DBUG_RETURN(error);
err:
- if (slave_run_triggers_for_rbr)
- restore_empty_query_table_list(thd->lex);
+ restore_empty_query_table_list(thd->lex);
rgi->slave_close_thread_tables(thd);
DBUG_RETURN(error);
}
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 9eeb82eeffd..8cb21771991 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -1082,7 +1082,7 @@ MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
DBUG_ASSERT(!debug_sync_set_action((owner->get_thd()),
STRING_WITH_LEN(act)));
};);
- if (wsrep_thd_is_BF(owner->get_thd(), false))
+ if (WSREP_ON && wsrep_thd_is_BF(owner->get_thd(), false))
{
wait_result= mysql_cond_wait(&m_COND_wait_status, &m_LOCK_wait_status);
}
@@ -1155,7 +1155,7 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket)
*/
DBUG_ASSERT(ticket->get_lock());
#ifdef WITH_WSREP
- if ((this == &(ticket->get_lock()->m_waiting)) &&
+ if (WSREP_ON && (this == &(ticket->get_lock()->m_waiting)) &&
wsrep_thd_is_BF(ticket->get_ctx()->get_thd(), false))
{
Ticket_iterator itw(ticket->get_lock()->m_waiting);
@@ -1581,7 +1581,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg,
ticket->is_incompatible_when_granted(type_arg))
{
#ifdef WITH_WSREP
- if (wsrep_thd_is_BF(requestor_ctx->get_thd(),false) &&
+ if (WSREP_ON && wsrep_thd_is_BF(requestor_ctx->get_thd(),false) &&
key.mdl_namespace() == MDL_key::GLOBAL)
{
WSREP_DEBUG("global lock granted for BF: %lu %s",
@@ -1615,7 +1615,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg,
}
else
{
- if (wsrep_thd_is_BF(requestor_ctx->get_thd(), false) &&
+ if (WSREP_ON && wsrep_thd_is_BF(requestor_ctx->get_thd(), false) &&
key.mdl_namespace() == MDL_key::GLOBAL)
{
WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s",
@@ -2842,6 +2842,9 @@ void MDL_context::rollback_to_savepoint(const MDL_savepoint &mdl_savepoint)
void MDL_context::release_transactional_locks()
{
DBUG_ENTER("MDL_context::release_transactional_locks");
+ /* Fail if there are active transactions */
+ DBUG_ASSERT(!(current_thd->server_status &
+ (SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY)));
release_locks_stored_before(MDL_STATEMENT, NULL);
release_locks_stored_before(MDL_TRANSACTION, NULL);
DBUG_VOID_RETURN;
diff --git a/sql/mf_iocache_encr.cc b/sql/mf_iocache_encr.cc
index 29d7074aeb1..434ae08fde0 100644
--- a/sql/mf_iocache_encr.cc
+++ b/sql/mf_iocache_encr.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2015, MariaDB
+ Copyright (c) 2015, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -85,7 +85,6 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count)
do
{
- size_t copied;
uint elength, wlength, length;
uchar iv[MY_AES_BLOCK_SIZE]= {0};
@@ -116,11 +115,13 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count)
DBUG_ASSERT(length <= info->buffer_length);
- copied= MY_MIN(Count, (size_t)(length - pos_offset));
-
- memcpy(Buffer, info->buffer + pos_offset, copied);
- Count-= copied;
- Buffer+= copied;
+ size_t copied= MY_MIN(Count, (size_t)(length - pos_offset));
+ if (copied)
+ {
+ memcpy(Buffer, info->buffer + pos_offset, copied);
+ Count-= copied;
+ Buffer+= copied;
+ }
info->read_pos= info->buffer + pos_offset + copied;
info->read_end= info->buffer + length;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d3e124e3405..48121ce2ea2 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -385,7 +385,6 @@ static bool binlog_format_used= false;
LEX_STRING opt_init_connect, opt_init_slave;
mysql_cond_t COND_thread_cache;
static mysql_cond_t COND_flush_thread_cache;
-mysql_cond_t COND_slave_background;
static DYNAMIC_ARRAY all_options;
/* Global variables */
@@ -758,7 +757,7 @@ mysql_mutex_t
LOCK_crypt,
LOCK_global_system_variables,
LOCK_user_conn, LOCK_slave_list,
- LOCK_connection_count, LOCK_error_messages, LOCK_slave_background;
+ LOCK_connection_count, LOCK_error_messages;
mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
LOCK_global_table_stats, LOCK_global_index_stats;
@@ -947,8 +946,7 @@ PSI_mutex_key key_LOCK_stats,
PSI_mutex_key key_LOCK_gtid_waiting;
PSI_mutex_key key_LOCK_after_binlog_sync;
-PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered,
- key_LOCK_slave_background;
+PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered;
PSI_mutex_key key_TABLE_SHARE_LOCK_share;
static PSI_mutex_info all_server_mutexes[]=
@@ -1017,7 +1015,6 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL},
{ &key_LOCK_after_binlog_sync, "LOCK_after_binlog_sync", PSI_FLAG_GLOBAL},
{ &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL},
- { &key_LOCK_slave_background, "LOCK_slave_background", PSI_FLAG_GLOBAL},
{ &key_LOG_INFO_lock, "LOG_INFO::lock", 0},
{ &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL},
{ &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL},
@@ -1074,7 +1071,7 @@ PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy;
PSI_cond_key key_COND_rpl_thread_queue, key_COND_rpl_thread,
key_COND_rpl_thread_stop, key_COND_rpl_thread_pool,
key_COND_parallel_entry, key_COND_group_commit_orderer,
- key_COND_prepare_ordered, key_COND_slave_background;
+ key_COND_prepare_ordered;
PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates;
static PSI_cond_info all_server_conds[]=
@@ -1124,7 +1121,6 @@ static PSI_cond_info all_server_conds[]=
{ &key_COND_parallel_entry, "COND_parallel_entry", 0},
{ &key_COND_group_commit_orderer, "COND_group_commit_orderer", 0},
{ &key_COND_prepare_ordered, "COND_prepare_ordered", 0},
- { &key_COND_slave_background, "COND_slave_background", 0},
{ &key_COND_start_thread, "COND_start_thread", PSI_FLAG_GLOBAL},
{ &key_COND_wait_gtid, "COND_wait_gtid", 0},
{ &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0}
@@ -2015,8 +2011,11 @@ static void __cdecl kill_server(int sig_ptr)
close_connections();
+#ifdef WITH_WSREP
if (wsrep_inited == 1)
wsrep_deinit(true);
+ wsrep_sst_auth_free();
+#endif /* WITH_WSREP */
if (sig != MYSQL_KILL_SIGNAL &&
sig != 0)
@@ -2136,6 +2135,7 @@ extern "C" void unireg_abort(int exit_code)
/* In bootstrap mode we deinitialize wsrep here. */
if (opt_bootstrap && wsrep_inited)
wsrep_deinit(true);
+ wsrep_sst_auth_free();
}
#endif // WITH_WSREP
@@ -2379,8 +2379,6 @@ static void clean_up_mutexes()
mysql_cond_destroy(&COND_prepare_ordered);
mysql_mutex_destroy(&LOCK_after_binlog_sync);
mysql_mutex_destroy(&LOCK_commit_ordered);
- mysql_mutex_destroy(&LOCK_slave_background);
- mysql_cond_destroy(&COND_slave_background);
DBUG_VOID_RETURN;
}
@@ -4838,9 +4836,6 @@ static int init_thread_environment()
MY_MUTEX_INIT_SLOW);
mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered,
MY_MUTEX_INIT_SLOW);
- mysql_mutex_init(key_LOCK_slave_background, &LOCK_slave_background,
- MY_MUTEX_INIT_SLOW);
- mysql_cond_init(key_COND_slave_background, &COND_slave_background, NULL);
#ifdef HAVE_OPENSSL
mysql_mutex_init(key_LOCK_des_key_file,
@@ -5422,6 +5417,10 @@ static int init_server_components()
that there are unprocessed options.
*/
my_getopt_skip_unknown= 0;
+#ifdef WITH_WSREP
+ if (wsrep_recovery)
+ my_getopt_skip_unknown= TRUE;
+#endif
if ((ho_error= handle_options(&remaining_argc, &remaining_argv, no_opts,
mysqld_get_one_option)))
@@ -5431,20 +5430,27 @@ static int init_server_components()
remaining_argv--;
my_getopt_skip_unknown= TRUE;
- if (remaining_argc > 1)
+#ifdef WITH_WSREP
+ if (!wsrep_recovery)
{
- fprintf(stderr, "%s: Too many arguments (first extra is '%s').\n",
- my_progname, remaining_argv[1]);
- unireg_abort(1);
+#endif
+ if (remaining_argc > 1)
+ {
+ fprintf(stderr, "%s: Too many arguments (first extra is '%s').\n",
+ my_progname, remaining_argv[1]);
+ unireg_abort(1);
+ }
+#ifdef WITH_WSREP
}
+#endif
}
- if (init_io_cache_encryption())
- unireg_abort(1);
-
if (opt_abort)
unireg_abort(0);
+ if (init_io_cache_encryption())
+ unireg_abort(1);
+
/* if the errmsg.sys is not loaded, terminate to maintain behaviour */
if (!DEFAULT_ERRMSGS[0][0])
unireg_abort(1);
@@ -8435,8 +8441,11 @@ static int show_memory_used(THD *thd, SHOW_VAR *var, char *buff,
var->type= SHOW_LONGLONG;
var->value= buff;
if (scope == OPT_GLOBAL)
+ {
+ calc_sum_of_all_status_if_needed(status_var);
*(longlong*) buff= (status_var->global_memory_used +
status_var->local_memory_used);
+ }
else
*(longlong*) buff= status_var->local_memory_used;
return 0;
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 2947734901c..64e5aef5946 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -568,8 +568,7 @@ extern mysql_mutex_t
LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_user_conn,
- LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count,
- LOCK_slave_background;
+ LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count;
extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count,
LOCK_global_system_variables;
extern mysql_mutex_t LOCK_start_thread;
@@ -583,7 +582,6 @@ extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern mysql_prlock_t LOCK_system_variables_hash;
extern mysql_cond_t COND_thread_count, COND_start_thread;
extern mysql_cond_t COND_manager;
-extern mysql_cond_t COND_slave_background;
extern int32 thread_running;
extern int32 thread_count, service_thread_count;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 798b1f284bc..f3f184367c9 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3248,8 +3248,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
void store_key_image_to_rec(Field *field, uchar *ptr, uint len)
{
- /* Do the same as print_key() does */
- my_bitmap_map *old_map;
+ /* Do the same as print_key() does */
if (field->real_maybe_null())
{
@@ -3261,10 +3260,10 @@ void store_key_image_to_rec(Field *field, uchar *ptr, uint len)
field->set_notnull();
ptr++;
}
- old_map= dbug_tmp_use_all_columns(field->table,
- field->table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(field->table,
+ &field->table->write_set);
field->set_key_image(ptr, len);
- dbug_tmp_restore_column_map(field->table->write_set, old_map);
+ dbug_tmp_restore_column_map(&field->table->write_set, old_map);
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -3479,7 +3478,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
PART_PRUNE_PARAM prune_param;
MEM_ROOT alloc;
RANGE_OPT_PARAM *range_par= &prune_param.range_param;
- my_bitmap_map *old_sets[2];
+ MY_BITMAP *old_sets[2];
prune_param.part_info= part_info;
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0,
@@ -3495,7 +3494,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
}
dbug_tmp_use_all_columns(table, old_sets,
- table->read_set, table->write_set);
+ &table->read_set, &table->write_set);
range_par->thd= thd;
range_par->table= table;
/* range_par->cond doesn't need initialization */
@@ -3592,7 +3591,7 @@ all_used:
retval= FALSE; // some partitions are used
mark_all_partitions_as_used(prune_param.part_info);
end:
- dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
+ dbug_tmp_restore_column_maps(&table->read_set, &table->write_set, old_sets);
thd->no_errors=0;
thd->mem_root= range_par->old_root;
free_root(&alloc,MYF(0)); // Return memory & allocator
@@ -7158,6 +7157,30 @@ SEL_TREE *Item_func_in::get_func_mm_tree(RANGE_OPT_PARAM *param,
if (array->count > NOT_IN_IGNORE_THRESHOLD || !value_item)
DBUG_RETURN(0);
+ /*
+ If this is "unique_key NOT IN (...)", do not consider it sargable (for
+ any index, not just the unique one). The logic is as follows:
+ - if there are only a few constants, this condition is not selective
+ (unless the table is also very small in which case we won't gain
+ anything)
+ - If there are a lot of constants, the overhead of building and
+ processing enormous range list is not worth it.
+ */
+ if (param->using_real_indexes)
+ {
+ key_map::Iterator it(field->key_start);
+ uint key_no;
+ while ((key_no= it++) != key_map::Iterator::BITMAP_END)
+ {
+ KEY *key_info= &field->table->key_info[key_no];
+ if (key_info->user_defined_key_parts == 1 &&
+ (key_info->flags & HA_NOSAME))
+ {
+ DBUG_RETURN(0);
+ }
+ }
+ }
+
/* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
uint i=0;
do
@@ -10362,6 +10385,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
uint keynr= param->real_keynr[idx];
DBUG_ENTER("check_quick_select");
+ param->is_ror_scan= FALSE;
/* Handle cases when we don't have a valid non-empty list of range */
if (!tree)
DBUG_RETURN(HA_POS_ERROR);
@@ -14786,6 +14810,113 @@ static void print_ror_scans_arr(TABLE *table, const char *msg,
DBUG_VOID_RETURN;
}
+static String dbug_print_sel_arg_buf;
+
+static void
+print_sel_arg_key(Field *field, const uchar *key, String *out)
+{
+ TABLE *table= field->table;
+ MY_BITMAP *old_sets[2];
+ dbug_tmp_use_all_columns(table, old_sets, &table->read_set, &table->write_set);
+
+ if (field->real_maybe_null())
+ {
+ if (*key)
+ {
+ out->append("NULL");
+ goto end;
+ }
+ key++; // Skip null byte
+ }
+
+ field->set_key_image(key, field->pack_length());
+
+ if (field->type() == MYSQL_TYPE_BIT)
+ (void) field->val_int_as_str(out, 1);
+ else
+ field->val_str(out);
+
+end:
+ dbug_tmp_restore_column_maps(&table->read_set, &table->write_set, old_sets);
+}
+
+
+/*
+ @brief
+ Produce a string representation of an individual SEL_ARG and return pointer
+ to it
+
+ @detail
+ Intended usage:
+
+ (gdb) p dbug_print_sel_arg(ptr)
+*/
+
+const char *dbug_print_sel_arg(SEL_ARG *sel_arg)
+{
+ StringBuffer<64> buf;
+ String &out= dbug_print_sel_arg_buf;
+ out.length(0);
+
+ if (!sel_arg)
+ {
+ out.append("NULL");
+ goto end;
+ }
+
+ out.append("SEL_ARG(");
+
+ const char *stype;
+ switch(sel_arg->type) {
+ case SEL_ARG::IMPOSSIBLE:
+ stype="IMPOSSIBLE";
+ break;
+ case SEL_ARG::MAYBE:
+ stype="MAYBE";
+ break;
+ case SEL_ARG::MAYBE_KEY:
+ stype="MAYBE_KEY";
+ break;
+ case SEL_ARG::KEY_RANGE:
+ default:
+ stype= NULL;
+ }
+
+ if (stype)
+ {
+ out.append("type=");
+ out.append(stype);
+ goto end;
+ }
+
+ if (sel_arg->min_flag & NO_MIN_RANGE)
+ out.append("-inf");
+ else
+ {
+ print_sel_arg_key(sel_arg->field, sel_arg->min_value, &buf);
+ out.append(buf);
+ }
+
+ out.append((sel_arg->min_flag & NEAR_MIN)? "<" : "<=");
+
+ out.append(sel_arg->field->field_name);
+
+ out.append((sel_arg->max_flag & NEAR_MAX)? "<" : "<=");
+
+ if (sel_arg->max_flag & NO_MAX_RANGE)
+ out.append("+inf");
+ else
+ {
+ print_sel_arg_key(sel_arg->field, sel_arg->max_value, &buf);
+ out.append(buf);
+ }
+
+ out.append(")");
+
+end:
+ return dbug_print_sel_arg_buf.c_ptr_safe();
+}
+
/*****************************************************************************
** Print a quick range for debugging
@@ -14801,9 +14932,9 @@ print_key(KEY_PART *key_part, const uchar *key, uint used_length)
const uchar *key_end= key+used_length;
uint store_length;
TABLE *table= key_part->field->table;
- my_bitmap_map *old_sets[2];
+ MY_BITMAP *old_sets[2];
- dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
+ dbug_tmp_use_all_columns(table, old_sets, &table->read_set, &table->write_set);
for (; key < key_end; key+=store_length, key_part++)
{
@@ -14830,7 +14961,7 @@ print_key(KEY_PART *key_part, const uchar *key, uint used_length)
if (key+store_length < key_end)
fputc('/',DBUG_FILE);
}
- dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
+ dbug_tmp_restore_column_maps(&table->read_set, &table->write_set, old_sets);
}
@@ -14838,16 +14969,16 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
{
char buf[MAX_KEY/8+1];
TABLE *table;
- my_bitmap_map *old_sets[2];
+ MY_BITMAP *old_sets[2];
DBUG_ENTER("print_quick");
if (!quick)
DBUG_VOID_RETURN;
DBUG_LOCK_FILE;
table= quick->head;
- dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
+ dbug_tmp_use_all_columns(table, old_sets, &table->read_set, &table->write_set);
quick->dbug_dump(0, TRUE);
- dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
+ dbug_tmp_restore_column_maps(&table->read_set, &table->write_set, old_sets);
fprintf(DBUG_FILE,"other_keys: 0x%s:\n", needed_reg->print(buf));
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 02b95dae44a..868d8b26f4b 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -830,7 +830,10 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
if (is_field_part)
{
if (between || eq_type)
+ {
*range_fl&= ~(NO_MAX_RANGE | NO_MIN_RANGE);
+ *range_fl&= ~(max_fl ? NEAR_MAX : NEAR_MIN);
+ }
else
{
*range_fl&= ~(max_fl ? NO_MAX_RANGE : NO_MIN_RANGE);
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index ef817fffe1e..503b523a66c 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -1642,13 +1642,13 @@ void partition_info::print_no_partition_found(TABLE *table_arg, myf errflag)
buf_ptr= (char*)"from column_list";
else
{
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table_arg, table_arg->read_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table_arg, &table_arg->read_set);
if (part_expr->null_value)
buf_ptr= (char*)"NULL";
else
longlong10_to_str(err_value, buf,
part_expr->unsigned_flag ? 10 : -10);
- dbug_tmp_restore_column_map(table_arg->read_set, old_map);
+ dbug_tmp_restore_column_map(&table_arg->read_set, old_map);
}
my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, errflag, buf_ptr);
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index de6d1b96f76..1bffcfb3bdb 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1250,15 +1250,15 @@ bool Protocol_text::store(Field *field)
CHARSET_INFO *tocs= this->thd->variables.character_set_results;
#ifndef DBUG_OFF
TABLE *table= field->table;
- my_bitmap_map *old_map= 0;
+ MY_BITMAP *old_map= 0;
if (table->file)
- old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ old_map= dbug_tmp_use_all_columns(table, &table->read_set);
#endif
field->val_str(&str);
#ifndef DBUG_OFF
if (old_map)
- dbug_tmp_restore_column_map(table->read_set, old_map);
+ dbug_tmp_restore_column_map(&table->read_set, old_map);
#endif
return store_string_aux(str.ptr(), str.length(), str.charset(), tocs);
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index 43fdeec9e6a..a8f7641fce4 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -432,7 +432,7 @@ rpl_slave_state::truncate_state_table(THD *thd)
close_thread_tables(thd);
ha_commit_trans(thd, TRUE);
}
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
reenable_binlog(thd);
@@ -726,7 +726,7 @@ end:
}
else
{
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
#ifdef HAVE_REPLICATION
rpl_group_info::pending_gtid_deletes_free(elist);
#endif
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index 53999d57bf6..3bcc0204036 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -68,34 +68,34 @@ injector::transaction::~transaction()
*/
int injector::transaction::commit()
{
- DBUG_ENTER("injector::transaction::commit()");
- int error= m_thd->binlog_flush_pending_rows_event(true);
- /*
- Cluster replication does not preserve statement or
- transaction boundaries of the master. Instead, a new
- transaction on replication slave is started when a new GCI
- (global checkpoint identifier) is issued, and is committed
- when the last event of the check point has been received and
- processed. This ensures consistency of each cluster in
- cluster replication, and there is no requirement for stronger
- consistency: MySQL replication is asynchronous with other
- engines as well.
-
- A practical consequence of that is that row level replication
- stream passed through the injector thread never contains
- COMMIT events.
- Here we should preserve the server invariant that there is no
- outstanding statement transaction when the normal transaction
- is committed by committing the statement transaction
- explicitly.
- */
- trans_commit_stmt(m_thd);
- if (!trans_commit(m_thd))
- {
- close_thread_tables(m_thd);
- m_thd->mdl_context.release_transactional_locks();
- }
- DBUG_RETURN(error);
+ DBUG_ENTER("injector::transaction::commit()");
+ int error= m_thd->binlog_flush_pending_rows_event(true);
+ /*
+ Cluster replication does not preserve statement or
+ transaction boundaries of the master. Instead, a new
+ transaction on replication slave is started when a new GCI
+ (global checkpoint identifier) is issued, and is committed
+ when the last event of the check point has been received and
+ processed. This ensures consistency of each cluster in
+ cluster replication, and there is no requirement for stronger
+ consistency: MySQL replication is asynchronous with other
+ engines as well.
+
+ A practical consequence of that is that row level replication
+ stream passed through the injector thread never contains
+ COMMIT events.
+ Here we should preserve the server invariant that there is no
+ outstanding statement transaction when the normal transaction
+ is committed by committing the statement transaction
+ explicitly.
+ */
+ trans_commit_stmt(m_thd);
+ if (!trans_commit(m_thd))
+ {
+ close_thread_tables(m_thd);
+ m_thd->release_transactional_locks();
+ }
+ DBUG_RETURN(error);
}
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 4cf87ba73b7..869640fd46f 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -4,6 +4,7 @@
#include "rpl_mi.h"
#include "sql_parse.h"
#include "debug_sync.h"
+#include "sql_repl.h"
/*
Code for optional parallel execution of replicated events on the slave.
@@ -82,7 +83,7 @@ handle_queued_pos_update(THD *thd, rpl_parallel_thread::queued_event *qev)
return;
mysql_mutex_lock(&rli->data_lock);
- cmp= strcmp(rli->group_relay_log_name, qev->event_relay_log_name);
+ cmp= compare_log_name(rli->group_relay_log_name, qev->event_relay_log_name);
if (cmp < 0)
{
rli->group_relay_log_pos= qev->future_event_relay_log_pos;
@@ -91,7 +92,7 @@ handle_queued_pos_update(THD *thd, rpl_parallel_thread::queued_event *qev)
rli->group_relay_log_pos < qev->future_event_relay_log_pos)
rli->group_relay_log_pos= qev->future_event_relay_log_pos;
- cmp= strcmp(rli->group_master_log_name, qev->future_event_master_log_name);
+ cmp= compare_log_name(rli->group_master_log_name, qev->future_event_master_log_name);
if (cmp < 0)
{
strcpy(rli->group_master_log_name, qev->future_event_master_log_name);
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 99f8da2c928..5273b33c728 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -454,7 +454,8 @@ static inline int add_relay_log(Relay_log_info* rli,LOG_INFO* linfo)
linfo->log_file_name);
DBUG_RETURN(1);
}
- rli->log_space_total += s.st_size;
+ my_atomic_add64_explicit((volatile int64*)(&rli->log_space_total),
+ s.st_size, MY_MEMORY_ORDER_RELAXED);
DBUG_PRINT("info",("log_space_total: %llu", rli->log_space_total));
DBUG_RETURN(0);
}
@@ -464,7 +465,8 @@ static int count_relay_log_space(Relay_log_info* rli)
{
LOG_INFO linfo;
DBUG_ENTER("count_relay_log_space");
- rli->log_space_total= 0;
+ my_atomic_store64_explicit((volatile int64*)(&rli->log_space_total), 0,
+ MY_MEMORY_ORDER_RELAXED);
if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
{
sql_print_error("Could not find first log while counting relay log space");
@@ -987,7 +989,7 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
if (rgi->is_parallel_exec)
{
/* In case of parallel replication, do not update the position backwards. */
- int cmp= strcmp(group_relay_log_name, rgi->event_relay_log_name);
+ int cmp= compare_log_name(group_relay_log_name, rgi->event_relay_log_name);
if (cmp < 0)
{
group_relay_log_pos= rgi->future_event_relay_log_pos;
@@ -999,7 +1001,7 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
In the parallel case we need to update the master_log_name here, rather
than in Rotate_log_event::do_update_pos().
*/
- cmp= strcmp(group_master_log_name, rgi->future_event_master_log_name);
+ cmp= compare_log_name(group_master_log_name, rgi->future_event_master_log_name);
if (cmp <= 0)
{
if (cmp < 0)
@@ -1223,8 +1225,8 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
strmake_buf(rli->group_relay_log_name, rli->relay_log.get_log_fname());
strmake_buf(rli->event_relay_log_name, rli->relay_log.get_log_fname());
rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
- rli->log_space_total= 0;
-
+ my_atomic_store64_explicit((volatile int64*)(&rli->log_space_total), 0,
+ MY_MEMORY_ORDER_RELAXED);
if (count_relay_log_space(rli))
{
*errmsg= "Error counting relay log space";
@@ -1734,7 +1736,7 @@ end:
if (table_opened)
{
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
if (array_inited)
delete_dynamic(&array);
@@ -1902,7 +1904,7 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
if (error)
{
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
if (thd == rli->sql_driver_thd)
{
@@ -2016,10 +2018,10 @@ void rpl_group_info::slave_close_thread_tables(THD *thd)
if (thd->transaction_rollback_request)
{
trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
else if (! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
else
thd->mdl_context.release_statement_locks();
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index c913a0477d7..61c53e6b6e3 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -30,6 +30,11 @@
#define SIGNAL_FMT "signal %d"
#endif
+
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#endif
+
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
@@ -51,7 +56,7 @@ extern const char *optimizer_switch_names[];
static inline void output_core_info()
{
/* proc is optional on some BSDs so it can't hurt to look */
-#ifdef HAVE_READLINK
+#if defined(HAVE_READLINK) && !defined(__APPLE__)
char buff[PATH_MAX];
ssize_t len;
int fd;
@@ -77,6 +82,13 @@ static inline void output_core_info()
my_close(fd, MYF(0));
}
#endif
+#elif defined(__APPLE__)
+ char buff[PATH_MAX];
+ size_t len = sizeof(buff);
+ if (sysctlbyname("kern.corefile", buff, &len, NULL, 0) == 0)
+ {
+ my_safe_printf_stderr("Core pattern: %.*s\n", (int) len, buff);
+ }
#else
char buff[80];
my_getwd(buff, sizeof(buff), 0);
diff --git a/sql/slave.cc b/sql/slave.cc
index 87eacfcfd0a..3124b2d10ab 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -60,6 +60,7 @@
#include "rpl_tblmap.h"
#include "debug_sync.h"
#include "rpl_parallel.h"
+#include "sql_manager.h"
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
@@ -279,8 +280,6 @@ static void init_slave_psi_keys(void)
#endif /* HAVE_PSI_INTERFACE */
-static bool slave_background_thread_running;
-static bool slave_background_thread_stop;
static bool slave_background_thread_gtid_loaded;
struct slave_background_kill_t {
@@ -289,24 +288,15 @@ struct slave_background_kill_t {
} *slave_background_kill_list;
-pthread_handler_t
-handle_slave_background(void *arg __attribute__((unused)))
+static void bg_rpl_load_gtid_slave_state(void *)
{
- THD *thd;
- PSI_stage_info old_stage;
- bool stop;
-
- my_thread_init();
- thd= new THD(next_thread_id());
+ THD *thd= new THD(next_thread_id());
thd->thread_stack= (char*) &thd; /* Set approximate stack start */
thd->system_thread = SYSTEM_THREAD_SLAVE_BACKGROUND;
- thread_safe_increment32(&service_thread_count);
thd->store_globals();
thd->security_ctx->skip_grants();
thd->set_command(COM_DAEMON);
-#ifdef WITH_WSREP
thd->variables.wsrep_on= 0;
-#endif
thd_proc_info(thd, "Loading slave GTID position from table");
if (rpl_load_gtid_slave_state(thd))
@@ -316,136 +306,34 @@ handle_slave_background(void *arg __attribute__((unused)))
thd->get_stmt_da()->sql_errno(),
thd->get_stmt_da()->message());
- mysql_mutex_lock(&LOCK_slave_background);
+ // hijacking global_rpl_thread_pool cond here - it's only once on startup
+ mysql_mutex_lock(&global_rpl_thread_pool.LOCK_rpl_thread_pool);
slave_background_thread_gtid_loaded= true;
- mysql_cond_broadcast(&COND_slave_background);
-
- THD_STAGE_INFO(thd, stage_slave_background_process_request);
- do
- {
- slave_background_kill_t *kill_list;
-
- thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background,
- &stage_slave_background_wait_request,
- &old_stage);
- for (;;)
- {
- stop= abort_loop || thd->killed || slave_background_thread_stop;
- kill_list= slave_background_kill_list;
- if (stop || kill_list)
- break;
- mysql_cond_wait(&COND_slave_background, &LOCK_slave_background);
- }
-
- slave_background_kill_list= NULL;
- thd->EXIT_COND(&old_stage);
-
- while (kill_list)
- {
- slave_background_kill_t *p = kill_list;
- THD *to_kill= p->to_kill;
- kill_list= p->next;
-
- mysql_mutex_lock(&to_kill->LOCK_thd_data);
- to_kill->awake(KILL_CONNECTION);
- mysql_mutex_unlock(&to_kill->LOCK_thd_data);
- mysql_mutex_lock(&to_kill->LOCK_wakeup_ready);
- to_kill->rgi_slave->killed_for_retry=
- rpl_group_info::RETRY_KILL_KILLED;
- mysql_cond_broadcast(&to_kill->COND_wakeup_ready);
- mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready);
- my_free(p);
- }
- mysql_mutex_lock(&LOCK_slave_background);
- } while (!stop);
-
- slave_background_thread_running= false;
- mysql_cond_broadcast(&COND_slave_background);
- mysql_mutex_unlock(&LOCK_slave_background);
-
+ mysql_cond_signal(&global_rpl_thread_pool.COND_rpl_thread_pool);
+ mysql_mutex_unlock(&global_rpl_thread_pool.LOCK_rpl_thread_pool);
delete thd;
- thread_safe_decrement32(&service_thread_count);
- signal_thd_deleted();
-
- my_thread_end();
- return 0;
}
-
-
-void
-slave_background_kill_request(THD *to_kill)
+static void bg_slave_kill(void *victim)
{
- if (to_kill->rgi_slave->killed_for_retry)
- return; // Already deadlock killed.
- slave_background_kill_t *p=
- (slave_background_kill_t *)my_malloc(sizeof(*p), MYF(MY_WME));
- if (p)
- {
- p->to_kill= to_kill;
- to_kill->rgi_slave->killed_for_retry=
- rpl_group_info::RETRY_KILL_PENDING;
- mysql_mutex_lock(&LOCK_slave_background);
- p->next= slave_background_kill_list;
- slave_background_kill_list= p;
- mysql_cond_signal(&COND_slave_background);
- mysql_mutex_unlock(&LOCK_slave_background);
- }
+ THD *to_kill= (THD *)victim;
+ mysql_mutex_lock(&to_kill->LOCK_thd_data);
+ to_kill->awake(KILL_CONNECTION);
+ mysql_mutex_unlock(&to_kill->LOCK_thd_data);
+ mysql_mutex_lock(&to_kill->LOCK_wakeup_ready);
+ to_kill->rgi_slave->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
+ mysql_cond_broadcast(&to_kill->COND_wakeup_ready);
+ mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready);
}
-
-/*
- Start the slave background thread.
-
- This thread is currently used for two purposes:
-
- 1. To load the GTID state from mysql.gtid_slave_pos at server start; reading
- from table requires valid THD, which is otherwise not available during
- server init.
-
- 2. To kill worker thread transactions during parallel replication, when a
- storage engine attempts to take an errorneous conflicting lock that would
- cause a deadlock. Killing is done asynchroneously, as the kill may not
- be safe within the context of a callback from inside storage engine
- locking code.
-*/
-static int
-start_slave_background_thread()
+void slave_background_kill_request(THD *to_kill)
{
- pthread_t th;
-
- slave_background_thread_running= true;
- slave_background_thread_stop= false;
- slave_background_thread_gtid_loaded= false;
- if (mysql_thread_create(key_thread_slave_background,
- &th, &connection_attrib, handle_slave_background,
- NULL))
- {
- sql_print_error("Failed to create thread while initialising slave");
- return 1;
- }
-
- mysql_mutex_lock(&LOCK_slave_background);
- while (!slave_background_thread_gtid_loaded)
- mysql_cond_wait(&COND_slave_background, &LOCK_slave_background);
- mysql_mutex_unlock(&LOCK_slave_background);
-
- return 0;
-}
-
-
-static void
-stop_slave_background_thread()
-{
- mysql_mutex_lock(&LOCK_slave_background);
- slave_background_thread_stop= true;
- mysql_cond_broadcast(&COND_slave_background);
- while (slave_background_thread_running)
- mysql_cond_wait(&COND_slave_background, &LOCK_slave_background);
- mysql_mutex_unlock(&LOCK_slave_background);
+ if (to_kill->rgi_slave->killed_for_retry)
+ return; // Already deadlock killed.
+ to_kill->rgi_slave->killed_for_retry= rpl_group_info::RETRY_KILL_PENDING;
+ mysql_manager_submit(bg_slave_kill, to_kill);
}
-
/* Initialize slave structures */
int init_slave()
@@ -457,12 +345,19 @@ int init_slave()
init_slave_psi_keys();
#endif
- if (start_slave_background_thread())
- return 1;
-
if (global_rpl_thread_pool.init(opt_slave_parallel_threads))
return 1;
+ slave_background_thread_gtid_loaded= false;
+ mysql_manager_submit(bg_rpl_load_gtid_slave_state, NULL);
+
+ // hijacking global_rpl_thread_pool cond here - it's only once on startup
+ mysql_mutex_lock(&global_rpl_thread_pool.LOCK_rpl_thread_pool);
+ while (!slave_background_thread_gtid_loaded)
+ mysql_cond_wait(&global_rpl_thread_pool.COND_rpl_thread_pool,
+ &global_rpl_thread_pool.LOCK_rpl_thread_pool);
+ mysql_mutex_unlock(&global_rpl_thread_pool.LOCK_rpl_thread_pool);
+
/*
This is called when mysqld starts. Before client connections are
accepted. However bootstrap may conflict with us if it does START SLAVE.
@@ -1080,7 +975,6 @@ void slave_prepare_for_shutdown()
mysql_mutex_lock(&LOCK_active_mi);
master_info_index->free_connections();
mysql_mutex_unlock(&LOCK_active_mi);
- stop_slave_background_thread();
}
/*
@@ -1111,8 +1005,6 @@ void end_slave()
active_mi= 0;
mysql_mutex_unlock(&LOCK_active_mi);
- stop_slave_background_thread();
-
global_rpl_thread_pool.destroy();
free_all_rpl_filters();
DBUG_VOID_RETURN;
@@ -2373,7 +2265,10 @@ static bool wait_for_relay_log_space(Relay_log_info* rli)
&rli->log_space_lock,
&stage_waiting_for_relay_log_space,
&old_stage);
- while (rli->log_space_limit < rli->log_space_total &&
+ while (rli->log_space_limit <
+ (ulonglong)my_atomic_load64_explicit((volatile int64*)
+ (&rli->log_space_total),
+ MY_MEMORY_ORDER_RELAXED) &&
!(slave_killed=io_slave_killed(mi)) &&
!rli->ignore_log_space_limit)
mysql_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
@@ -2923,7 +2818,10 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
protocol->store(mi->rli.last_error().message, &my_charset_bin);
protocol->store((uint32) mi->rli.slave_skip_counter);
protocol->store((ulonglong) mi->rli.group_master_log_pos);
- protocol->store((ulonglong) mi->rli.log_space_total);
+ protocol->store((ulonglong)
+ my_atomic_load64_explicit((volatile int64*)
+ (&mi->rli.log_space_total),
+ MY_MEMORY_ORDER_RELAXED));
protocol->store(
mi->rli.until_condition==Relay_log_info::UNTIL_NONE ? "None":
@@ -4329,9 +4227,7 @@ pthread_handler_t handle_slave_io(void *arg)
goto err;
}
-#ifdef WITH_WSREP
thd->variables.wsrep_on= 0;
-#endif
if (RUN_HOOK(binlog_relay_io, thread_start, (thd, mi)))
{
mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL,
@@ -4623,7 +4519,9 @@ Stopping slave I/O thread due to out-of-memory error from master");
#endif
if (rli->log_space_limit && rli->log_space_limit <
- rli->log_space_total &&
+ (ulonglong) my_atomic_load64_explicit((volatile int64*)
+ (&rli->log_space_total),
+ MY_MEMORY_ORDER_RELAXED) &&
!rli->ignore_log_space_limit)
if (wait_for_relay_log_space(rli))
{
@@ -4638,8 +4536,11 @@ log space");
err:
// print the current replication position
if (mi->using_gtid == Master_info::USE_GTID_NO)
+ {
sql_print_information("Slave I/O thread exiting, read up to log '%s', "
"position %llu", IO_RPL_LOG_NAME, mi->master_log_pos);
+ sql_print_information("master was %s:%d", mi->host, mi->port);
+ }
else
{
StringBuffer<100> tmp;
@@ -4648,6 +4549,7 @@ err:
"position %llu; GTID position %s",
IO_RPL_LOG_NAME, mi->master_log_pos,
tmp.c_ptr_safe());
+ sql_print_information("master was %s:%d", mi->host, mi->port);
}
RUN_HOOK(binlog_relay_io, thread_stop, (thd, mi));
thd->reset_query();
@@ -5236,6 +5138,7 @@ pthread_handler_t handle_slave_sql(void *arg)
sql_print_information("Slave SQL thread exiting, replication stopped in "
"log '%s' at position %llu%s", RPL_LOG_NAME,
rli->group_master_log_pos, tmp.c_ptr_safe());
+ sql_print_information("master was %s:%d", mi->host, mi->port);
}
err_before_start:
@@ -7222,7 +7125,10 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size)
is are able to rotate and purge sometime soon.
*/
if (rli->log_space_limit &&
- rli->log_space_limit < rli->log_space_total)
+ rli->log_space_limit <
+ (ulonglong) my_atomic_load64_explicit((volatile int64*)
+ (&rli->log_space_total),
+ MY_MEMORY_ORDER_RELAXED))
{
/* force rotation if not in an unfinished group */
rli->sql_force_rotate_relay= !rli->is_in_group();
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 6a650183fb8..b205d253733 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2163,10 +2163,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (thd->transaction_rollback_request)
{
trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
else if (! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
else
thd->mdl_context.release_statement_locks();
}
@@ -3119,10 +3119,10 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
if (thd->transaction_rollback_request)
{
trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
else if (! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
else
thd->mdl_context.release_statement_locks();
}
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 83905fc9f3d..711efa91394 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -605,6 +605,7 @@ Geometry *Geometry::create_from_json(Geometry_buffer *buffer,
if (feature_type_found)
goto handle_geometry_key;
}
+ goto err_return;
}
else
{
@@ -1031,6 +1032,119 @@ const Geometry::Class_info *Gis_point::get_class_info() const
}
+/**
+ Function to calculate haversine.
+ Taking as arguments Point and Multipoint geometries.
+ Multipoint geometry has to be single point only.
+ It is up to caller to ensure valid input.
+
+ @param g pointer to the Geometry
+ @param r sphere radius
+ @param error pointer describing the error in case of the boundary conditions
+
+ @return distance in case without error, it is caclulcated distance (non-negative),
+ in case error exist, negative value.
+*/
+double Gis_point::calculate_haversine(const Geometry *g,
+ const double sphere_radius,
+ int *error)
+{
+ DBUG_ASSERT(sphere_radius > 0);
+ double x1r, x2r, y1r, y2r, dlong, dlat, res;
+
+ // This check is done only for optimization purposes where we know it will
+ // be one and only one point in Multipoint
+ if (g->get_class_info()->m_type_id == Geometry::wkb_multipoint)
+ {
+ const char point_size= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE+1; //1 for the type
+ char point_temp[point_size];
+ memset(point_temp+4, Geometry::wkb_point, 1);
+ memcpy(point_temp+5, static_cast<const Gis_multi_point *>(g)->get_data_ptr()+5, 4);
+ memcpy(point_temp+4+WKB_HEADER_SIZE, g->get_data_ptr()+4+WKB_HEADER_SIZE,
+ POINT_DATA_SIZE);
+ point_temp[point_size-1]= '\0';
+ Geometry_buffer gbuff;
+ Geometry *gg= Geometry::construct(&gbuff, point_temp, point_size-1);
+ DBUG_ASSERT(gg);
+ if (static_cast<Gis_point *>(gg)->get_xy_radian(&x2r, &y2r))
+ DBUG_ASSERT(0);
+ }
+ else
+ {
+ if (static_cast<const Gis_point *>(g)->get_xy_radian(&x2r, &y2r))
+ DBUG_ASSERT(0);
+ }
+ if (this->get_xy_radian(&x1r, &y1r))
+ DBUG_ASSERT(0);
+ // Check boundary conditions: longitude[-180,180]
+ if (!((x2r >= -M_PI && x2r <= M_PI) && (x1r >= -M_PI && x1r <= M_PI)))
+ {
+ *error=1;
+ return -1;
+ }
+ // Check boundary conditions: lattitude[-90,90]
+ if (!((y2r >= -M_PI/2 && y2r <= M_PI/2) && (y1r >= -M_PI/2 && y1r <= M_PI/2)))
+ {
+ *error=-1;
+ return -1;
+ }
+ dlat= sin((y2r - y1r)/2)*sin((y2r - y1r)/2);
+ dlong= sin((x2r - x1r)/2)*sin((x2r - x1r)/2);
+ res= 2*sphere_radius*asin((sqrt(dlat + cos(y1r)*cos(y2r)*dlong)));
+ return res;
+}
+
+
+/**
+ Function that calculate spherical distance of Point from Multipoint geometries.
+ In case there is single point in Multipoint geometries calculate_haversine()
+ can handle such case. Otherwise, new geometry (Point) has to be constructed.
+
+ @param g pointer to the Geometry
+ @param r sphere radius
+ @param result pointer to the result
+ @param err pointer to the error obtained from calculate_haversin()
+
+ @return state
+ @retval TRUE failed
+ @retval FALSE success
+*/
+int Gis_point::spherical_distance_multipoints(Geometry *g, const double r,
+ double *result, int *err)
+{
+ uint32 num_of_points2;
+ // To find the minimum radius it cannot be greater than Earth radius
+ double res= 6370986.0;
+ double temp_res= 0.0;
+ const uint32 len= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE + 1;
+ char s[len];
+ g->num_geometries(&num_of_points2);
+ DBUG_ASSERT(num_of_points2 >= 1);
+ if (num_of_points2 == 1)
+ {
+ *result= this->calculate_haversine(g, r, err);
+ return 0;
+ }
+ for (uint32 i=1; i <= num_of_points2; i++)
+ {
+ Geometry_buffer buff_temp;
+ Geometry *temp;
+
+ // First 4 bytes are handled already, make sure to create a Point
+ memset(s + 4, Geometry::wkb_point, 1);
+ memcpy(s + 5, g->get_data_ptr() + 5, 4);
+ memcpy(s + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\
+ POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE);
+ s[len-1]= '\0';
+ temp= Geometry::construct(&buff_temp, s, len);
+ DBUG_ASSERT(temp);
+ temp_res= this->calculate_haversine(temp, r, err);
+ if (res > temp_res)
+ res= temp_res;
+ }
+ *result= res;
+ return 0;
+}
/***************************** LineString *******************************/
uint32 Gis_line_string::get_data_size() const
@@ -2161,6 +2275,81 @@ const Geometry::Class_info *Gis_multi_point::get_class_info() const
}
+/**
+ Function that calculate spherical distance of Multipoints geometries.
+ In case there is single point in Multipoint geometries calculate_haversine()
+ can handle such case. Otherwise, new geometry (Point) has to be constructed.
+
+ @param g pointer to the Geometry
+ @param r sphere radius
+ @param result pointer to the result
+ @param err pointer to the error obtained from calculate_haversin()
+
+ @return state
+ @retval TRUE failed
+ @retval FALSE success
+*/
+int Gis_multi_point::spherical_distance_multipoints(Geometry *g, const double r,
+ double *result, int *err)
+{
+ const uint32 len= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE + 1;
+ // Check how many points are stored in Multipoints
+ uint32 num_of_points1, num_of_points2;
+ // To find the minimum radius it cannot be greater than Earth radius
+ double res= 6370986.0;
+
+ /* From Item_func_sphere_distance::spherical_distance_points,
+ we are sure that there will be multiple points and we have to construct
+ Point geometry and return the smallest result.
+ */
+ num_geometries(&num_of_points1);
+ DBUG_ASSERT(num_of_points1 >= 1);
+ g->num_geometries(&num_of_points2);
+ DBUG_ASSERT(num_of_points2 >= 1);
+
+ for (uint32 i=1; i <= num_of_points1; i++)
+ {
+ Geometry_buffer buff_temp;
+ Geometry *temp;
+ double temp_res= 0.0;
+ char s[len];
+ // First 4 bytes are handled already, make sure to create a Point
+ memset(s + 4, Geometry::wkb_point, 1);
+ memcpy(s + 5, this->get_data_ptr() + 5, 4);
+ memcpy(s + 4 + WKB_HEADER_SIZE, this->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\
+ POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE);
+ s[len-1]= '\0';
+ temp= Geometry::construct(&buff_temp, s, len);
+ DBUG_ASSERT(temp);
+ // Optimization for single Multipoint
+ if (num_of_points2 == 1)
+ {
+ *result= static_cast<Gis_point *>(temp)->calculate_haversine(g, r, err);
+ return 0;
+ }
+ for (uint32 j=1; j<= num_of_points2; j++)
+ {
+ Geometry_buffer buff_temp2;
+ Geometry *temp2;
+ char s2[len];
+ // First 4 bytes are handled already, make sure to create a Point
+ memset(s2 + 4, Geometry::wkb_point, 1);
+ memcpy(s2 + 5, g->get_data_ptr() + 5, 4);
+ memcpy(s2 + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*j +\
+ POINT_DATA_SIZE*(j-1), POINT_DATA_SIZE);
+ s2[len-1]= '\0';
+ temp2= Geometry::construct(&buff_temp2, s2, len);
+ DBUG_ASSERT(temp2);
+ temp_res= static_cast<Gis_point *>(temp)->calculate_haversine(temp2, r, err);
+ if (res > temp_res)
+ res= temp_res;
+ }
+ }
+ *result= res;
+ return 0;
+}
+
+
/***************************** MultiLineString *******************************/
uint32 Gis_multi_line_string::get_data_size() const
diff --git a/sql/spatial.h b/sql/spatial.h
index e78da6e615d..1da788b07a0 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -332,6 +332,11 @@ public:
m_data+= WKB_HEADER_SIZE;
}
+ const char *get_data_ptr() const
+ {
+ return m_data;
+ }
+
bool envelope(String *result) const;
static Class_info *ci_collection[wkb_last+1];
@@ -410,6 +415,17 @@ public:
return 0;
}
+ int get_xy_radian(double *x, double *y) const
+ {
+ if (!get_xy(x, y))
+ {
+ *x= (*x)*M_PI/180;
+ *y= (*y)*M_PI/180;
+ return 0;
+ }
+ return 1;
+ }
+
int get_x(double *x) const
{
if (no_data(m_data, SIZEOF_STORED_DOUBLE))
@@ -436,6 +452,10 @@ public:
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
+ double calculate_haversine(const Geometry *g, const double sphere_radius,
+ int *error);
+ int spherical_distance_multipoints(Geometry *g, const double r, double *result,
+ int *error);
};
@@ -535,6 +555,8 @@ public:
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
+ int spherical_distance_multipoints(Geometry *g, const double r, double *res,
+ int *error);
};
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 641ab69c2a7..f1034986f22 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2770,6 +2770,12 @@ end:
int acl_check_setrole(THD *thd, char *rolename, ulonglong *access)
{
+ if (!initialized)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
+ return 1;
+ }
+
return check_user_can_set_role(thd, thd->security_ctx->priv_user,
thd->security_ctx->host, thd->security_ctx->ip, rolename, access);
}
@@ -8945,7 +8951,8 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry,
if (!handle_as_role)
add_user_parameters(&global, (ACL_USER *)acl_entry, (want_access & GRANT_ACL));
-
+ else if (want_access & GRANT_ACL)
+ global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
protocol->prepare_for_resend();
protocol->store(global.ptr(),global.length(),global.charset());
if (protocol->write())
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index af4b9127f8f..17eede61337 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -42,7 +42,7 @@ static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list)
trans_rollback_stmt(thd);
trans_rollback(thd);
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
/*
table_list->table has been closed and freed. Do not reference
@@ -115,7 +115,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
acquire the exclusive lock to satisfy MDL asserts and avoid
deadlocks.
*/
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
/*
Attempt to do full-blown table open in mysql_admin_table() has failed.
Let us try to open at least a .FRM for this table.
@@ -266,7 +266,7 @@ end:
}
/* In case of a temporary table there will be no metadata lock. */
if (error && has_mdl_lock)
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
DBUG_RETURN(error);
}
@@ -543,7 +543,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
trans_rollback(thd);
close_thread_tables(thd);
table->table= NULL;
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
MDL_SHARED_NO_READ_WRITE, MDL_TRANSACTION);
}
@@ -597,7 +597,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
trans_rollback_stmt(thd);
trans_rollback(thd);
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
DBUG_PRINT("admin", ("simple error, admin next table"));
continue;
case -1: // error, message could be written to net
@@ -670,7 +670,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
trans_commit_stmt(thd);
trans_commit(thd);
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
lex->reset_query_tables_list(FALSE);
/*
Restore Query_tables_list::sql_command value to make statement
@@ -803,7 +803,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
thd->open_options|= extra_open_options;
close_thread_tables(thd);
table->table= NULL;
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
MDL_SHARED_NO_READ_WRITE, MDL_TRANSACTION);
table->mdl_request.set_type(MDL_SHARED_READ);
@@ -1035,7 +1035,7 @@ send_result_message:
trans_commit_stmt(thd);
trans_commit(thd);
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
/* Clear references to TABLE and MDL_ticket after releasing them. */
table->mdl_request.ticket= NULL;
@@ -1188,7 +1188,7 @@ send_result_message:
goto err;
}
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
/*
If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run
@@ -1226,7 +1226,7 @@ err:
table->table= 0;
}
close_thread_tables(thd); // Shouldn't be needed
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
thd->resume_subsequent_commits(suspended_wfc);
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 635e17d1865..b8d18abb50c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -4341,6 +4341,70 @@ bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_STRING *db,
return false;
}
+/**
+ Extend the table_list to include foreign tables for prelocking.
+
+ @param[in] thd Thread context.
+ @param[in] prelocking_ctx Prelocking context of the statement.
+ @param[in] table_list Table list element for table.
+ @param[in] sp Routine body.
+ @param[out] need_prelocking Set to TRUE if method detects that prelocking
+ required, not changed otherwise.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (OOM).
+*/
+inline bool
+prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking,
+ uint8 op)
+{
+ List <FOREIGN_KEY_INFO> fk_list;
+ List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
+ FOREIGN_KEY_INFO *fk;
+ Query_arena *arena, backup;
+
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+
+ table_list->table->file->get_parent_foreign_key_list(thd, &fk_list);
+ if (thd->is_error())
+ {
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ return TRUE;
+ }
+
+ *need_prelocking= TRUE;
+
+ while ((fk= fk_list_it++))
+ {
+ // FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access
+ static bool can_write[]= { true, false, true, true, false, true };
+ thr_lock_type lock_type;
+
+ if ((op & (1 << TRG_EVENT_DELETE) && can_write[fk->delete_method])
+ || (op & (1 << TRG_EVENT_UPDATE) && can_write[fk->update_method]))
+ lock_type= TL_WRITE_ALLOW_WRITE;
+ else
+ lock_type= TL_READ;
+
+ if (table_already_fk_prelocked(prelocking_ctx->query_tables,
+ fk->foreign_db, fk->foreign_table,
+ lock_type))
+ continue;
+
+ TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
+ tl->init_one_table_for_prelocking(fk->foreign_db->str, fk->foreign_db->length,
+ fk->foreign_table->str, fk->foreign_table->length,
+ NULL, lock_type, false, table_list->belong_to_view,
+ op, &prelocking_ctx->query_tables_last);
+ }
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+
+ return FALSE;
+}
+
/**
Defines how prelocking algorithm for DML statements should handle table list
@@ -4381,55 +4445,21 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list))
return TRUE;
}
-
if (table_list->table->file->referenced_by_foreign_key())
{
- List <FOREIGN_KEY_INFO> fk_list;
- List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
- FOREIGN_KEY_INFO *fk;
- Query_arena *arena, backup;
-
- arena= thd->activate_stmt_arena_if_needed(&backup);
-
- table_list->table->file->get_parent_foreign_key_list(thd, &fk_list);
- if (thd->is_error())
- {
- if (arena)
- thd->restore_active_arena(arena, &backup);
- return TRUE;
- }
-
- *need_prelocking= TRUE;
-
- while ((fk= fk_list_it++))
- {
- // FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access
- static bool can_write[]= { true, false, true, true, false, true };
- uint8 op= table_list->trg_event_map;
- thr_lock_type lock_type;
-
- if ((op & (1 << TRG_EVENT_DELETE) && can_write[fk->delete_method])
- || (op & (1 << TRG_EVENT_UPDATE) && can_write[fk->update_method]))
- lock_type= TL_WRITE_ALLOW_WRITE;
- else
- lock_type= TL_READ;
-
- if (table_already_fk_prelocked(prelocking_ctx->query_tables,
- fk->foreign_db, fk->foreign_table,
- lock_type))
- continue;
-
- TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
- tl->init_one_table_for_prelocking(fk->foreign_db->str, fk->foreign_db->length,
- fk->foreign_table->str, fk->foreign_table->length,
- NULL, lock_type, false, table_list->belong_to_view,
- op, &prelocking_ctx->query_tables_last);
- }
- if (arena)
- thd->restore_active_arena(arena, &backup);
+ return (prepare_fk_prelocking_list(thd, prelocking_ctx, table_list,
+ need_prelocking,
+ table_list->trg_event_map));
}
}
+ else if (table_list->slave_fk_event_map &&
+ table_list->table->file->referenced_by_foreign_key())
+ {
+ return (prepare_fk_prelocking_list(thd, prelocking_ctx,
+ table_list, need_prelocking,
+ table_list->slave_fk_event_map));
+ }
return FALSE;
}
@@ -5795,6 +5825,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Check if there are sufficient access rights to the found field. */
if (check_privileges &&
+ !table_list->is_derived() &&
check_column_grant_in_table_ref(thd, *actual_table, name, length))
fld= WRONG_GRANT;
else
@@ -7647,36 +7678,23 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
- Ensure that we have access rights to all fields to be inserted. Under
- some circumstances, this check may be skipped.
-
- - If any_privileges is true, skip the check.
+ Ensure that we have access rights to all fields to be inserted
+ the table 'tables'. Under some circumstances, this check may be skipped.
- - If the SELECT privilege has been found as fulfilled already for both
- the TABLE and TABLE_LIST objects (and both of these exist, of
- course), the check is skipped.
+ The check is skipped in the following cases:
- - If the SELECT privilege has been found fulfilled for the TABLE object
- and the TABLE_LIST represents a derived table other than a view (see
- below), the check is skipped.
+ - any_privileges is true
- - If the TABLE_LIST object represents a view, we may skip checking if
- the SELECT privilege has been found fulfilled for it, regardless of
- the TABLE object.
+ - the table is a derived table
- - If there is no TABLE object, the test is skipped if either
- * the TABLE_LIST does not represent a view, or
- * the SELECT privilege has been found fulfilled.
+ - the table is a view with SELECT privilege
- A TABLE_LIST that is not a view may be a subquery, an
- information_schema table, or a nested table reference. See the comment
- for TABLE_LIST.
+ - the table is a base table with SELECT privilege
*/
- if (!((table && tables->is_non_derived() &&
- (table->grant.privilege & SELECT_ACL)) ||
- ((!tables->is_non_derived() &&
- (tables->grant.privilege & SELECT_ACL)))) &&
- !any_privileges)
+ if (!any_privileges &&
+ !tables->is_derived() &&
+ !(tables->is_view() && (tables->grant.privilege & SELECT_ACL)) &&
+ !(table && (table->grant.privilege & SELECT_ACL)))
{
field_iterator.set(tables);
if (check_grant_all_columns(thd, SELECT_ACL, &field_iterator))
@@ -8652,7 +8670,7 @@ close_mysql_tables(THD *thd)
if (! thd->in_sub_stmt)
trans_commit_stmt(thd);
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
/*
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 8555ae6ee3e..0de153a5e7d 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1451,7 +1451,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
DBUG_PRINT("qcache", ("\
long %d, 4.1: %d, eof: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
CS client: %u, CS result: %u, CS conn: %u, limit: %llu, TZ: %p, \
-sql mode: 0x%llx, sort len: %llu, conncat len: %llu, div_precision: %lu, \
+sql mode: 0x%llx, sort len: %llu, concat len: %u, div_precision: %lu, \
def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.client_long_flag,
(int)flags.client_protocol_41,
@@ -1951,7 +1951,7 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length)
DBUG_PRINT("qcache", ("\
long %d, 4.1: %d, eof: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
CS client: %u, CS result: %u, CS conn: %u, limit: %llu, TZ: %p, \
-sql mode: 0x%llx, sort len: %llu, conncat len: %llu, div_precision: %lu, \
+sql mode: 0x%llx, sort len: %llu, concat len: %u, div_precision: %lu, \
def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.client_long_flag,
(int)flags.client_protocol_41,
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 6ad73bbb0a2..d428c7fdb80 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -554,11 +554,11 @@ struct Query_cache_query_flags
uint character_set_client_num;
uint character_set_results_num;
uint collation_connection_num;
+ uint group_concat_max_len;
ha_rows limit;
Time_zone *time_zone;
sql_mode_t sql_mode;
ulonglong max_sort_length;
- ulonglong group_concat_max_len;
ulong default_week_format;
ulong div_precision_increment;
MY_LOCALE *lc_time_names;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 0a8c136e556..047d6517a4b 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2020, MariaDB Corporation.
+ Copyright (c) 2008, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -444,6 +444,7 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton,
const void *ha_data)
{
plugin_ref *lock= &thd->ha_data[hton->slot].lock;
+ DBUG_ASSERT(thd == current_thd);
if (ha_data && !*lock)
*lock= ha_lock_engine(NULL, (handlerton*) hton);
else if (!ha_data && *lock)
@@ -451,7 +452,9 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton,
plugin_unlock(NULL, *lock);
*lock= NULL;
}
+ mysql_mutex_lock(&thd->LOCK_thd_data);
*thd_ha_data(thd, hton)= (void*) ha_data;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
}
@@ -2859,12 +2862,12 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
}
/* Create the file world readable */
if ((file= mysql_file_create(key_select_to_file,
- path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
+ path, 0644, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
return file;
#ifdef HAVE_FCHMOD
- (void) fchmod(file, 0666); // Because of umask()
+ (void) fchmod(file, 0644); // Because of umask()
#else
- (void) chmod(path, 0666);
+ (void) chmod(path, 0644);
#endif
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
{
@@ -4485,7 +4488,7 @@ void destroy_thd(MYSQL_THD thd)
void reset_thd(MYSQL_THD thd)
{
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
thd->free_items();
free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
}
@@ -4548,7 +4551,8 @@ extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen)
if (!mysql_mutex_trylock(&thd->LOCK_thd_data))
{
len= MY_MIN(buflen - 1, thd->query_length());
- memcpy(buf, thd->query(), len);
+ if (len)
+ memcpy(buf, thd->query(), len);
mysql_mutex_unlock(&thd->LOCK_thd_data);
}
buf[len]= '\0';
@@ -4726,6 +4730,18 @@ thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd)
DBUG_EXECUTE_IF("disable_thd_need_ordering_with", return 1;);
if (!thd || !other_thd)
return 1;
+#ifdef WITH_WSREP
+ /* wsrep applier, replayer and TOI processing threads are ordered
+ by replication provider, relaxed GAP locking protocol can be used
+ between high priority wsrep threads. Note that this function
+ is called while holding lock_sys mutex, therefore we can't
+ use THD::LOCK_thd_data mutex below to follow mutex ordering rules.
+ */
+ if (WSREP_ON &&
+ wsrep_thd_is_BF(const_cast<THD *>(thd), false) &&
+ wsrep_thd_is_BF(const_cast<THD *>(other_thd), false))
+ return 0;
+#endif /* WITH_WSREP */
rgi= thd->rgi_slave;
other_rgi= other_thd->rgi_slave;
if (!rgi || !other_rgi)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2727b4c84d5..c47ea9c9020 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -555,7 +555,6 @@ typedef struct system_variables
ulonglong bulk_insert_buff_size;
ulonglong join_buff_size;
ulonglong sortbuff_size;
- ulonglong group_concat_max_len;
ulonglong default_regex_flags;
ulonglong max_mem_used;
@@ -645,6 +644,8 @@ typedef struct system_variables
uint32 gtid_domain_id;
uint64 gtid_seq_no;
+ uint group_concat_max_len;
+
/**
Default transaction access mode. READ ONLY (true) or READ WRITE (false).
*/
@@ -864,11 +865,24 @@ void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
STATUS_VAR *dec_var);
+uint calc_sum_of_all_status(STATUS_VAR *to);
+static inline void calc_sum_of_all_status_if_needed(STATUS_VAR *to)
+{
+ if (to->local_memory_used == 0)
+ {
+ mysql_mutex_lock(&LOCK_status);
+ *to= global_status_var;
+ mysql_mutex_unlock(&LOCK_status);
+ calc_sum_of_all_status(to);
+ DBUG_ASSERT(to->local_memory_used);
+ }
+}
+
/*
Update global_memory_used. We have to do this with atomic_add as the
global value can change outside of LOCK_status.
*/
-inline void update_global_memory_status(int64 size)
+static inline void update_global_memory_status(int64 size)
{
DBUG_PRINT("info", ("global memory_used: %lld size: %lld",
(longlong) global_status_var.global_memory_used,
@@ -886,7 +900,7 @@ inline void update_global_memory_status(int64 size)
@retval NULL on error
@retval Pointter to CHARSET_INFO with the given name on success
*/
-inline CHARSET_INFO *
+static inline CHARSET_INFO *
mysqld_collation_get_by_name(const char *name,
CHARSET_INFO *name_cs= system_charset_info)
{
@@ -905,7 +919,7 @@ mysqld_collation_get_by_name(const char *name,
return cs;
}
-inline bool is_supported_parser_charset(CHARSET_INFO *cs)
+static inline bool is_supported_parser_charset(CHARSET_INFO *cs)
{
return MY_TEST(cs->mbminlen == 1);
}
@@ -4177,6 +4191,13 @@ public:
locked_tables_mode= mode_arg;
}
void leave_locked_tables_mode();
+ /* Relesae transactional locks if there are no active transactions */
+ void release_transactional_locks()
+ {
+ if (!(server_status &
+ (SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY)))
+ mdl_context.release_transactional_locks();
+ }
int decide_logging_format(TABLE_LIST *tables);
/*
In Some cases when decide_logging_format is called it does not have all
@@ -5144,10 +5165,15 @@ class select_union_recursive :public select_union
public:
/* The temporary table with the new records generated by one iterative step */
TABLE *incr_table;
+ /* The TMP_TABLE_PARAM structure used to create incr_table */
+ TMP_TABLE_PARAM incr_table_param;
/* One of tables from the list rec_tables (determined dynamically) */
TABLE *first_rec_table_to_update;
- /* The temporary tables used for recursive table references */
- List<TABLE> rec_tables;
+ /*
+ The list of all recursive table references to the CTE for whose
+ specification this select_union_recursive was created
+ */
+ List<TABLE_LIST> rec_table_refs;
/*
The count of how many times cleanup() was called with cleaned==false
for the unit specifying the recursive CTE for which this object was created
@@ -5157,7 +5183,8 @@ class select_union_recursive :public select_union
select_union_recursive(THD *thd_arg):
select_union(thd_arg),
- incr_table(0), first_rec_table_to_update(0), cleanup_count(0) {};
+ incr_table(0), first_rec_table_to_update(0), cleanup_count(0)
+ { incr_table_param.init(); };
int send_data(List<Item> &items);
bool create_result_table(THD *thd, List<Item> *column_types,
@@ -5449,8 +5476,6 @@ struct SORT_FIELD_ATTR
{
uint length; /* Length of sort field */
uint suffix_length; /* Length suffix (0-4) */
- enum Type { FIXED_SIZE, VARIABLE_SIZE } type;
- bool is_variable_sized() { return type == VARIABLE_SIZE; }
};
@@ -5985,6 +6010,38 @@ class Sql_mode_save
sql_mode_t old_mode; // SQL mode saved at construction time.
};
+class Abort_on_warning_instant_set
+{
+ THD *m_thd;
+ bool m_save_abort_on_warning;
+public:
+ Abort_on_warning_instant_set(THD *thd, bool temporary_value)
+ :m_thd(thd), m_save_abort_on_warning(thd->abort_on_warning)
+ {
+ thd->abort_on_warning= temporary_value;
+ }
+ ~Abort_on_warning_instant_set()
+ {
+ m_thd->abort_on_warning= m_save_abort_on_warning;
+ }
+};
+
+class Check_level_instant_set
+{
+ THD *m_thd;
+ enum_check_fields m_check_level;
+public:
+ Check_level_instant_set(THD *thd, enum_check_fields temporary_value)
+ :m_thd(thd), m_check_level(thd->count_cuted_fields)
+ {
+ thd->count_cuted_fields= temporary_value;
+ }
+ ~Check_level_instant_set()
+ {
+ m_thd->count_cuted_fields= m_check_level;
+ }
+};
+
class Switch_to_definer_security_ctx
{
public:
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index b2900a20b28..ec1bc45433a 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -85,7 +85,6 @@ int get_or_create_user_conn(THD *thd, const char *user,
uc->host= uc->user + user_len + 1;
uc->len= temp_len;
uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
- uc->user_resources= *mqh;
uc->reset_utime= thd->thr_create_utime;
if (my_hash_insert(&hash_user_connections, (uchar*) uc))
{
@@ -95,6 +94,7 @@ int get_or_create_user_conn(THD *thd, const char *user,
goto end;
}
}
+ uc->user_resources= *mqh;
thd->user_connect=uc;
uc->connections++;
end:
@@ -1112,7 +1112,7 @@ void end_connection(THD *thd)
{
NET *net= &thd->net;
#ifdef WITH_WSREP
- if (WSREP(thd))
+ if (WSREP(thd) && wsrep)
{
wsrep_status_t rcode= wsrep->free_connection(wsrep, thd->thread_id);
if (rcode) {
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index fe8e0de71b4..3a2301a5730 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -227,6 +227,7 @@ With_element *With_clause::find_table_def(TABLE_LIST *table,
!table->is_fqtn)
{
table->set_derived();
+ table->db= empty_c_string;
return with_elem;
}
}
@@ -863,8 +864,6 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
goto err;
spec_tables_tail= tbl;
}
- if (check_table_access(thd, SELECT_ACL, spec_tables, FALSE, UINT_MAX, FALSE))
- goto err;
if (spec_tables)
{
if (with_table->next_global)
@@ -880,6 +879,7 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
with_table->next_global= spec_tables;
}
res= &lex->unit;
+ res->with_element= this;
lex->unit.include_down(with_table->select_lex);
lex->unit.set_slave(with_select);
@@ -890,6 +890,22 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
with_select));
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
res= NULL;
+ /*
+ Resolve references to CTE from the spec_tables list that has not
+ been resolved yet.
+ */
+ for (TABLE_LIST *tbl= spec_tables;
+ tbl;
+ tbl= tbl->next_global)
+ {
+ if (!tbl->with)
+ tbl->with= with_select->find_table_def_in_with_clauses(tbl);
+ if (tbl == spec_tables_tail)
+ break;
+ }
+ if (check_table_access(thd, SELECT_ACL, spec_tables, FALSE, UINT_MAX, FALSE))
+ goto err;
+
lex->sphead= NULL; // in order not to delete lex->sphead
lex_end(lex);
err:
@@ -1428,10 +1444,11 @@ void With_element::print(String *str, enum_query_type query_type)
bool With_element::instantiate_tmp_tables()
{
- List_iterator_fast<TABLE> li(rec_result->rec_tables);
- TABLE *rec_table;
- while ((rec_table= li++))
+ List_iterator_fast<TABLE_LIST> li(rec_result->rec_table_refs);
+ TABLE_LIST *rec_tbl;
+ while ((rec_tbl= li++))
{
+ TABLE *rec_table= rec_tbl->table;
if (!rec_table->is_created() &&
instantiate_tmp_table(rec_table,
rec_table->s->key_info,
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 39499e6895f..be5905da683 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -677,7 +677,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
if (derived->is_with_table_recursive_reference())
{
/* Here 'derived" is a secondary recursive table reference */
- unit->with_element->rec_result->rec_tables.push_back(derived->table);
+ unit->with_element->rec_result->rec_table_refs.push_back(derived);
}
}
DBUG_ASSERT(derived->table || res);
@@ -733,17 +733,17 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->fill_me= FALSE;
- if (!(derived->derived_result= new (thd->mem_root) select_union(thd)))
+ if ((!derived->is_with_table_recursive_reference() ||
+ !derived->derived_result) &&
+ !(derived->derived_result= new (thd->mem_root) select_union(thd)))
DBUG_RETURN(TRUE); // out of memory
- lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
// st_select_lex_unit::prepare correctly work for single select
if ((res= unit->prepare(thd, derived->derived_result, 0)))
goto exit;
if (derived->with &&
(res= derived->with->rename_columns_of_derived_unit(thd, unit)))
goto exit;
- lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
if ((res= check_duplicate_names(thd, unit->types, 0)))
goto exit;
@@ -752,7 +752,8 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
Depending on the result field translation will or will not
be created.
*/
- if (derived->init_derived(thd, FALSE))
+ if (!derived->is_with_table_recursive_reference() &&
+ derived->init_derived(thd, FALSE))
goto exit;
/*
@@ -1199,7 +1200,8 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
DBUG_RETURN(false);
st_select_lex_unit *unit= derived->get_unit();
- st_select_lex *sl= unit->first_select();
+ st_select_lex *first_sl= unit->first_select();
+ st_select_lex *sl= first_sl;
if (derived->prohibit_cond_pushdown)
DBUG_RETURN(false);
@@ -1311,7 +1313,24 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!extracted_cond_copy)
continue;
}
-
+
+ /*
+ Rename the columns of all non-first selects of a union to be compatible
+ by names with the columns of the first select. It will allow to use copies
+ of the same expression pushed into having clauses of different selects.
+ */
+ if (sl != first_sl)
+ {
+ DBUG_ASSERT(sl->item_list.elements == first_sl->item_list.elements);
+ List_iterator_fast<Item> it(sl->item_list);
+ List_iterator_fast<Item> nm_it(unit->types);
+ Item * item;
+ while((item= it++))
+ {
+ item->share_name_with(nm_it++);
+ }
+ }
+
/*
Transform the references to the 'derived' columns from the condition
pushed into the having clause of sl to make them usable in the new context
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index a811cee998f..7c2122b6a0a 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -600,7 +600,6 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler,
}
for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++)
{
- my_bitmap_map *old_map;
/* note that 'item' can be changed by fix_fields() call */
if ((!item->fixed &&
item->fix_fields(thd, it_ke.ref())) ||
@@ -613,9 +612,9 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler,
}
if (!in_prepare)
{
- old_map= dbug_tmp_use_all_columns(table, table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set);
(void) item->save_in_field(key_part->field, 1);
- dbug_tmp_restore_column_map(table->write_set, old_map);
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
}
key_len+= key_part->store_length;
keypart_map= (keypart_map << 1) | 1;
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index c05c9a7d229..5ae9d3beb8b 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -741,6 +741,9 @@ static bool mysqld_help_internal(THD *thd, const char *mask)
&name, &description, &example);
delete select;
+ if (thd->is_error())
+ goto error;
+
if (count_topics == 0)
{
int UNINIT_VAR(key_id);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 0c50a251d26..ec79ff6d688 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2948,7 +2948,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
if (thd->mdl_context.clone_ticket(&di->grl_protection) ||
thd->mdl_context.clone_ticket(&di->table_list.mdl_request))
{
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
di->handler_thread_initialized= TRUE;
goto err;
}
@@ -3144,7 +3144,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
mysql_mutex_unlock(&thd->LOCK_thd_data);
close_thread_tables(thd); // Free the table
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
mysql_cond_broadcast(&di->cond_client); // Safety
mysql_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table
@@ -4580,7 +4580,8 @@ bool select_create::send_eof()
WSREP_ERROR("Appending table key for CTAS failed: %s, %d",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
- return true;
+ abort_result_set();
+ DBUG_RETURN(true);
}
/* If commit fails, we should be able to reset the OK status. */
thd->get_stmt_da()->set_overwrite_status(TRUE);
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index 77017812074..4f9facc6d0c 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -1199,7 +1199,7 @@ bool JOIN_CACHE::check_emb_key_usage()
Item *item= ref->items[i]->real_item();
Field *fld= ((Item_field *) item)->field;
CACHE_FIELD *init_copy= field_descr+flag_fields+i;
- for (j= i, copy= init_copy; i < local_key_arg_fields; i++, copy++)
+ for (j= i, copy= init_copy; j < local_key_arg_fields; j++, copy++)
{
if (fld->eq(copy->field))
{
@@ -1395,7 +1395,8 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full)
blob_field->get_image(cp, copy->length,
blob_field->charset());
DBUG_ASSERT(cp + copy->length + copy->blob_length <= buff + buff_size);
- memcpy(cp+copy->length, copy->str, copy->blob_length);
+ if (copy->blob_length)
+ memcpy(cp+copy->length, copy->str, copy->blob_length);
cp+= copy->length+copy->blob_length;
}
break;
@@ -1648,7 +1649,7 @@ void JOIN_CACHE::get_record_by_pos(uchar *rec_ptr)
}
-/*
+/*
Get the match flag from the referenced record: the default implementation
SYNOPSIS
@@ -1660,6 +1661,7 @@ void JOIN_CACHE::get_record_by_pos(uchar *rec_ptr)
get the match flag for the record pointed by the reference at the position
rec_ptr. If the match flag is placed in one of the previous buffers the
function first reaches the linked record fields in this buffer.
+ The function returns the value of the first encountered match flag.
RETURN VALUE
match flag for the record at the position rec_ptr
@@ -1684,6 +1686,39 @@ enum JOIN_CACHE::Match_flag JOIN_CACHE::get_match_flag_by_pos(uchar *rec_ptr)
/*
+ Get the match flag for the referenced record from specified join buffer
+
+ SYNOPSIS
+ get_match_flag_by_pos_from_join_buffer()
+ rec_ptr position of the first field of the record in the join buffer
+ tab join table with join buffer where to look for the match flag
+
+ DESCRIPTION
+ This default implementation of the get_match_flag_by_pos_from_join_buffer
+ method gets the match flag for the record pointed by the reference at the
+ position rec_ptr from the join buffer attached to the join table tab.
+
+ RETURN VALUE
+ match flag for the record at the position rec_ptr from the join
+ buffer attached to the table tab.
+*/
+
+enum JOIN_CACHE::Match_flag
+JOIN_CACHE::get_match_flag_by_pos_from_join_buffer(uchar *rec_ptr,
+ JOIN_TAB *tab)
+{
+ DBUG_ASSERT(tab->cache && tab->cache->with_match_flag);
+ for (JOIN_CACHE *cache= this; ; )
+ {
+ if (cache->join_tab == tab)
+ return (enum Match_flag) rec_ptr[0];
+ cache= cache->prev_cache;
+ rec_ptr= cache->get_rec_ref(rec_ptr);
+ }
+}
+
+
+/*
Calculate the increment of the auxiliary buffer for a record write
SYNOPSIS
@@ -1953,6 +1988,10 @@ bool JOIN_CACHE::read_referenced_field(CACHE_FIELD *copy,
If the record is skipped the value of 'pos' is set to point to the position
right after the record.
+ NOTE
+ Currently this function is called only when generating null complemented
+ records for outer joins (=> only when join_tab->first_unmatched != NULL).
+
RETURN VALUE
TRUE the match flag is set to MATCH_FOUND and the record has been skipped
FALSE otherwise
@@ -1965,7 +2004,9 @@ bool JOIN_CACHE::skip_if_matched()
if (prev_cache)
offset+= prev_cache->get_size_of_rec_offset();
/* Check whether the match flag is MATCH_FOUND */
- if (get_match_flag_by_pos(pos+offset) == MATCH_FOUND)
+ if (get_match_flag_by_pos_from_join_buffer(pos+offset,
+ join_tab->first_unmatched) ==
+ MATCH_FOUND)
{
pos+= size_of_rec_len + get_rec_length(pos);
return TRUE;
@@ -1982,13 +2023,23 @@ bool JOIN_CACHE::skip_if_matched()
DESCRIPTION
This default implementation of the virtual function skip_if_not_needed_match
- skips the next record from the join buffer if its match flag is not
- MATCH_NOT_FOUND, and, either its value is MATCH_FOUND and join_tab is the
- first inner table of an inner join, or, its value is MATCH_IMPOSSIBLE
- and join_tab is the first inner table of an outer join.
+ skips the next record from the join when generating join extensions
+ for the records in the join buffer depending on the value of the match flag.
+ - In the case of a semi-nest the match flag may be in two states
+ {MATCH_NOT_FOUND, MATCH_FOUND}. The record is skipped if the flag is set
+ to MATCH_FOUND.
+ - In the case of a outer join nest when not_exists optimization is applied
+ the match may be in three states {MATCH_NOT_FOUND, MATCH_IMPOSSIBLE,
+ MATCH_FOUND. The record is skipped if the flag is set to MATCH_FOUND or
+ to MATCH_IMPOSSIBLE.
+
If the record is skipped the value of 'pos' is set to point to the position
right after the record.
+ NOTE
+ Currently the function is called only when generating non-null complemented
+ extensions for records in the join buffer.
+
RETURN VALUE
TRUE the record has to be skipped
FALSE otherwise
@@ -1999,11 +2050,19 @@ bool JOIN_CACHE::skip_if_not_needed_match()
DBUG_ASSERT(with_length);
enum Match_flag match_fl;
uint offset= size_of_rec_len;
+ bool skip= FALSE;
if (prev_cache)
offset+= prev_cache->get_size_of_rec_offset();
- if ((match_fl= get_match_flag_by_pos(pos+offset)) != MATCH_NOT_FOUND &&
- (join_tab->check_only_first_match() == (match_fl == MATCH_FOUND)) )
+ if (!join_tab->check_only_first_match())
+ return FALSE;
+
+ match_fl= get_match_flag_by_pos(pos+offset);
+ skip= join_tab->first_sj_inner_tab ?
+ match_fl == MATCH_FOUND : // the case of semi-join
+ match_fl != MATCH_NOT_FOUND; // the case of outer-join
+
+ if (skip)
{
pos+= size_of_rec_len + get_rec_length(pos);
return TRUE;
@@ -2103,7 +2162,14 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last)
goto finish;
}
join_tab->not_null_compl= FALSE;
- /* Prepare for generation of null complementing extensions */
+ /*
+ Prepare for generation of null complementing extensions.
+ For all inner tables of the outer join operation for which
+ regular matches have been just found the field 'first_unmatched'
+ is set to point the the first inner table. After all null
+ complement rows are generated for this outer join this field
+ is set back to NULL.
+ */
for (tab= join_tab->first_inner; tab <= join_tab->last_inner; tab++)
tab->first_unmatched= join_tab->first_inner;
}
@@ -2220,7 +2286,10 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
int error;
enum_nested_loop_state rc= NESTED_LOOP_OK;
join_tab->table->null_row= 0;
- bool check_only_first_match= join_tab->check_only_first_match();
+ bool check_only_first_match=
+ join_tab->check_only_first_match() &&
+ (!join_tab->first_inner || // semi-join case
+ join_tab->first_inner == join_tab->first_unmatched); // outer join case
bool outer_join_first_inner= join_tab->is_first_inner_for_outer_join();
DBUG_ENTER("JOIN_CACHE::join_matching_records");
diff --git a/sql/sql_join_cache.h b/sql/sql_join_cache.h
index 1cbc6acfd79..456991037d1 100644
--- a/sql/sql_join_cache.h
+++ b/sql/sql_join_cache.h
@@ -206,7 +206,9 @@ protected:
/*
This flag indicates that records written into the join buffer contain
- a match flag field. The flag must be set by the init method.
+ a match flag field. The flag must be set by the init method.
+ Currently any implementation of the virtial init method calls
+ the function JOIN_CACHE::calc_record_fields() to set this flag.
*/
bool with_match_flag;
/*
@@ -646,6 +648,13 @@ public:
/* Shall return the value of the match flag for the positioned record */
virtual enum Match_flag get_match_flag_by_pos(uchar *rec_ptr);
+ /*
+ Shall return the value of the match flag for the positioned record
+ from the join buffer attached to the specified table
+ */
+ virtual enum Match_flag
+ get_match_flag_by_pos_from_join_buffer(uchar *rec_ptr, JOIN_TAB *tab);
+
/* Shall return the position of the current record */
virtual uchar *get_curr_rec() { return curr_rec_pos; }
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index e1e307330e3..5059e4f656e 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4450,9 +4450,11 @@ void st_select_lex::set_explain_type(bool on_the_fly)
/*
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
*/
- if (tab->table && tab->table->pos_in_table_list &&
- tab->table->pos_in_table_list->with &&
- tab->table->pos_in_table_list->with->is_recursive)
+ if (!(tab->table && tab->table->pos_in_table_list))
+ continue;
+ TABLE_LIST *tbl= tab->table->pos_in_table_list;
+ if (tbl->with && tbl->with->is_recursive &&
+ tbl->is_with_table_recursive_reference())
{
uses_cte= true;
break;
@@ -4583,6 +4585,9 @@ bool LEX::save_prep_leaf_tables()
bool st_select_lex::save_prep_leaf_tables(THD *thd)
{
+ if (prep_leaf_list_state == SAVED)
+ return FALSE;
+
List_iterator_fast<TABLE_LIST> li(leaf_tables);
TABLE_LIST *table;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 965c3f29834..f733f783d0e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -280,7 +280,7 @@ struct LEX_MASTER_INFO
}
host= user= password= log_file_name= ssl_key= ssl_cert= ssl_ca=
- ssl_capath= ssl_cipher= relay_log_name= 0;
+ ssl_capath= ssl_cipher= ssl_crl= ssl_crlpath= relay_log_name= NULL;
pos= relay_log_pos= server_id= port= connect_retry= 0;
heartbeat_period= 0;
ssl= ssl_verify_server_cert= heartbeat_opt=
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 7fa9a78f06f..d57963cceb0 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -26,8 +26,8 @@
#include "sql_manager.h"
#include "sql_base.h" // flush_tables
-static bool volatile manager_thread_in_use;
-static bool abort_manager;
+static bool volatile manager_thread_in_use = 0;
+static bool abort_manager = false;
pthread_t manager_thread;
mysql_mutex_t LOCK_manager;
@@ -35,31 +35,31 @@ mysql_cond_t COND_manager;
struct handler_cb {
struct handler_cb *next;
- void (*action)(void);
+ void (*action)(void *);
+ void *data;
};
-static struct handler_cb * volatile cb_list;
+static struct handler_cb *cb_list; // protected by LOCK_manager
-bool mysql_manager_submit(void (*action)())
+bool mysql_manager_submit(void (*action)(void *), void *data)
{
bool result= FALSE;
DBUG_ASSERT(manager_thread_in_use);
- struct handler_cb * volatile *cb;
+ struct handler_cb **cb;
mysql_mutex_lock(&LOCK_manager);
cb= &cb_list;
- while (*cb && (*cb)->action != action)
+ while (*cb)
cb= &(*cb)->next;
+ *cb= (struct handler_cb *)my_malloc(sizeof(struct handler_cb), MYF(MY_WME));
if (!*cb)
+ result= TRUE;
+ else
{
- *cb= (struct handler_cb *)my_malloc(sizeof(struct handler_cb), MYF(MY_WME));
- if (!*cb)
- result= TRUE;
- else
- {
- (*cb)->next= NULL;
- (*cb)->action= action;
- }
+ (*cb)->next= NULL;
+ (*cb)->action= action;
+ (*cb)->data= data;
}
+ mysql_cond_signal(&COND_manager);
mysql_mutex_unlock(&LOCK_manager);
return result;
}
@@ -69,18 +69,14 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
int error = 0;
struct timespec abstime;
bool reset_flush_time = TRUE;
- struct handler_cb *cb= NULL;
my_thread_init();
DBUG_ENTER("handle_manager");
pthread_detach_this_thread();
manager_thread = pthread_self();
- mysql_cond_init(key_COND_manager, &COND_manager,NULL);
- mysql_mutex_init(key_LOCK_manager, &LOCK_manager, NULL);
- manager_thread_in_use = 1;
- for (;;)
+ mysql_mutex_lock(&LOCK_manager);
+ while (!abort_manager)
{
- mysql_mutex_lock(&LOCK_manager);
/* XXX: This will need to be made more general to handle different
* polling needs. */
if (flush_time)
@@ -90,40 +86,37 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
set_timespec(abstime, flush_time);
reset_flush_time = FALSE;
}
- while ((!error || error == EINTR) && !abort_manager)
+ while ((!error || error == EINTR) && !abort_manager && !cb_list)
error= mysql_cond_timedwait(&COND_manager, &LOCK_manager, &abstime);
+
+ if (error == ETIMEDOUT || error == ETIME)
+ {
+ tc_purge();
+ error = 0;
+ reset_flush_time = TRUE;
+ }
}
else
{
- while ((!error || error == EINTR) && !abort_manager)
+ while ((!error || error == EINTR) && !abort_manager && !cb_list)
error= mysql_cond_wait(&COND_manager, &LOCK_manager);
}
- if (cb == NULL)
- {
- cb= cb_list;
- cb_list= NULL;
- }
- mysql_mutex_unlock(&LOCK_manager);
- if (abort_manager)
- break;
-
- if (error == ETIMEDOUT || error == ETIME)
- {
- tc_purge();
- error = 0;
- reset_flush_time = TRUE;
- }
+ struct handler_cb *cb= cb_list;
+ cb_list= NULL;
+ mysql_mutex_unlock(&LOCK_manager);
while (cb)
{
struct handler_cb *next= cb->next;
- cb->action();
+ cb->action(cb->data);
my_free(cb);
cb= next;
}
+ mysql_mutex_lock(&LOCK_manager);
}
manager_thread_in_use = 0;
+ mysql_mutex_unlock(&LOCK_manager);
mysql_mutex_destroy(&LOCK_manager);
mysql_cond_destroy(&COND_manager);
DBUG_LEAVE; // Can't use DBUG_RETURN after my_thread_end
@@ -137,15 +130,15 @@ void start_handle_manager()
{
DBUG_ENTER("start_handle_manager");
abort_manager = false;
- if (flush_time && flush_time != ~(ulong) 0L)
{
pthread_t hThread;
- int error;
- if ((error= mysql_thread_create(key_thread_handle_manager,
- &hThread, &connection_attrib,
- handle_manager, 0)))
- sql_print_warning("Can't create handle_manager thread (errno= %d)",
- error);
+ int err;
+ manager_thread_in_use = 1;
+ mysql_cond_init(key_COND_manager, &COND_manager,NULL);
+ mysql_mutex_init(key_LOCK_manager, &LOCK_manager, NULL);
+ if ((err= mysql_thread_create(key_thread_handle_manager, &hThread,
+ &connection_attrib, handle_manager, 0)))
+ sql_print_warning("Can't create handle_manager thread (errno: %M)", err);
}
DBUG_VOID_RETURN;
}
@@ -155,10 +148,10 @@ void start_handle_manager()
void stop_handle_manager()
{
DBUG_ENTER("stop_handle_manager");
- abort_manager = true;
if (manager_thread_in_use)
{
mysql_mutex_lock(&LOCK_manager);
+ abort_manager = true;
DBUG_PRINT("quit", ("initiate shutdown of handle manager thread: %lu",
(ulong)manager_thread));
mysql_cond_signal(&COND_manager);
diff --git a/sql/sql_manager.h b/sql/sql_manager.h
index 9c6c84450ed..f97d4a2cfc5 100644
--- a/sql/sql_manager.h
+++ b/sql/sql_manager.h
@@ -18,6 +18,6 @@
void start_handle_manager();
void stop_handle_manager();
-bool mysql_manager_submit(void (*action)());
+bool mysql_manager_submit(void (*action)(void *), void *data);
#endif /* SQL_MANAGER_INCLUDED */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 83100e743ad..573df24cb33 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2034,7 +2034,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
locks.
*/
trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
thd->cleanup_after_query();
@@ -2099,7 +2099,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ulonglong options= (ulonglong) (uchar) packet[0];
if (trans_commit_implicit(thd))
break;
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
if (check_global_access(thd,RELOAD_ACL))
break;
general_log_print(thd, command, NullS);
@@ -2132,7 +2132,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (trans_commit_implicit(thd))
break;
close_thread_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
my_ok(thd);
break;
}
@@ -2179,6 +2179,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
general_log_print(thd, command, NullS);
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
+ *current_global_status_var= global_status_var;
calc_sum_of_all_status(current_global_status_var);
if (!(uptime= (ulong) (thd->start_time - server_start_time)))
queries_per_second1000= 0;
@@ -2934,7 +2935,7 @@ err:
/* Close tables and release metadata locks. */
close_thread_tables(thd);
DBUG_ASSERT(!thd->locked_tables_mode);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
return TRUE;
}
@@ -2994,6 +2995,146 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
/**
+ Check whether the SQL statement being processed is prepended by
+ SET STATEMENT clause and handle variables assignment if it is.
+
+ @param thd thread handle
+ @param lex current lex
+
+ @return false in case of success, true in case of error.
+*/
+
+bool run_set_statement_if_requested(THD *thd, LEX *lex)
+{
+ if (!lex->stmt_var_list.is_empty() && !thd->slave_thread)
+ {
+ Query_arena backup;
+ DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements));
+
+ lex->old_var_list.empty();
+ List_iterator_fast<set_var_base> it(lex->stmt_var_list);
+ set_var_base *var;
+
+ if (lex->set_arena_for_set_stmt(&backup))
+ return true;
+
+ MEM_ROOT *mem_root= thd->mem_root;
+ while ((var= it++))
+ {
+ DBUG_ASSERT(var->is_system());
+ set_var *o= NULL, *v= (set_var*)var;
+ if (!v->var->is_set_stmt_ok())
+ {
+ my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str);
+ lex->reset_arena_for_set_stmt(&backup);
+ lex->old_var_list.empty();
+ lex->free_arena_for_set_stmt();
+ return true;
+ }
+ if (v->var->session_is_default(thd))
+ o= new set_var(thd,v->type, v->var, &v->base, NULL);
+ else
+ {
+ switch (v->var->option.var_type & GET_TYPE_MASK)
+ {
+ case GET_BOOL:
+ case GET_INT:
+ case GET_LONG:
+ case GET_LL:
+ {
+ bool null_value;
+ longlong val= v->var->val_int(&null_value, thd, v->type, &v->base);
+ o= new set_var(thd, v->type, v->var, &v->base,
+ (null_value ?
+ (Item *) new (mem_root) Item_null(thd) :
+ (Item *) new (mem_root) Item_int(thd, val)));
+ }
+ break;
+ case GET_UINT:
+ case GET_ULONG:
+ case GET_ULL:
+ {
+ bool null_value;
+ ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base);
+ o= new set_var(thd, v->type, v->var, &v->base,
+ (null_value ?
+ (Item *) new (mem_root) Item_null(thd) :
+ (Item *) new (mem_root) Item_uint(thd, val)));
+ }
+ break;
+ case GET_DOUBLE:
+ {
+ bool null_value;
+ double val= v->var->val_real(&null_value, thd, v->type, &v->base);
+ o= new set_var(thd, v->type, v->var, &v->base,
+ (null_value ?
+ (Item *) new (mem_root) Item_null(thd) :
+ (Item *) new (mem_root) Item_float(thd, val, 1)));
+ }
+ break;
+ default:
+ case GET_NO_ARG:
+ case GET_DISABLED:
+ DBUG_ASSERT(0);
+ /* fall through */
+ case 0:
+ case GET_FLAGSET:
+ case GET_ENUM:
+ case GET_SET:
+ case GET_STR:
+ case GET_STR_ALLOC:
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String tmp(buff, sizeof(buff), v->var->charset(thd)),*val;
+ val= v->var->val_str(&tmp, thd, v->type, &v->base);
+ if (val)
+ {
+ Item_string *str=
+ new (mem_root) Item_string(thd, v->var->charset(thd),
+ val->ptr(), val->length());
+ o= new set_var(thd, v->type, v->var, &v->base, str);
+ }
+ else
+ o= new set_var(thd, v->type, v->var, &v->base,
+ new (mem_root) Item_null(thd));
+ }
+ break;
+ }
+ }
+ DBUG_ASSERT(o);
+ lex->old_var_list.push_back(o, thd->mem_root);
+ }
+ lex->reset_arena_for_set_stmt(&backup);
+
+ if (lex->old_var_list.is_empty())
+ lex->free_arena_for_set_stmt();
+
+ if (thd->is_error() ||
+ sql_set_variables(thd, &lex->stmt_var_list, false))
+ {
+ if (!thd->is_error())
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET");
+ lex->restore_set_statement_var();
+ return true;
+ }
+ /*
+ The value of last_insert_id is remembered in THD to be written to binlog
+ when it's used *the first time* in the statement. But SET STATEMENT
+ must read the old value of last_insert_id to be able to restore it at
+ the end. This should not count at "reading of last_insert_id" and
+ should not remember last_insert_id for binlog. That is, it should clear
+ stmt_depends_on_first_successful_insert_id_in_prev_stmt flag.
+ */
+ if (!thd->in_sub_stmt)
+ {
+ thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
+ }
+ }
+ return false;
+}
+
+
+/**
Execute command saved in thd and lex->sql_command.
@param thd Thread handle
@@ -3195,6 +3336,11 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
} /* endif unlikely slave */
#endif
+ /* store old value of binlog format */
+ enum_binlog_format orig_binlog_format,orig_current_stmt_binlog_format;
+
+ thd->get_binlog_format(&orig_binlog_format,
+ &orig_current_stmt_binlog_format);
#ifdef WITH_WSREP
if (wsrep && WSREP(thd))
{
@@ -3246,132 +3392,13 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
- /* store old value of binlog format */
- enum_binlog_format orig_binlog_format,orig_current_stmt_binlog_format;
-
- thd->get_binlog_format(&orig_binlog_format,
- &orig_current_stmt_binlog_format);
-
- if (!lex->stmt_var_list.is_empty() && !thd->slave_thread)
- {
- Query_arena backup;
- DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements));
-
- lex->old_var_list.empty();
- List_iterator_fast<set_var_base> it(lex->stmt_var_list);
- set_var_base *var;
-
- if (lex->set_arena_for_set_stmt(&backup))
- goto error;
-
- MEM_ROOT *mem_root= thd->mem_root;
- while ((var= it++))
- {
- DBUG_ASSERT(var->is_system());
- set_var *o= NULL, *v= (set_var*)var;
- if (!v->var->is_set_stmt_ok())
- {
- my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str);
- lex->reset_arena_for_set_stmt(&backup);
- lex->old_var_list.empty();
- lex->free_arena_for_set_stmt();
- goto error;
- }
- if (v->var->session_is_default(thd))
- o= new set_var(thd,v->type, v->var, &v->base, NULL);
- else
- {
- switch (v->var->option.var_type & GET_TYPE_MASK)
- {
- case GET_BOOL:
- case GET_INT:
- case GET_LONG:
- case GET_LL:
- {
- bool null_value;
- longlong val= v->var->val_int(&null_value, thd, v->type, &v->base);
- o= new set_var(thd, v->type, v->var, &v->base,
- (null_value ?
- (Item *) new (mem_root) Item_null(thd) :
- (Item *) new (mem_root) Item_int(thd, val)));
- }
- break;
- case GET_UINT:
- case GET_ULONG:
- case GET_ULL:
- {
- bool null_value;
- ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base);
- o= new set_var(thd, v->type, v->var, &v->base,
- (null_value ?
- (Item *) new (mem_root) Item_null(thd) :
- (Item *) new (mem_root) Item_uint(thd, val)));
- }
- break;
- case GET_DOUBLE:
- {
- bool null_value;
- double val= v->var->val_real(&null_value, thd, v->type, &v->base);
- o= new set_var(thd, v->type, v->var, &v->base,
- (null_value ?
- (Item *) new (mem_root) Item_null(thd) :
- (Item *) new (mem_root) Item_float(thd, val, 1)));
- }
- break;
- default:
- case GET_NO_ARG:
- case GET_DISABLED:
- DBUG_ASSERT(0);
- case 0:
- case GET_FLAGSET:
- case GET_ENUM:
- case GET_SET:
- case GET_STR:
- case GET_STR_ALLOC:
- {
- char buff[STRING_BUFFER_USUAL_SIZE];
- String tmp(buff, sizeof(buff), v->var->charset(thd)),*val;
- val= v->var->val_str(&tmp, thd, v->type, &v->base);
- if (val)
- {
- Item_string *str= new (mem_root) Item_string(thd, v->var->charset(thd),
- val->ptr(), val->length());
- o= new set_var(thd, v->type, v->var, &v->base, str);
- }
- else
- o= new set_var(thd, v->type, v->var, &v->base,
- new (mem_root) Item_null(thd));
- }
- break;
- }
- }
- DBUG_ASSERT(o);
- lex->old_var_list.push_back(o, thd->mem_root);
- }
- lex->reset_arena_for_set_stmt(&backup);
- if (lex->old_var_list.is_empty())
- lex->free_arena_for_set_stmt();
- if (thd->is_error() ||
- (res= sql_set_variables(thd, &lex->stmt_var_list, false)))
- {
- if (!thd->is_error())
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET");
- lex->restore_set_statement_var();
- goto error;
- }
- /*
- The value of last_insert_id is remembered in THD to be written to binlog
- when it's used *the first time* in the statement. But SET STATEMENT
- must read the old value of last_insert_id to be able to restore it at
- the end. This should not count at "reading of last_insert_id" and
- should not remember last_insert_id for binlog. That is, it should clear
- stmt_depends_on_first_successful_insert_id_in_prev_stmt flag.
- */
- if (!thd->in_sub_stmt)
- {
- thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
- }
- }
+ /*
+ Assign system variables with values specified by the clause
+ SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement>
+ if they are any.
+ */
+ if (run_set_statement_if_requested(thd, lex))
+ goto error;
if (thd->lex->mi.connection_name.str == NULL)
thd->lex->mi.connection_name= thd->variables.default_master_connection;
@@ -3406,7 +3433,7 @@ mysql_execute_command(THD *thd)
/* Commit the normal transaction if one is active. */
bool commit_failed= trans_commit_implicit(thd);
/* Release metadata locks acquired in this transaction. */
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
if (commit_failed)
{
WSREP_DEBUG("implicit commit failed, MDL released: %lld",
@@ -4645,7 +4672,7 @@ mysql_execute_command(THD *thd)
{
res= trans_commit_implicit(thd);
thd->locked_tables_list.unlock_locked_tables(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
}
if (thd->global_read_lock.is_acquired())
@@ -4659,7 +4686,7 @@ mysql_execute_command(THD *thd)
res= trans_commit_implicit(thd);
thd->locked_tables_list.unlock_locked_tables(thd);
/* Release transactional metadata locks. */
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
if (res)
goto error;
@@ -5313,7 +5340,7 @@ mysql_execute_command(THD *thd)
DBUG_PRINT("info", ("Executing SQLCOM_BEGIN thd: %p", thd));
if (trans_begin(thd, lex->start_transaction_opt))
{
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
WSREP_DEBUG("BEGIN failed, MDL released: %lld",
(longlong) thd->thread_id);
goto error;
@@ -5331,7 +5358,7 @@ mysql_execute_command(THD *thd)
(thd->variables.completion_type == 2 &&
lex->tx_release != TVL_NO));
bool commit_failed= trans_commit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
if (commit_failed)
{
WSREP_DEBUG("COMMIT failed, MDL released: %lld",
@@ -5382,7 +5409,7 @@ mysql_execute_command(THD *thd)
(thd->variables.completion_type == 2 &&
lex->tx_release != TVL_NO));
bool rollback_failed= trans_rollback(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
if (rollback_failed)
{
@@ -5859,7 +5886,6 @@ mysql_execute_command(THD *thd)
case SQLCOM_XA_COMMIT:
{
bool commit_failed= trans_xa_commit(thd);
- thd->mdl_context.release_transactional_locks();
if (commit_failed)
{
WSREP_DEBUG("XA commit failed, MDL released: %lld",
@@ -5877,7 +5903,6 @@ mysql_execute_command(THD *thd)
case SQLCOM_XA_ROLLBACK:
{
bool rollback_failed= trans_xa_rollback(thd);
- thd->mdl_context.release_transactional_locks();
if (rollback_failed)
{
WSREP_DEBUG("XA rollback failed, MDL released: %lld",
@@ -6095,7 +6120,7 @@ finish:
all storage engines including binary log.
*/
trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
{
@@ -6108,7 +6133,7 @@ finish:
/* Commit the normal transaction if one is active. */
trans_commit_implicit(thd);
thd->get_stmt_da()->set_overwrite_status(false);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
}
else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
@@ -6123,7 +6148,7 @@ finish:
- If in autocommit mode, or outside a transactional context,
automatically release metadata locks of the current statement.
*/
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
else if (! thd->in_sub_stmt)
{
@@ -6145,7 +6170,7 @@ finish:
{
WSREP_DEBUG("Forcing release of transactional locks for thd: %lld",
(longlong) thd->thread_id);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
#endif /* WITH_WSREP */
@@ -6641,6 +6666,9 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool check_single_table_access(THD *thd, ulong privilege, TABLE_LIST *tables,
bool no_errors)
{
+ if (tables->derived)
+ return 0;
+
Switch_to_definer_security_ctx backup_sctx(thd, tables);
const char *db_name;
@@ -7332,8 +7360,13 @@ void THD::reset_for_next_command(bool do_clear_error)
thd->save_prep_leaf_list= false;
- DBUG_PRINT("debug",
- ("is_current_stmt_binlog_format_row(): %d",
+#ifdef WITH_WSREP
+#if !defined(DBUG_OFF)
+ if (mysql_bin_log.is_open())
+#endif
+#endif
+ DBUG_PRINT("debug",
+ ("is_current_stmt_binlog_format_row(): %d",
thd->is_current_stmt_binlog_format_row()));
DBUG_VOID_RETURN;
@@ -8745,6 +8778,8 @@ push_new_name_resolution_context(THD *thd,
left_op->first_leaf_for_name_resolution();
on_context->last_name_resolution_table=
right_op->last_leaf_for_name_resolution();
+ on_context->select_lex = thd->lex->current_select;
+ on_context->outer_context = thd->lex->current_context()->outer_context;
return thd->lex->push_context(on_context, thd->mem_root);
}
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index ce5953696a2..968fa223e1e 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -101,6 +101,7 @@ void mysql_init_multi_delete(LEX *lex);
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void create_table_set_open_action_and_adjust_tables(LEX *lex);
pthread_handler_t handle_bootstrap(void *arg);
+bool run_set_statement_if_requested(THD *thd, LEX *lex);
int mysql_execute_command(THD *thd);
bool do_command(THD *thd);
void do_handle_bootstrap(THD *thd);
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index 64194b5a1b5..13f7296e0cd 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -22,9 +22,10 @@
that is defined in plugin.h
*/
#define SHOW_always_last SHOW_KEY_CACHE_LONG, \
- SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, \
SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, \
- SHOW_LONG_NOFLUSH, SHOW_LONGLONG_STATUS, SHOW_LEX_STRING
+ SHOW_LONG_NOFLUSH, SHOW_LEX_STRING, \
+ /* SHOW_*_STATUS must be at the end, SHOW_LONG_STATUS being first */ \
+ SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, SHOW_LONGLONG_STATUS
#include <my_global.h>
#undef SHOW_always_last
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index 43fe540731e..358052132a0 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -177,7 +177,6 @@ static struct wsrep_service_st wsrep_handler = {
wsrep_thd_ignore_table,
wsrep_thd_trx_seqno,
wsrep_thd_ws_handle,
- wsrep_thd_auto_increment_variables,
wsrep_set_load_multi_commit,
wsrep_is_load_multi_commit,
wsrep_trx_is_aborting,
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 4bf8142959d..fa335465f02 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB
+ Copyright (c) 2008, 2021, 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
@@ -117,15 +117,15 @@ When one supplies long data for a placeholder:
#include <mysql.h>
#else
#include <mysql_com.h>
+/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */
+static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8;
#endif
#include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
+#include "log_event.h" // class Log_event
#include "sql_handler.h"
#include "transaction.h" // trans_rollback_implicit
#include "wsrep_mysqld.h"
-/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */
-static const uint PARAMETER_FLAG_UNSIGNED = 128U << 8;
-
/**
A result class used to send cursor rows using the binary protocol.
*/
@@ -2522,6 +2522,16 @@ static bool check_prepared_statement(Prepared_statement *stmt)
DBUG_RETURN(FALSE);
}
break;
+ case SQLCOM_SHOW_BINLOG_EVENTS:
+ case SQLCOM_SHOW_RELAYLOG_EVENTS:
+ {
+ List<Item> field_list;
+ Log_event::init_show_field_list(thd, &field_list);
+
+ if ((res= send_stmt_metadata(thd, stmt, &field_list)) == 2)
+ DBUG_RETURN(FALSE);
+ }
+ break;
#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SHOW_CREATE_PROC:
if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_PROCEDURE)) == 2)
@@ -4239,6 +4249,16 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
*/
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ /*
+ Set variables specified by
+ SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement>
+ clause for duration of prepare phase. Original values of variable
+ listed in the SET STATEMENT clause is restored right after return
+ from the function check_prepared_statement()
+ */
+ if (likely(error == 0))
+ error= run_set_statement_if_requested(thd, lex);
+
/*
The only case where we should have items in the thd->free_list is
after stmt->set_params_from_vars(), which may in some cases create
@@ -4257,6 +4277,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE;
}
+ /*
+ Restore original values of variables modified on handling
+ SET STATEMENT clause.
+ */
+ thd->lex->restore_set_statement_var();
+
/* The order is important */
lex->unit.cleanup();
@@ -4278,7 +4304,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (thd->transaction_rollback_request)
{
trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
}
/* Preserve CHANGE MASTER attributes */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 4af8ebc2dd8..59a3f686e45 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -4541,5 +4541,22 @@ rpl_gtid_pos_update(THD *thd, char *str, size_t len)
return false;
}
+int compare_log_name(const char *log_1, const char *log_2) {
+ int res= 1;
+ const char *ext1_str= strrchr(log_1, '.');
+ const char *ext2_str= strrchr(log_2, '.');
+ char file_name_1[255], file_name_2[255];
+ strmake(file_name_1, log_1, (ext1_str - log_1));
+ strmake(file_name_2, log_2, (ext2_str - log_2));
+ char *endptr = NULL;
+ res= strcmp(file_name_1, file_name_2);
+ if (!res)
+ {
+ ulong ext1= strtoul(++ext1_str, &endptr, 10);
+ ulong ext2= strtoul(++ext2_str, &endptr, 10);
+ res= (ext1 > ext2 ? 1 : ((ext1 == ext2) ? 0 : -1));
+ }
+ return res;
+}
#endif /* HAVE_REPLICATION */
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 8ddfa9239f6..9129aaeed5e 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -56,6 +56,7 @@ bool show_binlogs(THD* thd);
extern int init_master_info(Master_info* mi);
void kill_zombie_dump_threads(uint32 slave_server_id);
int check_binlog_magic(IO_CACHE* log, const char** errmsg);
+int compare_log_name(const char *log_1, const char *log_2);
struct LOAD_FILE_IO_CACHE : public IO_CACHE
{
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3b090093060..7bfbf719017 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -729,22 +729,6 @@ JOIN::prepare(TABLE_LIST *tables_init,
tables_list, select_lex->leaf_tables,
FALSE, SELECT_ACL, SELECT_ACL, FALSE))
DBUG_RETURN(-1);
-
- /*
- Permanently remove redundant parts from the query if
- 1) This is a subquery
- 2) This is the first time this query is optimized (since the
- transformation is permanent
- 3) Not normalizing a view. Removal should take place when a
- query involving a view is optimized, not when the view
- is created
- */
- if (select_lex->master_unit()->item && // 1)
- select_lex->first_cond_optimization && // 2)
- !thd->lex->is_view_context_analysis()) // 3)
- {
- remove_redundant_subquery_clauses(select_lex);
- }
/*
TRUE if the SELECT list mixes elements with and without grouping,
@@ -824,6 +808,23 @@ JOIN::prepare(TABLE_LIST *tables_init,
&hidden_group_fields,
&select_lex->select_n_reserved))
DBUG_RETURN(-1);
+
+ /*
+ Permanently remove redundant parts from the query if
+ 1) This is a subquery
+ 2) This is the first time this query is optimized (since the
+ transformation is permanent
+ 3) Not normalizing a view. Removal should take place when a
+ query involving a view is optimized, not when the view
+ is created
+ */
+ if (select_lex->master_unit()->item && // 1)
+ select_lex->first_cond_optimization && // 2)
+ !thd->lex->is_view_context_analysis()) // 3)
+ {
+ remove_redundant_subquery_clauses(select_lex);
+ }
+
/* Resolve the ORDER BY that was skipped, then remove it. */
if (skip_order_by && select_lex !=
select_lex->master_unit()->global_parameters())
@@ -3800,6 +3801,9 @@ mysql_select(THD *thd,
}
else
{
+ if (thd->lex->describe)
+ select_options|= SELECT_DESCRIBE;
+
/*
When in EXPLAIN, delay deleting the joins so that they are still
available when we're producing EXPLAIN EXTENDED warning text.
@@ -11929,10 +11933,6 @@ void JOIN_TAB::cleanup()
{
DBUG_ENTER("JOIN_TAB::cleanup");
- if (tab_list && tab_list->is_with_table_recursive_reference() &&
- tab_list->with->is_cleaned())
- DBUG_VOID_RETURN;
-
DBUG_PRINT("enter", ("tab: %p table %s.%s",
this,
(table ? table->s->db.str : "?"),
@@ -12275,6 +12275,9 @@ void JOIN::join_free()
for (tmp_unit= select_lex->first_inner_unit();
tmp_unit;
tmp_unit= tmp_unit->next_unit())
+ {
+ if (tmp_unit->with_element && tmp_unit->with_element->is_recursive)
+ continue;
for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
{
Item_subselect *subselect= sl->master_unit()->item;
@@ -12292,7 +12295,7 @@ void JOIN::join_free()
/* Can't unlock if at least one JOIN is still needed */
can_unlock= can_unlock && full_local;
}
-
+ }
/*
We are not using tables anymore
Unlock all tables. We may be in an INSERT .... SELECT statement.
@@ -12668,6 +12671,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
{
table_map order_tables=order->item[0]->used_tables();
if (order->item[0]->with_sum_func ||
+ order->item[0]->with_window_func ||
/*
If the outer table of an outer join is const (either by itself or
after applying WHERE condition), grouping on a field from such a
@@ -22464,7 +22468,7 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
{
enum enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set);
bool result= 0;
for (store_key **copy=ref->key_copy ; *copy ; copy++)
@@ -22476,7 +22480,7 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
}
}
thd->count_cuted_fields= save_count_cuted_fields;
- dbug_tmp_restore_column_map(table->write_set, old_map);
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
return result;
}
@@ -26064,10 +26068,10 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
if (save_to)
{
DBUG_ASSERT(!keyuse.elements);
- memcpy(keyuse.buffer,
- save_to->keyuse.buffer,
- (size_t) save_to->keyuse.elements * keyuse.size_of_element);
keyuse.elements= save_to->keyuse.elements;
+ if (size_t e= keyuse.elements)
+ memcpy(keyuse.buffer,
+ save_to->keyuse.buffer, e * keyuse.size_of_element);
}
/* Add the new access methods to the keyuse array. */
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 4584460ca3f..f41c0df5ad8 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1842,8 +1842,8 @@ class store_key_field: public store_key
enum store_key_result copy_inner()
{
TABLE *table= copy_field.to_field->table;
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
- table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table,
+ &table->write_set);
/*
It looks like the next statement is needed only for a simplified
@@ -1854,7 +1854,7 @@ class store_key_field: public store_key
bzero(copy_field.to_ptr,copy_field.to_length);
copy_field.do_copy(&copy_field);
- dbug_tmp_restore_column_map(table->write_set, old_map);
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
null_key= to_field->is_null();
return err != 0 ? STORE_KEY_FATAL : STORE_KEY_OK;
}
@@ -1889,8 +1889,8 @@ public:
enum store_key_result copy_inner()
{
TABLE *table= to_field->table;
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
- table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table,
+ &table->write_set);
int res= FALSE;
/*
@@ -1911,7 +1911,7 @@ public:
*/
if (!res && table->in_use->is_error())
res= 1; /* STORE_KEY_FATAL */
- dbug_tmp_restore_column_map(table->write_set, old_map);
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
null_key= to_field->is_null() || item->null_value;
return ((err != 0 || res < 0 || res > 2) ? STORE_KEY_FATAL :
(store_key_result) res);
@@ -1947,8 +1947,8 @@ protected:
{
inited=1;
TABLE *table= to_field->table;
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
- table->write_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(table,
+ &table->write_set);
if ((res= item->save_in_field(to_field, 1)))
{
if (!err)
@@ -1960,7 +1960,7 @@ protected:
*/
if (!err && to_field->table->in_use->is_error())
err= 1; /* STORE_KEY_FATAL */
- dbug_tmp_restore_column_map(table->write_set, old_map);
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
}
null_key= to_field->is_null() || item->null_value;
return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 5544c765775..7023e5fe9ea 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1925,7 +1925,6 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
bool check_options= !(sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS) &&
!create_info_arg;
handlerton *hton;
- my_bitmap_map *old_map;
int error= 0;
DBUG_ENTER("show_create_table");
DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
@@ -1987,7 +1986,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
We have to restore the read_set if we are called from insert in case
of row based replication.
*/
- old_map= tmp_use_all_columns(table, table->read_set);
+ MY_BITMAP *old_map= tmp_use_all_columns(table, &table->read_set);
for (ptr=table->field ; (field= *ptr); ptr++)
{
@@ -2014,8 +2013,13 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
/*
For string types dump collation name only if
collation is not primary for the given charset
+
+ For generated fields don't print the COLLATE clause if
+ the collation matches the expression's collation.
*/
- if (!(field->charset()->state & MY_CS_PRIMARY) && !field->vcol_info)
+ if (!(field->charset()->state & MY_CS_PRIMARY) &&
+ (!field->vcol_info ||
+ field->charset() != field->vcol_info->expr->collation.collation))
{
packet->append(STRING_WITH_LEN(" COLLATE "));
packet->append(field->charset()->name);
@@ -2352,7 +2356,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
}
}
#endif
- tmp_restore_column_map(table->read_set, old_map);
+ tmp_restore_column_map(&table->read_set, old_map);
DBUG_RETURN(error);
}
@@ -3576,6 +3580,9 @@ static bool show_status_array(THD *thd, const char *wild,
if (show_type == SHOW_SYS)
mysql_mutex_lock(&LOCK_global_system_variables);
+ else if (show_type >= SHOW_LONG_STATUS && scope == OPT_GLOBAL)
+ calc_sum_of_all_status_if_needed(status_var);
+
pos= get_one_variable(thd, var, scope, show_type, status_var,
&charset, buff, &length);
@@ -3616,8 +3623,6 @@ uint calc_sum_of_all_status(STATUS_VAR *to)
I_List_iterator<THD> it(threads);
THD *tmp;
- /* Get global values as base */
- *to= global_status_var;
to->local_memory_used= 0;
/* Add to this status from existing threads */
@@ -5046,6 +5051,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
continue;
}
+ if (thd->killed == ABORT_QUERY)
+ {
+ error= 0;
+ goto err;
+ }
+
DEBUG_SYNC(thd, "before_open_in_get_all_tables");
if (fill_schema_table_by_open(thd, FALSE,
table, schema_table,
@@ -7582,13 +7593,7 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
if (partial_cond)
partial_cond->val_int();
- if (scope == OPT_GLOBAL)
- {
- /* We only hold LOCK_status for summary status vars */
- mysql_mutex_lock(&LOCK_status);
- calc_sum_of_all_status(&tmp);
- mysql_mutex_unlock(&LOCK_status);
- }
+ tmp.local_memory_used= 0; // meaning tmp was not populated yet
mysql_mutex_lock(&LOCK_show_status);
res= show_status_array(thd, wild,
@@ -9410,7 +9415,7 @@ ST_FIELD_INFO check_constraints_fields_info[]=
{"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
{"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
OPEN_FULL_TABLE},
- {"CHECK_CLAUSE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
+ {"CHECK_CLAUSE", MAX_FIELD_VARCHARLENGTH , MYSQL_TYPE_STRING, 0, 0, 0,
OPEN_FULL_TABLE},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index d22921ba1e2..59c6423e388 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1042,16 +1042,15 @@ public:
void store_stat_fields()
{
- char buff[MAX_FIELD_WIDTH];
- String val(buff, sizeof(buff), &my_charset_bin);
- my_bitmap_map *old_map;
+ StringBuffer<MAX_FIELD_WIDTH> val;
- old_map= dbug_tmp_use_all_columns(stat_table, stat_table->read_set);
+ MY_BITMAP *old_map= dbug_tmp_use_all_columns(stat_table, &stat_table->read_set);
for (uint i= COLUMN_STAT_MIN_VALUE; i <= COLUMN_STAT_HISTOGRAM; i++)
{
Field *stat_field= stat_table->field[i];
- if (table_field->collected_stats->is_null(i))
+ Column_statistics *stats= table_field->collected_stats;
+ if (stats->is_null(i))
stat_field->set_null();
else
{
@@ -1059,10 +1058,10 @@ public:
switch (i) {
case COLUMN_STAT_MIN_VALUE:
if (table_field->type() == MYSQL_TYPE_BIT)
- stat_field->store(table_field->collected_stats->min_value->val_int(),true);
+ stat_field->store(stats->min_value->val_int(),true);
else
{
- table_field->collected_stats->min_value->val_str(&val);
+ stats->min_value->val_str(&val);
uint32 length= Well_formed_prefix(val.charset(), val.ptr(),
MY_MIN(val.length(), stat_field->field_length)).length();
stat_field->store(val.ptr(), length, &my_charset_bin);
@@ -1070,42 +1069,38 @@ public:
break;
case COLUMN_STAT_MAX_VALUE:
if (table_field->type() == MYSQL_TYPE_BIT)
- stat_field->store(table_field->collected_stats->max_value->val_int(),true);
+ stat_field->store(stats->max_value->val_int(),true);
else
{
- table_field->collected_stats->max_value->val_str(&val);
+ stats->max_value->val_str(&val);
uint32 length= Well_formed_prefix(val.charset(), val.ptr(),
MY_MIN(val.length(), stat_field->field_length)).length();
stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_NULLS_RATIO:
- stat_field->store(table_field->collected_stats->get_nulls_ratio());
+ stat_field->store(stats->get_nulls_ratio());
break;
case COLUMN_STAT_AVG_LENGTH:
- stat_field->store(table_field->collected_stats->get_avg_length());
+ stat_field->store(stats->get_avg_length());
break;
case COLUMN_STAT_AVG_FREQUENCY:
- stat_field->store(table_field->collected_stats->get_avg_frequency());
+ stat_field->store(stats->get_avg_frequency());
break;
case COLUMN_STAT_HIST_SIZE:
- stat_field->store(table_field->collected_stats->histogram.get_size());
+ stat_field->store(stats->histogram.get_size());
break;
case COLUMN_STAT_HIST_TYPE:
- stat_field->store(table_field->collected_stats->histogram.get_type() +
- 1);
+ stat_field->store(stats->histogram.get_type() + 1);
break;
case COLUMN_STAT_HISTOGRAM:
- const char * col_histogram=
- (const char *) (table_field->collected_stats->histogram.get_values());
- stat_field->store(col_histogram,
- table_field->collected_stats->histogram.get_size(),
- &my_charset_bin);
+ stat_field->store((char *)stats->histogram.get_values(),
+ stats->histogram.get_size(), &my_charset_bin);
break;
}
}
}
- dbug_tmp_restore_column_map(stat_table->read_set, old_map);
+ dbug_tmp_restore_column_map(&stat_table->read_set, old_map);
}
@@ -1155,16 +1150,30 @@ public:
switch (i) {
case COLUMN_STAT_MIN_VALUE:
- table_field->read_stats->min_value->set_notnull();
- stat_field->val_str(&val);
- table_field->read_stats->min_value->store(val.ptr(), val.length(),
- &my_charset_bin);
+ table_field->read_stats->min_value->set_notnull();
+ if (table_field->type() == MYSQL_TYPE_BIT)
+ table_field->read_stats->min_value->store(stat_field->val_int(),
+ true);
+ else
+ {
+ stat_field->val_str(&val);
+ table_field->read_stats->min_value->store(val.ptr(),
+ val.length(),
+ &my_charset_bin);
+ }
break;
case COLUMN_STAT_MAX_VALUE:
- table_field->read_stats->max_value->set_notnull();
- stat_field->val_str(&val);
- table_field->read_stats->max_value->store(val.ptr(), val.length(),
- &my_charset_bin);
+ table_field->read_stats->max_value->set_notnull();
+ if (table_field->type() == MYSQL_TYPE_BIT)
+ table_field->read_stats->max_value->store(stat_field->val_int(),
+ true);
+ else
+ {
+ stat_field->val_str(&val);
+ table_field->read_stats->max_value->store(val.ptr(),
+ val.length(),
+ &my_charset_bin);
+ }
break;
case COLUMN_STAT_NULLS_RATIO:
table_field->read_stats->set_nulls_ratio(stat_field->val_real());
@@ -2087,20 +2096,24 @@ void create_min_max_statistical_fields_for_table_share(THD *thd,
int alloc_statistics_for_table(THD* thd, TABLE *table)
{
Field **field_ptr;
- uint fields;
DBUG_ENTER("alloc_statistics_for_table");
+ uint columns= 0;
+ for (field_ptr= table->field; *field_ptr; field_ptr++)
+ {
+ if (bitmap_is_set(table->read_set, (*field_ptr)->field_index))
+ columns++;
+ }
Table_statistics *table_stats=
(Table_statistics *) alloc_root(&table->mem_root,
sizeof(Table_statistics));
- fields= table->s->fields ;
Column_statistics_collected *column_stats=
(Column_statistics_collected *) alloc_root(&table->mem_root,
sizeof(Column_statistics_collected) *
- (fields+1));
+ columns);
uint keys= table->s->keys;
Index_statistics *index_stats=
@@ -2111,12 +2124,6 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
ulonglong *idx_avg_frequency= (ulonglong*) alloc_root(&table->mem_root,
sizeof(ulonglong) * key_parts);
- uint columns= 0;
- for (field_ptr= table->field; *field_ptr; field_ptr++)
- {
- if (bitmap_is_set(table->read_set, (*field_ptr)->field_index))
- columns++;
- }
uint hist_size= thd->variables.histogram_size;
Histogram_type hist_type= (Histogram_type) (thd->variables.histogram_type);
uchar *histogram= NULL;
@@ -2138,19 +2145,17 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
table_stats->idx_avg_frequency= idx_avg_frequency;
table_stats->histograms= histogram;
- memset(column_stats, 0, sizeof(Column_statistics) * (fields+1));
+ memset(column_stats, 0, sizeof(Column_statistics) * columns);
- for (field_ptr= table->field; *field_ptr; field_ptr++, column_stats++)
+ for (field_ptr= table->field; *field_ptr; field_ptr++)
{
- (*field_ptr)->collected_stats= column_stats;
- (*field_ptr)->collected_stats->max_value= NULL;
- (*field_ptr)->collected_stats->min_value= NULL;
if (bitmap_is_set(table->read_set, (*field_ptr)->field_index))
{
column_stats->histogram.set_size(hist_size);
column_stats->histogram.set_type(hist_type);
column_stats->histogram.set_values(histogram);
histogram+= hist_size;
+ (*field_ptr)->collected_stats= column_stats++;
}
}
@@ -2599,7 +2604,7 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
table_field= *field_ptr;
- if (!bitmap_is_set(table->read_set, table_field->field_index))
+ if (!table_field->collected_stats)
continue;
table_field->collected_stats->init(thd, table_field);
}
@@ -2626,7 +2631,7 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
table_field= *field_ptr;
- if (!bitmap_is_set(table->read_set, table_field->field_index))
+ if (!table_field->collected_stats)
continue;
if ((rc= table_field->collected_stats->add(rows)))
break;
@@ -2654,7 +2659,7 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
table_field= *field_ptr;
- if (!bitmap_is_set(table->read_set, table_field->field_index))
+ if (!table_field->collected_stats)
continue;
bitmap_set_bit(table->write_set, table_field->field_index);
if (!rc)
@@ -2758,7 +2763,7 @@ int update_statistics_for_table(THD *thd, TABLE *table)
for (Field **field_ptr= table->field; *field_ptr; field_ptr++)
{
Field *table_field= *field_ptr;
- if (!bitmap_is_set(table->read_set, table_field->field_index))
+ if (!table_field->collected_stats)
continue;
restore_record(stat_table, s->default_values);
column_stat.set_key_fields(table_field);
@@ -3715,6 +3720,7 @@ double get_column_range_cardinality(Field *field,
if (!table->stats_is_read)
return tab_records;
+ THD *thd= table->in_use;
double col_nulls= tab_records * col_stats->get_nulls_ratio();
double col_non_nulls= tab_records - col_nulls;
@@ -3745,7 +3751,7 @@ double get_column_range_cardinality(Field *field,
col_stats->min_max_values_are_provided())
{
Histogram *hist= &col_stats->histogram;
- if (hist->is_available())
+ if (hist->is_usable(thd))
{
store_key_image_to_rec(field, (uchar *) min_endp->key,
field->key_length());
@@ -3789,10 +3795,10 @@ double get_column_range_cardinality(Field *field,
max_mp_pos= 1.0;
Histogram *hist= &col_stats->histogram;
- if (!hist->is_available())
- sel= (max_mp_pos - min_mp_pos);
- else
+ if (hist->is_usable(thd))
sel= hist->range_selectivity(min_mp_pos, max_mp_pos);
+ else
+ sel= (max_mp_pos - min_mp_pos);
res= col_non_nulls * sel;
set_if_bigger(res, col_stats->get_avg_frequency());
}
diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h
index fa3e8d6b894..d8788d99574 100644
--- a/sql/sql_statistics.h
+++ b/sql/sql_statistics.h
@@ -212,6 +212,17 @@ public:
bool is_available() { return get_size() > 0 && get_values(); }
+ /*
+ This function checks that histograms should be usable only when
+ 1) the level of optimizer_use_condition_selectivity > 3
+ 2) histograms have been collected
+ */
+ bool is_usable(THD *thd)
+ {
+ return thd->variables.optimizer_use_condition_selectivity > 3 &&
+ is_available();
+ }
+
void set_value(uint i, double val)
{
switch (type) {
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index b79ca82698b..4e0c7aea84b 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2016, MariaDB
+ Copyright (c) 2016, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -175,8 +175,8 @@ bool String::copy(const String &str)
{
if (alloc(str.str_length))
return TRUE;
- str_length=str.str_length;
- bmove(Ptr,str.Ptr,str_length); // May be overlapping
+ if ((str_length=str.str_length))
+ bmove(Ptr,str.Ptr,str_length); // May be overlapping
Ptr[str_length]=0;
str_charset=str.str_charset;
return FALSE;
@@ -539,8 +539,11 @@ bool String::append_ulonglong(ulonglong val)
bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs)
{
+ if (!arg_length)
+ return false;
+
uint32 offset;
-
+
if (needs_conversion(arg_length, cs, str_charset, &offset))
{
uint32 add_length;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 57284272316..cb28c6adcec 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3983,8 +3983,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
{
/* not a critical problem */
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_TOO_LONG_KEY,
- ER_THD(thd, ER_TOO_LONG_KEY),
+ ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY),
key_part_length);
/* Align key length to multibyte char boundary */
key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
@@ -4030,7 +4029,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (key->type == Key::MULTIPLE)
{
/* not a critical problem */
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY),
key_part_length);
/* Align key length to multibyte char boundary */
@@ -4254,7 +4253,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
ER_ILLEGAL_HA_CREATE_OPTION,
ER_THD(thd, ER_ILLEGAL_HA_CREATE_OPTION),
file->engine_name()->str,
- "TRANSACTIONAL=1");
+ create_info->transactional == HA_CHOICE_YES
+ ? "TRANSACTIONAL=1" : "TRANSACTIONAL=0");
if (parse_option_list(thd, file->partition_ht(), &create_info->option_struct,
&create_info->option_list,
@@ -5132,6 +5132,9 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
if (!opt_explicit_defaults_for_timestamp)
promote_first_timestamp_column(&alter_info->create_list);
+ /* We can abort create table for any table type */
+ thd->abort_on_warning= thd->is_strict_mode();
+
if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info,
&is_trans, create_table_mode) > 0)
{
@@ -5164,6 +5167,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
}
err:
+ thd->abort_on_warning= 0;
+
/* In RBR we don't need to log CREATE TEMPORARY TABLE */
if (!result && thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
DBUG_RETURN(result);
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 4e68ec2ec2e..4ad0b365612 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -564,6 +564,7 @@ void mysql_print_status()
STATUS_VAR tmp;
uint count;
+ tmp= global_status_var;
count= calc_sum_of_all_status(&tmp);
printf("\nStatus information:\n\n");
(void) my_getwd(current_dir, sizeof(current_dir),MYF(0));
@@ -615,8 +616,12 @@ Next alarm time: %lu\n",
(ulong)alarm_info.next_alarm_time);
#endif
display_table_locks();
-#ifdef HAVE_MALLINFO
+#if defined(HAVE_MALLINFO2)
+ struct mallinfo2 info = mallinfo2();
+#elif defined(HAVE_MALLINFO)
struct mallinfo info= mallinfo();
+#endif
+#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
char llbuff[10][22];
printf("\nMemory status:\n\
Non-mmapped space allocated from system: %s\n\
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index ea4d7399ea3..7d1f630b88c 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -439,6 +439,15 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
*/
error= handler_truncate(thd, table_ref, FALSE);
+ if (error == TRUNCATE_OK && thd->locked_tables_mode &&
+ (table_ref->table->file->ht->flags &
+ HTON_REQUIRES_CLOSE_AFTER_TRUNCATE))
+ {
+ thd->locked_tables_list.mark_table_for_reopen(thd, table_ref->table);
+ if (unlikely(thd->locked_tables_list.reopen_tables(thd, true)))
+ thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
+ }
+
/*
All effects of a TRUNCATE TABLE operation are committed even if
truncation fails in the case of non transactional tables. Thus, the
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 046b42e4a83..42090037ead 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -92,7 +92,6 @@ public:
virtual void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const= 0;
- virtual bool is_packable() const { return false; }
};
@@ -170,7 +169,6 @@ public:
void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
- bool is_packable()const { return true; }
};
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 8b1719c60cb..7baedfb259c 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -211,7 +211,10 @@ select_union_recursive::create_result_table(THD *thd_arg,
create_table, keep_row_order))
return true;
- if (! (incr_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
+ incr_table_param.init();
+ incr_table_param.field_count= column_types->elements;
+ incr_table_param.bit_fields_as_long= bit_fields_as_long;
+ if (! (incr_table= create_tmp_table(thd_arg, &incr_table_param, *column_types,
(ORDER*) 0, false, 1,
options, HA_POS_ERROR, "",
true, keep_row_order)))
@@ -221,20 +224,6 @@ select_union_recursive::create_result_table(THD *thd_arg,
for (uint i=0; i < table->s->fields; i++)
incr_table->field[i]->flags &= ~(PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG);
- TABLE *rec_table= 0;
- if (! (rec_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
- (ORDER*) 0, false, 1,
- options, HA_POS_ERROR, alias,
- true, keep_row_order)))
- return true;
-
- rec_table->keys_in_use_for_query.clear_all();
- for (uint i=0; i < table->s->fields; i++)
- rec_table->field[i]->flags &= ~(PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG);
-
- if (rec_tables.push_back(rec_table))
- return true;
-
return false;
}
@@ -272,23 +261,25 @@ void select_union_recursive::cleanup()
free_tmp_table(thd, incr_table);
}
- List_iterator<TABLE> it(rec_tables);
- TABLE *tab;
- while ((tab= it++))
+ List_iterator<TABLE_LIST> it(rec_table_refs);
+ TABLE_LIST *tbl;
+ while ((tbl= it++))
{
+ TABLE *tab= tbl->table;
if (tab->is_created())
{
tab->file->extra(HA_EXTRA_RESET_STATE);
tab->file->ha_delete_all_rows();
}
- /*
+ /*
The table will be closed later in close_thread_tables(),
because it might be used in the statements like
ANALYZE WITH r AS (...) SELECT * from r
- where r is defined through recursion.
+ where r is defined through recursion.
*/
tab->next= thd->rec_tables;
thd->rec_tables= tab;
+ tbl->derived_result= 0;
}
}
@@ -715,9 +706,29 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
goto err;
if (!derived->table)
{
- derived->table= with_element->rec_result->rec_tables.head();
- if (derived->derived_result)
- derived->derived_result->table= derived->table;
+ bool res= false;
+
+ if ((!derived->is_with_table_recursive_reference() ||
+ !derived->derived_result) &&
+ !(derived->derived_result= new (thd->mem_root) select_union(thd)))
+ goto err; // out of memory
+ thd->create_tmp_table_for_derived= TRUE;
+ res= derived->derived_result->create_result_table(thd,
+ &types,
+ FALSE,
+ create_options,
+ derived->alias,
+ FALSE, FALSE);
+ thd->create_tmp_table_for_derived= FALSE;
+ if (res)
+ goto err;
+ derived->derived_result->set_unit(this);
+ derived->table= derived->derived_result->table;
+ if (derived->is_with_table_recursive_reference())
+ {
+ /* Here 'derived" is the primary recursive table reference */
+ derived->with->rec_result->rec_table_refs.push_back(derived);
+ }
}
with_element->mark_as_with_prepared_anchor();
is_rec_result_table_created= true;
@@ -1272,11 +1283,11 @@ bool st_select_lex_unit::exec_recursive()
TABLE *incr_table= with_element->rec_result->incr_table;
st_select_lex *end= NULL;
bool is_unrestricted= with_element->is_unrestricted();
- List_iterator_fast<TABLE> li(with_element->rec_result->rec_tables);
+ List_iterator_fast<TABLE_LIST> li(with_element->rec_result->rec_table_refs);
TMP_TABLE_PARAM *tmp_table_param= &with_element->rec_result->tmp_table_param;
ha_rows examined_rows= 0;
bool was_executed= executed;
- TABLE *rec_table;
+ TABLE_LIST *rec_tbl;
DBUG_ENTER("st_select_lex_unit::exec_recursive");
@@ -1335,8 +1346,9 @@ bool st_select_lex_unit::exec_recursive()
else
with_element->level++;
- while ((rec_table= li++))
+ while ((rec_tbl= li++))
{
+ TABLE *rec_table= rec_tbl->table;
saved_error=
incr_table->insert_all_rows_into_tmp_table(thd, rec_table,
tmp_table_param,
@@ -1370,13 +1382,7 @@ bool st_select_lex_unit::cleanup()
{
DBUG_RETURN(FALSE);
}
- /*
- When processing a PS/SP or an EXPLAIN command cleanup of a unit can
- be performed immediately when the unit is reached in the cleanup
- traversal initiated by the cleanup of the main unit.
- */
- if (!thd->stmt_arena->is_stmt_prepare() && !thd->lex->describe &&
- with_element && with_element->is_recursive && union_result)
+ if (with_element && with_element->is_recursive && union_result)
{
select_union_recursive *result= with_element->rec_result;
if (++result->cleanup_count == with_element->rec_outer_references)
@@ -1554,27 +1560,32 @@ bool st_select_lex::cleanup()
if (join)
{
+ List_iterator<TABLE_LIST> ti(leaf_tables);
+ TABLE_LIST *tbl;
+ while ((tbl= ti++))
+ {
+ if (tbl->is_recursive_with_table() &&
+ !tbl->is_with_table_recursive_reference())
+ {
+ /*
+ If query is killed before open_and_process_table() for tbl
+ is called then 'with' is already set, but 'derived' is not.
+ */
+ st_select_lex_unit *unit= tbl->with->spec;
+ error|= (bool) error | (uint) unit->cleanup();
+ }
+ }
DBUG_ASSERT((st_select_lex*)join->select_lex == this);
error= join->destroy();
delete join;
join= 0;
}
- for (TABLE_LIST *tbl= get_table_list(); tbl; tbl= tbl->next_local)
- {
- if (tbl->is_recursive_with_table() &&
- !tbl->is_with_table_recursive_reference())
- {
- /*
- If query is killed before open_and_process_table() for tbl
- is called then 'with' is already set, but 'derived' is not.
- */
- st_select_lex_unit *unit= tbl->with->spec;
- error|= (bool) error | (uint) unit->cleanup();
- }
- }
+ leaf_tables.empty();
for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
lex_unit= lex_unit->next_unit())
{
+ if (lex_unit->with_element && lex_unit->with_element->is_recursive)
+ continue;
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
}
inner_refs_list.empty();
@@ -1594,8 +1605,12 @@ void st_select_lex::cleanup_all_joins(bool full)
join->cleanup(full);
for (unit= first_inner_unit(); unit; unit= unit->next_unit())
+ {
+ if (unit->with_element && unit->with_element->is_recursive)
+ continue;
for (sl= unit->first_select(); sl; sl= sl->next_select())
sl->cleanup_all_joins(full);
+ }
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 5e40cd242a4..01743a6751e 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1398,6 +1398,9 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
if (select_lex->handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(1);
+ if (thd->lex->save_prep_leaf_tables())
+ DBUG_RETURN(1);
+
List<Item> *fields= &lex->select_lex.item_list;
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
*fields, MARK_COLUMNS_WRITE, 0, 0))
@@ -1534,7 +1537,11 @@ int mysql_multi_update_prepare(THD *thd)
During prepare phase acquire only S metadata locks instead of SW locks to
keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
and global read lock.
+
+ Don't evaluate any subqueries even if constant, because
+ tables aren't locked yet.
*/
+ lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI)
{
if (open_tables(thd, &table_list, &table_count,
@@ -1557,6 +1564,9 @@ int mysql_multi_update_prepare(THD *thd)
{
DBUG_RETURN(TRUE);
}
+
+ lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
+
(void) read_statistics_for_tables_if_needed(thd, table_list);
/* @todo: downgrade the metadata locks here. */
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 8bfe6896ea2..0701c5233ac 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -291,6 +291,8 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
{
for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local)
{
+ if (!tbl->with && tbl->select_lex)
+ tbl->with= tbl->select_lex->find_table_def_in_with_clauses(tbl);
/*
Ensure that we have some privileges on this table, more strict check
will be done on column level after preparation,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 2eabc4f0a6d..6eb47f1e49f 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1030,10 +1030,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 105 shift/reduce conflicts.
+ Currently there are 98 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 105
+%expect 115
/*
Comments for TOKENS.
@@ -1774,7 +1774,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <field_type> int_type real_type
-%type <Lex_field_type> type_with_opt_collate field_type
+%type <Lex_field_type> field_type
%type <Lex_dyncol_type> opt_dyncol_type dyncol_type
numeric_dyncol_type temporal_dyncol_type string_dyncol_type
@@ -1836,7 +1836,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item>
literal text_literal insert_ident order_ident temporal_literal
simple_ident expr opt_expr opt_else sum_expr in_sum_expr
- variable variable_aux bool_pri
+ variable variable_aux
predicate bit_expr parenthesized_expr
table_wild simple_expr column_default_non_parenthesized_expr udf_expr
expr_or_default set_expr_or_default
@@ -3010,11 +3010,12 @@ sp_param_name_and_type:
thd->variables.collation_database);
$<spvar>$= spvar;
}
- type_with_opt_collate
+ field_type
{
LEX *lex= Lex;
sp_variable *spvar= $<spvar>2;
+ Lex->set_last_field_type($3);
if (lex->sphead->fill_field_definition(thd, lex, lex->last_field))
{
MYSQL_YYABORT;
@@ -3096,14 +3097,15 @@ sp_decl:
thd->lex->init_last_field(&spvar->field_def, spvar->name.str,
thd->variables.collation_database);
}
- type_with_opt_collate
+ field_type
sp_opt_default
{
LEX *lex= Lex;
sp_pcontext *pctx= lex->spcont;
uint num_vars= pctx->context_var_count();
Item *dflt_value_item= $5;
-
+ Lex->set_last_field_type($4);
+
if (!dflt_value_item)
{
dflt_value_item= new (thd->mem_root) Item_null(thd);
@@ -6665,20 +6667,6 @@ serial_attribute:
;
-type_with_opt_collate:
- field_type opt_collate
- {
- $$= $1;
-
- if ($2)
- {
- if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2)))
- MYSQL_YYABORT;
- }
- Lex->set_last_field_type($1);
- }
- ;
-
charset:
CHAR_SYM SET {}
| CHARSET {}
@@ -6751,12 +6739,25 @@ charset_or_alias:
}
;
+collate: COLLATE_SYM collation_name_or_default
+ {
+ Lex->charset= Lex->last_field->charset= $2;
+ }
+ ;
+
opt_binary:
/* empty */ { bincmp_collation(NULL, false); }
| BYTE_SYM { bincmp_collation(&my_charset_bin, false); }
| charset_or_alias opt_bin_mod { bincmp_collation($1, $2); }
| BINARY { bincmp_collation(NULL, true); }
| BINARY charset_or_alias { bincmp_collation($2, true); }
+ | charset_or_alias collate
+ {
+ if (!my_charset_same(Lex->charset, $1))
+ my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ Lex->charset->name, $1->csname));
+ }
+ | collate { }
;
opt_bin_mod:
@@ -8972,23 +8973,19 @@ expr:
if ($$ == NULL)
MYSQL_YYABORT;
}
- | bool_pri
- ;
-
-bool_pri:
- bool_pri EQUAL_SYM predicate %prec EQUAL_SYM
+ | expr EQUAL_SYM predicate %prec EQUAL_SYM
{
$$= new (thd->mem_root) Item_func_equal(thd, $1, $3);
if ($$ == NULL)
MYSQL_YYABORT;
}
- | bool_pri comp_op predicate %prec '='
+ | expr comp_op predicate %prec '='
{
$$= (*$2)(0)->create(thd, $1, $3);
if ($$ == NULL)
MYSQL_YYABORT;
}
- | bool_pri comp_op all_or_any '(' subselect ')' %prec '='
+ | expr comp_op all_or_any '(' subselect ')' %prec '='
{
$$= all_any_subquery_creator(thd, $1, $2, $3, $5);
if ($$ == NULL)
@@ -13528,7 +13525,7 @@ kill:
lex->sql_command= SQLCOM_KILL;
lex->kill_type= KILL_TYPE_ID;
}
- kill_type kill_option kill_expr
+ kill_type kill_option
{
Lex->kill_signal= (killed_state) ($3 | $4);
}
@@ -13541,16 +13538,21 @@ kill_type:
;
kill_option:
- /* empty */ { $$= (int) KILL_CONNECTION; }
- | CONNECTION_SYM { $$= (int) KILL_CONNECTION; }
- | QUERY_SYM { $$= (int) KILL_QUERY; }
- | QUERY_SYM ID_SYM
+ opt_connection kill_expr { $$= (int) KILL_CONNECTION; }
+ | QUERY_SYM kill_expr { $$= (int) KILL_QUERY; }
+ | QUERY_SYM ID_SYM expr
{
$$= (int) KILL_QUERY;
Lex->kill_type= KILL_TYPE_QUERY;
+ Lex->value_list.push_front($3, thd->mem_root);
}
;
+opt_connection:
+ /* empty */ { }
+ | CONNECTION_SYM { }
+ ;
+
kill_expr:
expr
{
@@ -13563,7 +13565,6 @@ kill_expr:
}
;
-
shutdown:
SHUTDOWN { Lex->sql_command= SQLCOM_SHUTDOWN; }
;
@@ -16858,8 +16859,9 @@ sf_tail:
lex->init_last_field(&lex->sphead->m_return_field_def, NULL,
thd->variables.collation_database);
}
- type_with_opt_collate /* $11 */
+ field_type /* $11 */
{ /* $12 */
+ Lex->set_last_field_type($11);
if (Lex->sphead->fill_field_definition(thd, Lex, Lex->last_field))
MYSQL_YYABORT;
}
diff --git a/sql/structs.h b/sql/structs.h
index 67fb0d5dd66..27b9725815b 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -90,7 +90,7 @@ class engine_option_value;
struct ha_index_option_struct;
typedef struct st_key {
- uint key_length; /* Tot length of key */
+ uint key_length; /* total length of user defined key parts */
ulong flags; /* dupp key and pack flags */
uint user_defined_key_parts; /* How many key_parts */
uint usable_key_parts; /* Should normally be = user_defined_key_parts */
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 2a582a098fb..e4de3d8d0aa 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2224,7 +2224,7 @@ static Sys_var_ulong Sys_max_sort_length(
"the first max_sort_length bytes of each value are used; the rest "
"are ignored)",
SESSION_VAR(max_sort_length), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(8, 8192*1024L), DEFAULT(1024), BLOCK_SIZE(1));
+ VALID_RANGE(64, 8192*1024L), DEFAULT(1024), BLOCK_SIZE(1));
static Sys_var_ulong Sys_max_sp_recursion_depth(
"max_sp_recursion_depth",
@@ -3730,7 +3730,7 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type)
if (trans_commit_stmt(thd) || trans_commit(thd))
{
thd->variables.option_bits&= ~OPTION_AUTOCOMMIT;
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
WSREP_DEBUG("autocommit, MDL TRX lock released: %lld",
(longlong) thd->thread_id);
return true;
@@ -4157,11 +4157,11 @@ static Sys_var_ulong Sys_default_week_format(
SESSION_VAR(default_week_format), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, 7), DEFAULT(0), BLOCK_SIZE(1));
-static Sys_var_ulonglong Sys_group_concat_max_len(
+static Sys_var_uint Sys_group_concat_max_len(
"group_concat_max_len",
"The maximum length of the result of function GROUP_CONCAT()",
SESSION_VAR(group_concat_max_len), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(4, SIZE_T_MAX), DEFAULT(1024*1024), BLOCK_SIZE(1));
+ VALID_RANGE(4, UINT_MAX32), DEFAULT(1024*1024), BLOCK_SIZE(1));
static char *glob_hostname_ptr;
static Sys_var_charptr Sys_hostname(
@@ -4958,7 +4958,7 @@ static Sys_var_tz Sys_time_zone(
static Sys_var_charptr Sys_wsrep_provider(
"wsrep_provider", "Path to replication provider library",
- PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG),
+ PREALLOCATED READ_ONLY GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG),
IN_FS_CHARSET, DEFAULT(WSREP_NONE),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_provider_check), ON_UPDATE(wsrep_provider_update));
@@ -5171,7 +5171,7 @@ static Sys_var_ulong Sys_wsrep_max_ws_rows (
static Sys_var_charptr Sys_wsrep_notify_cmd(
"wsrep_notify_cmd", "",
- GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG),
+ READ_ONLY GLOBAL_VAR(wsrep_notify_cmd), CMD_LINE(REQUIRED_ARG),
IN_SYSTEM_CHARSET, DEFAULT(""));
static Sys_var_mybool Sys_wsrep_certify_nonPK(
diff --git a/sql/table.cc b/sql/table.cc
index e4492f21a30..1004f583448 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2273,6 +2273,12 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
key_part->null_bit= field->null_bit;
key_part->store_length+=HA_KEY_NULL_LENGTH;
keyinfo->flags|=HA_NULL_PART_KEY;
+
+ /*
+ This branch is executed only for user defined key parts of the
+ secondary indexes.
+ */
+ DBUG_ASSERT(i < keyinfo->user_defined_key_parts);
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
if (field->type() == MYSQL_TYPE_BLOB ||
@@ -2285,7 +2291,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
else
key_part->key_part_flag|= HA_VAR_LENGTH_PART;
key_part->store_length+=HA_KEY_BLOB_LENGTH;
- keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
+ if (i < keyinfo->user_defined_key_parts)
+ keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
}
if (field->type() == MYSQL_TYPE_BIT)
key_part->key_part_flag|= HA_BIT_PART;
@@ -2378,7 +2385,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
set_if_bigger(share->max_key_length,keyinfo->key_length+
keyinfo->user_defined_key_parts);
- share->total_key_length+= keyinfo->key_length;
/*
MERGE tables do not have unique indexes. But every key could be
an unique index on the underlying MyISAM table. (Bug #10400)
diff --git a/sql/table.h b/sql/table.h
index 14ab0027a79..83c72f76831 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -773,7 +773,7 @@ struct TABLE_SHARE
uint rec_buff_length; /* Size of table->record[] buffer */
uint keys, key_parts;
uint ext_key_parts; /* Total number of key parts in extended keys */
- uint max_key_length, max_unique_length, total_key_length;
+ uint max_key_length, max_unique_length;
uint uniques; /* Number of UNIQUE index */
uint db_create_options; /* Create options from database */
uint db_options_in_use; /* Options in use */
@@ -2277,8 +2277,12 @@ struct TABLE_LIST
Indicates what triggers we need to pre-load for this TABLE_LIST
when opening an associated TABLE. This is filled after
the parsed tree is created.
+
+ slave_fk_event_map is filled on the slave side with bitmaps value
+ representing row-based event operation to help find and prelock
+ possible FK constrain-related child tables.
*/
- uint8 trg_event_map;
+ uint8 trg_event_map, slave_fk_event_map;
/* TRUE <=> this table is a const one and was optimized away. */
bool optimized_away;
@@ -2766,25 +2770,25 @@ typedef struct st_open_table_list{
} OPEN_TABLE_LIST;
-static inline my_bitmap_map *tmp_use_all_columns(TABLE *table,
- MY_BITMAP *bitmap)
+static inline MY_BITMAP *tmp_use_all_columns(TABLE *table,
+ MY_BITMAP **bitmap)
{
- my_bitmap_map *old= bitmap->bitmap;
- bitmap->bitmap= table->s->all_set.bitmap;
+ MY_BITMAP *old= *bitmap;
+ *bitmap= &table->s->all_set;
return old;
}
-static inline void tmp_restore_column_map(MY_BITMAP *bitmap,
- my_bitmap_map *old)
+static inline void tmp_restore_column_map(MY_BITMAP **bitmap,
+ MY_BITMAP *old)
{
- bitmap->bitmap= old;
+ *bitmap= old;
}
/* The following is only needed for debugging */
-static inline my_bitmap_map *dbug_tmp_use_all_columns(TABLE *table,
- MY_BITMAP *bitmap)
+static inline MY_BITMAP *dbug_tmp_use_all_columns(TABLE *table,
+ MY_BITMAP **bitmap)
{
#ifndef DBUG_OFF
return tmp_use_all_columns(table, bitmap);
@@ -2793,8 +2797,8 @@ static inline my_bitmap_map *dbug_tmp_use_all_columns(TABLE *table,
#endif
}
-static inline void dbug_tmp_restore_column_map(MY_BITMAP *bitmap,
- my_bitmap_map *old)
+static inline void dbug_tmp_restore_column_map(MY_BITMAP **bitmap,
+ MY_BITMAP *old)
{
#ifndef DBUG_OFF
tmp_restore_column_map(bitmap, old);
@@ -2807,22 +2811,22 @@ static inline void dbug_tmp_restore_column_map(MY_BITMAP *bitmap,
Provide for the possiblity of the read set being the same as the write set
*/
static inline void dbug_tmp_use_all_columns(TABLE *table,
- my_bitmap_map **save,
- MY_BITMAP *read_set,
- MY_BITMAP *write_set)
+ MY_BITMAP **save,
+ MY_BITMAP **read_set,
+ MY_BITMAP **write_set)
{
#ifndef DBUG_OFF
- save[0]= read_set->bitmap;
- save[1]= write_set->bitmap;
+ save[0]= *read_set;
+ save[1]= *write_set;
(void) tmp_use_all_columns(table, read_set);
(void) tmp_use_all_columns(table, write_set);
#endif
}
-static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set,
- MY_BITMAP *write_set,
- my_bitmap_map **old)
+static inline void dbug_tmp_restore_column_maps(MY_BITMAP **read_set,
+ MY_BITMAP **write_set,
+ MY_BITMAP **old)
{
#ifndef DBUG_OFF
tmp_restore_column_map(read_set, old[0]);
@@ -2924,7 +2928,8 @@ inline void mark_as_null_row(TABLE *table)
{
table->null_row=1;
table->status|=STATUS_NULL_ROW;
- bfill(table->null_flags,table->s->null_bytes,255);
+ if (table->s->null_bytes)
+ bfill(table->null_flags,table->s->null_bytes,255);
}
bool is_simple_order(ORDER *order);
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 72b7f8e6fe4..543e0b7ad38 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -212,7 +212,7 @@ bool trans_begin(THD *thd, uint flags)
Release transactional metadata locks only after the
transaction has been committed.
*/
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
// The RO/RW options are mutually exclusive.
DBUG_ASSERT(!((flags & MYSQL_START_TRANS_OPT_READ_ONLY) &&
@@ -889,11 +889,13 @@ bool trans_xa_prepare(THD *thd)
/**
Commit and terminate the a XA transaction.
+ Transactional locks are released if transaction ended
@param thd Current thread
@retval FALSE Success
@retval TRUE Failure
+
*/
bool trans_xa_commit(THD *thd)
@@ -984,6 +986,7 @@ bool trans_xa_commit(THD *thd)
thd->transaction.xid_state.xa_state= XA_NOTR;
trans_track_end_trx(thd);
+ thd->mdl_context.release_transactional_locks();
DBUG_RETURN(res);
}
@@ -991,6 +994,7 @@ bool trans_xa_commit(THD *thd)
/**
Roll back and terminate a XA transaction.
+ Transactional locks are released if transaction ended
@param thd Current thread
@@ -1041,6 +1045,7 @@ bool trans_xa_rollback(THD *thd)
thd->transaction.xid_state.xa_state= XA_NOTR;
trans_track_end_trx(thd);
+ thd->mdl_context.release_transactional_locks();
DBUG_RETURN(res);
}
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 083960523c1..7974255af35 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -921,8 +921,11 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
it.rewind();
while ((field=it++))
{
- memcpy(buff, field->comment.str, field->comment.length);
- buff+= field->comment.length;
+ if (size_t l= field->comment.length)
+ {
+ memcpy(buff, field->comment.str, l);
+ buff+= l;
+ }
}
}
*buff_arg= buff;
@@ -941,7 +944,8 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
TABLE table;
TABLE_SHARE share;
Create_field *field;
- enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
+ Check_level_instant_set old_count_cuted_fields(thd, CHECK_FIELD_WARN);
+ Abort_on_warning_instant_set old_abort_on_warning(thd, 0);
DBUG_ENTER("make_empty_rec");
/* We need a table to generate columns for default values */
@@ -960,7 +964,6 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
null_pos= buff;
List_iterator<Create_field> it(create_fields);
- thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values
while ((field=it++))
{
/* regfield don't have to be deleted as it's allocated on THD::mem_root */
@@ -1036,6 +1039,5 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
*(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
err:
- thd->count_cuted_fields= old_count_cuted_fields;
DBUG_RETURN(error);
} /* make_empty_rec */
diff --git a/sql/unireg.h b/sql/unireg.h
index 6ce638928e8..efc3d6958f5 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -78,7 +78,8 @@
#define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->s->reclength)
#define empty_record(A) { \
restore_record((A),s->default_values); \
- bfill((A)->null_flags,(A)->s->null_bytes,255);\
+ if ((A)->s->null_bytes) \
+ bfill((A)->null_flags,(A)->s->null_bytes,255); \
}
/* Defines for use with openfrm, openprt and openfrd */
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
index 66335c412e2..ea8ebb7522f 100644
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@ -187,7 +187,7 @@ static wsrep_cb_status_t wsrep_apply_events(THD* thd,
trans_rollback(thd);
thd->locked_tables_list.unlock_locked_tables(thd);
/* Release transactional metadata locks. */
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
thd->wsrep_conflict_state= NO_CONFLICT;
DBUG_RETURN(WSREP_CB_FAILURE);
}
@@ -369,7 +369,7 @@ wsrep_cb_status_t wsrep_commit_cb(void* const ctx,
/* Cleanup */
wsrep_set_apply_format(thd, NULL);
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
thd->reset_query(); /* Mutex protected */
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 53941c06892..f5e88aeac1f 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -125,14 +125,6 @@ longlong wsrep_thd_trx_seqno(THD *)
struct wsrep_ws_handle* wsrep_thd_ws_handle(THD *)
{ return 0; }
-void wsrep_thd_auto_increment_variables(THD *thd,
- unsigned long long *offset,
- unsigned long long *increment)
-{
- *offset= thd->variables.auto_increment_offset;
- *increment= thd->variables.auto_increment_increment;
-}
-
void wsrep_set_load_multi_commit(THD *thd, bool split)
{ }
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index d392d1c2a61..f22d8bf0f5a 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -2762,9 +2762,7 @@ extern "C" void wsrep_thd_awake(THD *thd, my_bool signal)
{
if (signal)
{
- mysql_mutex_lock(&thd->LOCK_thd_data);
thd->awake(KILL_QUERY);
- mysql_mutex_unlock(&thd->LOCK_thd_data);
}
else
{
@@ -2790,16 +2788,18 @@ extern "C" bool wsrep_thd_ignore_table(THD *thd)
extern int
wsrep_trx_order_before(THD *thd1, THD *thd2)
{
- if (wsrep_thd_trx_seqno(thd1) < wsrep_thd_trx_seqno(thd2)) {
- WSREP_DEBUG("BF conflict, order: %lld %lld\n",
- (long long)wsrep_thd_trx_seqno(thd1),
- (long long)wsrep_thd_trx_seqno(thd2));
- return 1;
- }
- WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
- (long long)wsrep_thd_trx_seqno(thd1),
- (long long)wsrep_thd_trx_seqno(thd2));
- return 0;
+ const longlong trx1_seqno= wsrep_thd_trx_seqno(thd1);
+ const longlong trx2_seqno= wsrep_thd_trx_seqno(thd2);
+ WSREP_DEBUG("BF conflict, order: %lld %lld\n",
+ trx1_seqno, trx2_seqno);
+
+ if (trx1_seqno == WSREP_SEQNO_UNDEFINED ||
+ trx2_seqno == WSREP_SEQNO_UNDEFINED)
+ return 1; /* trx is not yet replicated */
+ else if (trx1_seqno < trx2_seqno)
+ return 1;
+
+ return 0;
}
diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc
index fb04d7be7c1..3683d70a980 100644
--- a/sql/wsrep_notify.cc
+++ b/sql/wsrep_notify.cc
@@ -40,11 +40,13 @@ void wsrep_notify_status (wsrep_member_status_t status,
return;
}
- char cmd_buf[1 << 16]; // this can be long
- long cmd_len = sizeof(cmd_buf) - 1;
- char* cmd_ptr = cmd_buf;
+ const long cmd_len = (1 << 16) - 1;
+ char* cmd_ptr = (char*) my_malloc(cmd_len + 1, MYF(MY_WME));
long cmd_off = 0;
+ if (!cmd_ptr)
+ return; // the warning is in the log
+
cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, "%s",
wsrep_notify_cmd);
@@ -93,6 +95,7 @@ void wsrep_notify_status (wsrep_member_status_t status,
{
WSREP_ERROR("Notification buffer too short (%ld). Aborting notification.",
cmd_len);
+ my_free(cmd_ptr);
return;
}
@@ -106,5 +109,6 @@ void wsrep_notify_status (wsrep_member_status_t status,
WSREP_ERROR("Notification command failed: %d (%s): \"%s\"",
err, strerror(err), cmd_ptr);
}
+ my_free(cmd_ptr);
}
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 65a3f971c62..f4092b9b8a7 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -149,6 +149,12 @@ static bool sst_auth_real_set (const char* value)
if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); }
wsrep_sst_auth= my_strdup(WSREP_SST_AUTH_MASK, MYF(0));
}
+ else
+ {
+ if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); }
+ wsrep_sst_auth= NULL;
+ }
+
return 0;
}
return 1;
@@ -701,8 +707,20 @@ static size_t estimate_cmd_len (bool* extra_args)
char c;
while ((c = *arg++) != 0)
{
- /* A whitespace or a single quote requires double quotation marks: */
- if (isspace(c) || c == '\'')
+ /*
+ Space, single quote, ampersand, and I/O redirection characters
+ require text to be enclosed in double quotes:
+ */
+ if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
+#ifdef __WIN__
+ c == '>' || c == '<')
+#else
+ /*
+ The semicolon is used to separate shell commands, so it must be
+ enclosed in double quotes as well:
+ */
+ c == '>' || c == '<' || c == ';')
+#endif
{
quotation= true;
}
@@ -725,10 +743,19 @@ static size_t estimate_cmd_len (bool* extra_args)
while ((c = *arg++) != 0)
{
/*
- A whitespace or a single quote requires double
- quotation marks:
+ Space, single quote, ampersand, and I/O redirection characters
+ require text to be enclosed in double quotes:
*/
- if (isspace(c) || c == '\'')
+ if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
+#ifdef __WIN__
+ c == '>' || c == '<')
+#else
+ /*
+ The semicolon is used to separate shell commands, so it must be
+ enclosed in double quotes as well:
+ */
+ c == '>' || c == '<' || c == ';')
+#endif
{
quotation= true;
}
@@ -809,8 +836,20 @@ static void copy_orig_argv (char* cmd_str)
char c;
while ((c = *arg_scan++) != 0)
{
- /* A whitespace or a single quote requires double quotation marks: */
- if (isspace(c) || c == '\'')
+ /*
+ Space, single quote, ampersand, and I/O redirection characters
+ require text to be enclosed in double quotes:
+ */
+ if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
+#ifdef __WIN__
+ c == '>' || c == '<')
+#else
+ /*
+ The semicolon is used to separate shell commands, so it must be
+ enclosed in double quotes as well:
+ */
+ c == '>' || c == '<' || c == ';')
+#endif
{
quotation= true;
}
@@ -884,10 +923,19 @@ static void copy_orig_argv (char* cmd_str)
while ((c = *arg_scan++) != 0)
{
/*
- A whitespace or a single quote requires double
- quotation marks:
+ Space, single quote, ampersand, and I/O redirection characters
+ require text to be enclosed in double quotes:
*/
- if (isspace(c) || c == '\'')
+ if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
+#ifdef __WIN__
+ c == '>' || c == '<')
+#else
+ /*
+ The semicolon is used to separate shell commands, so it must be
+ enclosed in double quotes as well:
+ */
+ c == '>' || c == '<' || c == ';')
+#endif
{
quotation= true;
}
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index 4dddb399bd1..ef8c0e132f7 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -22,6 +22,7 @@
//#include "global_threads.h" // LOCK_thread_count, etc.
#include "sql_base.h" // close_thread_tables()
#include "mysqld.h" // start_wsrep_THD();
+#include "debug_sync.h"
#include "slave.h" // opt_log_slave_updates
#include "rpl_filter.h"
@@ -75,7 +76,7 @@ void wsrep_client_rollback(THD *thd)
}
/* Release transactional metadata locks. */
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
/* release explicit MDL locks */
thd->mdl_context.release_explicit_locks();
@@ -146,11 +147,12 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
// Disable general logging on applier threads
thd->variables.option_bits |= OPTION_LOG_OFF;
- // Enable binlogging if opt_log_slave_updates is set
- if (opt_log_slave_updates)
- thd->variables.option_bits|= OPTION_BIN_LOG;
- else
- thd->variables.option_bits&= ~(OPTION_BIN_LOG);
+
+ /* enable binlogging regardless of log_slave_updates setting
+ this is for ensuring that both local and applier transaction go through
+ same commit ordering algorithm in group commit control
+ */
+ thd->variables.option_bits|= OPTION_BIN_LOG;
if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init(thd, "wsrep_relay");
@@ -211,7 +213,7 @@ void wsrep_replay_sp_transaction(THD* thd)
thd->locked_tables_list.unlock_locked_tables(thd);
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
}
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
mysql_mutex_unlock(&thd->LOCK_thd_data);
THD *replay_thd= new THD(true);
@@ -350,7 +352,7 @@ void wsrep_replay_transaction(THD *thd)
thd->locked_tables_list.unlock_locked_tables(thd);
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
}
- thd->mdl_context.release_transactional_locks();
+ thd->release_transactional_locks();
/*
Replaying will call MYSQL_START_STATEMENT when handling
BEGIN Query_log_event so end statement must be called before
@@ -370,6 +372,19 @@ void wsrep_replay_transaction(THD *thd)
thd->variables.option_bits|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
+ /* Allow tests to block the replayer thread using the DBUG facilities */
+#ifdef ENABLED_DEBUG_SYNC
+ DBUG_EXECUTE_IF("sync.wsrep_replay_cb",
+ {
+ const char act[]=
+ "now "
+ "SIGNAL sync.wsrep_replay_cb_reached "
+ "WAIT_FOR signal.wsrep_replay_cb";
+ DBUG_ASSERT(!debug_sync_set_action(thd,
+ STRING_WITH_LEN(act)));
+ };);
+#endif /* ENABLED_DEBUG_SYNC */
+
int rcode = wsrep->replay_trx(wsrep,
&thd->wsrep_ws_handle,
(void *)thd);
@@ -836,27 +851,6 @@ bool wsrep_thd_has_explicit_locks(THD *thd)
return thd->mdl_context.has_explicit_locks();
}
-/*
- Get auto increment variables for THD. Use global settings for
- applier threads.
- */
-void wsrep_thd_auto_increment_variables(THD* thd,
- unsigned long long* offset,
- unsigned long long* increment)
-{
- if (thd->wsrep_exec_mode == REPL_RECV &&
- thd->wsrep_conflict_state != REPLAYING)
- {
- *offset= global_system_variables.auto_increment_offset;
- *increment= global_system_variables.auto_increment_increment;
- }
- else
- {
- *offset= thd->variables.auto_increment_offset;
- *increment= thd->variables.auto_increment_increment;
- }
-}
-
my_bool wsrep_thd_is_applier(MYSQL_THD thd)
{
my_bool is_applier= false;