summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2018-10-31 08:46:37 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2018-10-31 08:46:37 +0200
commitd6ee7ab1a1cec0143e66f3ac75d8cee7c60f69b0 (patch)
tree3db0ed5372812c7eaa6754db689f1baa6418c572 /sql
parentb0fe082b365d989fcf905e5c40c3fe60fd756858 (diff)
parenta737135ae39dafe8b1136386ce23dfa8bed877f9 (diff)
downloadmariadb-git-d6ee7ab1a1cec0143e66f3ac75d8cee7c60f69b0.tar.gz
Merge remote-tracking branch 'origin/10.0' into bb-10.0-galera
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h4
-rw-r--r--sql/field.cc17
-rw-r--r--sql/ha_partition.cc9
-rw-r--r--sql/ha_partition.h1
-rw-r--r--sql/item_cmpfunc.cc15
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/lex.h6
-rw-r--r--sql/lock.cc17
-rw-r--r--sql/lock.h1
-rw-r--r--sql/mysqld.cc11
-rw-r--r--sql/opt_range.cc27
-rw-r--r--sql/sp_head.cc33
-rw-r--r--sql/sql_acl.cc1
-rw-r--r--sql/sql_alter.h2
-rw-r--r--sql/sql_base.cc150
-rw-r--r--sql/sql_base.h2
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_show.cc9
-rw-r--r--sql/sql_statistics.cc3
-rw-r--r--sql/sql_statistics.h29
-rw-r--r--sql/sql_table.cc64
-rw-r--r--sql/sql_yacc.yy38
-rw-r--r--sql/table.cc20
-rw-r--r--sql/table.h49
-rw-r--r--sql/table_cache.cc3
29 files changed, 328 insertions, 198 deletions
diff --git a/sql/contributors.h b/sql/contributors.h
index a0d05af3fa6..69f8fa6bd4c 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -45,12 +45,14 @@ struct show_table_contributors_st show_table_contributors[]= {
{"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", "http://www.acronis.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"},
/* Sponsors of important features */
{"Google", "USA", "Sponsoring encryption, parallel replication and GTID"},
diff --git a/sql/field.cc b/sql/field.cc
index 2bc090e8942..2a3394be411 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -9066,13 +9066,18 @@ void Create_field::create_length_to_internal_length(void)
}
break;
case MYSQL_TYPE_NEWDECIMAL:
- key_length= pack_length=
- my_decimal_get_binary_size(my_decimal_length_to_precision(length,
- decimals,
- flags &
- UNSIGNED_FLAG),
- decimals);
+ {
+ /*
+ This code must be identical to code in
+ Field_new_decimal::Field_new_decimal as otherwise the record layout
+ gets out of sync.
+ */
+ uint precision= my_decimal_length_to_precision(length, decimals,
+ flags & UNSIGNED_FLAG);
+ set_if_smaller(precision, DECIMAL_MAX_PRECISION);
+ key_length= pack_length= my_decimal_get_binary_size(precision, decimals);
break;
+ }
default:
key_length= pack_length= calc_pack_length(sql_type, length);
break;
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 7bffb68c6de..9ceee47bcd0 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -3913,9 +3913,14 @@ THR_LOCK_DATA **ha_partition::store_lock(THD *thd,
}
else
{
- for (i= bitmap_get_first_set(&(m_part_info->lock_partitions));
+ MY_BITMAP *used_partitions= lock_type == TL_UNLOCK ||
+ lock_type == TL_IGNORE ?
+ &m_locked_partitions :
+ &m_part_info->lock_partitions;
+
+ for (i= bitmap_get_first_set(used_partitions);
i < m_tot_parts;
- i= bitmap_get_next_set(&m_part_info->lock_partitions, i))
+ i= bitmap_get_next_set(used_partitions, i))
{
DBUG_PRINT("info", ("store lock %d iteration", i));
to= m_file[i]->store_lock(thd, to, lock_type);
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 33a1a8ab43b..98c987b3589 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -251,7 +251,6 @@ private:
/*
Variables for lock structures.
*/
- THR_LOCK_DATA lock; /* MySQL lock */
bool auto_increment_lock; /**< lock reading/updating auto_inc */
/**
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 49bbee9edd2..bdef3c1a89f 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4172,11 +4172,20 @@ void Item_func_in::fix_length_and_dec()
if (field_item->field_type() == MYSQL_TYPE_LONGLONG ||
field_item->field_type() == MYSQL_TYPE_YEAR)
{
- bool all_converted= TRUE;
+ bool all_converted= true;
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- if (!convert_const_to_int(thd, field_item, &arg[0]))
- all_converted= FALSE;
+ /*
+ Explicit NULLs should not affect data cmp_type resolution:
+ - we ignore NULLs when calling collect_cmp_type()
+ - we ignore NULLs here
+ So this expression:
+ year_column IN (DATE'2001-01-01', NULL)
+ switches from TIME_RESULT to INT_RESULT.
+ */
+ if (arg[0]->type() != Item::NULL_ITEM &&
+ !convert_const_to_int(thd, field_item, &arg[0]))
+ all_converted= false;
}
if (all_converted)
cmp_type= INT_RESULT;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index a8dfdff9809..14b2ccd3985 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -575,7 +575,7 @@ bool Item_subselect::is_expensive()
*/
if (cur_join->optimized &&
(cur_join->zero_result_cause || !cur_join->tables_list))
- return false;
+ continue;
/*
If a subquery is not optimized we cannot estimate its cost. A subquery is
diff --git a/sql/lex.h b/sql/lex.h
index 591f0def43e..868f19ed9c4 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -630,7 +630,7 @@ static SYMBOL symbols[] = {
{ "UPGRADE", SYM(UPGRADE_SYM)},
{ "USAGE", SYM(USAGE)},
{ "USE", SYM(USE_SYM)},
- { "USER", SYM(USER)},
+ { "USER", SYM(USER_SYM)},
{ "USER_RESOURCES", SYM(RESOURCES)},
{ "USER_STATISTICS", SYM(USER_STATS_SYM)},
{ "USE_FRM", SYM(USE_FRM)},
@@ -688,7 +688,7 @@ static SYMBOL sql_functions[] = {
{ "MIN", SYM(MIN_SYM)},
{ "NOW", SYM(NOW_SYM)},
{ "POSITION", SYM(POSITION_SYM)},
- { "SESSION_USER", SYM(USER)},
+ { "SESSION_USER", SYM(USER_SYM)},
{ "STD", SYM(STD_SYM)},
{ "STDDEV", SYM(STD_SYM)},
{ "STDDEV_POP", SYM(STD_SYM)},
@@ -698,7 +698,7 @@ static SYMBOL sql_functions[] = {
{ "SUBSTRING", SYM(SUBSTRING)},
{ "SUM", SYM(SUM_SYM)},
{ "SYSDATE", SYM(SYSDATE)},
- { "SYSTEM_USER", SYM(USER)},
+ { "SYSTEM_USER", SYM(USER_SYM)},
{ "TRIM", SYM(TRIM)},
{ "VARIANCE", SYM(VARIANCE_SYM)},
{ "VAR_POP", SYM(VARIANCE_SYM)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 965f7dcab99..28aa39d96ae 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -557,23 +557,6 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
}
-/** Abort all other threads waiting to get lock in table. */
-
-void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
-{
- MYSQL_LOCK *locked;
- DBUG_ENTER("mysql_lock_abort");
-
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
- {
- for (uint i=0; i < locked->lock_count; i++)
- thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
- my_free(locked);
- }
- DBUG_VOID_RETURN;
-}
-
-
/**
Abort one thread / table combination.
diff --git a/sql/lock.h b/sql/lock.h
index a4833cdc38e..a9183bf8580 100644
--- a/sql/lock.h
+++ b/sql/lock.h
@@ -32,7 +32,6 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock= 1);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
-void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock);
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
/* Lock based on name */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ab58928273a..6194f539674 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1774,7 +1774,14 @@ static void close_connections(void)
tmp->thread_id,
(tmp->main_security_ctx.user ?
tmp->main_security_ctx.user : ""));
+ /*
+ close_connection() might need a valid current_thd
+ for memory allocation tracking.
+ */
+ THD* save_thd= current_thd;
+ set_current_thd(tmp);
close_connection(tmp,ER_SERVER_SHUTDOWN);
+ set_current_thd(save_thd);
}
#endif
#ifdef WITH_WSREP
@@ -4246,6 +4253,10 @@ static int init_common_variables()
/* MyISAM requires two file handles per table. */
wanted_files= (10 + max_connections + extra_max_connections +
tc_size * 2);
+#if defined(HAVE_POOL_OF_THREADS) && !defined(__WIN__)
+ // add epoll or kevent fd for each threadpool group, in case pool of threads is used
+ wanted_files+= (thread_handling > SCHEDULER_NO_THREADS) ? 0 : threadpool_size;
+#endif
/*
We are trying to allocate no less than max_connections*5 file
handles (i.e. we are trying to set the limit so that they will
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index f1d84e5c623..0fd2cd267fc 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3326,13 +3326,19 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
- if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
+ Column_statistics* col_stats= (*field_ptr)->read_stats;
+ if (bitmap_is_set(used_fields, (*field_ptr)->field_index)
+ && col_stats && !col_stats->no_stat_values_provided()
+ && !((*field_ptr)->type() == MYSQL_TYPE_GEOMETRY))
parts++;
}
KEY_PART *key_part;
uint keys= 0;
+ if (!parts)
+ return TRUE;
+
if (!(key_part= (KEY_PART *) alloc_root(param->mem_root,
sizeof(KEY_PART) * parts)))
return TRUE;
@@ -3344,6 +3350,9 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
{
Field *field= *field_ptr;
+ if (field->type() == MYSQL_TYPE_GEOMETRY)
+ continue;
+
uint16 store_length;
uint16 max_key_part_length= (uint16) table->file->max_key_part_length();
key_part->key= keys;
@@ -3501,7 +3510,18 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
table->cond_selectivity= 1.0;
- if (!cond || table_records == 0)
+ if (table_records == 0)
+ DBUG_RETURN(FALSE);
+
+ QUICK_SELECT_I *quick;
+ if ((quick=table->reginfo.join_tab->quick) &&
+ quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ table->cond_selectivity*= (quick->records/table_records);
+ DBUG_RETURN(FALSE);
+ }
+
+ if (!cond)
DBUG_RETURN(FALSE);
if (table->pos_in_table_list->schema_table)
@@ -3617,7 +3637,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
*/
if (thd->variables.optimizer_use_condition_selectivity > 2 &&
- !bitmap_is_clear_all(used_fields))
+ !bitmap_is_clear_all(used_fields) &&
+ thd->variables.use_stat_tables > 0)
{
PARAM param;
MEM_ROOT alloc;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 164ceb677ee..701036d10d0 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -4219,7 +4219,7 @@ sp_head::add_used_tables_to_table_list(THD *thd,
if (stab->temp)
continue;
- if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
+ if (!(tab_buff= (char *)thd->alloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
stab->lock_count)) ||
!(key_buff= (char*)thd->memdup(stab->qname.str,
stab->qname.length)))
@@ -4228,32 +4228,11 @@ sp_head::add_used_tables_to_table_list(THD *thd,
for (uint j= 0; j < stab->lock_count; j++)
{
table= (TABLE_LIST *)tab_buff;
-
- table->db= key_buff;
- table->db_length= stab->db_length;
- table->table_name= table->db + table->db_length + 1;
- table->table_name_length= stab->table_name_length;
- table->alias= table->table_name + table->table_name_length + 1;
- table->lock_type= stab->lock_type;
- table->cacheable_table= 1;
- table->prelocking_placeholder= 1;
- table->belong_to_view= belong_to_view;
- table->trg_event_map= stab->trg_event_map;
- /*
- Since we don't allow DDL on base tables in prelocked mode it
- is safe to infer the type of metadata lock from the type of
- table lock.
- */
- table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
- table->lock_type >= TL_WRITE_ALLOW_WRITE ?
- MDL_SHARED_WRITE : MDL_SHARED_READ,
- MDL_TRANSACTION);
-
- /* Everyting else should be zeroed */
-
- **query_tables_last_ptr= table;
- table->prev_global= *query_tables_last_ptr;
- *query_tables_last_ptr= &table->next_global;
+ table->init_one_table_for_prelocking(key_buff, stab->db_length,
+ key_buff + stab->db_length + 1, stab->table_name_length,
+ key_buff + stab->db_length + stab->table_name_length + 2,
+ stab->lock_type, true, belong_to_view, stab->trg_event_map,
+ query_tables_last_ptr);
tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST));
result= TRUE;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index ecce9ad2b39..a47f94cfc7f 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -9990,7 +9990,6 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
combo->user.str= (char *) sctx->priv_user;
mysql_mutex_lock(&acl_cache->lock);
-
if ((au= find_user_exact(combo->host.str= (char *) sctx->priv_host,
combo->user.str)))
goto found_acl;
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 7114694124b..a4505f1d6c1 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -163,7 +163,7 @@ public:
// Columns and keys to be dropped.
List<Alter_drop> drop_list;
- // Columns for ALTER_COLUMN_CHANGE_DEFAULT.
+ // Columns for ALTER_CHANGE_COLUMN_DEFAULT.
List<Alter_column> alter_list;
// List of keys, used by both CREATE and ALTER TABLE.
List<Key> key_list;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 36c5b06c378..b260034bbac 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -810,6 +810,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
uint key_length= share->table_cache_key.length;
const char *db= key;
const char *table_name= db + share->db.length + 1;
+ bool remove_from_locked_tables= extra != HA_EXTRA_NOT_USED;
memcpy(key, share->table_cache_key.str, key_length);
@@ -823,7 +824,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
{
thd->locked_tables_list.unlink_from_list(thd,
table->pos_in_locked_tables,
- extra != HA_EXTRA_NOT_USED);
+ remove_from_locked_tables);
/* Inform handler that there is a drop table or a rename going on */
if (extra != HA_EXTRA_NOT_USED && table->db_stat)
{
@@ -4835,6 +4836,25 @@ handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
}
+/*
+ @note this can be changed to use a hash, instead of scanning the linked
+ list, if the performance of this function will ever become an issue
+*/
+bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_STRING *db,
+ LEX_STRING *table, thr_lock_type lock_type)
+{
+ for (; tl; tl= tl->next_global )
+ {
+ if (tl->lock_type >= lock_type &&
+ tl->prelocking_placeholder == TABLE_LIST::FK &&
+ strcmp(tl->db, db->str) == 0 &&
+ strcmp(tl->table_name, table->str) == 0)
+ return true;
+ }
+ return false;
+}
+
+
/**
Defines how prelocking algorithm for DML statements should handle table list
elements:
@@ -4874,6 +4894,52 @@ 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
+ uint8 op= table_list->trg_event_map;
+ thr_lock_type lock_type;
+
+ if ((op & (1 << TRG_EVENT_DELETE) && fk_modifies_child(fk->delete_method))
+ || (op & (1 << TRG_EVENT_UPDATE) && fk_modifies_child(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;
@@ -9078,88 +9144,6 @@ my_bool mysql_rm_tmp_tables(void)
unireg support functions
*****************************************************************************/
-/**
- A callback to the server internals that is used to address
- special cases of the locking protocol.
- Invoked when acquiring an exclusive lock, for each thread that
- has a conflicting shared metadata lock.
-
- This function:
- - aborts waiting of the thread on a data lock, to make it notice
- the pending exclusive lock and back off.
- - if the thread is an INSERT DELAYED thread, sends it a KILL
- signal to terminate it.
-
- @note This function does not wait for the thread to give away its
- locks. Waiting is done outside for all threads at once.
-
- @param thd Current thread context
- @param in_use The thread to wake up
- @param needs_thr_lock_abort Indicates that to wake up thread
- this call needs to abort its waiting
- on table-level lock.
-
- @retval TRUE if the thread was woken up
- @retval FALSE otherwise.
-
- @note It is one of two places where border between MDL and the
- rest of the server is broken.
-*/
-
-bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
- bool needs_thr_lock_abort)
-{
- bool signalled= FALSE;
- if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
- !in_use->killed)
- {
- in_use->killed= KILL_SYSTEM_THREAD;
- mysql_mutex_lock(&in_use->mysys_var->mutex);
- if (in_use->mysys_var->current_cond)
- {
- mysql_mutex_lock(in_use->mysys_var->current_mutex);
- mysql_cond_broadcast(in_use->mysys_var->current_cond);
- mysql_mutex_unlock(in_use->mysys_var->current_mutex);
- }
- mysql_mutex_unlock(&in_use->mysys_var->mutex);
- signalled= TRUE;
- }
-
- if (needs_thr_lock_abort)
- {
- mysql_mutex_lock(&in_use->LOCK_thd_data);
- for (TABLE *thd_table= in_use->open_tables;
- thd_table ;
- thd_table= thd_table->next)
- {
- /*
- Check for TABLE::needs_reopen() is needed since in some places we call
- handler::close() for table instance (and set TABLE::db_stat to 0)
- and do not remove such instances from the THD::open_tables
- for some time, during which other thread can see those instances
- (e.g. see partitioning code).
- */
- if (!thd_table->needs_reopen())
-#ifdef WITH_WSREP
- {
- signalled|= mysql_lock_abort_for_thread(thd, thd_table);
- if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true))
- {
- WSREP_DEBUG("remove_table_from_cache: %llu",
- (unsigned long long) thd->real_id);
- wsrep_abort_thd((void *)thd, (void *)in_use, FALSE);
- }
- }
-#else
- signalled|= mysql_lock_abort_for_thread(thd, thd_table);
-#endif
- }
- mysql_mutex_unlock(&in_use->LOCK_thd_data);
- }
- return signalled;
-}
-
-
int setup_ftfuncs(SELECT_LEX *select_lex)
{
List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)),
diff --git a/sql/sql_base.h b/sql/sql_base.h
index af42a15ab29..43b78833efb 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -148,6 +148,8 @@ my_bool mysql_rm_tmp_tables(void);
bool rm_temporary_table(handlerton *base, const char *path);
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
const MDL_savepoint &start_of_statement_svp);
+bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_STRING *db,
+ LEX_STRING *table, thr_lock_type lock_type);
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
TABLE_LIST *TABLE_LIST::*link,
const char *db_name,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 385ced114c8..34a696b3cc6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5377,7 +5377,8 @@ has_write_table_with_auto_increment_and_select(TABLE_LIST *tables)
for(TABLE_LIST *table= tables; table; table= table->next_global)
{
if (!table->placeholder() &&
- (table->lock_type <= TL_READ_NO_INSERT))
+ table->lock_type <= TL_READ_NO_INSERT &&
+ table->prelocking_placeholder != TABLE_LIST::FK)
{
has_select= true;
break;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index b6fde5f6875..3631112d7e7 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -338,8 +338,6 @@ class Foreign_key: public Key {
public:
enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
- enum fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE,
- FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT};
LEX_STRING ref_db;
LEX_STRING ref_table;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 18eb42734e3..f202a76306b 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2357,7 +2357,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
The thread could be killed with an error message if
di->handle_inserts() or di->open_and_lock_table() fails.
The thread could be killed without an error message if
- killed using mysql_notify_thread_having_shared_lock() or
+ killed using THD::notify_shared_lock() or
kill_delayed_threads_for_table().
*/
if (!thd.is_error())
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 3fed9808f57..d58be8b336a 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2482,8 +2482,8 @@ struct LEX: public Query_tables_list
uint uint_geom_type;
uint grant, grant_tot_col, which_columns;
enum Foreign_key::fk_match_opt fk_match_option;
- enum Foreign_key::fk_option fk_update_opt;
- enum Foreign_key::fk_option fk_delete_opt;
+ enum_fk_option fk_update_opt;
+ enum_fk_option fk_delete_opt;
uint slave_thd_opt, start_transaction_opt;
int nest_level;
/*
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f7f34e3048f..ca9a6a46fda 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -24585,7 +24585,7 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str,
const char *t_alias= alias;
str->append(' ');
- if (lower_case_table_names== 1)
+ if (lower_case_table_names == 1)
{
if (alias && alias[0])
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index badeda50597..c8985ef76b5 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -7586,6 +7586,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
LEX_STRING *db_name, LEX_STRING *table_name)
{
CHARSET_INFO *cs= system_charset_info;
+ LEX_CSTRING *s;
DBUG_ENTER("get_referential_constraints_record");
if (res)
@@ -7630,10 +7631,10 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
else
table->field[5]->set_null();
table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
- table->field[7]->store(f_key_info->update_method->str,
- f_key_info->update_method->length, cs);
- table->field[8]->store(f_key_info->delete_method->str,
- f_key_info->delete_method->length, cs);
+ s= fk_option_name(f_key_info->update_method);
+ table->field[7]->store(s->str, s->length, cs);
+ s= fk_option_name(f_key_info->delete_method);
+ table->field[8]->store(s->str, s->length, cs);
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
}
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 537ede91710..cb75a5c2176 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -3129,6 +3129,9 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables)
if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table)
{
TABLE_SHARE *table_share= tl->table->s;
+ if (table_share && !(table_share->table_category == TABLE_CATEGORY_USER))
+ continue;
+
if (table_share &&
table_share->stats_cb.stats_can_be_read &&
!table_share->stats_cb.stats_is_read)
diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h
index 6a43e42ab96..f28d56e4a69 100644
--- a/sql/sql_statistics.h
+++ b/sql/sql_statistics.h
@@ -342,12 +342,17 @@ private:
public:
Histogram histogram;
+
+ uint32 no_values_provided_bitmap()
+ {
+ return
+ ((1 << (COLUMN_STAT_HISTOGRAM-COLUMN_STAT_COLUMN_NAME))-1) <<
+ (COLUMN_STAT_COLUMN_NAME+1);
+ }
void set_all_nulls()
{
- column_stat_nulls=
- ((1 << (COLUMN_STAT_HISTOGRAM-COLUMN_STAT_COLUMN_NAME))-1) <<
- (COLUMN_STAT_COLUMN_NAME+1);
+ column_stat_nulls= no_values_provided_bitmap();
}
void set_not_null(uint stat_field_no)
@@ -393,8 +398,22 @@ public:
bool min_max_values_are_provided()
{
return !is_null(COLUMN_STAT_MIN_VALUE) &&
- !is_null(COLUMN_STAT_MIN_VALUE);
- }
+ !is_null(COLUMN_STAT_MAX_VALUE);
+ }
+ /*
+ This function checks whether the values for the fields of the statistical
+ tables that were NULL by DEFAULT for a column have changed or not.
+
+ @retval
+ TRUE: Statistics are not present for a column
+ FALSE: Statisitics are present for a column
+ */
+ bool no_stat_values_provided()
+ {
+ if (column_stat_nulls == no_values_provided_bitmap())
+ return true;
+ return false;
+ }
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index d9e00602dfc..dc4c20f6698 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3340,6 +3340,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
+ /* Virtual fields are always NULL */
+ if (sql_field->vcol_info)
+ sql_field->flags&= ~NOT_NULL_FLAG;
+
if (sql_field->sql_type == MYSQL_TYPE_SET ||
sql_field->sql_type == MYSQL_TYPE_ENUM)
{
@@ -5095,7 +5099,7 @@ err:
/* Write log if no error or if we already deleted a table */
if (!result || thd->log_current_statement)
{
- if (result && create_info->table_was_deleted)
+ if (result && create_info->table_was_deleted && pos_in_locked_tables)
{
/*
Possible locked table was dropped. We should remove meta data locks
@@ -9150,8 +9154,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
alter_ctx.tmp_name, strlen(alter_ctx.tmp_name),
alter_ctx.tmp_name, TL_READ_NO_INSERT);
/* Table is in thd->temporary_tables */
- (void) open_temporary_table(thd, &tbl);
+ if (open_temporary_table(thd, &tbl))
+ goto err_new_table_cleanup;
new_table= tbl.table;
+ DBUG_ASSERT(new_table);
}
else
{
@@ -9160,9 +9166,59 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
new_table= open_table_uncached(thd, new_db_type, alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
true, true);
+ if (!new_table)
+ goto err_new_table_cleanup;
+
+ /*
+ Normally, an attempt to modify an FK parent table will cause
+ FK children to be prelocked, so the table-being-altered cannot
+ be modified by a cascade FK action, because ALTER holds a lock
+ and prelocking will wait.
+
+ But if a new FK is being added by this very ALTER, then the target
+ table is not locked yet (it's a temporary table). So, we have to
+ lock FK parents explicitly.
+ */
+ if (alter_info->flags & Alter_info::ADD_FOREIGN_KEY)
+ {
+ List <FOREIGN_KEY_INFO> fk_list;
+ List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
+ FOREIGN_KEY_INFO *fk;
+
+ /* tables_opened can be > 1 only for MERGE tables */
+ DBUG_ASSERT(tables_opened == 1);
+ DBUG_ASSERT(&table_list->next_global == thd->lex->query_tables_last);
+
+ new_table->file->get_foreign_key_list(thd, &fk_list);
+ while ((fk= fk_list_it++))
+ {
+ if (lower_case_table_names)
+ {
+ char buf[NAME_LEN];
+ uint len;
+ strmake_buf(buf, fk->referenced_db->str);
+ len = my_casedn_str(files_charset_info, buf);
+ thd->make_lex_string(fk->referenced_db, buf, len);
+ strmake_buf(buf, fk->referenced_table->str);
+ len = my_casedn_str(files_charset_info, buf);
+ thd->make_lex_string(fk->referenced_table, buf, len);
+ }
+ if (table_already_fk_prelocked(table_list, fk->referenced_db,
+ fk->referenced_table, TL_READ_NO_INSERT))
+ continue;
+
+ TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
+ tl->init_one_table_for_prelocking(fk->referenced_db->str, fk->referenced_db->length,
+ fk->referenced_table->str, fk->referenced_table->length,
+ NULL, TL_READ_NO_INSERT, false, NULL, 0,
+ &thd->lex->query_tables_last);
+ }
+
+ if (open_tables(thd, &table_list->next_global, &tables_opened, 0,
+ &alter_prelocking_strategy))
+ goto err_new_table_cleanup;
+ }
}
- if (!new_table)
- goto err_new_table_cleanup;
/*
Note: In case of MERGE table, we do not attach children. We do not
copy data for MERGE tables. Only the children have data.
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 0e222bf3504..919e061fc85 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -939,7 +939,7 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
struct p_elem_val *p_elem_value;
enum index_hint_type index_hint;
enum enum_filetype filetype;
- enum Foreign_key::fk_option m_fk_option;
+ enum enum_fk_option m_fk_option;
enum enum_yes_no_unknown m_yes_no_unk;
Diag_condition_item_name diag_condition_item_name;
Diagnostics_information::Which_area diag_area;
@@ -1584,7 +1584,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token UPDATE_SYM /* SQL-2003-R */
%token UPGRADE_SYM
%token USAGE /* SQL-2003-N */
-%token USER /* SQL-2003-R */
+%token USER_SYM /* SQL-2003-R */
%token USER_STATS_SYM
%token USE_FRM
%token USE_SYM
@@ -2455,7 +2455,7 @@ create:
MYSQL_YYABORT;
}
}
- | CREATE USER clear_privileges grant_list
+ | CREATE USER_SYM clear_privileges grant_list
{
Lex->sql_command = SQLCOM_CREATE_USER;
}
@@ -2496,7 +2496,7 @@ server_options_list:
;
server_option:
- USER TEXT_STRING_sys
+ USER_SYM TEXT_STRING_sys
{
Lex->server_options.username= $2.str;
}
@@ -6752,19 +6752,19 @@ opt_on_update_delete:
/* empty */
{
LEX *lex= Lex;
- lex->fk_update_opt= Foreign_key::FK_OPTION_UNDEF;
- lex->fk_delete_opt= Foreign_key::FK_OPTION_UNDEF;
+ lex->fk_update_opt= FK_OPTION_UNDEF;
+ lex->fk_delete_opt= FK_OPTION_UNDEF;
}
| ON UPDATE_SYM delete_option
{
LEX *lex= Lex;
lex->fk_update_opt= $3;
- lex->fk_delete_opt= Foreign_key::FK_OPTION_UNDEF;
+ lex->fk_delete_opt= FK_OPTION_UNDEF;
}
| ON DELETE_SYM delete_option
{
LEX *lex= Lex;
- lex->fk_update_opt= Foreign_key::FK_OPTION_UNDEF;
+ lex->fk_update_opt= FK_OPTION_UNDEF;
lex->fk_delete_opt= $3;
}
| ON UPDATE_SYM delete_option
@@ -6784,11 +6784,11 @@ opt_on_update_delete:
;
delete_option:
- RESTRICT { $$= Foreign_key::FK_OPTION_RESTRICT; }
- | CASCADE { $$= Foreign_key::FK_OPTION_CASCADE; }
- | SET NULL_SYM { $$= Foreign_key::FK_OPTION_SET_NULL; }
- | NO_SYM ACTION { $$= Foreign_key::FK_OPTION_NO_ACTION; }
- | SET DEFAULT { $$= Foreign_key::FK_OPTION_DEFAULT; }
+ RESTRICT { $$= FK_OPTION_RESTRICT; }
+ | CASCADE { $$= FK_OPTION_CASCADE; }
+ | SET NULL_SYM { $$= FK_OPTION_SET_NULL; }
+ | NO_SYM ACTION { $$= FK_OPTION_NO_ACTION; }
+ | SET DEFAULT { $$= FK_OPTION_SET_DEFAULT; }
;
normal_key_type:
@@ -8157,7 +8157,7 @@ rename:
}
table_to_table_list
{}
- | RENAME USER clear_privileges rename_list
+ | RENAME USER_SYM clear_privileges rename_list
{
Lex->sql_command = SQLCOM_RENAME_USER;
}
@@ -9476,7 +9476,7 @@ function_call_keyword:
if ($$ == NULL)
MYSQL_YYABORT;
}
- | USER '(' ')'
+ | USER_SYM '(' ')'
{
$$= new (thd->mem_root) Item_func_user();
if ($$ == NULL)
@@ -11766,7 +11766,7 @@ drop:
lex->check_exists= $3;
lex->spname= $4;
}
- | DROP USER clear_privileges user_list
+ | DROP USER_SYM clear_privileges user_list
{
Lex->sql_command = SQLCOM_DROP_USER;
}
@@ -13024,7 +13024,7 @@ kill_expr:
{
Lex->value_list.push_front($$);
}
- | USER user
+ | USER_SYM user
{
Lex->users_list.push_back($2);
Lex->kill_type= KILL_TYPE_USER;
@@ -14372,7 +14372,7 @@ keyword_sp:
| UNDOFILE_SYM {}
| UNKNOWN_SYM {}
| UNTIL_SYM {}
- | USER {}
+ | USER_SYM {}
| USER_STATS_SYM {}
| USE_FRM {}
| VARIABLES {}
@@ -15263,7 +15263,7 @@ object_privilege:
| SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; }
| CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; }
| ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; }
- | CREATE USER { Lex->grant |= CREATE_USER_ACL; }
+ | CREATE USER_SYM { Lex->grant |= CREATE_USER_ACL; }
| EVENT_SYM { Lex->grant |= EVENT_ACL;}
| TRIGGER_SYM { Lex->grant |= TRIGGER_ACL; }
| CREATE TABLESPACE { Lex->grant |= CREATE_TABLESPACE_ACL; }
diff --git a/sql/table.cc b/sql/table.cc
index 757e1fa444e..15c7617eccc 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -413,6 +413,7 @@ void TABLE_SHARE::destroy()
ha_share= NULL; // Safety
}
+ delete_stat_values_for_table_share(this);
free_root(&stats_cb.mem_root, MYF(0));
stats_cb.stats_can_be_read= FALSE;
stats_cb.stats_is_read= FALSE;
@@ -7254,3 +7255,22 @@ double KEY::actual_rec_per_key(uint i)
read_stats->get_avg_frequency(i) : (double) rec_per_key[i]);
}
+LEX_CSTRING *fk_option_name(enum_fk_option opt)
+{
+ static LEX_CSTRING names[]=
+ {
+ { STRING_WITH_LEN("???") },
+ { STRING_WITH_LEN("RESTRICT") },
+ { STRING_WITH_LEN("CASCADE") },
+ { STRING_WITH_LEN("SET NULL") },
+ { STRING_WITH_LEN("NO ACTION") },
+ { STRING_WITH_LEN("SET DEFAULT") }
+ };
+ return names + opt;
+}
+
+bool fk_modifies_child(enum_fk_option opt)
+{
+ static bool can_write[]= { false, false, true, true, false, true };
+ return can_write[opt];
+}
diff --git a/sql/table.h b/sql/table.h
index 05596b605a5..4a1552f8c0d 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1429,6 +1429,9 @@ enum enum_schema_table_state
PROCESSED_BY_JOIN_EXEC
};
+enum enum_fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE,
+ FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_SET_DEFAULT};
+
typedef struct st_foreign_key_info
{
LEX_STRING *foreign_id;
@@ -1436,13 +1439,16 @@ typedef struct st_foreign_key_info
LEX_STRING *foreign_table;
LEX_STRING *referenced_db;
LEX_STRING *referenced_table;
- LEX_STRING *update_method;
- LEX_STRING *delete_method;
+ enum_fk_option update_method;
+ enum_fk_option delete_method;
LEX_STRING *referenced_key_name;
List<LEX_STRING> foreign_fields;
List<LEX_STRING> referenced_fields;
} FOREIGN_KEY_INFO;
+LEX_CSTRING *fk_option_name(enum_fk_option opt);
+bool fk_modifies_child(enum_fk_option opt);
+
#define MY_I_S_MAYBE_NULL 1
#define MY_I_S_UNSIGNED 2
@@ -1689,6 +1695,14 @@ struct TABLE_LIST
const char *alias_arg,
enum thr_lock_type lock_type_arg)
{
+ enum enum_mdl_type mdl_type;
+ if (lock_type_arg >= TL_WRITE_ALLOW_WRITE)
+ mdl_type= MDL_SHARED_WRITE;
+ else if (lock_type_arg == TL_READ_NO_INSERT)
+ mdl_type= MDL_SHARED_NO_WRITE;
+ else
+ mdl_type= MDL_SHARED_READ;
+
bzero((char*) this, sizeof(*this));
db= (char*) db_name_arg;
db_length= db_length_arg;
@@ -1696,10 +1710,31 @@ struct TABLE_LIST
table_name_length= table_name_length_arg;
alias= (char*) (alias_arg ? alias_arg : table_name_arg);
lock_type= lock_type_arg;
- mdl_request.init(MDL_key::TABLE, db, table_name,
- (lock_type >= TL_WRITE_ALLOW_WRITE) ?
- MDL_SHARED_WRITE : MDL_SHARED_READ,
- MDL_TRANSACTION);
+ mdl_request.init(MDL_key::TABLE, db, table_name, mdl_type, MDL_TRANSACTION);
+ }
+
+ inline void init_one_table_for_prelocking(const char *db_name_arg,
+ size_t db_length_arg,
+ const char *table_name_arg,
+ size_t table_name_length_arg,
+ const char *alias_arg,
+ enum thr_lock_type lock_type_arg,
+ bool routine,
+ TABLE_LIST *belong_to_view_arg,
+ uint8 trg_event_map_arg,
+ TABLE_LIST ***last_ptr)
+ {
+ init_one_table(db_name_arg, db_length_arg, table_name_arg,
+ table_name_length_arg, alias_arg, lock_type_arg);
+ cacheable_table= 1;
+ prelocking_placeholder= routine ? ROUTINE : FK;
+ open_type= routine ? OT_TEMPORARY_OR_BASE : OT_BASE_ONLY;
+ belong_to_view= belong_to_view_arg;
+ trg_event_map= trg_event_map_arg;
+
+ **last_ptr= this;
+ prev_global= *last_ptr;
+ *last_ptr= &next_global;
}
/*
@@ -1977,7 +2012,7 @@ struct TABLE_LIST
This TABLE_LIST object is just placeholder for prelocking, it will be
used for implicit LOCK TABLES only and won't be used in real statement.
*/
- bool prelocking_placeholder;
+ enum { USER, ROUTINE, FK } prelocking_placeholder;
/**
Indicates that if TABLE_LIST object corresponds to the table/view
which requires special handling.
diff --git a/sql/table_cache.cc b/sql/table_cache.cc
index a31068c9bc3..f13d7183a99 100644
--- a/sql/table_cache.cc
+++ b/sql/table_cache.cc
@@ -52,7 +52,6 @@
#include "hash.h"
#include "table.h"
#include "sql_base.h"
-#include "sql_statistics.h"
/** Configuration. */
ulong tdc_size; /**< Table definition cache threshold for LRU eviction. */
@@ -377,6 +376,7 @@ bool tc_release_table(TABLE *table)
{
DBUG_ASSERT(table->in_use);
DBUG_ASSERT(table->file);
+ DBUG_ASSERT(!table->pos_in_locked_tables);
if (table->needs_reopen() || tc_records() > tc_size)
{
@@ -870,7 +870,6 @@ void tdc_release_share(TABLE_SHARE *share)
mysql_mutex_lock(&share->tdc.LOCK_table_share);
if (share->tdc.flushed)
{
- delete_stat_values_for_table_share(share);
mysql_mutex_unlock(&share->tdc.LOCK_table_share);
mysql_mutex_unlock(&LOCK_unused_shares);
tdc_delete_share_from_hash(share);