1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

10.0-base merge

This commit is contained in:
Sergei Golubchik
2013-04-15 15:09:22 +02:00
976 changed files with 38123 additions and 26781 deletions

View File

@@ -30,7 +30,7 @@
#include "sql_parse.h" // check_stack_overrun
#include "sql_acl.h" // SUPER_ACL
#include "sql_base.h" // free_io_cache
#include "discover.h" // writefrm
#include "discover.h" // extension_based_table_discovery, etc
#include "log_event.h" // *_rows_log_event
#include "create_options.h"
#include "rpl_filter.h"
@@ -229,13 +229,6 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
(void) RUN_HOOK(transaction, after_rollback, (thd, FALSE));
switch (database_type) {
case DB_TYPE_MRG_ISAM:
return ha_resolve_by_legacy_type(thd, DB_TYPE_MRG_MYISAM);
default:
break;
}
return ha_default_handlerton(thd);
} /* ha_checktype */
@@ -388,6 +381,34 @@ static int ha_finish_errors(void)
return 0;
}
static volatile int32 need_full_discover_for_existence= 0;
static volatile int32 engines_with_discover_table_names= 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; }
static int hton_ext_based_table_discovery(handlerton *hton, LEX_STRING *db,
MY_DIR *dir, handlerton::discovered_list *result)
{
/*
tablefile_extensions[0] is the metadata file, see
the comment above tablefile_extensions declaration
*/
return extension_based_table_discovery(dir, hton->tablefile_extensions[0],
result);
}
static void update_discovery_counters(handlerton *hton, int val)
{
if (hton->discover_table_existence == full_discover_for_existence)
my_atomic_add32(&need_full_discover_for_existence, val);
if (hton->discover_table_names)
my_atomic_add32(&engines_with_discover_table_names, val);
}
int ha_finalize_handlerton(st_plugin_int *plugin)
{
@@ -425,6 +446,9 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
}
}
free_sysvar_table_options(hton);
update_discovery_counters(hton, -1);
/*
In case a plugin is uninstalled and re-installed later, it should
reuse an array slot. Otherwise the number of uninstall/install
@@ -448,12 +472,12 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
int ha_initialize_handlerton(st_plugin_int *plugin)
{
handlerton *hton;
static const char *no_exts[]= { 0 };
DBUG_ENTER("ha_initialize_handlerton");
DBUG_PRINT("plugin", ("initialize plugin: '%s'", plugin->name.str));
hton= (handlerton *)my_malloc(sizeof(handlerton),
MYF(MY_WME | MY_ZEROFILL));
if (hton == NULL)
{
sql_print_error("Unable to allocate memory for plugin '%s' handlerton.",
@@ -461,6 +485,9 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
goto err_no_hton_memory;
}
hton->tablefile_extensions= no_exts;
hton->discover_table_names= hton_ext_based_table_discovery;
hton->slot= HA_SLOT_UNDEF;
/* Historical Requirement */
plugin->data= hton; // shortcut for the future
@@ -471,6 +498,21 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
goto err;
}
// hton_ext_based_table_discovery() works only when discovery
// is supported and the engine if file-based.
if (hton->discover_table_names == hton_ext_based_table_discovery &&
(!hton->discover_table || !hton->tablefile_extensions[0]))
hton->discover_table_names= NULL;
// default discover_table_existence implementation
if (!hton->discover_table_existence && hton->discover_table)
{
if (hton->tablefile_extensions[0])
hton->discover_table_existence= ext_based_existence;
else
hton->discover_table_existence= full_discover_for_existence;
}
/*
the switch below and hton->state should be removed when
command-line options for plugins will be implemented
@@ -560,6 +602,9 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
break;
};
resolve_sysvar_table_options(hton);
update_discovery_counters(hton, 1);
DBUG_RETURN(0);
err_deinit:
@@ -1096,7 +1141,8 @@ int ha_prepare(THD *thd)
else
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
ER_GET_ERRNO, ER(ER_GET_ERRNO),
HA_ERR_WRONG_COMMAND,
ha_resolve_storage_engine_name(ht));
}
}
@@ -1967,7 +2013,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
}
if ((err= ht->savepoint_set(ht, thd, (uchar *)(sv+1)+ht->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
my_error(ER_GET_ERRNO, MYF(0), err, hton_name(ht)->str);
error=1;
}
status_var_increment(thd->status_var.ha_savepoint_count);
@@ -1998,7 +2044,7 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
if ((err= ht->savepoint_release(ht, thd,
(uchar *)(sv+1) + ht->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
my_error(ER_GET_ERRNO, MYF(0), err, hton_name(ht)->str);
error=1;
}
}
@@ -2172,15 +2218,15 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
TABLE_SHARE dummy_share;
DBUG_ENTER("ha_delete_table");
/* table_type is NULL in ALTER TABLE when renaming only .frm files */
if (table_type == NULL || table_type == view_pseudo_hton ||
! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type)))
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
bzero((char*) &dummy_table, sizeof(dummy_table));
bzero((char*) &dummy_share, sizeof(dummy_share));
dummy_table.s= &dummy_share;
/* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
if (table_type == NULL ||
! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type)))
DBUG_RETURN(ENOENT);
path= get_canonical_filename(file, path, tmp_path);
if ((error= file->ha_delete_table(path)) && generate_warning)
{
@@ -2195,6 +2241,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
/* Fill up strucutures that print_error may need */
dummy_share.path.str= (char*) path;
dummy_share.path.length= strlen(path);
dummy_share.normalized_path= dummy_share.path;
dummy_share.db.str= (char*) db;
dummy_share.db.length= strlen(db);
dummy_share.table_name.str= (char*) alias;
@@ -3122,7 +3169,7 @@ void handler::print_error(int error, myf errflag)
DBUG_ENTER("handler::print_error");
DBUG_PRINT("enter",("error: %d",error));
int textno=ER_GET_ERRNO;
int textno= -1; // impossible value
switch (error) {
case EACCES:
textno=ER_OPEN_AS_READONLY;
@@ -3235,7 +3282,9 @@ void handler::print_error(int error, myf errflag)
textno=ER_OUT_OF_RESOURCES;
break;
case HA_ERR_WRONG_COMMAND:
textno=ER_ILLEGAL_HA;
my_error(ER_ILLEGAL_HA, MYF(0), table_type(), table_share->db.str,
table_share->table_name.str);
DBUG_VOID_RETURN;
break;
case HA_ERR_OLD_FILE:
textno=ER_OLD_KEYFILE;
@@ -3354,10 +3403,11 @@ void handler::print_error(int error, myf errflag)
}
}
else
my_error(ER_GET_ERRNO,errflag,error);
my_error(ER_GET_ERRNO, errflag, error, table_type());
DBUG_VOID_RETURN;
}
}
DBUG_ASSERT(textno > 0);
if (fatal_error)
{
/* Ensure this becomes a true error */
@@ -3371,7 +3421,17 @@ void handler::print_error(int error, myf errflag)
errflag|= ME_NOREFRESH;
}
}
my_error(textno, errflag, table_share->table_name.str, error);
/* if we got an OS error from a file-based engine, specify a path of error */
if (error < HA_ERR_FIRST && bas_ext()[0])
{
char buff[FN_REFLEN];
strxnmov(buff, sizeof(buff),
table_share->normalized_path.str, bas_ext()[0], NULL);
my_error(textno, errflag, buff, error);
}
else
my_error(textno, errflag, table_share->table_name.str, error);
DBUG_VOID_RETURN;
}
@@ -3573,9 +3633,14 @@ int handler::delete_table(const char *name)
{
int saved_error= 0;
int error= 0;
int enoent_or_zero= ENOENT; // Error if no file was deleted
int enoent_or_zero;
char buff[FN_REFLEN];
if (ht->discover_table)
enoent_or_zero= 0; // the table may not exist in the engine, it's ok
else
enoent_or_zero= ENOENT; // the first file of bas_ext() *must* exist
for (const char **ext=bas_ext(); *ext ; ext++)
{
fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT);
@@ -3959,16 +4024,16 @@ handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info)
/**
Create handler files for CREATE TABLE: public interface.
@sa handler::create_handler_files()
@sa handler::create_partitioning_metadata()
*/
int
handler::ha_create_handler_files(const char *name, const char *old_name,
int action_flag, HA_CREATE_INFO *info)
handler::ha_create_partitioning_metadata(const char *name, const char *old_name,
int action_flag)
{
mark_trx_read_write();
return create_handler_files(name, old_name, action_flag, info);
return create_partitioning_metadata(name, old_name, action_flag);
}
@@ -4256,154 +4321,69 @@ end:
*/
int ha_create_table(THD *thd, const char *path,
const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
bool update_create_info)
HA_CREATE_INFO *create_info, LEX_CUSTRING *frm)
{
int error= 1;
TABLE table;
char name_buff[FN_REFLEN];
const char *name;
TABLE_SHARE share;
bool temp_table __attribute__((unused)) = create_info->tmp_table() ||
is_prefix(table_name, tmp_file_prefix);
DBUG_ENTER("ha_create_table");
#ifdef HAVE_PSI_TABLE_INTERFACE
my_bool temp_table= (my_bool)is_prefix(table_name, tmp_file_prefix) ||
(create_info->options & HA_LEX_CREATE_TMP_TABLE ? TRUE : FALSE);
#endif
init_tmp_table_share(thd, &share, db, 0, table_name, path);
if (open_table_def(thd, &share, 0))
goto err;
if (frm)
{
bool write_frm_now= !create_info->db_type->discover_table &&
!create_info->tmp_table();
share.frm_image= frm;
// open an frm image
if (share.init_from_binary_frm_image(thd, write_frm_now,
frm->str, frm->length))
goto err;
}
else
{
// open an frm file
share.db_plugin= ha_lock_engine(thd, create_info->db_type);
if (open_table_def(thd, &share))
goto err;
}
#ifdef HAVE_PSI_TABLE_INTERFACE
share.m_psi= PSI_CALL(get_table_share)(temp_table, &share);
#endif
if (open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table,
TRUE))
if (open_table_from_share(thd, &share, "", 0, READ_ALL, 0, &table, true))
goto err;
if (update_create_info)
update_create_info_from_table(create_info, &table);
update_create_info_from_table(create_info, &table);
name= get_canonical_filename(table.file, share.path.str, name_buff);
error= table.file->ha_create(name, &table, create_info);
(void) closefrm(&table, 0);
if (error)
{
strxmov(name_buff, db, ".", table_name, NullS);
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
my_error(ER_CANT_CREATE_TABLE, MYF(0), db, table_name, error);
#ifdef HAVE_PSI_TABLE_INTERFACE
PSI_CALL(drop_table_share)(temp_table, db, strlen(db), table_name,
strlen(table_name));
PSI_CALL(drop_table_share)(temp_table, share.db.str, share.db.length,
share.table_name.str, share.table_name.length);
#endif
}
err:
free_table_share(&share);
DBUG_RETURN(error != 0);
}
/**
Try to discover table from engine.
@note
If found, write the frm file to disk.
@retval
-1 Table did not exists
@retval
0 Table created ok
@retval
> 0 Error, table existed but could not be created
*/
int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
{
int error;
uchar *frmblob;
size_t frmlen;
char path[FN_REFLEN + 1];
HA_CREATE_INFO create_info;
TABLE table;
TABLE_SHARE share;
DBUG_ENTER("ha_create_table_from_engine");
DBUG_PRINT("enter", ("name '%s'.'%s'", db, name));
bzero((uchar*) &create_info,sizeof(create_info));
if ((error= ha_discover(thd, db, name, &frmblob, &frmlen)))
{
/* Table could not be discovered and thus not created */
DBUG_RETURN(error);
}
/*
Table exists in handler and could be discovered
frmblob and frmlen are set, write the frm to disk
*/
build_table_filename(path, sizeof(path) - 1, db, name, "", 0);
// Save the frm file
error= writefrm(path, frmblob, frmlen);
my_free(frmblob);
if (error)
DBUG_RETURN(2);
init_tmp_table_share(thd, &share, db, 0, name, path);
if (open_table_def(thd, &share, 0))
{
DBUG_RETURN(3);
}
#ifdef HAVE_PSI_TABLE_INTERFACE
/*
Table discovery is not instrumented.
Once discovered, the table will be opened normally,
and instrumented normally.
*/
#endif
if (open_table_from_share(thd, &share, "" ,0, 0, 0, &table, FALSE))
{
free_table_share(&share);
DBUG_RETURN(3);
}
update_create_info_from_table(&create_info, &table);
create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE;
get_canonical_filename(table.file, path, path);
error=table.file->ha_create(path, &table, &create_info);
(void) closefrm(&table, 1);
DBUG_RETURN(error != 0);
}
/**
Try to find a table in a storage engine.
@param db Normalized table schema name
@param name Normalized table name.
@param[out] exists Only valid if the function succeeded.
@retval TRUE An error is found
@retval FALSE Success, check *exists
*/
bool
ha_check_if_table_exists(THD* thd, const char *db, const char *name,
bool *exists)
{
uchar *frmblob= NULL;
size_t frmlen;
DBUG_ENTER("ha_check_if_table_exists");
*exists= ! ha_discover(thd, db, name, &frmblob, &frmlen);
if (*exists)
my_free(frmblob);
DBUG_RETURN(FALSE);
}
void st_ha_check_opt::init()
{
flags= sql_flags= 0;
@@ -4526,149 +4506,348 @@ 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,
void *arg)
{
st_discover_args *vargs= (st_discover_args *)arg;
TABLE_SHARE *share= (TABLE_SHARE *)arg;
handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->discover &&
(!(hton->discover(hton, thd, vargs->db, vargs->name,
vargs->frmblob,
vargs->frmlen))))
return TRUE;
if (hton->state == SHOW_OPTION_YES && hton->discover_table)
{
share->db_plugin= plugin;
int error= hton->discover_table(hton, thd, share);
if (error != HA_ERR_NO_SUCH_TABLE)
{
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, plugin_name(plugin)->str);
share->db_plugin= 0;
}
else
share->error= OPEN_FRM_OK;
return FALSE;
status_var_increment(thd->status_var.ha_discover_count);
return TRUE; // abort the search
}
share->db_plugin= 0;
}
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,
uchar **frmblob, size_t *frmlen)
int ha_discover_table(THD *thd, TABLE_SHARE *share)
{
int error= -1; // Table does not exist in any handler
DBUG_ENTER("ha_discover");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
st_discover_args args= {db, name, frmblob, frmlen};
DBUG_ENTER("ha_discover_table");
int found;
if (is_prefix(name,tmp_file_prefix)) /* skip temporary tables */
DBUG_RETURN(error);
DBUG_ASSERT(share->error == OPEN_FRM_OPEN_ERROR); // share is not OK yet
if (plugin_foreach(thd, discover_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &args))
error= 0;
if (share->db_plugin)
found= discover_handlerton(thd, share->db_plugin, share);
else
found= plugin_foreach(thd, discover_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, share);
if (!found)
open_table_error(share, OPEN_FRM_OPEN_ERROR, ENOENT); // not found
if (!error)
status_var_increment(thd->status_var.ha_discover_count);
DBUG_RETURN(error);
DBUG_RETURN(share->error != OPEN_FRM_OK);
}
/**
Call this function in order to give the handler the possiblity
to ask engine if there are any new tables that should be written to disk
or any dropped tables that need to be removed from disk
*/
struct st_find_files_args
static my_bool file_ext_exists(char *path, size_t path_len, const char *ext)
{
const char *db;
const char *path;
const char *wild;
bool dir;
List<LEX_STRING> *files;
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;
handlerton *hton;
};
static my_bool find_files_handlerton(THD *thd, plugin_ref plugin,
void *arg)
static my_bool discover_existence(THD *thd, plugin_ref plugin,
void *arg)
{
st_find_files_args *vargs= (st_find_files_args *)arg;
handlerton *hton= plugin_data(plugin, handlerton *);
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;
args->hton= ht;
if (hton->state == SHOW_OPTION_YES && hton->find_files)
if (hton->find_files(hton, thd, vargs->db, vargs->path, vargs->wild,
vargs->dir, vargs->files))
return TRUE;
if (ht->discover_table_existence == ext_based_existence)
return file_ext_exists(args->path, args->path_len,
ht->tablefile_extensions[0]);
return FALSE;
return ht->discover_table_existence(ht, args->db, args->table_name);
}
int
ha_find_files(THD *thd,const char *db,const char *path,
const char *wild, bool dir, List<LEX_STRING> *files)
class Table_exists_error_handler : public Internal_error_handler
{
int error= 0;
DBUG_ENTER("ha_find_files");
DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d",
db, path, wild, dir));
st_find_files_args args= {db, path, wild, dir, files};
public:
Table_exists_error_handler()
: m_handled_errors(0), m_unhandled_errors(0)
{}
plugin_foreach(thd, find_files_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
/* The return value is not currently used */
DBUG_RETURN(error);
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)
{
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;
};
/**
Check if a given table exists, without doing a full discover, if possible
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.
@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)
*/
bool ha_table_exists(THD *thd, const char *db, const char *table_name,
handlerton **hton)
{
DBUG_ENTER("ha_table_exists");
if (hton)
*hton= 0;
if (need_full_discover_for_existence)
{
TABLE_LIST table;
uint flags = GTS_TABLE | GTS_VIEW;
if (!hton)
flags|= GTS_NOLOCK;
Table_exists_error_handler no_such_table_handler;
thd->push_internal_handler(&no_such_table_handler);
TABLE_SHARE *share= get_table_share(thd, db, table_name, flags);
thd->pop_internal_handler();
if (hton && share)
{
*hton= share->db_type();
mysql_mutex_lock(&LOCK_open);
release_table_share(share);
mysql_mutex_unlock(&LOCK_open);
}
// 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);
TABLE_SHARE *share= get_cached_table_share(db, table_name);
if (hton && share)
*hton= share->db_type();
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))
{
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);
}
/**
Ask handler if the table exists in engine.
@retval
HA_ERR_NO_SUCH_TABLE Table does not exist
@retval
HA_ERR_TABLE_EXIST Table exists
@retval
\# Error code
Discover all table names in a given database
*/
struct st_table_exists_in_engine_args
extern "C" {
static int cmp_file_names(const void *a, const void *b)
{
const char *db;
const char *name;
int err;
CHARSET_INFO *cs= character_set_filesystem;
char *aa= ((FILEINFO *)a)->name;
char *bb= ((FILEINFO *)b)->name;
return my_strnncoll(cs, (uchar*)aa, strlen(aa), (uchar*)bb, strlen(bb));
}
static int cmp_table_names(LEX_STRING * const *a, LEX_STRING * const *b)
{
return my_strnncoll(&my_charset_bin, (uchar*)((*a)->str), (*a)->length,
(uchar*)((*b)->str), (*b)->length);
}
}
Discovered_table_list::Discovered_table_list(THD *thd_arg,
Dynamic_array<LEX_STRING*> *tables_arg,
const LEX_STRING *wild_arg)
{
thd= thd_arg;
tables= tables_arg;
if (wild_arg->str && wild_arg->str[0])
{
wild= wild_arg->str;
wend= wild + wild_arg->length;
}
else
wild= 0;
}
bool Discovered_table_list::add_table(const char *tname, size_t tlen)
{
if (wild && my_wildcmp(files_charset_info, tname, tname + tlen, wild, wend,
wild_prefix, wild_one, wild_many))
return 0;
LEX_STRING *name= thd->make_lex_string(tname, tlen);
if (!name || tables->append(name))
return 1;
return 0;
}
bool Discovered_table_list::add_file(const char *fname)
{
char tname[SAFE_NAME_LEN + 1];
size_t tlen= filename_to_tablename(fname, tname, sizeof(tname));
return add_table(tname, tlen);
}
void Discovered_table_list::sort()
{
tables->sort(cmp_table_names);
}
void Discovered_table_list::remove_duplicates()
{
LEX_STRING **src= tables->front();
LEX_STRING **dst= src;
while (++dst < tables->back())
{
LEX_STRING *s= *src, *d= *dst;
DBUG_ASSERT(strncmp(s->str, d->str, min(s->length, d->length)) <= 0);
if ((s->length != d->length || strncmp(s->str, d->str, d->length)))
{
src++;
if (src != dst)
*src= *dst;
}
}
tables->set_elements(src - tables->front() + 1);
}
struct st_discover_names_args
{
LEX_STRING *db;
MY_DIR *dirp;
Discovered_table_list *result;
uint possible_duplicates;
};
static my_bool table_exists_in_engine_handlerton(THD *thd, plugin_ref plugin,
void *arg)
static my_bool discover_names(THD *thd, plugin_ref plugin,
void *arg)
{
st_table_exists_in_engine_args *vargs= (st_table_exists_in_engine_args *)arg;
handlerton *hton= plugin_data(plugin, handlerton *);
st_discover_names_args *args= (st_discover_names_args *)arg;
handlerton *ht= plugin_data(plugin, handlerton *);
int err= HA_ERR_NO_SUCH_TABLE;
if (ht->state == SHOW_OPTION_YES && ht->discover_table_names)
{
uint old_elements= args->result->tables->elements();
if (ht->discover_table_names(ht, args->db, args->dirp, args->result))
return 1;
if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine)
err = hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name);
/*
hton_ext_based_table_discovery never discovers a table that has
a corresponding .frm file; but custom engine discover methods might
*/
if (ht->discover_table_names != hton_ext_based_table_discovery)
args->possible_duplicates+= args->result->tables->elements() - old_elements;
}
vargs->err = err;
if (vargs->err == HA_ERR_TABLE_EXIST)
return TRUE;
return FALSE;
return 0;
}
int ha_table_exists_in_engine(THD* thd, const char* db, const char* name)
int ha_discover_table_names(THD *thd, LEX_STRING *db, MY_DIR *dirp,
Discovered_table_list *result)
{
DBUG_ENTER("ha_table_exists_in_engine");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
st_table_exists_in_engine_args args= {db, name, HA_ERR_NO_SUCH_TABLE};
plugin_foreach(thd, table_exists_in_engine_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
DBUG_PRINT("exit", ("error: %d", args.err));
DBUG_RETURN(args.err);
int error;
DBUG_ENTER("ha_discover_table_names");
if (engines_with_discover_table_names == 0)
{
error= ext_table_discovery_simple(dirp, result);
result->sort();
}
else
{
st_discover_names_args args= {db, dirp, result, 0};
/* extension_based_table_discovery relies on dirp being sorted */
my_qsort(dirp->dir_entry, dirp->number_of_files,
sizeof(FILEINFO), cmp_file_names);
error= extension_based_table_discovery(dirp, reg_ext, result) ||
plugin_foreach(thd, discover_names,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
result->sort();
if (args.possible_duplicates > 0)
result->remove_duplicates();
}
DBUG_RETURN(error);
}
#ifdef HAVE_NDB_BINLOG
/*
TODO: change this into a dynamic struct
@@ -5017,26 +5196,20 @@ static my_bool exts_handlerton(THD *unused, plugin_ref plugin,
{
List<char> *found_exts= (List<char> *) arg;
handlerton *hton= plugin_data(plugin, handlerton *);
handler *file;
if (hton->state == SHOW_OPTION_YES && hton->create &&
(file= hton->create(hton, (TABLE_SHARE*) 0, current_thd->mem_root)))
List_iterator_fast<char> it(*found_exts);
const char **ext, *old_ext;
for (ext= hton->tablefile_extensions; *ext; ext++)
{
List_iterator_fast<char> it(*found_exts);
const char **ext, *old_ext;
for (ext= file->bas_ext(); *ext; ext++)
while ((old_ext= it++))
{
while ((old_ext= it++))
{
if (!strcmp(old_ext, *ext))
break;
}
if (!old_ext)
found_exts->push_back((char *) *ext);
it.rewind();
if (!strcmp(old_ext, *ext))
break;
}
delete file;
if (!old_ext)
found_exts->push_back((char *) *ext);
it.rewind();
}
return FALSE;
}
@@ -5137,7 +5310,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
if (!result && !thd->is_error())
my_eof(thd);
else if (!thd->is_error())
my_error(ER_GET_ERRNO, MYF(0), errno);
my_error(ER_GET_ERRNO, MYF(0), errno, hton_name(db_type)->str);
return result;
}