mirror of
https://github.com/MariaDB/server.git
synced 2026-05-10 00:54:30 +02:00
MDEV-4955 discover of table non-existance on CREATE
Fix ha_table_exists() to take discovery into account correctly. It must be able to discover both table existence (when no frm is found) and table non-existance (when frm was found).
This commit is contained in:
parent
570c1a6fef
commit
8d0238a6d8
6 changed files with 73 additions and 85 deletions
|
|
@ -135,7 +135,7 @@ select * from t1;
|
||||||
a
|
a
|
||||||
flush tables;
|
flush tables;
|
||||||
create table t1 (a int) engine=archive;
|
create table t1 (a int) engine=archive;
|
||||||
ERROR 42S01: Table 't1' already exists
|
|
||||||
flush tables;
|
flush tables;
|
||||||
create table t1 (a int) engine=archive;
|
create table t1 (a int) engine=archive;
|
||||||
|
ERROR 42S01: Table 't1' already exists
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
|
||||||
|
|
@ -125,10 +125,10 @@ create table t1 (a int) engine=archive;
|
||||||
select * from t1;
|
select * from t1;
|
||||||
flush tables;
|
flush tables;
|
||||||
remove_file $mysqld_datadir/test/t1.ARZ;
|
remove_file $mysqld_datadir/test/t1.ARZ;
|
||||||
--error ER_TABLE_EXISTS_ERROR
|
|
||||||
create table t1 (a int) engine=archive;
|
create table t1 (a int) engine=archive;
|
||||||
remove_file $mysqld_datadir/test/t1.frm;
|
remove_file $mysqld_datadir/test/t1.frm;
|
||||||
flush tables;
|
flush tables;
|
||||||
|
--error ER_TABLE_EXISTS_ERROR
|
||||||
create table t1 (a int) engine=archive;
|
create table t1 (a int) engine=archive;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
|
|
||||||
114
sql/handler.cc
114
sql/handler.cc
|
|
@ -386,12 +386,13 @@ static int ha_finish_errors(void)
|
||||||
|
|
||||||
static volatile int32 need_full_discover_for_existence= 0;
|
static volatile int32 need_full_discover_for_existence= 0;
|
||||||
static volatile int32 engines_with_discover_table_names= 0;
|
static volatile int32 engines_with_discover_table_names= 0;
|
||||||
|
static volatile int32 engines_with_discover= 0;
|
||||||
|
|
||||||
static int full_discover_for_existence(handlerton *, const char *, const char *)
|
static int full_discover_for_existence(handlerton *, const char *, const char *)
|
||||||
{ return 1; }
|
{ return 0; }
|
||||||
|
|
||||||
static int ext_based_existence(handlerton *, const char *, const char *)
|
static int ext_based_existence(handlerton *, const char *, const char *)
|
||||||
{ return 1; }
|
{ return 0; }
|
||||||
|
|
||||||
static int hton_ext_based_table_discovery(handlerton *hton, LEX_STRING *db,
|
static int hton_ext_based_table_discovery(handlerton *hton, LEX_STRING *db,
|
||||||
MY_DIR *dir, handlerton::discovered_list *result)
|
MY_DIR *dir, handlerton::discovered_list *result)
|
||||||
|
|
@ -411,6 +412,9 @@ static void update_discovery_counters(handlerton *hton, int val)
|
||||||
|
|
||||||
if (hton->discover_table_names)
|
if (hton->discover_table_names)
|
||||||
my_atomic_add32(&engines_with_discover_table_names, val);
|
my_atomic_add32(&engines_with_discover_table_names, val);
|
||||||
|
|
||||||
|
if (hton->discover_table)
|
||||||
|
my_atomic_add32(&engines_with_discover, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ha_finalize_handlerton(st_plugin_int *plugin)
|
int ha_finalize_handlerton(st_plugin_int *plugin)
|
||||||
|
|
@ -4787,7 +4791,9 @@ int ha_discover_table(THD *thd, TABLE_SHARE *share)
|
||||||
|
|
||||||
DBUG_ASSERT(share->error == OPEN_FRM_OPEN_ERROR); // share is not OK yet
|
DBUG_ASSERT(share->error == OPEN_FRM_OPEN_ERROR); // share is not OK yet
|
||||||
|
|
||||||
if (share->db_plugin)
|
if (!engines_with_discover)
|
||||||
|
found= FALSE;
|
||||||
|
else if (share->db_plugin)
|
||||||
found= discover_handlerton(thd, share->db_plugin, share);
|
found= discover_handlerton(thd, share->db_plugin, share);
|
||||||
else
|
else
|
||||||
found= plugin_foreach(thd, discover_handlerton,
|
found= plugin_foreach(thd, discover_handlerton,
|
||||||
|
|
@ -4811,6 +4817,7 @@ struct st_discover_existence_args
|
||||||
size_t path_len;
|
size_t path_len;
|
||||||
const char *db, *table_name;
|
const char *db, *table_name;
|
||||||
handlerton *hton;
|
handlerton *hton;
|
||||||
|
bool frm_exists;
|
||||||
};
|
};
|
||||||
|
|
||||||
static my_bool discover_existence(THD *thd, plugin_ref plugin,
|
static my_bool discover_existence(THD *thd, plugin_ref plugin,
|
||||||
|
|
@ -4819,7 +4826,7 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin,
|
||||||
st_discover_existence_args *args= (st_discover_existence_args*)arg;
|
st_discover_existence_args *args= (st_discover_existence_args*)arg;
|
||||||
handlerton *ht= plugin_hton(plugin);
|
handlerton *ht= plugin_hton(plugin);
|
||||||
if (ht->state != SHOW_OPTION_YES || !ht->discover_table_existence)
|
if (ht->state != SHOW_OPTION_YES || !ht->discover_table_existence)
|
||||||
return FALSE;
|
return args->frm_exists;
|
||||||
|
|
||||||
args->hton= ht;
|
args->hton= ht;
|
||||||
|
|
||||||
|
|
@ -4874,17 +4881,80 @@ private:
|
||||||
If the 'hton' is not NULL, it's set to the handlerton of the storage engine
|
If the 'hton' is not NULL, it's set to the handlerton of the storage engine
|
||||||
of this table, or to view_pseudo_hton if the frm belongs to a view.
|
of this table, or to view_pseudo_hton if the frm belongs to a view.
|
||||||
|
|
||||||
|
This function takes discovery correctly into account. If frm is found,
|
||||||
|
it discovers the table to make sure it really exists in the engine.
|
||||||
|
If no frm is found it discovers the table, in case it still exists in
|
||||||
|
the engine.
|
||||||
|
|
||||||
|
While it tries to cut corners (don't open .frm if no discovering engine is
|
||||||
|
enabled, no full discovery if all discovering engines support
|
||||||
|
discover_table_existence, etc), it still *may* be quite expensive
|
||||||
|
and must be used sparingly.
|
||||||
|
|
||||||
@retval true Table exists (even if the error occurred, like bad frm)
|
@retval true Table exists (even if the error occurred, like bad frm)
|
||||||
@retval false Table does not exist (one can do CREATE TABLE table_name)
|
@retval false Table does not exist (one can do CREATE TABLE table_name)
|
||||||
|
|
||||||
|
@note if frm exists and the table in engine doesn't, *hton will be set,
|
||||||
|
but the return value will be false.
|
||||||
|
|
||||||
|
@note if frm file exists, but the table cannot be opened (engine not
|
||||||
|
loaded, frm is invalid), the return value will be true, but
|
||||||
|
*hton will be NULL.
|
||||||
*/
|
*/
|
||||||
bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
||||||
handlerton **hton)
|
handlerton **hton)
|
||||||
{
|
{
|
||||||
|
handlerton *dummy;
|
||||||
DBUG_ENTER("ha_table_exists");
|
DBUG_ENTER("ha_table_exists");
|
||||||
|
|
||||||
if (hton)
|
if (hton)
|
||||||
*hton= 0;
|
*hton= 0;
|
||||||
|
else if (engines_with_discover)
|
||||||
|
hton= &dummy;
|
||||||
|
|
||||||
|
TABLE_SHARE *share= tdc_lock_share(db, table_name);
|
||||||
|
if (share)
|
||||||
|
{
|
||||||
|
if (hton)
|
||||||
|
*hton= share->db_type();
|
||||||
|
tdc_unlock_share(share);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
char path[FN_REFLEN + 1];
|
||||||
|
size_t path_len = build_table_filename(path, sizeof(path) - 1,
|
||||||
|
db, table_name, "", 0);
|
||||||
|
st_discover_existence_args args= {path, path_len, db, table_name, 0, true};
|
||||||
|
|
||||||
|
if (file_ext_exists(path, path_len, reg_ext))
|
||||||
|
{
|
||||||
|
bool exists= true;
|
||||||
|
if (hton)
|
||||||
|
{
|
||||||
|
enum legacy_db_type db_type;
|
||||||
|
if (dd_frm_type(thd, path, &db_type) != FRMTYPE_VIEW)
|
||||||
|
{
|
||||||
|
handlerton *ht= ha_resolve_by_legacy_type(thd, db_type);
|
||||||
|
if ((*hton= ht))
|
||||||
|
// verify that the table really exists
|
||||||
|
exists= discover_existence(thd,
|
||||||
|
plugin_int_to_ref(hton2plugin[ht->slot]), &args);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*hton= view_pseudo_hton;
|
||||||
|
}
|
||||||
|
DBUG_RETURN(exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
args.frm_exists= false;
|
||||||
|
if (plugin_foreach(thd, discover_existence, MYSQL_STORAGE_ENGINE_PLUGIN,
|
||||||
|
&args))
|
||||||
|
{
|
||||||
|
if (hton)
|
||||||
|
*hton= args.hton;
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (need_full_discover_for_existence)
|
if (need_full_discover_for_existence)
|
||||||
{
|
{
|
||||||
|
|
@ -4909,42 +4979,6 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
||||||
DBUG_RETURN(!no_such_table_handler.safely_trapped_errors());
|
DBUG_RETURN(!no_such_table_handler.safely_trapped_errors());
|
||||||
}
|
}
|
||||||
|
|
||||||
TABLE_SHARE *share= tdc_lock_share(db, table_name);
|
|
||||||
if (share)
|
|
||||||
{
|
|
||||||
if (hton)
|
|
||||||
*hton= share->db_type();
|
|
||||||
tdc_unlock_share(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))
|
|
||||||
{
|
|
||||||
if (hton)
|
|
||||||
{
|
|
||||||
enum legacy_db_type db_type;
|
|
||||||
if (dd_frm_type(thd, path, &db_type) != FRMTYPE_VIEW)
|
|
||||||
*hton= ha_resolve_by_legacy_type(thd, db_type);
|
|
||||||
else
|
|
||||||
*hton= view_pseudo_hton;
|
|
||||||
}
|
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
st_discover_existence_args args= {path, path_len, db, table_name, 0};
|
|
||||||
|
|
||||||
if (plugin_foreach(thd, discover_existence, MYSQL_STORAGE_ENGINE_PLUGIN,
|
|
||||||
&args))
|
|
||||||
{
|
|
||||||
if (hton)
|
|
||||||
*hton= args.hton;
|
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2389,7 +2389,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||||
This handles the case where a "DROP" was executed and a regular
|
This handles the case where a "DROP" was executed and a regular
|
||||||
table "may be" dropped as drop_temporary is FALSE and error is
|
table "may be" dropped as drop_temporary is FALSE and error is
|
||||||
TRUE. If the error was FALSE a temporary table was dropped and
|
TRUE. If the error was FALSE a temporary table was dropped and
|
||||||
regardless of the status of drop_tempoary a "DROP TEMPORARY"
|
regardless of the status of drop_temporary a "DROP TEMPORARY"
|
||||||
must be used.
|
must be used.
|
||||||
*/
|
*/
|
||||||
if (!dont_log_query)
|
if (!dont_log_query)
|
||||||
|
|
@ -2417,15 +2417,15 @@ 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 || !ha_table_exists(thd, db, alias, &table_type) ||
|
if (drop_temporary ||
|
||||||
(!drop_view && (was_view= (table_type == view_pseudo_hton)))))
|
(ha_table_exists(thd, db, alias, &table_type) == 0 && table_type == 0) ||
|
||||||
|
(!drop_view && (was_view= (table_type == view_pseudo_hton))))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
One of the following cases happened:
|
One of the following cases happened:
|
||||||
. "DROP TEMPORARY" but a temporary table was not found.
|
. "DROP TEMPORARY" but a temporary table was not found.
|
||||||
. "DROP" but table was not found on disk and table can't be
|
. "DROP" but table was not found
|
||||||
created from engine.
|
. "DROP TABLE" statement, but it's a view.
|
||||||
. ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
|
|
||||||
*/
|
*/
|
||||||
if (if_exists)
|
if (if_exists)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
--- suite/archive/discover.result 2013-04-08 00:06:37.000000000 +0200
|
|
||||||
+++ /usr/home/serg/Abk/mysql/10.0-serg/storage/test_sql_discovery/mysql-test/archive/discover.reject 2013-04-08 00:07:02.000000000 +0200
|
|
||||||
@@ -42,6 +42,7 @@
|
|
||||||
t1 BASE TABLE
|
|
||||||
t2 BASE TABLE
|
|
||||||
t1.ARZ
|
|
||||||
+t1.frm
|
|
||||||
t2.ARZ
|
|
||||||
t2.frm
|
|
||||||
#
|
|
||||||
@@ -60,6 +61,7 @@
|
|
||||||
flush tables;
|
|
||||||
rename table t2 to t0;
|
|
||||||
t0.ARZ
|
|
||||||
+t0.frm
|
|
||||||
t1.ARZ
|
|
||||||
t1.frm
|
|
||||||
#
|
|
||||||
@@ -77,6 +79,7 @@
|
|
||||||
flush tables;
|
|
||||||
drop table t1;
|
|
||||||
t0.ARZ
|
|
||||||
+t0.frm
|
|
||||||
#
|
|
||||||
# discover of table non-existance on drop
|
|
||||||
#
|
|
||||||
@@ -86,7 +89,7 @@
|
|
||||||
drop table t0;
|
|
||||||
show status like 'Handler_discover';
|
|
||||||
Variable_name Value
|
|
||||||
-Handler_discover 6
|
|
||||||
+Handler_discover 7
|
|
||||||
#
|
|
||||||
# Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE
|
|
||||||
#
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
--- r/plugin.result 2013-02-21 19:46:59.000000000 +0100
|
|
||||||
+++ r/plugin.reject 2013-02-27 11:13:22.000000000 +0100
|
|
||||||
@@ -71,6 +71,8 @@
|
|
||||||
SELECT * FROM t2;
|
|
||||||
ERROR 42000: Unknown storage engine 'EXAMPLE'
|
|
||||||
DROP TABLE t2;
|
|
||||||
+Warnings:
|
|
||||||
+Error 1286 Unknown storage engine 'EXAMPLE'
|
|
||||||
UNINSTALL PLUGIN EXAMPLE;
|
|
||||||
ERROR 42000: PLUGIN EXAMPLE does not exist
|
|
||||||
UNINSTALL PLUGIN non_exist;
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue