mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
BUG#10365 Cluster handler uses non-standard error codes
- Added better error messages when trying to open a table that can't be discovered or unpacked. The most likely cause of this is that it does not have any frm data, probably since it has been created from NdbApi or is a NDB system table. - Separated functionality that was in ha_create_table_from_engine into two functions. One that checks if the table exists and another one that tries to create the table from the engine. mysql-test/r/ndb_autodiscover.result: Add tests for reading from a table that can't be discovered(SYSTAB_0) Discovery is not performed during create table anymore. mysql-test/t/ndb_autodiscover.test: Add tests for reading from a table that can't be discovered(SYSTAB_0) Discovery is not performed during create table anymore. ndb/test/ndbapi/create_tab.cpp: Set connectstring before creating Ndb object. sql/ha_ndbcluster.cc: Rename and use the function ndbcluster_table_exists_in_engine. Correct return valu from ndbcluster_discover Remove old code "ndb_discover_tables" sql/ha_ndbcluster.h: Rename function ndbcluster_table_exists to ndb ndbcluster_table_exists_in_engine sql/handler.cc: Update comment of ha_create_table_from_engine Remove parameter create_if_found from ha_create_table_from_engine, the function ha_table_exists_in_engine is now used toi check if table is found in engine. Cleanup return codes from ha_create_table_from_engine. Change name of ha_table_exists to ha_table_exists_in_engine, update comment and returne codes. sql/handler.h: Remove paramter create_if_cound from ha_create_table_from_engine Rename ha_table_exists to ha_table_exists_in_engine sql/sql_base.cc: Use the function ha_table_exists_in_engine to detect if table exists in enegine. If it exists, call function ha_create_table_from_engine to try and create it. If create of table fails, set correct error message. sql/sql_table.cc: Add comments, remove parameter create_if_found to ha_create_table_from_engine. When dropping a table, try to discover it from engine. If discover fails, use same error message as if the table didn't exists. Maybe another message should be displayed here, ex: "Table could not be dropped, unpack failed" When creating a new table, use ha_table_exists_in_engine to check if a table with the given name already exists.
This commit is contained in:
parent
5f767b11e4
commit
09944efd71
9 changed files with 126 additions and 84 deletions
|
@ -93,7 +93,7 @@ name char(20), a int, b float, c char(24)
|
|||
ERROR 42S01: Table 't3' already exists
|
||||
show status like 'handler_discover%';
|
||||
Variable_name Value
|
||||
Handler_discover 1
|
||||
Handler_discover 0
|
||||
create table IF NOT EXISTS t3(
|
||||
id int not null primary key,
|
||||
id2 int not null,
|
||||
|
@ -101,7 +101,7 @@ name char(20)
|
|||
) engine=ndb;
|
||||
show status like 'handler_discover%';
|
||||
Variable_name Value
|
||||
Handler_discover 2
|
||||
Handler_discover 0
|
||||
SHOW CREATE TABLE t3;
|
||||
Table Create Table
|
||||
t3 CREATE TABLE `t3` (
|
||||
|
@ -114,7 +114,7 @@ id name
|
|||
1 Explorer
|
||||
show status like 'handler_discover%';
|
||||
Variable_name Value
|
||||
Handler_discover 2
|
||||
Handler_discover 1
|
||||
drop table t3;
|
||||
flush status;
|
||||
create table t7(
|
||||
|
@ -358,6 +358,20 @@ Database
|
|||
mysql
|
||||
test
|
||||
use test;
|
||||
CREATE TABLE sys.SYSTAB_0 (a int);
|
||||
ERROR 42S01: Table 'SYSTAB_0' already exists
|
||||
select * from sys.SYSTAB_0;
|
||||
ERROR HY000: Failed to open 'SYSTAB_0', error while unpacking from engine
|
||||
CREATE TABLE IF NOT EXISTS sys.SYSTAB_0 (a int);
|
||||
show warnings;
|
||||
Level Code Message
|
||||
select * from sys.SYSTAB_0;
|
||||
ERROR HY000: Failed to open 'SYSTAB_0', error while unpacking from engine
|
||||
drop table sys.SYSTAB_0;
|
||||
ERROR 42S02: Unknown table 'SYSTAB_0'
|
||||
drop table IF EXISTS sys.SYSTAB_0;
|
||||
Warnings:
|
||||
Note 1051 Unknown table 'SYSTAB_0'
|
||||
CREATE TABLE t9 (
|
||||
a int NOT NULL PRIMARY KEY,
|
||||
b int
|
||||
|
|
|
@ -453,6 +453,27 @@ drop database test2;
|
|||
show databases;
|
||||
use test;
|
||||
|
||||
#####################################################
|
||||
# Test that it's not possible to create tables
|
||||
# with same name as NDB internal tables
|
||||
# This will also test that it's not possible to create
|
||||
# a table with tha same name as a table that can't be
|
||||
# discovered( for example a table created via NDBAPI)
|
||||
|
||||
--error 1050
|
||||
CREATE TABLE sys.SYSTAB_0 (a int);
|
||||
--error 1105
|
||||
select * from sys.SYSTAB_0;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys.SYSTAB_0 (a int);
|
||||
show warnings;
|
||||
--error 1105
|
||||
select * from sys.SYSTAB_0;
|
||||
|
||||
--error 1051
|
||||
drop table sys.SYSTAB_0;
|
||||
drop table IF EXISTS sys.SYSTAB_0;
|
||||
|
||||
######################################################
|
||||
# Note! This should always be the last step in this
|
||||
# file, the table t9 will be used and dropped
|
||||
|
|
|
@ -77,8 +77,8 @@ int main(int argc, const char** argv){
|
|||
*/
|
||||
|
||||
// Connect to Ndb
|
||||
Ndb::setConnectString(_connectstr);
|
||||
Ndb MyNdb( "TEST_DB" );
|
||||
MyNdb.setConnectString(_connectstr);
|
||||
|
||||
if(MyNdb.init() != 0){
|
||||
ERR(MyNdb.getNdbError());
|
||||
|
|
|
@ -4308,13 +4308,15 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
|
|||
len= tab->getFrmLength();
|
||||
if (len == 0 || tab->getFrmData() == NULL)
|
||||
{
|
||||
DBUG_PRINT("No frm data found",
|
||||
("Table is probably created via NdbApi"));
|
||||
DBUG_RETURN(2);
|
||||
DBUG_PRINT("error", ("No frm data found."));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (unpackfrm(&data, &len, tab->getFrmData()))
|
||||
DBUG_RETURN(3);
|
||||
{
|
||||
DBUG_PRINT("error", ("Could not unpack table"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
*frmlen= len;
|
||||
*frmblob= data;
|
||||
|
@ -4327,13 +4329,13 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
|
|||
|
||||
*/
|
||||
|
||||
int ndbcluster_table_exists(THD* thd, const char *db, const char *name)
|
||||
int ndbcluster_table_exists_in_engine(THD* thd, const char *db, const char *name)
|
||||
{
|
||||
uint len;
|
||||
const void* data;
|
||||
const NDBTAB* tab;
|
||||
Ndb* ndb;
|
||||
DBUG_ENTER("ndbcluster_table_exists");
|
||||
DBUG_ENTER("ndbcluster_table_exists_in_engine");
|
||||
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
|
||||
|
||||
if (!(ndb= check_ndb_in_thd(thd)))
|
||||
|
@ -4512,7 +4514,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
|
|||
DBUG_PRINT("info", ("%s existed on disk", name));
|
||||
// The .ndb file exists on disk, but it's not in list of tables in ndb
|
||||
// Verify that handler agrees table is gone.
|
||||
if (ndbcluster_table_exists(thd, db, file_name) == 0)
|
||||
if (ndbcluster_table_exists_in_engine(thd, db, file_name) == 0)
|
||||
{
|
||||
DBUG_PRINT("info", ("NDB says %s does not exists", file_name));
|
||||
it.remove();
|
||||
|
@ -4563,7 +4565,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
|
|||
while ((file_name=it2++))
|
||||
{
|
||||
DBUG_PRINT("info", ("Table %s need discovery", name));
|
||||
if (ha_create_table_from_engine(thd, db, file_name, TRUE) == 0)
|
||||
if (ha_create_table_from_engine(thd, db, file_name) == 0)
|
||||
files->push_back(thd->strdup(file_name));
|
||||
}
|
||||
|
||||
|
@ -4639,11 +4641,8 @@ bool ndbcluster_init()
|
|||
pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
|
||||
|
||||
ndbcluster_inited= 1;
|
||||
#ifdef USE_DISCOVER_ON_STARTUP
|
||||
if (ndb_discover_tables() != 0)
|
||||
goto ndbcluster_init_error;
|
||||
#endif
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
ndbcluster_init_error:
|
||||
ndbcluster_end();
|
||||
DBUG_RETURN(TRUE);
|
||||
|
|
|
@ -275,7 +275,8 @@ int ndbcluster_discover(THD* thd, const char* dbname, const char* name,
|
|||
const void** frmblob, uint* frmlen);
|
||||
int ndbcluster_find_files(THD *thd,const char *db,const char *path,
|
||||
const char *wild, bool dir, List<char> *files);
|
||||
int ndbcluster_table_exists(THD* thd, const char *db, const char *name);
|
||||
int ndbcluster_table_exists_in_engine(THD* thd,
|
||||
const char *db, const char *name);
|
||||
int ndbcluster_drop_database(const char* path);
|
||||
|
||||
void ndbcluster_print_error(int error, const NdbOperation *error_op);
|
||||
|
|
101
sql/handler.cc
101
sql/handler.cc
|
@ -1336,21 +1336,18 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
|
|||
}
|
||||
|
||||
/*
|
||||
Try to discover table from engine and
|
||||
Try to discover table from engine and
|
||||
if found, write the frm file to disk.
|
||||
|
||||
|
||||
RETURN VALUES:
|
||||
0 : Table existed in engine and created
|
||||
on disk if so requested
|
||||
1 : Table does not exist
|
||||
>1 : error
|
||||
0 : Table created ok
|
||||
1 : Table could not be created
|
||||
|
||||
*/
|
||||
|
||||
int ha_create_table_from_engine(THD* thd,
|
||||
const char *db,
|
||||
const char *name,
|
||||
bool create_if_found)
|
||||
int ha_create_table_from_engine(THD* thd,
|
||||
const char *db,
|
||||
const char *name)
|
||||
{
|
||||
int error;
|
||||
const void *frmblob;
|
||||
|
@ -1359,45 +1356,47 @@ int ha_create_table_from_engine(THD* thd,
|
|||
HA_CREATE_INFO create_info;
|
||||
TABLE table;
|
||||
DBUG_ENTER("ha_create_table_from_engine");
|
||||
DBUG_PRINT("enter", ("name '%s'.'%s' create_if_found: %d",
|
||||
db, name, create_if_found));
|
||||
DBUG_PRINT("enter", ("name '%s'.'%s'",
|
||||
db, name));
|
||||
|
||||
bzero((char*) &create_info,sizeof(create_info));
|
||||
|
||||
if ((error= ha_discover(thd, db, name, &frmblob, &frmlen)))
|
||||
DBUG_RETURN(error);
|
||||
/*
|
||||
Table exists in handler
|
||||
frmblob and frmlen are set
|
||||
*/
|
||||
|
||||
if (create_if_found)
|
||||
if(ha_discover(thd, db, name, &frmblob, &frmlen))
|
||||
{
|
||||
(void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS);
|
||||
// Save the frm file
|
||||
if ((error = writefrm(path, frmblob, frmlen)))
|
||||
goto err_end;
|
||||
|
||||
if (openfrm(path,"",0,(uint) READ_ALL, 0, &table))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
update_create_info_from_table(&create_info, &table);
|
||||
create_info.table_options|= HA_CREATE_FROM_ENGINE;
|
||||
|
||||
if (lower_case_table_names == 2 &&
|
||||
!(table.file->table_flags() & HA_FILE_BASED))
|
||||
{
|
||||
/* Ensure that handler gets name in lower case */
|
||||
my_casedn_str(files_charset_info, path);
|
||||
}
|
||||
|
||||
error=table.file->create(path,&table,&create_info);
|
||||
VOID(closefrm(&table));
|
||||
// Table could not be discovered and thus not created
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
err_end:
|
||||
/*
|
||||
Table exists in handler and could be discovered
|
||||
frmblob and frmlen are set, write the frm to disk
|
||||
*/
|
||||
|
||||
(void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS);
|
||||
// Save the frm file
|
||||
if (writefrm(path, frmblob, frmlen))
|
||||
{
|
||||
my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (openfrm(path,"",0,(uint) READ_ALL, 0, &table))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
update_create_info_from_table(&create_info, &table);
|
||||
create_info.table_options|= HA_CREATE_FROM_ENGINE;
|
||||
|
||||
if (lower_case_table_names == 2 &&
|
||||
!(table.file->table_flags() & HA_FILE_BASED))
|
||||
{
|
||||
/* Ensure that handler gets name in lower case */
|
||||
my_casedn_str(files_charset_info, path);
|
||||
}
|
||||
error=table.file->create(path,&table,&create_info);
|
||||
VOID(closefrm(&table));
|
||||
my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR));
|
||||
DBUG_RETURN(error);
|
||||
|
||||
DBUG_RETURN(error != 0);
|
||||
}
|
||||
|
||||
static int NEAR_F delete_file(const char *name,const char *ext,int extflag)
|
||||
|
@ -1507,8 +1506,8 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
|
|||
Try to discover one table from handler(s)
|
||||
|
||||
RETURN
|
||||
0 ok. In this case *frmblob and *frmlen are set
|
||||
1 error. frmblob and frmlen may not be set
|
||||
0 ok. In this case *frmblob and *frmlen are set
|
||||
>=1 error. frmblob and frmlen may not be set
|
||||
*/
|
||||
|
||||
int ha_discover(THD *thd, const char *db, const char *name,
|
||||
|
@ -1546,11 +1545,8 @@ ha_find_files(THD *thd,const char *db,const char *path,
|
|||
error= ndbcluster_find_files(thd, db, path, wild, dir, files);
|
||||
#endif
|
||||
DBUG_RETURN(error);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef NOT_YET_USED
|
||||
|
||||
/*
|
||||
Ask handler if the table exists in engine
|
||||
|
@ -1561,20 +1557,19 @@ ha_find_files(THD *thd,const char *db,const char *path,
|
|||
# Error code
|
||||
|
||||
*/
|
||||
int ha_table_exists(THD* thd, const char* db, const char* name)
|
||||
int ha_table_exists_in_engine(THD* thd, const char* db, const char* name)
|
||||
{
|
||||
int error= 2;
|
||||
DBUG_ENTER("ha_table_exists");
|
||||
int error= 0;
|
||||
DBUG_ENTER("ha_table_exists_in_engine");
|
||||
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
|
||||
#ifdef HAVE_NDBCLUSTER_DB
|
||||
if (have_ndbcluster == SHOW_OPTION_YES)
|
||||
error= ndbcluster_table_exists(thd, db, name);
|
||||
error= ndbcluster_table_exists_in_engine(thd, db, name);
|
||||
#endif
|
||||
DBUG_PRINT("exit", ("error: %d", error));
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Read first row between two ranges.
|
||||
|
|
|
@ -547,8 +547,7 @@ enum db_type ha_checktype(enum db_type database_type);
|
|||
my_bool ha_storage_engine_is_enabled(enum db_type database_type);
|
||||
int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
|
||||
bool update_create_info);
|
||||
int ha_create_table_from_engine(THD* thd, const char *db, const char *name,
|
||||
bool create_if_found);
|
||||
int ha_create_table_from_engine(THD* thd, const char *db, const char *name);
|
||||
int ha_delete_table(enum db_type db_type, const char *path);
|
||||
void ha_drop_database(char* path);
|
||||
int ha_init_key_cache(const char *name, KEY_CACHE *key_cache);
|
||||
|
@ -574,6 +573,6 @@ int ha_discover(THD* thd, const char* dbname, const char* name,
|
|||
const void** frmblob, uint* frmlen);
|
||||
int ha_find_files(THD *thd,const char *db,const char *path,
|
||||
const char *wild, bool dir,List<char>* files);
|
||||
int ha_table_exists(THD* thd, const char* db, const char* name);
|
||||
int ha_table_exists_in_engine(THD* thd, const char* db, const char* name);
|
||||
TYPELIB *ha_known_exts(void);
|
||||
int ha_start_consistent_snapshot(THD *thd);
|
||||
|
|
|
@ -1375,9 +1375,20 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
|
|||
trying to discover the table at the same time.
|
||||
*/
|
||||
if (discover_retry_count++ != 0)
|
||||
goto err;
|
||||
if (ha_create_table_from_engine(thd, db, name, TRUE) != 0)
|
||||
goto err;
|
||||
goto err;
|
||||
if (ha_table_exists_in_engine(thd, db, name) &&
|
||||
ha_create_table_from_engine(thd, db, name))
|
||||
{
|
||||
/* Give right error message */
|
||||
thd->clear_error();
|
||||
DBUG_PRINT("error", ("Dicovery of %s/%s failed", db, name));
|
||||
my_printf_error(ER_UNKNOWN_ERROR,
|
||||
"Failed to open '%-.64s', error while "
|
||||
"unpacking from engine",
|
||||
MYF(0), name);
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
thd->clear_error(); // Clear error message
|
||||
continue;
|
||||
|
|
|
@ -217,15 +217,18 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||
strxmov(path, mysql_data_home, "/", db, "/", alias, reg_ext, NullS);
|
||||
(void) unpack_filename(path,path);
|
||||
}
|
||||
if (drop_temporary ||
|
||||
(access(path,F_OK) && ha_create_table_from_engine(thd,db,alias,TRUE)))
|
||||
if (drop_temporary ||
|
||||
(access(path,F_OK) &&
|
||||
ha_create_table_from_engine(thd, db, alias)))
|
||||
{
|
||||
// Table was not found on disk and table can't be created from engine
|
||||
if (if_exists)
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
|
||||
table->real_name);
|
||||
else
|
||||
error= 1;
|
||||
error= 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1371,15 +1374,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
|||
{
|
||||
bool create_if_not_exists =
|
||||
create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
|
||||
if (!ha_create_table_from_engine(thd, db, table_name,
|
||||
create_if_not_exists))
|
||||
if (ha_table_exists_in_engine(thd, db, table_name))
|
||||
{
|
||||
DBUG_PRINT("info", ("Table already existed in handler"));
|
||||
DBUG_PRINT("info", ("Table with same name already existed in handler"));
|
||||
|
||||
if (create_if_not_exists)
|
||||
{
|
||||
create_info->table_existed= 1; // Mark that table existed
|
||||
error= 0;
|
||||
create_info->table_existed= 1; // Mark that table existed
|
||||
error= 0;
|
||||
}
|
||||
else
|
||||
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
|
||||
|
|
Loading…
Add table
Reference in a new issue