mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
handlerton::discover_table_existence() method
This commit is contained in:
@ -383,6 +383,11 @@ static int ha_finish_errors(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volatile int32 need_full_discover_for_existence= 0;
|
||||||
|
static int full_discover_for_existence(handlerton *, const char *, const char *)
|
||||||
|
{ return 1; }
|
||||||
|
static int ext_based_existence(handlerton *, const char *, const char *)
|
||||||
|
{ return 1; }
|
||||||
|
|
||||||
int ha_finalize_handlerton(st_plugin_int *plugin)
|
int ha_finalize_handlerton(st_plugin_int *plugin)
|
||||||
{
|
{
|
||||||
@ -433,6 +438,9 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
|
|||||||
hton2plugin[hton->slot]= NULL;
|
hton2plugin[hton->slot]= NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hton->discover_table_existence == full_discover_for_existence)
|
||||||
|
my_atomic_add32(&need_full_discover_for_existence, -1);
|
||||||
|
|
||||||
if (hton->discover_table_names)
|
if (hton->discover_table_names)
|
||||||
my_atomic_add32(&engines_with_discover_table_names, -1);
|
my_atomic_add32(&engines_with_discover_table_names, -1);
|
||||||
|
|
||||||
@ -486,6 +494,18 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
|
|||||||
hton->discover && hton->tablefile_extensions[0])
|
hton->discover && hton->tablefile_extensions[0])
|
||||||
hton->discover_table_names= hton_ext_based_table_discovery;
|
hton->discover_table_names= hton_ext_based_table_discovery;
|
||||||
|
|
||||||
|
// default discover_table_existence implementation
|
||||||
|
if (!hton->discover_table_existence && hton->discover)
|
||||||
|
{
|
||||||
|
if (hton->tablefile_extensions[0])
|
||||||
|
hton->discover_table_existence= ext_based_existence;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hton->discover_table_existence= full_discover_for_existence;
|
||||||
|
my_atomic_add32(&need_full_discover_for_existence, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
the switch below and hton->state should be removed when
|
the switch below and hton->state should be removed when
|
||||||
command-line options for plugins will be implemented
|
command-line options for plugins will be implemented
|
||||||
@ -4377,6 +4397,83 @@ int ha_discover(THD *thd, const char *db, const char *name,
|
|||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check if a given table exists, without doing a full discover, if possible
|
||||||
|
*/
|
||||||
|
|
||||||
|
static my_bool file_ext_exists(char *path, size_t path_len, const char *ext)
|
||||||
|
{
|
||||||
|
strmake(path + path_len, ext, FN_REFLEN - path_len);
|
||||||
|
return !access(path, F_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct st_discover_existence_args
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
size_t path_len;
|
||||||
|
const char *db, *table_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static my_bool discover_existence(THD *thd, plugin_ref plugin,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
st_discover_existence_args *args= (st_discover_existence_args*)arg;
|
||||||
|
handlerton *ht= plugin_data(plugin, handlerton *);
|
||||||
|
if (ht->state != SHOW_OPTION_YES || !ht->discover_table_existence)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (ht->discover_table_existence == ext_based_existence)
|
||||||
|
return file_ext_exists(args->path, args->path_len,
|
||||||
|
ht->tablefile_extensions[0]);
|
||||||
|
|
||||||
|
return ht->discover_table_existence(ht, args->db, args->table_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ha_table_exists(THD *thd, const char *db, const char *table_name)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("ha_discover_table_existence");
|
||||||
|
|
||||||
|
if (need_full_discover_for_existence)
|
||||||
|
{
|
||||||
|
enum open_frm_error err;
|
||||||
|
TABLE_LIST table;
|
||||||
|
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
TABLE_SHARE *share= get_table_share(thd, db, table_name,
|
||||||
|
FRM_READ_TABLE_ONLY, &err);
|
||||||
|
|
||||||
|
if (share)
|
||||||
|
{
|
||||||
|
mysql_mutex_lock(&LOCK_open);
|
||||||
|
release_table_share(share);
|
||||||
|
mysql_mutex_unlock(&LOCK_open);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_mutex_lock(&LOCK_open);
|
||||||
|
TABLE_SHARE *share= get_cached_table_share(db, table_name);
|
||||||
|
mysql_mutex_unlock(&LOCK_open);
|
||||||
|
|
||||||
|
if (share)
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
|
char path[FN_REFLEN + 1];
|
||||||
|
size_t path_len = build_table_filename(path, sizeof(path) - 1,
|
||||||
|
db, table_name, "", 0);
|
||||||
|
|
||||||
|
if (file_ext_exists(path, path_len, reg_ext))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
|
st_discover_existence_args args= {path, path_len, db, table_name};
|
||||||
|
|
||||||
|
if (plugin_foreach(thd, discover_existence, MYSQL_STORAGE_ENGINE_PLUGIN,
|
||||||
|
&args))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
|
DBUG_RETURN(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Discover all table names in a given database
|
Discover all table names in a given database
|
||||||
|
@ -1136,6 +1136,27 @@ struct handlerton
|
|||||||
*/
|
*/
|
||||||
int (*discover_table_names)(handlerton *hton, LEX_STRING *db, MY_DIR *dir,
|
int (*discover_table_names)(handlerton *hton, LEX_STRING *db, MY_DIR *dir,
|
||||||
discovered_list *result);
|
discovered_list *result);
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a method that allows to server to check if a table exists without
|
||||||
|
an overhead of the complete discovery.
|
||||||
|
|
||||||
|
By default (if not implemented by the engine, but the discovery_table() is
|
||||||
|
implemented) it will try to perform a file-based discovery:
|
||||||
|
|
||||||
|
- if tablefile_extensions[0] is not null this will look for a file name
|
||||||
|
with the tablefile_extensions[0] extension.
|
||||||
|
|
||||||
|
- if tablefile_extensions[0] is null, this will resort to discover_table().
|
||||||
|
|
||||||
|
Note that resorting to discover_table() is slow and the engine
|
||||||
|
should probably implement its own discover_table_existence() method,
|
||||||
|
if its tablefile_extensions[0] is null.
|
||||||
|
|
||||||
|
Returns 1 if the table exists and 0 if it does not.
|
||||||
|
*/
|
||||||
|
int (*discover_table_existence)(handlerton *hton, const char *db,
|
||||||
|
const char *table_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3072,6 +3093,8 @@ int ha_discover(THD* thd, const char* dbname, const char* name,
|
|||||||
uchar** frmblob, size_t* frmlen);
|
uchar** frmblob, size_t* frmlen);
|
||||||
int ha_discover_table_names(THD *thd, LEX_STRING *db, MY_DIR *dirp,
|
int ha_discover_table_names(THD *thd, LEX_STRING *db, MY_DIR *dirp,
|
||||||
handlerton::discovered_list *result);
|
handlerton::discovered_list *result);
|
||||||
|
bool ha_table_exists(THD *thd, const char *db, const char *table_name);
|
||||||
|
|
||||||
#ifdef MYSQL_SERVER
|
#ifdef MYSQL_SERVER
|
||||||
extern volatile int32 engines_with_discover_table_names;
|
extern volatile int32 engines_with_discover_table_names;
|
||||||
#endif
|
#endif
|
||||||
|
@ -771,7 +771,7 @@ void release_table_share(TABLE_SHARE *share)
|
|||||||
# TABLE_SHARE for table
|
# TABLE_SHARE for table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name)
|
TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name)
|
||||||
{
|
{
|
||||||
char key[SAFE_NAME_LEN*2+2];
|
char key[SAFE_NAME_LEN*2+2];
|
||||||
uint key_length;
|
uint key_length;
|
||||||
@ -2337,58 +2337,6 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check that table exists in table definition cache, on disk
|
|
||||||
or in some storage engine.
|
|
||||||
|
|
||||||
@param thd Thread context
|
|
||||||
@param db database name
|
|
||||||
@param table_name table name
|
|
||||||
@param path (optional) path to the frm file
|
|
||||||
|
|
||||||
@note This function acquires LOCK_open internally.
|
|
||||||
|
|
||||||
@note If there is no .FRM file for the table but it exists in one
|
|
||||||
of engines (e.g. it was created on another node of NDB cluster)
|
|
||||||
this function will fetch and create proper .FRM file for it.
|
|
||||||
|
|
||||||
@retval TRUE Some error occurred
|
|
||||||
@retval FALSE No error. 'exists' out parameter set accordingly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool table_exists(THD *thd, const char *db, const char *table_name,
|
|
||||||
const char *path)
|
|
||||||
{
|
|
||||||
char path_buf[FN_REFLEN + 1];
|
|
||||||
TABLE_SHARE *share;
|
|
||||||
DBUG_ENTER("table_exists");
|
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_open);
|
|
||||||
share= get_cached_table_share(db, table_name);
|
|
||||||
mysql_mutex_unlock(&LOCK_open);
|
|
||||||
|
|
||||||
if (share)
|
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
|
|
||||||
if (!path)
|
|
||||||
{
|
|
||||||
build_table_filename(path_buf, sizeof(path_buf) - 1,
|
|
||||||
db, table_name, reg_ext, 0);
|
|
||||||
path= path_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access(path, F_OK))
|
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
|
|
||||||
/* .FRM file doesn't exist. Try to discover it */
|
|
||||||
uchar *frmblob= NULL;
|
|
||||||
size_t frmlen;
|
|
||||||
bool exists= ! ha_discover(thd, db, table_name, &frmblob, &frmlen);
|
|
||||||
my_free(frmblob);
|
|
||||||
DBUG_RETURN(exists);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An error handler which converts, if possible, ER_LOCK_DEADLOCK error
|
An error handler which converts, if possible, ER_LOCK_DEADLOCK error
|
||||||
that can occur when we are trying to acquire a metadata lock to
|
that can occur when we are trying to acquire a metadata lock to
|
||||||
@ -2926,7 +2874,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
|
|
||||||
if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS)
|
if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS)
|
||||||
{
|
{
|
||||||
if (!table_exists(thd, table_list))
|
if (!ha_table_exists(thd, table_list->db, table_list->table_name))
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
|
|
||||||
/* Table exists. Let us try to open it. */
|
/* Table exists. Let us try to open it. */
|
||||||
@ -4705,7 +4653,7 @@ lock_table_names(THD *thd,
|
|||||||
We come here in the case of lock timeout when executing CREATE TABLE.
|
We come here in the case of lock timeout when executing CREATE TABLE.
|
||||||
Verify that table does exist (it usually does, as we got a lock conflict)
|
Verify that table does exist (it usually does, as we got a lock conflict)
|
||||||
*/
|
*/
|
||||||
if (table_exists(thd, tables_start))
|
if (ha_table_exists(thd, tables_start->db, tables_start->table_name))
|
||||||
{
|
{
|
||||||
if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||||
{
|
{
|
||||||
|
@ -113,7 +113,7 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
|
|||||||
enum open_frm_error *error,
|
enum open_frm_error *error,
|
||||||
my_hash_value_type hash_value);
|
my_hash_value_type hash_value);
|
||||||
void release_table_share(TABLE_SHARE *share);
|
void release_table_share(TABLE_SHARE *share);
|
||||||
|
TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
|
||||||
|
|
||||||
// convenience helper: call get_table_share() without precomputed hash_value
|
// convenience helper: call get_table_share() without precomputed hash_value
|
||||||
static inline TABLE_SHARE *get_table_share(THD *thd, const char *db,
|
static inline TABLE_SHARE *get_table_share(THD *thd, const char *db,
|
||||||
@ -369,13 +369,6 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
|
|||||||
bool no_error);
|
bool no_error);
|
||||||
void mark_tmp_table_for_reuse(TABLE *table);
|
void mark_tmp_table_for_reuse(TABLE *table);
|
||||||
|
|
||||||
bool table_exists(THD *thd, const char *db, const char *table_name,
|
|
||||||
const char *path);
|
|
||||||
static inline bool table_exists(THD *thd, TABLE_LIST *table)
|
|
||||||
{
|
|
||||||
return table_exists(thd, table->db, table->table_name, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int update_virtual_fields(THD *thd, TABLE *table,
|
int update_virtual_fields(THD *thd, TABLE *table,
|
||||||
enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
|
enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
|
||||||
int dynamic_column_error_message(enum_dyncol_func_result rc);
|
int dynamic_column_error_message(enum_dyncol_func_result rc);
|
||||||
|
@ -937,7 +937,7 @@ update_binlog:
|
|||||||
char quoted_name[FN_REFLEN+3];
|
char quoted_name[FN_REFLEN+3];
|
||||||
|
|
||||||
// Only write drop table to the binlog for tables that no longer exist.
|
// Only write drop table to the binlog for tables that no longer exist.
|
||||||
if (table_exists(thd, tbl))
|
if (ha_table_exists(thd, tbl->db, tbl->table_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
my_snprintf(quoted_name, sizeof(quoted_name), "%`s", tbl->table_name);
|
my_snprintf(quoted_name, sizeof(quoted_name), "%`s", tbl->table_name);
|
||||||
|
@ -2279,8 +2279,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
}
|
}
|
||||||
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
|
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
|
||||||
error= 0;
|
error= 0;
|
||||||
if (drop_temporary || !table_exists(thd, db, alias, path) ||
|
if (!table->internal_tmp_table &&
|
||||||
(!drop_view && dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))
|
(drop_temporary || !ha_table_exists(thd, db, alias) ||
|
||||||
|
(!drop_view && dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
One of the following cases happened:
|
One of the following cases happened:
|
||||||
@ -2288,6 +2289,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
. "DROP" but table was not found on disk and table can't be
|
. "DROP" but table was not found on disk and table can't be
|
||||||
created from engine.
|
created from engine.
|
||||||
. ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
|
. ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
|
||||||
|
|
||||||
|
Table->internal_tmp_table is set when one of the #sql-xxx files
|
||||||
|
was left in the datadir after a crash during ALTER TABLE.
|
||||||
|
See Bug#30152.
|
||||||
*/
|
*/
|
||||||
if (if_exists)
|
if (if_exists)
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||||
@ -4317,7 +4322,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
|||||||
|
|
||||||
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
||||||
{
|
{
|
||||||
if (table_exists(thd, db, table_name, path))
|
if (ha_table_exists(thd, db, table_name))
|
||||||
{
|
{
|
||||||
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||||
goto warn;
|
goto warn;
|
||||||
|
Reference in New Issue
Block a user