summaryrefslogtreecommitdiff
path: root/sql/table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/table.cc')
-rw-r--r--sql/table.cc438
1 files changed, 244 insertions, 194 deletions
diff --git a/sql/table.cc b/sql/table.cc
index f6bea7221ce..a4065f2c393 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -31,7 +31,7 @@
#include "sql_partition.h" // mysql_unpack_partition,
// fix_partition_func, partition_info
#include "sql_acl.h" // *_ACL, acl_getroot_no_password
-#include "sql_base.h" // release_table_share
+#include "sql_base.h"
#include "create_options.h"
#include <m_ctype.h>
#include "my_md5.h"
@@ -148,7 +148,7 @@ View_creation_ctx * View_creation_ctx::create(THD *thd,
if (!view->view_client_cs_name.str ||
!view->view_connection_cl_name.str)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_VIEW_NO_CREATION_CTX,
ER(ER_VIEW_NO_CREATION_CTX),
(const char *) view->db,
@@ -182,7 +182,7 @@ View_creation_ctx * View_creation_ctx::create(THD *thd,
(const char *) view->view_client_cs_name.str,
(const char *) view->view_connection_cl_name.str);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_VIEW_INVALID_CREATION_CTX,
ER(ER_VIEW_INVALID_CREATION_CTX),
(const char *) view->db,
@@ -273,7 +273,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name)
/*
- Allocate a setup TABLE_SHARE structure
+ Allocate and setup a TABLE_SHARE structure
SYNOPSIS
alloc_table_share()
@@ -287,7 +287,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name)
*/
TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
- char *key, uint key_length)
+ const char *key, uint key_length)
{
MEM_ROOT mem_root;
TABLE_SHARE *share;
@@ -315,29 +315,20 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
strmov(share->path.str, path);
share->normalized_path.str= share->path.str;
share->normalized_path.length= path_length;
+ /* TEMPORARY FIX: if true, this means this is mysql.gtid_slave_pos table */
+ share->is_gtid_slave_pos= FALSE;
share->table_category= get_table_category(& share->db, & share->table_name);
- share->set_refresh_version();
share->open_errno= ENOENT;
-
- /*
- Since alloc_table_share() can be called without any locking (for
- example, ha_create_table... functions), we do not assign a table
- map id here. Instead we assign a value that is not used
- elsewhere, and then assign a table map id inside open_table()
- under the protection of the LOCK_open mutex.
- */
- share->table_map_id= ~0UL;
share->cached_row_logging_check= -1;
- share->used_tables.empty();
- share->free_tables.empty();
- share->m_flush_tickets.empty();
-
init_sql_alloc(&share->stats_cb.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root));
+ mysql_mutex_init(key_TABLE_SHARE_LOCK_share,
+ &share->LOCK_share, MY_MUTEX_INIT_SLOW);
mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data,
&share->LOCK_ha_data, MY_MUTEX_INIT_FAST);
+ tdc_init_share(share);
}
DBUG_RETURN(share);
}
@@ -350,7 +341,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
init_tmp_table_share()
thd thread handle
share Share to fill
- key Table_cache_key, as generated from create_table_def_key.
+ key Table_cache_key, as generated from tdc_create_key.
must start with db name.
key_length Length of key
table_name Table name
@@ -400,11 +391,6 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
compatibility checks.
*/
share->table_map_id= (ulong) thd->query_id;
-
- share->used_tables.empty();
- share->free_tables.empty();
- share->m_flush_tickets.empty();
-
DBUG_VOID_RETURN;
}
@@ -419,20 +405,28 @@ void TABLE_SHARE::destroy()
{
uint idx;
KEY *info_it;
+ DBUG_ENTER("TABLE_SHARE::destroy");
+ DBUG_PRINT("info", ("db: %s table: %s", db.str, table_name.str));
+
+ if (ha_share)
+ {
+ delete ha_share;
+ ha_share= NULL; // Safety
+ }
- if (tmp_table == NO_TMP_TABLE)
- mysql_mutex_lock(&LOCK_ha_data);
free_root(&stats_cb.mem_root, MYF(0));
stats_cb.stats_can_be_read= FALSE;
stats_cb.stats_is_read= FALSE;
stats_cb.histograms_can_be_read= FALSE;
stats_cb.histograms_are_read= FALSE;
- if (tmp_table == NO_TMP_TABLE)
- mysql_mutex_unlock(&LOCK_ha_data);
- /* The mutex is initialized only for shares that are part of the TDC */
+ /* The mutexes are initialized only for shares that are part of the TDC */
if (tmp_table == NO_TMP_TABLE)
+ {
+ mysql_mutex_destroy(&LOCK_share);
mysql_mutex_destroy(&LOCK_ha_data);
+ tdc_deinit_share(this);
+ }
my_hash_free(&name_hash);
plugin_unlock(NULL, db_plugin);
@@ -448,25 +442,20 @@ void TABLE_SHARE::destroy()
info_it->flags= 0;
}
}
- if (ha_data_destroy)
- {
- ha_data_destroy(ha_data);
- ha_data_destroy= NULL;
- }
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
plugin_unlock(NULL, default_part_plugin);
- if (ha_part_data_destroy)
- {
- ha_part_data_destroy(ha_part_data);
- ha_part_data_destroy= NULL;
- }
#endif /* WITH_PARTITION_STORAGE_ENGINE */
+
+ PSI_CALL_release_table_share(m_psi);
+
/*
Make a copy since the share is allocated in its own root,
and free_root() updates its argument after freeing the memory.
*/
MEM_ROOT own_root= mem_root;
free_root(&own_root, MYF(0));
+ DBUG_VOID_RETURN;
}
/*
@@ -481,37 +470,7 @@ void free_table_share(TABLE_SHARE *share)
{
DBUG_ENTER("free_table_share");
DBUG_PRINT("enter", ("table: %s.%s", share->db.str, share->table_name.str));
- DBUG_ASSERT(share->ref_count == 0);
-
- if (share->m_flush_tickets.is_empty())
- {
- /*
- No threads are waiting for this share to be flushed (the
- share is not old, is for a temporary table, or just nobody
- happens to be waiting for it). Destroy it.
- */
- share->destroy();
- }
- else
- {
- Wait_for_flush_list::Iterator it(share->m_flush_tickets);
- Wait_for_flush *ticket;
- /*
- We're about to iterate over a list that is used
- concurrently. Make sure this never happens without a lock.
- */
- mysql_mutex_assert_owner(&LOCK_open);
-
- while ((ticket= it++))
- (void) ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED);
- /*
- If there are threads waiting for this share to be flushed,
- the last one to receive the notification will destroy the
- share. At this point the share is removed from the table
- definition cache, so is OK to proceed here without waiting
- for this thread to do the work.
- */
- }
+ share->destroy();
DBUG_VOID_RETURN;
}
@@ -556,12 +515,16 @@ inline bool is_system_table_name(const char *name, uint length)
my_tolower(ci, name[2]) == 'm' &&
my_tolower(ci, name[3]) == 'e') ||
- /* one of mysql.*_stat tables */
- (my_tolower(ci, name[length-5]) == 's' &&
- my_tolower(ci, name[length-4]) == 't' &&
- my_tolower(ci, name[length-3]) == 'a' &&
- my_tolower(ci, name[length-2]) == 't' &&
- my_tolower(ci, name[length-1]) == 's') ||
+ /* one of mysql.*_stat tables, but not mysql.innodb* tables*/
+ ((my_tolower(ci, name[length-5]) == 's' &&
+ my_tolower(ci, name[length-4]) == 't' &&
+ my_tolower(ci, name[length-3]) == 'a' &&
+ my_tolower(ci, name[length-2]) == 't' &&
+ my_tolower(ci, name[length-1]) == 's') &&
+ !(my_tolower(ci, name[0]) == 'i' &&
+ my_tolower(ci, name[1]) == 'n' &&
+ my_tolower(ci, name[2]) == 'n' &&
+ my_tolower(ci, name[3]) == 'o')) ||
/* mysql.event table */
(my_tolower(ci, name[0]) == 'e' &&
@@ -586,7 +549,7 @@ inline bool is_system_table_name(const char *name, uint length)
NOTES
This function is called when the table definition is not cached in
- table_def_cache
+ table definition cache
The data is returned in 'share', which is alloced by
alloc_table_share().. The code assumes that share is initialized.
*/
@@ -732,7 +695,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
return 1;
keyinfo->flags= (uint) uint2korr(strpos) ^ HA_NOSAME;
keyinfo->key_length= (uint) uint2korr(strpos+2);
- keyinfo->key_parts= (uint) strpos[4];
+ keyinfo->user_defined_key_parts= (uint) strpos[4];
keyinfo->algorithm= (enum ha_key_alg) strpos[5];
keyinfo->block_size= uint2korr(strpos+6);
strpos+=8;
@@ -743,14 +706,14 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
return 1;
keyinfo->flags= ((uint) strpos[0]) ^ HA_NOSAME;
keyinfo->key_length= (uint) uint2korr(strpos+1);
- keyinfo->key_parts= (uint) strpos[3];
+ keyinfo->user_defined_key_parts= (uint) strpos[3];
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
strpos+=4;
}
if (i == 0)
{
- ext_key_parts+= (share->use_ext_keys ? first_keyinfo->key_parts*(keys-1) : 0);
+ ext_key_parts+= (share->use_ext_keys ? first_keyinfo->user_defined_key_parts*(keys-1) : 0);
n_length=keys * sizeof(KEY) + ext_key_parts * sizeof(KEY_PART_INFO);
if (!(keyinfo= (KEY*) alloc_root(&share->mem_root,
n_length + len)))
@@ -763,10 +726,10 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
sizeof(ulong) * ext_key_parts)))
return 1;
first_key_part= key_part;
- first_key_parts= first_keyinfo->key_parts;
+ first_key_parts= first_keyinfo->user_defined_key_parts;
keyinfo->flags= first_keyinfo->flags;
keyinfo->key_length= first_keyinfo->key_length;
- keyinfo->key_parts= first_keyinfo->key_parts;
+ keyinfo->user_defined_key_parts= first_keyinfo->user_defined_key_parts;
keyinfo->algorithm= first_keyinfo->algorithm;
if (new_frm_ver >= 3)
keyinfo->block_size= first_keyinfo->block_size;
@@ -774,7 +737,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
keyinfo->key_part= key_part;
keyinfo->rec_per_key= rec_per_key;
- for (j=keyinfo->key_parts ; j-- ; key_part++)
+ for (j=keyinfo->user_defined_key_parts ; j-- ; key_part++)
{
if (strpos + (new_frm_ver >= 1 ? 9 : 7) >= frm_image_end)
return 1;
@@ -802,17 +765,22 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
}
key_part->store_length=key_part->length;
}
- keyinfo->ext_key_parts= keyinfo->key_parts;
+
+ /*
+ Add primary key to end of extended keys for non unique keys for
+ storage engines that supports it.
+ */
+ keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
keyinfo->ext_key_flags= keyinfo->flags;
keyinfo->ext_key_part_map= 0;
- if (share->use_ext_keys && i)
+ if (share->use_ext_keys && i && !(keyinfo->flags & HA_NOSAME))
{
keyinfo->ext_key_part_map= 0;
for (j= 0;
j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS;
j++)
{
- uint key_parts= keyinfo->key_parts;
+ uint key_parts= keyinfo->user_defined_key_parts;
KEY_PART_INFO* curr_key_part= keyinfo->key_part;
KEY_PART_INFO* curr_key_part_end= curr_key_part+key_parts;
for ( ; curr_key_part < curr_key_part_end; curr_key_part++)
@@ -865,6 +833,42 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
/**
+ Check if a collation has changed number
+
+ @param mysql_version
+ @param current collation number
+
+ @retval new collation number (same as current collation number of no change)
+*/
+
+static uint
+upgrade_collation(ulong mysql_version, uint cs_number)
+{
+ if (mysql_version >= 50300 && mysql_version <= 50399)
+ {
+ switch (cs_number) {
+ case 149: return MY_PAGE2_COLLATION_ID_UCS2; // ucs2_crotian_ci
+ case 213: return MY_PAGE2_COLLATION_ID_UTF8; // utf8_crotian_ci
+ }
+ }
+ if ((mysql_version >= 50500 && mysql_version <= 50599) ||
+ (mysql_version >= 100000 && mysql_version <= 100005))
+ {
+ switch (cs_number) {
+ case 149: return MY_PAGE2_COLLATION_ID_UCS2; // ucs2_crotian_ci
+ case 213: return MY_PAGE2_COLLATION_ID_UTF8; // utf8_crotian_ci
+ case 214: return MY_PAGE2_COLLATION_ID_UTF32; // utf32_croatian_ci
+ case 215: return MY_PAGE2_COLLATION_ID_UTF16; // utf16_croatian_ci
+ case 245: return MY_PAGE2_COLLATION_ID_UTF8MB4;// utf8mb4_croatian_ci
+ }
+ }
+ return cs_number;
+}
+
+
+
+
+/**
Read data from a binary .frm file image into a TABLE_SHARE
@note
@@ -1041,13 +1045,21 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->null_field_first= 0;
if (!frm_image[32]) // New frm file in 3.23
{
+ uint cs_org= (((uint) frm_image[41]) << 8) + (uint) frm_image[38];
+ uint cs_new= upgrade_collation(share->mysql_version, cs_org);
+ if (cs_org != cs_new)
+ share->incompatible_version|= HA_CREATE_USED_CHARSET;
+
share->avg_row_length= uint4korr(frm_image+34);
share->transactional= (ha_choice) (frm_image[39] & 3);
share->page_checksum= (ha_choice) ((frm_image[39] >> 2) & 3);
share->row_type= (enum row_type) frm_image[40];
- share->table_charset= get_charset((((uint) frm_image[41]) << 8) +
- (uint) frm_image[38],MYF(0));
+
+ if (cs_new && !(share->table_charset= get_charset(cs_new, MYF(MY_WME))))
+ goto err;
share->null_field_first= 1;
+ share->stats_sample_pages= uint2korr(frm_image+42);
+ share->stats_auto_recalc= (enum_stats_auto_recalc)(frm_image[44]);
}
if (!share->table_charset)
{
@@ -1062,9 +1074,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
share->table_charset= default_charset_info;
}
+
share->db_record_offset= 1;
- if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
- share->blob_ptr_size= portable_sizeof_char_ptr;
share->max_rows= uint4korr(frm_image+18);
share->min_rows= uint4korr(frm_image+22);
@@ -1383,6 +1394,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
plugin_hton(se_plugin))))
goto err;
+ if (handler_file->set_ha_share_ref(&share->ha_share))
+ goto err;
+
record= share->default_values-1; /* Fieldstart = 1 */
null_bits_are_used= share->null_fields != 0;
if (share->null_field_first)
@@ -1447,16 +1461,19 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
else
{
- uint csid= strpos[14] + (((uint) strpos[11]) << 8);
- if (!csid)
+ uint cs_org= strpos[14] + (((uint) strpos[11]) << 8);
+ uint cs_new= upgrade_collation(share->mysql_version, cs_org);
+ if (cs_org != cs_new)
+ share->incompatible_version|= HA_CREATE_USED_CHARSET;
+ if (!cs_new)
charset= &my_charset_bin;
- else if (!(charset= get_charset(csid, MYF(0))))
+ else if (!(charset= get_charset(cs_new, MYF(0))))
{
- const char *csname= get_charset_name((uint) csid);
+ const char *csname= get_charset_name((uint) cs_new);
char tmp[10];
if (!csname || csname[0] =='?')
{
- my_snprintf(tmp, sizeof(tmp), "#%d", csid);
+ my_snprintf(tmp, sizeof(tmp), "#%d", cs_new);
csname= tmp;
}
my_printf_error(ER_UNKNOWN_COLLATION,
@@ -1580,7 +1597,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
"Please do \"ALTER TABLE '%s' FORCE\" to fix it!",
share->fieldnames.type_names[i], share->table_name.str,
share->table_name.str);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_CRASHED_ON_USAGE,
"Found incompatible DECIMAL field '%s' in %s; "
"Please do \"ALTER TABLE '%s' FORCE\" to fix it!",
@@ -1667,12 +1684,12 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
else
{
- add_first_key_parts= first_keyinfo.key_parts;
+ add_first_key_parts= first_keyinfo.user_defined_key_parts;
/*
Do not add components of the primary key starting from
the major component defined over the beginning of a field.
*/
- for (i= 0; i < first_keyinfo.key_parts; i++)
+ for (i= 0; i < first_keyinfo.user_defined_key_parts; i++)
{
uint fieldnr= keyinfo[0].key_part[i].fieldnr;
if (share->field[fieldnr-1]->key_length() !=
@@ -1711,7 +1728,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
Do not extend the key that contains a component
defined over the beginning of a field.
*/
- for (i= 0; i < keyinfo->key_parts; i++)
+ for (i= 0; i < keyinfo->user_defined_key_parts; i++)
{
uint fieldnr= keyinfo->key_part[i].fieldnr;
if (share->field[fieldnr-1]->key_length() !=
@@ -1722,11 +1739,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
}
- if (add_first_key_parts < keyinfo->ext_key_parts-keyinfo->key_parts)
+ if (add_first_key_parts < keyinfo->ext_key_parts-keyinfo->user_defined_key_parts)
{
share->ext_key_parts-= keyinfo->ext_key_parts;
key_part_map ext_key_part_map= keyinfo->ext_key_part_map;
- keyinfo->ext_key_parts= keyinfo->key_parts;
+ keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
keyinfo->ext_key_flags= keyinfo->flags;
keyinfo->ext_key_part_map= 0;
for (i= 0; i < add_first_key_parts; i++)
@@ -1759,7 +1776,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
*/
primary_key=key;
key_part= keyinfo->key_part;
- for (i=0 ; i < keyinfo->key_parts ;i++)
+ for (i=0 ; i < keyinfo->user_defined_key_parts ;i++)
{
uint fieldnr= key_part[i].fieldnr;
if (!fieldnr ||
@@ -1775,7 +1792,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
key_part= keyinfo->key_part;
uint key_parts= share->use_ext_keys ? keyinfo->ext_key_parts :
- keyinfo->key_parts;
+ keyinfo->user_defined_key_parts;
for (i=0; i < key_parts; key_part++, i++)
{
Field *field;
@@ -1815,7 +1832,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (i == 0 && key != primary_key)
field->flags |= (((keyinfo->flags & HA_NOSAME) &&
- (keyinfo->key_parts == 1)) ?
+ (keyinfo->user_defined_key_parts == 1)) ?
UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
if (i == 0)
field->key_start.set_bit(key);
@@ -1826,7 +1843,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
{
share->keys_for_keyread.set_bit(key);
field->part_of_key.set_bit(key);
- if (i < keyinfo->key_parts)
+ if (i < keyinfo->user_defined_key_parts)
field->part_of_key_not_clustered.set_bit(key);
}
if (handler_file->index_flags(key, i, 1) & HA_READ_ORDER)
@@ -1872,7 +1889,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
"Please do \"ALTER TABLE '%s' FORCE \" to fix it!",
share->table_name.str,
share->table_name.str);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_CRASHED_ON_USAGE,
"Found wrong key definition in %s; "
"Please do \"ALTER TABLE '%s' FORCE\" to fix "
@@ -1900,7 +1917,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
keyinfo->usable_key_parts= usable_parts; // Filesort
set_if_bigger(share->max_key_length,keyinfo->key_length+
- keyinfo->key_parts);
+ keyinfo->user_defined_key_parts);
share->total_key_length+= keyinfo->key_length;
/*
MERGE tables do not have unique indexes. But every key could be
@@ -1918,7 +1935,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
If we are using an integer as the primary key then allow the user to
refer to it as '_rowid'
*/
- if (share->key_info[primary_key].key_parts == 1)
+ if (share->key_info[primary_key].user_defined_key_parts == 1)
{
Field *field= share->key_info[primary_key].key_part[0].field;
if (field && field->result_type() == INT_RESULT)
@@ -2017,18 +2034,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
delete handler_file;
plugin_unlock(0, se_plugin);
my_hash_free(&share->name_hash);
- if (share->ha_data_destroy)
- {
- share->ha_data_destroy(share->ha_data);
- share->ha_data_destroy= NULL;
- }
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (share->ha_part_data_destroy)
- {
- share->ha_part_data_destroy(share->ha_part_data);
- share->ha_data_destroy= NULL;
- }
-#endif /* WITH_PARTITION_STORAGE_ENGINE */
if (!thd->is_error())
open_table_error(share, OPEN_FRM_CORRUPTED, share->open_errno);
@@ -2038,7 +2043,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
-static bool sql_unusable_for_discovery(THD *thd, const char *sql)
+static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
+ const char *sql)
{
LEX *lex= thd->lex;
HA_CREATE_INFO *create_info= &lex->create_info;
@@ -2053,7 +2059,7 @@ static bool sql_unusable_for_discovery(THD *thd, const char *sql)
if (lex->select_lex.item_list.elements)
return 1;
// ... temporary
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ if (create_info->tmp_table())
return 1;
// ... if exists
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
@@ -2070,7 +2076,7 @@ static bool sql_unusable_for_discovery(THD *thd, const char *sql)
if (create_info->data_file_name || create_info->index_file_name)
return 1;
// ... engine
- if (create_info->used_fields & HA_CREATE_USED_ENGINE)
+ if (create_info->db_type && create_info->db_type != engine)
return 1;
return 0;
@@ -2088,6 +2094,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
LEX *old_lex;
Query_arena *arena, backup;
LEX tmp_lex;
+ KEY *unused1;
+ uint unused2;
+ handlerton *hton= plugin_hton(db_plugin);
LEX_CUSTRING frm= {0,0};
DBUG_ENTER("TABLE_SHARE::init_from_sql_statement_string");
@@ -2119,17 +2128,18 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
lex_start(thd);
if ((error= parse_sql(thd, & parser_state, NULL) ||
- sql_unusable_for_discovery(thd, sql_copy)))
+ sql_unusable_for_discovery(thd, hton, sql_copy)))
goto ret;
- thd->lex->create_info.db_type= plugin_hton(db_plugin);
+ thd->lex->create_info.db_type= hton;
if (tabledef_version.str)
thd->lex->create_info.tabledef_version= tabledef_version;
+ promote_first_timestamp_column(&thd->lex->alter_info.create_list);
file= mysql_create_frm_image(thd, db.str, table_name.str,
&thd->lex->create_info, &thd->lex->alter_info,
- C_ORDINARY_CREATE, &frm);
+ C_ORDINARY_CREATE, &unused1, &unused2, &frm);
error|= file == 0;
delete file;
@@ -2528,6 +2538,13 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
outparam->db_stat= db_stat;
outparam->write_row_record= NULL;
+ if (share->incompatible_version &&
+ !(ha_open_flags & (HA_OPEN_FOR_ALTER | HA_OPEN_FOR_REPAIR)))
+ {
+ /* one needs to run mysql_upgrade on the table */
+ error= OPEN_FRM_NEEDS_REBUILD;
+ goto err;
+ }
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
if (outparam->alias.copy(alias, strlen(alias), table_alias_charset))
@@ -2544,6 +2561,9 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
if (!(outparam->file= get_new_handler(share, &outparam->mem_root,
share->db_type())))
goto err;
+
+ if (outparam->file->set_ha_share_ref(&share->ha_share))
+ goto err;
}
else
{
@@ -2643,7 +2663,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
key_info->key_part= key_part;
key_part_end= key_part + (share->use_ext_keys ? key_info->ext_key_parts :
- key_info->key_parts) ;
+ key_info->user_defined_key_parts) ;
for ( ; key_part < key_part_end; key_part++)
{
Field *field= key_part->field= outparam->field[key_part->fieldnr - 1];
@@ -2661,7 +2681,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
}
}
if (!share->use_ext_keys)
- key_part+= key_info->ext_key_parts - key_info->key_parts;
+ key_part+= key_info->ext_key_parts - key_info->user_defined_key_parts;
}
}
@@ -2754,8 +2774,9 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
}
outparam->part_info->is_auto_partitioned= share->auto_partitioned;
DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
- /* we should perform the fix_partition_func in either local or
- caller's arena depending on work_part_info_used value
+ /*
+ We should perform the fix_partition_func in either local or
+ caller's arena depending on work_part_info_used value.
*/
if (!work_part_info_used)
tmp= fix_partition_func(thd, outparam, is_create_table);
@@ -2864,9 +2885,22 @@ partititon_err:
bzero((char*) bitmaps, bitmap_size*3);
#endif
- outparam->no_replicate= outparam->file &&
- test(outparam->file->ha_table_flags() &
- HA_HAS_OWN_BINLOGGING);
+ if (share->table_category == TABLE_CATEGORY_LOG)
+ {
+ outparam->no_replicate= TRUE;
+ }
+ else if (outparam->file)
+ {
+ handler::Table_flags flags= outparam->file->ha_table_flags();
+ outparam->no_replicate= ! test(flags & (HA_BINLOG_STMT_CAPABLE
+ | HA_BINLOG_ROW_CAPABLE))
+ || test(flags & HA_HAS_OWN_BINLOGGING);
+ }
+ else
+ {
+ outparam->no_replicate= FALSE;
+ }
+
thd->status_var.opened_tables++;
thd->lex->context_analysis_only= save_context_analysis_only;
@@ -2926,6 +2960,7 @@ int closefrm(register TABLE *table, bool free_share)
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (table->part_info)
{
+ /* Allocated through table->mem_root, freed below */
free_items(table->part_info->item_free_list);
table->part_info->item_free_list= 0;
table->part_info= 0;
@@ -2934,7 +2969,7 @@ int closefrm(register TABLE *table, bool free_share)
if (free_share)
{
if (table->s->tmp_table == NO_TMP_TABLE)
- release_table_share(table->s);
+ tdc_release_share(table->s);
else
free_table_share(table->s);
}
@@ -3033,6 +3068,11 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error,
strxmov(buff, share->normalized_path.str, reg_ext, NullS);
my_error(ER_ERROR_ON_READ, errortype, buff, db_errno);
break;
+ case OPEN_FRM_NEEDS_REBUILD:
+ strxnmov(buff, sizeof(buff)-1,
+ share->db.str, ".", share->table_name.str, NullS);
+ my_error(ER_TABLE_NEEDS_REBUILD, errortype, buff);
+ break;
}
DBUG_VOID_RETURN;
} /* open_table_error */
@@ -3264,11 +3304,10 @@ void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo,
fileinfo[39]= (uchar) ((uint) create_info->transactional |
((uint) create_info->page_checksum << 2));
fileinfo[40]= (uchar) create_info->row_type;
- /* Next few bytes where for RAID support */
+ /* Bytes 41-46 were for RAID support; now reused for other purposes */
fileinfo[41]= (uchar) (csid >> 8);
- fileinfo[42]= 0;
- fileinfo[43]= 0;
- fileinfo[44]= 0;
+ int2store(fileinfo+42, create_info->stats_sample_pages & 0xffff);
+ fileinfo[44]= (uchar) create_info->stats_auto_recalc;
fileinfo[45]= 0;
fileinfo[46]= 0;
int4store(fileinfo+47, key_length);
@@ -3342,7 +3381,7 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
}
if (!(to= strmake_root(mem, str.ptr(), length)))
length= 0; // Safety fix
- res->set(to, length, ((Field_str*)field)->charset());
+ res->set(to, length, field->charset());
return 0;
}
@@ -3579,9 +3618,9 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
}
else if (MYSQL_VERSION_ID == table->s->mysql_version)
{
- report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED,
- ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED),
- table->alias.c_ptr(),
+ report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2,
+ ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2),
+ table->s->db.str, table->s->table_name.str,
table_def->count, table->s->fields);
DBUG_RETURN(TRUE);
}
@@ -3693,18 +3732,18 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
else
{
KEY *pk= &table->s->key_info[table->s->primary_key];
- if (pk->key_parts != table_def->primary_key_parts)
+ if (pk->user_defined_key_parts != table_def->primary_key_parts)
{
report_error(0, "Incorrect definition of table %s.%s: "
"Expected primary key to have %u columns, but instead "
"found %u columns.", table->s->db.str,
table->alias.c_ptr(), table_def->primary_key_parts,
- pk->key_parts);
+ pk->user_defined_key_parts);
error= TRUE;
}
else
{
- for (i= 0; i < pk->key_parts; ++i)
+ for (i= 0; i < pk->user_defined_key_parts; ++i)
{
if (table_def->primary_key_columns[i] + 1 != pk->key_part[i].fieldnr)
{
@@ -3778,7 +3817,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
if (gvisitor->m_lock_open_count++ == 0)
mysql_mutex_lock(&LOCK_open);
- I_P_List_iterator <TABLE, TABLE_share> tables_it(used_tables);
+ All_share_tables_list::Iterator tables_it(tdc.all_tables);
/*
In case of multiple searches running in parallel, avoid going
@@ -3796,7 +3835,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
while ((table= tables_it++))
{
- if (gvisitor->inspect_edge(&table->in_use->mdl_context))
+ if (table->in_use && gvisitor->inspect_edge(&table->in_use->mdl_context))
{
goto end_leave_node;
}
@@ -3805,7 +3844,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
tables_it.rewind();
while ((table= tables_it++))
{
- if (table->in_use->mdl_context.visit_subgraph(gvisitor))
+ if (table->in_use && table->in_use->mdl_context.visit_subgraph(gvisitor))
{
goto end_leave_node;
}
@@ -3832,10 +3871,15 @@ end:
@param abstime Timeout for waiting as absolute time value.
@param deadlock_weight Weight of this wait for deadlock detector.
- @pre LOCK_open is write locked, the share is used (has
- non-zero reference count), is marked for flush and
+ @pre LOCK_table_share is locked, the share is marked for flush and
this connection does not reference the share.
- LOCK_open will be unlocked temporarily during execution.
+ LOCK_table_share will be unlocked temporarily during execution.
+
+ It may happen that another FLUSH TABLES thread marked this share
+ for flush, but didn't yet purge it from table definition cache.
+ In this case we may start waiting for a table share that has no
+ references (ref_count == 0). We do this with assumption that this
+ another FLUSH TABLES thread is about to purge this share.
@retval FALSE - Success.
@retval TRUE - Error (OOM, deadlock, timeout, etc...).
@@ -3848,41 +3892,40 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
Wait_for_flush ticket(mdl_context, this, deadlock_weight);
MDL_wait::enum_wait_status wait_status;
- mysql_mutex_assert_owner(&LOCK_open);
- /*
- We should enter this method only when share's version is not
- up to date and the share is referenced. Otherwise our
- thread will never be woken up from wait.
- */
- DBUG_ASSERT(version != refresh_version && ref_count != 0);
+ mysql_mutex_assert_owner(&tdc.LOCK_table_share);
+ DBUG_ASSERT(has_old_version());
- m_flush_tickets.push_front(&ticket);
+ tdc.m_flush_tickets.push_front(&ticket);
mdl_context->m_wait.reset_status();
- mysql_mutex_unlock(&LOCK_open);
+ mysql_mutex_unlock(&tdc.LOCK_table_share);
mdl_context->will_wait_for(&ticket);
mdl_context->find_deadlock();
wait_status= mdl_context->m_wait.timed_wait(thd, abstime, TRUE,
- "Waiting for table flush");
+ &stage_waiting_for_table_flush);
mdl_context->done_waiting_for();
- mysql_mutex_lock(&LOCK_open);
+ mysql_mutex_lock(&tdc.LOCK_table_share);
- m_flush_tickets.remove(&ticket);
+ tdc.m_flush_tickets.remove(&ticket);
- if (m_flush_tickets.is_empty() && ref_count == 0)
+ if (tdc.m_flush_tickets.is_empty() && tdc.ref_count == 0)
{
/*
If our thread was the last one using the share,
we must destroy it here.
*/
+ mysql_mutex_unlock(&tdc.LOCK_table_share);
destroy();
}
+ else
+ mysql_mutex_unlock(&tdc.LOCK_table_share);
+
/*
In cases when our wait was aborted by KILL statement,
@@ -3927,7 +3970,7 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
void TABLE::init(THD *thd, TABLE_LIST *tl)
{
- DBUG_ASSERT(s->ref_count > 0 || s->tmp_table != NO_TMP_TABLE);
+ DBUG_ASSERT(s->tdc.ref_count > 0 || s->tmp_table != NO_TMP_TABLE);
if (thd->lex->need_correct_ident())
alias_name_used= my_strcasecmp(table_alias_charset,
@@ -4054,7 +4097,8 @@ void TABLE::reset_item_list(List<Item> *item_list) const
void TABLE_LIST::calc_md5(char *buffer)
{
uchar digest[16];
- MY_MD5_HASH(digest, (uchar *) select_stmt.str, select_stmt.length);
+ compute_md5_hash((char*) digest, select_stmt.str,
+ select_stmt.length);
sprintf((char *) buffer,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
@@ -4445,27 +4489,32 @@ void TABLE_LIST::hide_view_error(THD *thd)
return;
/* Hide "Unknown column" or "Unknown function" error */
DBUG_ASSERT(thd->is_error());
+ switch (thd->get_stmt_da()->sql_errno()) {
+ case ER_BAD_FIELD_ERROR:
+ case ER_SP_DOES_NOT_EXIST:
+ case ER_FUNC_INEXISTENT_NAME_COLLISION:
+ case ER_PROCACCESS_DENIED_ERROR:
+ case ER_COLUMNACCESS_DENIED_ERROR:
+ case ER_TABLEACCESS_DENIED_ERROR:
+ case ER_TABLE_NOT_LOCKED:
+ case ER_NO_SUCH_TABLE:
+ {
+ TABLE_LIST *top= top_table();
+ thd->clear_error();
+ my_error(ER_VIEW_INVALID, MYF(0),
+ top->view_db.str, top->view_name.str);
+ break;
+ }
- if (thd->stmt_da->sql_errno() == ER_BAD_FIELD_ERROR ||
- thd->stmt_da->sql_errno() == ER_SP_DOES_NOT_EXIST ||
- thd->stmt_da->sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
- thd->stmt_da->sql_errno() == ER_PROCACCESS_DENIED_ERROR ||
- thd->stmt_da->sql_errno() == ER_COLUMNACCESS_DENIED_ERROR ||
- thd->stmt_da->sql_errno() == ER_TABLEACCESS_DENIED_ERROR ||
- thd->stmt_da->sql_errno() == ER_TABLE_NOT_LOCKED ||
- thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
- {
- TABLE_LIST *top= top_table();
- thd->clear_error();
- my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
- }
- else if (thd->stmt_da->sql_errno() == ER_NO_DEFAULT_FOR_FIELD)
- {
- TABLE_LIST *top= top_table();
- thd->clear_error();
- // TODO: make correct error message
- my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0),
- top->view_db.str, top->view_name.str);
+ case ER_NO_DEFAULT_FOR_FIELD:
+ {
+ TABLE_LIST *top= top_table();
+ thd->clear_error();
+ // TODO: make correct error message
+ my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0),
+ top->view_db.str, top->view_name.str);
+ break;
+ }
}
}
@@ -4541,7 +4590,7 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure)
TABLE_LIST *main_view= top_table();
if (ignore_failure)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED),
main_view->view_db.str, main_view->view_name.str);
return(VIEW_CHECK_SKIP);
@@ -4834,7 +4883,7 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd)
if ((thd->lex->sql_command == SQLCOM_SHOW_CREATE) ||
(thd->lex->sql_command == SQLCOM_SHOW_FIELDS))
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_NO_SUCH_USER,
ER(ER_NO_SUCH_USER),
definer.user.str, definer.host.str);
@@ -4863,6 +4912,7 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd)
}
}
DBUG_RETURN(FALSE);
+
}
#endif
@@ -5627,7 +5677,7 @@ void TABLE::mark_columns_used_by_index_no_reset(uint index,
{
KEY_PART_INFO *key_part= key_info[index].key_part;
KEY_PART_INFO *key_part_end= (key_part +
- key_info[index].key_parts);
+ key_info[index].user_defined_key_parts);
for (;key_part != key_part_end; key_part++)
{
bitmap_set_bit(bitmap, key_part->fieldnr-1);
@@ -6057,8 +6107,8 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
return TRUE;
keyinfo= key_info + key;
keyinfo->key_part= key_part_info;
- keyinfo->usable_key_parts= keyinfo->key_parts = key_parts;
- keyinfo->ext_key_parts= keyinfo->key_parts;
+ keyinfo->usable_key_parts= keyinfo->user_defined_key_parts = key_parts;
+ keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
keyinfo->key_length=0;
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
keyinfo->flags= HA_GENERATED_KEY;
@@ -6157,7 +6207,7 @@ bool TABLE::is_filled_at_execution()
uint TABLE::actual_n_key_parts(KEY *keyinfo)
{
return optimizer_flag(in_use, OPTIMIZER_SWITCH_EXTENDED_KEYS) ?
- keyinfo->ext_key_parts : keyinfo->key_parts;
+ keyinfo->ext_key_parts : keyinfo->user_defined_key_parts;
}
@@ -6474,7 +6524,7 @@ bool TABLE::update_const_key_parts(COND *conds)
for (uint index= 0; index < s->keys; index++)
{
KEY_PART_INFO *keyinfo= key_info[index].key_part;
- KEY_PART_INFO *keyinfo_end= keyinfo + key_info[index].key_parts;
+ KEY_PART_INFO *keyinfo_end= keyinfo + key_info[index].user_defined_key_parts;
for (key_part_map part_map= (key_part_map)1;
keyinfo < keyinfo_end;