summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-04-09 15:35:57 +0200
committerSergei Golubchik <sergii@pisem.net>2013-04-09 15:35:57 +0200
commit6a839ff40d1be946b4391eb7a316b0404e1cd82b (patch)
tree770dce5797a309f58d4741856fa4b4b7ba735a68 /sql
parent934115184b52a28a30d576a8a47d0ec66b1b0712 (diff)
downloadmariadb-git-6a839ff40d1be946b4391eb7a316b0404e1cd82b.tar.gz
handlerton::discover_table_existence() method
Diffstat (limited to 'sql')
-rw-r--r--sql/handler.cc97
-rw-r--r--sql/handler.h23
-rw-r--r--sql/sql_base.cc58
-rw-r--r--sql/sql_base.h9
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_table.cc11
6 files changed, 133 insertions, 67 deletions
diff --git a/sql/handler.cc b/sql/handler.cc
index 8da997c2df2..f4987b9b36f 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -383,6 +383,11 @@ static int ha_finish_errors(void)
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)
{
@@ -433,6 +438,9 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
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)
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_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
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);
}
+/**
+ 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
diff --git a/sql/handler.h b/sql/handler.h
index 79e757c5649..ee1d54c3253 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1136,6 +1136,27 @@ struct handlerton
*/
int (*discover_table_names)(handlerton *hton, LEX_STRING *db, MY_DIR *dir,
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);
int ha_discover_table_names(THD *thd, LEX_STRING *db, MY_DIR *dirp,
handlerton::discovered_list *result);
+bool ha_table_exists(THD *thd, const char *db, const char *table_name);
+
#ifdef MYSQL_SERVER
extern volatile int32 engines_with_discover_table_names;
#endif
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 14389e840e9..d1feba264f1 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -771,7 +771,7 @@ void release_table_share(TABLE_SHARE *share)
# 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];
uint key_length;
@@ -2338,58 +2338,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
that can occur when we are trying to acquire a metadata lock to
a request for back-off and re-start of open_tables() process.
@@ -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_exists(thd, table_list))
+ if (!ha_table_exists(thd, table_list->db, table_list->table_name))
DBUG_RETURN(FALSE);
/* 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.
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)
{
diff --git a/sql/sql_base.h b/sql/sql_base.h
index e0ced3992eb..1880b4f4321 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -113,7 +113,7 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
enum open_frm_error *error,
my_hash_value_type hash_value);
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
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);
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,
enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
int dynamic_column_error_message(enum_dyncol_func_result rc);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 359f74155db..6dee6b4bcc5 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -937,7 +937,7 @@ update_binlog:
char quoted_name[FN_REFLEN+3];
// 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;
my_snprintf(quoted_name, sizeof(quoted_name), "%`s", tbl->table_name);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ea1b7b3398b..b19e179f022 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -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");
error= 0;
- if (drop_temporary || !table_exists(thd, db, alias, path) ||
- (!drop_view && dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))
+ if (!table->internal_tmp_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:
@@ -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
created from engine.
. ./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)
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 (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)
goto warn;