Commit e5a323e1 authored by Sergei Golubchik's avatar Sergei Golubchik

single table discovery: handlerton::discover_table() method.

fixes for need_full_discover_for_existence mode
parent f532653c
...@@ -29,7 +29,9 @@ ALTER TABLE t1 ANALYZE PARTITION ALL; ...@@ -29,7 +29,9 @@ ALTER TABLE t1 ANALYZE PARTITION ALL;
ALTER TABLE t1 REBUILD PARTITION ALL; ALTER TABLE t1 REBUILD PARTITION ALL;
ALTER TABLE t1 ENGINE Memory; ALTER TABLE t1 ENGINE Memory;
ALTER TABLE t1 ADD (new INT); ALTER TABLE t1 ADD (new INT);
--disable_warnings
DROP TABLE t1; DROP TABLE t1;
--enable_warnings
--error ER_OPTION_PREVENTS_STATEMENT --error ER_OPTION_PREVENTS_STATEMENT
CREATE TABLE t1 ( CREATE TABLE t1 (
......
...@@ -429,7 +429,9 @@ system echo "this is a junk file for test" >> $MYSQLD_DATADIR/test/t1.frm ; ...@@ -429,7 +429,9 @@ system echo "this is a junk file for test" >> $MYSQLD_DATADIR/test/t1.frm ;
SHOW TABLE STATUS like 't1'; SHOW TABLE STATUS like 't1';
--error ER_NOT_FORM_FILE --error ER_NOT_FORM_FILE
show create table t1; show create table t1;
--disable_warnings
drop table if exists t1; drop table if exists t1;
--enable_warnings
--error 1,0 --error 1,0
--remove_file $MYSQLD_DATADIR/test/t1.frm --remove_file $MYSQLD_DATADIR/test/t1.frm
......
...@@ -491,11 +491,11 @@ int ha_initialize_handlerton(st_plugin_int *plugin) ...@@ -491,11 +491,11 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
// if the enfine can discover a single table and it is file-based // if the enfine can discover a single table and it is file-based
// then it can use a default file-based table names discovery // then it can use a default file-based table names discovery
if (!hton->discover_table_names && if (!hton->discover_table_names &&
hton->discover && hton->tablefile_extensions[0]) hton->discover_table && 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 // default discover_table_existence implementation
if (!hton->discover_table_existence && hton->discover) if (!hton->discover_table_existence && hton->discover_table)
{ {
if (hton->tablefile_extensions[0]) if (hton->tablefile_extensions[0])
hton->discover_table_existence= ext_based_existence; hton->discover_table_existence= ext_based_existence;
...@@ -4279,56 +4279,44 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, ...@@ -4279,56 +4279,44 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
} }
/**
Try to discover one table from handler(s).
@retval
-1 Table did not exists
@retval
0 OK. In this case *frmblob and *frmlen are set
@retval
>0 error. frmblob and frmlen may not be set
*/
struct st_discover_args
{
const char *db;
const char *name;
uchar **frmblob;
size_t *frmlen;
};
static my_bool discover_handlerton(THD *thd, plugin_ref plugin, static my_bool discover_handlerton(THD *thd, plugin_ref plugin,
void *arg) void *arg)
{ {
st_discover_args *vargs= (st_discover_args *)arg; TABLE_SHARE *share= (TABLE_SHARE *)arg;
handlerton *hton= plugin_data(plugin, handlerton *); handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->discover && if (hton->state == SHOW_OPTION_YES && hton->discover_table)
(!(hton->discover(hton, thd, vargs->db, vargs->name, {
vargs->frmblob, int error= hton->discover_table(hton, thd, share);
vargs->frmlen)))) if (error != HA_ERR_NO_SUCH_TABLE)
return TRUE; {
if (error)
{
DBUG_ASSERT(share->error); // MUST be always set for get_cached_table_share to work
my_error(ER_GET_ERRNO, MYF(0), error);
}
else
share->error= OPEN_FRM_OK;
return FALSE; status_var_increment(thd->status_var.ha_discover_count);
return TRUE; // abort the search
}
}
DBUG_ASSERT(share->error == OPEN_FRM_OPEN_ERROR);
return FALSE; // continue with the next engine
} }
int ha_discover(THD *thd, const char *db, const char *name, int ha_discover_table(THD *thd, TABLE_SHARE *share)
uchar **frmblob, size_t *frmlen)
{ {
int error= -1; // Table does not exist in any handler DBUG_ENTER("ha_discover_table");
DBUG_ENTER("ha_discover");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
st_discover_args args= {db, name, frmblob, frmlen};
if (is_prefix(name,tmp_file_prefix)) /* skip temporary tables */ DBUG_ASSERT(share->error == OPEN_FRM_OPEN_ERROR); // share is not OK yet
DBUG_RETURN(error);
if (plugin_foreach(thd, discover_handlerton, if (!plugin_foreach(thd, discover_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &args)) MYSQL_STORAGE_ENGINE_PLUGIN, share))
error= 0; open_table_error(share, OPEN_FRM_OPEN_ERROR, ENOENT); // not found
if (!error) DBUG_RETURN(share->error != OPEN_FRM_OK);
status_var_increment(thd->status_var.ha_discover_count);
DBUG_RETURN(error);
} }
/** /**
...@@ -4363,6 +4351,45 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin, ...@@ -4363,6 +4351,45 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin,
return ht->discover_table_existence(ht, args->db, args->table_name); return ht->discover_table_existence(ht, args->db, args->table_name);
} }
class Table_exists_error_handler : public Internal_error_handler
{
public:
Table_exists_error_handler()
: m_handled_errors(0), m_unhandled_errors(0)
{}
bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg,
MYSQL_ERROR ** cond_hdl)
{
*cond_hdl= NULL;
if (sql_errno == ER_NO_SUCH_TABLE ||
sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE ||
sql_errno == ER_WRONG_OBJECT ||
sql_errno == ER_OPTION_PREVENTS_STATEMENT) // partition_disabled.test
{
m_handled_errors++;
return TRUE;
}
if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
m_unhandled_errors++;
return FALSE;
}
bool safely_trapped_errors()
{
return ((m_handled_errors > 0) && (m_unhandled_errors == 0));
}
private:
int m_handled_errors;
int m_unhandled_errors;
};
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)
{ {
DBUG_ENTER("ha_discover_table_existence"); DBUG_ENTER("ha_discover_table_existence");
...@@ -4371,10 +4398,13 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name) ...@@ -4371,10 +4398,13 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name)
{ {
TABLE_LIST table; TABLE_LIST table;
DBUG_ASSERT(0); Table_exists_error_handler no_such_table_handler;
TABLE_SHARE *share= get_table_share(thd, db, table_name, thd->push_internal_handler(&no_such_table_handler);
GTS_TABLE | GTS_NOLOCK); get_table_share(thd, db, table_name, GTS_TABLE | GTS_VIEW | GTS_NOLOCK);
DBUG_RETURN(share != 0); thd->pop_internal_handler();
// the table doesn't exist if we've caught ER_NO_SUCH_TABLE and nothing else
DBUG_RETURN(!no_such_table_handler.safely_trapped_errors());
} }
mysql_mutex_lock(&LOCK_open); mysql_mutex_lock(&LOCK_open);
......
...@@ -1075,10 +1075,6 @@ struct handlerton ...@@ -1075,10 +1075,6 @@ struct handlerton
enum handler_create_iterator_result enum handler_create_iterator_result
(*create_iterator)(handlerton *hton, enum handler_iterator_type type, (*create_iterator)(handlerton *hton, enum handler_iterator_type type,
struct handler_iterator *fill_this_in); struct handler_iterator *fill_this_in);
int (*discover)(handlerton *hton, THD* thd, const char *db,
const char *name,
uchar **frmblob,
size_t *frmlen);
/* /*
Optional clauses in the CREATE/ALTER TABLE Optional clauses in the CREATE/ALTER TABLE
*/ */
...@@ -1110,6 +1106,20 @@ struct handlerton ...@@ -1110,6 +1106,20 @@ struct handlerton
engine, without user issuing an explicit CREATE TABLE statement. engine, without user issuing an explicit CREATE TABLE statement.
**********************************************************************/ **********************************************************************/
/*
This method is required for any engine that supports automatic table
discovery, there is no default implementation.
Given a TABLE_SHARE discover_table() fills it in with a correct table
structure using one of the TABLE_SHARE::init_from_* methods.
Returns HA_ERR_NO_SUCH_TABLE if the table did not exist in the engine,
zero if the table was discovered successfully, or any other
HA_ERR_* error code as appropriate if the table existed, but the
discovery failed.
*/
int (*discover_table)(handlerton *hton, THD* thd, TABLE_SHARE *share);
/* /*
The discover_table_names method tells the server The discover_table_names method tells the server
about all tables in the specified database that the engine about all tables in the specified database that the engine
...@@ -1157,6 +1167,7 @@ struct handlerton ...@@ -1157,6 +1167,7 @@ struct handlerton
*/ */
int (*discover_table_existence)(handlerton *hton, const char *db, int (*discover_table_existence)(handlerton *hton, const char *db,
const char *table_name); const char *table_name);
}; };
...@@ -3088,8 +3099,7 @@ int ha_delete_table(THD *thd, handlerton *db_type, const char *path, ...@@ -3088,8 +3099,7 @@ int ha_delete_table(THD *thd, handlerton *db_type, const char *path,
bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat); bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat);
/* discovery */ /* discovery */
int ha_discover(THD* thd, const char* dbname, const char* name, int ha_discover_table(THD *thd, TABLE_SHARE *share);
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); bool ha_table_exists(THD *thd, const char *db, const char *table_name);
......
...@@ -585,24 +585,15 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name, ...@@ -585,24 +585,15 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
char *key, uint key_length, uint flags, char *key, uint key_length, uint flags,
my_hash_value_type hash_value) my_hash_value_type hash_value)
{ {
bool open_failed;
TABLE_SHARE *share; TABLE_SHARE *share;
DBUG_ENTER("get_table_share"); DBUG_ENTER("get_table_share");
DBUG_ASSERT(!(flags & GTS_FORCE_DISCOVERY)); // FIXME not implemented
mysql_mutex_lock(&LOCK_open); mysql_mutex_lock(&LOCK_open);
/*
To be able perform any operation on table we should own
some kind of metadata lock on it.
*/
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
MDL_SHARED));
/* Read table definition from cache */ /* Read table definition from cache */
share= (TABLE_SHARE*) my_hash_search_using_hash_value(&table_def_cache, share= (TABLE_SHARE*) my_hash_search_using_hash_value(&table_def_cache,
hash_value, (uchar*) key, key_length); hash_value, (uchar*) key, key_length);
if (!share) if (!share)
{ {
if (!(share= alloc_table_share(db, table_name, key, key_length))) if (!(share= alloc_table_share(db, table_name, key, key_length)))
...@@ -633,12 +624,15 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name, ...@@ -633,12 +624,15 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
mysql_mutex_lock(&share->LOCK_ha_data); mysql_mutex_lock(&share->LOCK_ha_data);
mysql_mutex_unlock(&LOCK_open); mysql_mutex_unlock(&LOCK_open);
open_failed= open_table_def(thd, share, flags); if (flags & GTS_FORCE_DISCOVERY)
ha_discover_table(thd, share); // don't read the frm at all
else
open_table_def(thd, share, flags | GTS_FORCE_DISCOVERY); // frm or discover
mysql_mutex_unlock(&share->LOCK_ha_data); mysql_mutex_unlock(&share->LOCK_ha_data);
mysql_mutex_lock(&LOCK_open); mysql_mutex_lock(&LOCK_open);
if (open_failed) if (share->error)
{ {
share->ref_count--; share->ref_count--;
(void) my_hash_delete(&table_def_cache, (uchar*) share); (void) my_hash_delete(&table_def_cache, (uchar*) share);
...@@ -650,6 +644,9 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name, ...@@ -650,6 +644,9 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
goto end; goto end;
} }
/* cannot force discovery of a cached share */
DBUG_ASSERT(!(flags & GTS_FORCE_DISCOVERY));
/* make sure that open_table_def() for this share is not running */ /* make sure that open_table_def() for this share is not running */
mysql_mutex_lock(&share->LOCK_ha_data); mysql_mutex_lock(&share->LOCK_ha_data);
mysql_mutex_unlock(&share->LOCK_ha_data); mysql_mutex_unlock(&share->LOCK_ha_data);
...@@ -706,7 +703,7 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name, ...@@ -706,7 +703,7 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
end: end:
if (flags & GTS_NOLOCK) if (flags & GTS_NOLOCK)
{ {
share->ref_count--; release_table_share(share);
/* /*
if GTS_NOLOCK is requested, the returned share pointer cannot be used, if GTS_NOLOCK is requested, the returned share pointer cannot be used,
the share it points to may go away any moment. the share it points to may go away any moment.
...@@ -716,6 +713,15 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name, ...@@ -716,6 +713,15 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
*/ */
share= (TABLE_SHARE*) 1; share= (TABLE_SHARE*) 1;
} }
else
{
/*
To be able perform any operation on table we should own
some kind of metadata lock on it.
*/
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
MDL_SHARED));
}
mysql_mutex_unlock(&LOCK_open); mysql_mutex_unlock(&LOCK_open);
DBUG_RETURN(share); DBUG_RETURN(share);
......
...@@ -832,11 +832,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -832,11 +832,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
mysql_ha_rm_tables(thd, tables); mysql_ha_rm_tables(thd, tables);
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
{
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
false);
deleted_tables++; deleted_tables++;
}
thd->push_internal_handler(&err_handler); thd->push_internal_handler(&err_handler);
if (!thd->killed && if (!thd->killed &&
......
...@@ -1928,10 +1928,6 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, ...@@ -1928,10 +1928,6 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout, if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
MYSQL_OPEN_SKIP_TEMPORARY)) MYSQL_OPEN_SKIP_TEMPORARY))
DBUG_RETURN(true); DBUG_RETURN(true);
for (table= tables; table; table= table->next_local)
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
false);
} }
else else
{ {
...@@ -2222,23 +2218,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -2222,23 +2218,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{ {
non_temp_tables_count++; non_temp_tables_count++;
if (thd->locked_tables_mode)
{
if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED,
TDC_RT_REMOVE_NOT_OWN_AND_MARK_NOT_USABLE))
{
error= -1;
goto err;
}
close_all_tables_for_name(thd, table->table->s,
HA_EXTRA_PREPARE_FOR_DROP);
table->table= 0;
}
/* Check that we have an exclusive lock on the table to be dropped. */
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db, DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
table->table_name, table->table_name,
MDL_EXCLUSIVE)); MDL_SHARED));
alias= (lower_case_table_names == 2) ? table->alias : table->table_name; alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove .frm file and engine files */ /* remove .frm file and engine files */
...@@ -2307,6 +2289,28 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -2307,6 +2289,28 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
else else
{ {
char *end; char *end;
if (thd->locked_tables_mode)
{
if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED,
TDC_RT_REMOVE_NOT_OWN_AND_MARK_NOT_USABLE))
{
error= -1;
goto err;
}
close_all_tables_for_name(thd, table->table->s,
HA_EXTRA_PREPARE_FOR_DROP);
table->table= 0;
}
else
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
false);
/* Check that we have an exclusive lock on the table to be dropped. */
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
table->table_name,
MDL_EXCLUSIVE));
/* /*
Cannot use the db_type from the table, since that might have changed Cannot use the db_type from the table, since that might have changed
while waiting for the exclusive name lock. while waiting for the exclusive name lock.
...@@ -2372,6 +2376,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -2372,6 +2376,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
err: err:
if (wrong_tables.length()) if (wrong_tables.length())
{ {
thd->clear_error();
if (!foreign_key_error) if (!foreign_key_error)
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0), my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
wrong_tables.c_ptr_safe()); wrong_tables.c_ptr_safe());
......
...@@ -316,6 +316,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, ...@@ -316,6 +316,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
share->normalized_path.length= path_length; share->normalized_path.length= path_length;
share->table_category= get_table_category(& share->db, & share->table_name); share->table_category= get_table_category(& share->db, & share->table_name);
share->set_refresh_version(); share->set_refresh_version();
share->open_errno= ENOENT;
/* /*
Since alloc_table_share() can be called without any locking (for Since alloc_table_share() can be called without any locking (for
...@@ -570,24 +571,21 @@ inline bool is_system_table_name(const char *name, uint length) ...@@ -570,24 +571,21 @@ inline bool is_system_table_name(const char *name, uint length)
} }
/** /*
Check if a string contains path elements We don't try to open 5.0 unencoded name, if
*/ - non-encoded name contains '@' signs,
because '@' can be misinterpreted.
It is not clear if '@' is escape character in 5.1,
or a normal character in 5.0.
- non-encoded db or table name contain "#mysql50#" prefix.
This kind of tables must have been opened only by the
mysql_file_open() above.
*/
static bool has_disabled_path_chars(const char *str) static bool has_disabled_path_chars(const char *str)
{ {
for (; *str; str++) return strpbrk(str, "/\\~@.") != 0 ||
{ strncmp(str, STRING_WITH_LEN(MYSQL50_TABLE_NAME_PREFIX)) == 0;
switch (*str) {
case FN_EXTCHAR:
case '/':
case '\\':
case '~':
case '@':
return TRUE;
}
}
return FALSE;
} }
...@@ -626,50 +624,45 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags) ...@@ -626,50 +624,45 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
if ((file= mysql_file_open(key_file_frm, if ((file= mysql_file_open(key_file_frm,
path, O_RDONLY | O_SHARE, MYF(0))) < 0) path, O_RDONLY | O_SHARE, MYF(0))) < 0)
{ {
/* if (!has_disabled_path_chars(share->table_name.str) &&
We don't try to open 5.0 unencoded name, if !has_disabled_path_chars(share->db.str))
- non-encoded name contains '@' signs, {
because '@' can be misinterpreted. /* Try unencoded 5.0 name */
It is not clear if '@' is escape character in 5.1, uint length;
or a normal character in 5.0. strxnmov(path, sizeof(path)-1,
mysql_data_home, "/", share->db.str, "/",
- non-encoded db or table name contain "#mysql50#" prefix. share->table_name.str, reg_ext, NullS);
This kind of tables must have been opened only by the length= unpack_filename(path, path) - reg_ext_length;
mysql_file_open() above. /*
*/ The following is a safety test and should never fail
if (has_disabled_path_chars(share->table_name.str) || as the old file name should never be longer than the new one.
has_disabled_path_chars(share->db.str) || */
!strncmp(share->db.str, MYSQL50_TABLE_NAME_PREFIX, DBUG_ASSERT(length <= share->normalized_path.length);
MYSQL50_TABLE_NAME_PREFIX_LENGTH) || /*
!strncmp(share->table_name.str, MYSQL50_TABLE_NAME_PREFIX, If the old and the new names have the same length,
MYSQL50_TABLE_NAME_PREFIX_LENGTH)) then table name does not have tricky characters,
goto err_not_open; so no need to check the old file name.
*/
/* Try unencoded 5.0 name */ if (length != share->normalized_path.length &&
uint length; (file= mysql_file_open(key_file_frm,
strxnmov(path, sizeof(path)-1, path, O_RDONLY | O_SHARE, MYF(0))) >= 0)
mysql_data_home, "/", share->db.str, "/", {
share->table_name.str, reg_ext, NullS); /* Unencoded 5.0 table name found */
length= unpack_filename(path, path) - reg_ext_length; path[length]= '\0'; // Remove .frm extension
/* strmov(share->normalized_path.str, path);
The following is a safety test and should never fail share->normalized_path.length= length;
as the old file name should never be longer than the new one. }
*/ }
DBUG_ASSERT(length <= share->normalized_path.length); /* still no luck? try to discover the table */
/* if (file < 0)
If the old and the new names have the same length, {
then table name does not have tricky characters, if (flags & GTS_TABLE && flags & GTS_FORCE_DISCOVERY)
so no need to check the old file name. {
*/ ha_discover_table(thd, share);
if (length == share->normalized_path.length || error_given= true;
((file= mysql_file_open(key_file_frm, }
path, O_RDONLY | O_SHARE, MYF(0))) < 0))
goto err_not_open; goto err_not_open;
}
/* Unencoded 5.0 table name found */
path[length]= '\0'; // Remove .frm extension
strmov(share->normalized_path.str, path);
share->normalized_path.length= length;
} }
if (mysql_file_read(file, head, sizeof(head), MYF(MY_NABP))) if (mysql_file_read(file, head, sizeof(head), MYF(MY_NABP)))
......
...@@ -2450,8 +2450,8 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set, ...@@ -2450,8 +2450,8 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set,
enum get_table_share_flags { enum get_table_share_flags {
GTS_TABLE = 1, GTS_TABLE = 1,
GTS_VIEW = 2, GTS_VIEW = 2,
GTS_NOLOCK = 4, // don't increase share->ref_count GTS_NOLOCK = 4,
GTS_FORCE_DISCOVERY = 8 // don't use the .frm file GTS_FORCE_DISCOVERY = 8
}; };
size_t max_row_length(TABLE *table, const uchar *data); size_t max_row_length(TABLE *table, const uchar *data);
......
...@@ -855,7 +855,7 @@ int azclose (azio_stream *s) ...@@ -855,7 +855,7 @@ int azclose (azio_stream *s)
Though this was added to support MySQL's FRM file, anything can be Though this was added to support MySQL's FRM file, anything can be
stored in this location. stored in this location.
*/ */
int azwrite_frm(azio_stream *s, char *blob, unsigned int length) int azwrite_frm(azio_stream *s, uchar *blob, unsigned int length)
{ {
if (s->mode == 'r') if (s->mode == 'r')
return 1; return 1;
...@@ -867,7 +867,7 @@ int azwrite_frm(azio_stream *s, char *blob, unsigned int length) ...@@ -867,7 +867,7 @@ int azwrite_frm(azio_stream *s, char *blob, unsigned int length)
s->frm_length= length; s->frm_length= length;
s->start+= length; s->start+= length;
if (my_pwrite(s->file, (uchar*) blob, s->frm_length, if (my_pwrite(s->file, blob, s->frm_length,
s->frm_start_pos, MYF(MY_NABP)) || s->frm_start_pos, MYF(MY_NABP)) ||
write_header(s) || write_header(s) ||
(my_seek(s->file, 0, MY_SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)) (my_seek(s->file, 0, MY_SEEK_END, MYF(0)) == MY_FILEPOS_ERROR))
...@@ -876,9 +876,9 @@ int azwrite_frm(azio_stream *s, char *blob, unsigned int length) ...@@ -876,9 +876,9 @@ int azwrite_frm(azio_stream *s, char *blob, unsigned int length)
return 0; return 0;
} }
int azread_frm(azio_stream *s, char *blob) int azread_frm(azio_stream *s, uchar *blob)
{ {
return my_pread(s->file, (uchar*) blob, s->frm_length, return my_pread(s->file, blob, s->frm_length,
s->frm_start_pos, MYF(MY_NABP)) ? 1 : 0; s->frm_start_pos, MYF(MY_NABP)) ? 1 : 0;
} }
......
...@@ -331,8 +331,8 @@ extern int azclose(azio_stream *file); ...@@ -331,8 +331,8 @@ extern int azclose(azio_stream *file);
error number (see function gzerror below). error number (see function gzerror below).
*/ */
extern int azwrite_frm (azio_stream *s, char *blob, unsigned int length); extern int azwrite_frm (azio_stream *s, uchar *blob, unsigned int length);
extern int azread_frm (azio_stream *s, char *blob); extern int azread_frm (azio_stream *s, uchar *blob);
extern int azwrite_comment (azio_stream *s, char *blob, unsigned int length); extern int azwrite_comment (azio_stream *s, char *blob, unsigned int length);
extern int azread_comment (azio_stream *s, char *blob); extern int azread_comment (azio_stream *s, char *blob);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <myisam.h> // T_EXTEND #include <myisam.h> // T_EXTEND
#include "ha_archive.h" #include "ha_archive.h"
#include "discover.h"
#include <my_dir.h> #include <my_dir.h>
#include <mysql/plugin.h> #include <mysql/plugin.h>
...@@ -120,10 +121,7 @@ extern "C" PSI_file_key arch_key_file_data; ...@@ -120,10 +121,7 @@ extern "C" PSI_file_key arch_key_file_data;
static handler *archive_create_handler(handlerton *hton, static handler *archive_create_handler(handlerton *hton,
TABLE_SHARE *table, TABLE_SHARE *table,
MEM_ROOT *mem_root); MEM_ROOT *mem_root);
int archive_discover(handlerton *hton, THD* thd, const char *db, int archive_discover(handlerton *hton, THD* thd, TABLE_SHARE *share);
const char *name,
uchar **frmblob,
size_t *frmlen);
/* /*
Number of rows that will force a bulk insert. Number of rows that will force a bulk insert.
...@@ -220,7 +218,7 @@ int archive_db_init(void *p) ...@@ -220,7 +218,7 @@ int archive_db_init(void *p)
archive_hton->db_type= DB_TYPE_ARCHIVE_DB; archive_hton->db_type= DB_TYPE_ARCHIVE_DB;
archive_hton->create= archive_create_handler; archive_hton->create= archive_create_handler;
archive_hton->flags= HTON_NO_FLAGS; archive_hton->flags= HTON_NO_FLAGS;
archive_hton->discover= archive_discover; archive_hton->discover_table= archive_discover;
archive_hton->tablefile_extensions= ha_archive_exts; archive_hton->tablefile_extensions= ha_archive_exts;
if (mysql_mutex_init(az_key_mutex_archive_mutex, if (mysql_mutex_init(az_key_mutex_archive_mutex,
...@@ -270,19 +268,17 @@ ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg) ...@@ -270,19 +268,17 @@ ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg)
archive_reader_open= FALSE; archive_reader_open= FALSE;
} }
int archive_discover(handlerton *hton, THD* thd, const char *db, int archive_discover(handlerton *hton, THD* thd, TABLE_SHARE *share)
const char *name,
uchar **frmblob,
size_t *frmlen)
{ {
DBUG_ENTER("archive_discover"); DBUG_ENTER("archive_discover");
DBUG_PRINT("archive_discover", ("db: %s, name: %s", db, name)); DBUG_PRINT("archive_discover", ("db: '%s' name: '%s'", share->db.str,
share->table_name.str));
azio_stream frm_stream; azio_stream frm_stream;
char az_file[FN_REFLEN]; char az_file[FN_REFLEN];
char *frm_ptr; uchar *frm_ptr;
MY_STAT file_stat; MY_STAT file_stat;
build_table_filename(az_file, sizeof(az_file) - 1, db, name, ARZ, 0); strxmov(az_file, share->normalized_path.str, ARZ, NullS);
if (!(mysql_file_stat(/* arch_key_file_data */ 0, az_file, &file_stat, MYF(0)))) if (!(mysql_file_stat(/* arch_key_file_data */ 0, az_file, &file_stat, MYF(0))))
goto err; goto err;
...@@ -295,19 +291,23 @@ int archive_discover(handlerton *hton, THD* thd, const char *db, ...@@ -295,19 +291,23 @@ int archive_discover(handlerton *hton, THD* thd, const char *db,
} }
if (frm_stream.frm_length == 0) if (frm_stream.frm_length == 0)
goto err; DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
frm_ptr= (char *)my_malloc(sizeof(char) * frm_stream.frm_length, MYF(0)); frm_ptr= (uchar *)my_malloc(sizeof(char) * frm_stream.frm_length, MYF(0));
azread_frm(&frm_stream, frm_ptr); azread_frm(&frm_stream, frm_ptr);
azclose(&frm_stream); azclose(&frm_stream);
*frmlen= frm_stream.frm_length; // don't go through the discovery again
*frmblob= (uchar*) frm_ptr; if (writefrm(share->normalized_path.str, frm_ptr, frm_stream.frm_length))
DBUG_RETURN(my_errno);
share->init_from_binary_frm_image(thd, frm_ptr);
my_free(frm_ptr);
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
my_errno= 0; DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
DBUG_RETURN(1);
} }
/* /*
...@@ -650,9 +650,9 @@ int ha_archive::close(void) ...@@ -650,9 +650,9 @@ int ha_archive::close(void)
int ha_archive::frm_copy(azio_stream *src, azio_stream *dst) int ha_archive::frm_copy(azio_stream *src, azio_stream *dst)
{ {
int rc= 0; int rc= 0;
char *frm_ptr; uchar *frm_ptr;
if (!(frm_ptr= (char *) my_malloc(src->frm_length, MYF(0)))) if (!(frm_ptr= (uchar *) my_malloc(src->frm_length, MYF(0))))
return HA_ERR_OUT_OF_MEM; return HA_ERR_OUT_OF_MEM;
/* Write file offset is set to the end of the file. */ /* Write file offset is set to the end of the file. */
...@@ -758,7 +758,7 @@ int ha_archive::create(const char *name, TABLE *table_arg, ...@@ -758,7 +758,7 @@ int ha_archive::create(const char *name, TABLE *table_arg,
if (frm_ptr) if (frm_ptr)
{ {
mysql_file_read(frm_file, frm_ptr, (size_t)file_stat.st_size, MYF(0)); mysql_file_read(frm_file, frm_ptr, (size_t)file_stat.st_size, MYF(0));
azwrite_frm(&create_stream, (char *)frm_ptr, (size_t)file_stat.st_size); azwrite_frm(&create_stream, frm_ptr, (size_t)file_stat.st_size);
my_free(frm_ptr); my_free(frm_ptr);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment