diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-04-15 15:09:22 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-04-15 15:09:22 +0200 |
commit | a9035be5b7a7b3865ddb4ef34a5d0cfc65dfc254 (patch) | |
tree | a9df7341e91623f62fe37cd47fce139d8888fc95 /sql/handler.cc | |
parent | 3a1c91d87d69ef243b3e78be6089102cafef0a8e (diff) | |
parent | f57ecb7786177e0af3b1e3ec94302720b2e0f967 (diff) | |
download | mariadb-git-a9035be5b7a7b3865ddb4ef34a5d0cfc65dfc254.tar.gz |
10.0-base merge
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 703 |
1 files changed, 438 insertions, 265 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index 5297a8e8cfc..398b6b5c8b1 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -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); } +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); +} -/** - 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 +struct st_discover_existence_args { - const char *db; - const char *path; - const char *wild; - bool dir; - List<LEX_STRING> *files; + 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}; - - plugin_foreach(thd, find_files_handlerton, - MYSQL_STORAGE_ENGINE_PLUGIN, &args); - /* The return value is not currently used */ - DBUG_RETURN(error); +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) + { + 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 my_bool table_exists_in_engine_handlerton(THD *thd, plugin_ref plugin, - void *arg) +static int cmp_table_names(LEX_STRING * const *a, LEX_STRING * const *b) { - st_table_exists_in_engine_args *vargs= (st_table_exists_in_engine_args *)arg; - handlerton *hton= plugin_data(plugin, handlerton *); + return my_strnncoll(&my_charset_bin, (uchar*)((*a)->str), (*a)->length, + (uchar*)((*b)->str), (*b)->length); +} - int err= HA_ERR_NO_SUCH_TABLE; +} - if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine) - err = hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name); +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; +} - vargs->err = err; - if (vargs->err == HA_ERR_TABLE_EXIST) - return TRUE; +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; - return FALSE; + 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 discover_names(THD *thd, plugin_ref plugin, + void *arg) +{ + st_discover_names_args *args= (st_discover_names_args *)arg; + handlerton *ht= plugin_data(plugin, handlerton *); + + 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; + + /* + 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; + } + + 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; + List_iterator_fast<char> it(*found_exts); + const char **ext, *old_ext; - for (ext= file->bas_ext(); *ext; ext++) + for (ext= hton->tablefile_extensions; *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; } |