diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-04-09 16:07:17 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-04-09 16:07:17 +0200 |
commit | 4853c7192ded76ede690746cde9eaabbc448479b (patch) | |
tree | 04c76fb9f4e4fd3998c6cc26427f3011f10a4cdd /sql | |
parent | 474f45b3dc684b14c3b5ab86303c8aa890d2dce5 (diff) | |
download | mariadb-git-4853c7192ded76ede690746cde9eaabbc448479b.tar.gz |
discovery using sql CREATE TABLE statement
Diffstat (limited to 'sql')
-rw-r--r-- | sql/handler.cc | 4 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 3 | ||||
-rw-r--r-- | sql/sql_table.cc | 275 | ||||
-rw-r--r-- | sql/sql_table.h | 7 | ||||
-rw-r--r-- | sql/table.cc | 161 | ||||
-rw-r--r-- | sql/table.h | 6 | ||||
-rw-r--r-- | sql/unireg.cc | 47 | ||||
-rw-r--r-- | sql/unireg.h | 18 |
8 files changed, 324 insertions, 197 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index d58040abaa8..735c2b012e6 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4317,6 +4317,7 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin, handlerton *hton= plugin_data(plugin, handlerton *); 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) { @@ -4324,6 +4325,7 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin, { DBUG_ASSERT(share->error); // MUST be always set for get_cached_table_share to work my_error(ER_GET_ERRNO, MYF(0), error); + share->db_plugin= 0; } else share->error= OPEN_FRM_OK; @@ -4331,6 +4333,7 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin, 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); @@ -4342,6 +4345,7 @@ int ha_discover_table(THD *thd, TABLE_SHARE *share) DBUG_ENTER("ha_discover_table"); DBUG_ASSERT(share->error == OPEN_FRM_OPEN_ERROR); // share is not OK yet + DBUG_ASSERT(!share->db_plugin); if (!plugin_foreach(thd, discover_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, share)) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e7f60987cc1..fd74af7d56d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6600,3 +6600,6 @@ ER_SLAVE_STARTED eng "SLAVE '%.*s' started" ER_SLAVE_STOPPED eng "SLAVE '%.*s' stopped" +ER_SQL_DISCOVER_ERROR + eng "Engine %s failed to discover table %`-.192s.%`-.192s with '%s'" + diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f6a5cc3448a..0a02e674c07 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1703,13 +1703,23 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) #endif /* Write shadow frm file */ lpt->create_info->table_options= lpt->db_options; - if ((mysql_create_frm(lpt->thd, shadow_path, lpt->db, - lpt->table_name, lpt->create_info, - lpt->alter_info->create_list, lpt->key_count, - lpt->key_info_buffer, lpt->table->file)) || - lpt->table->file->ha_create_partitioning_metadata(shadow_path, NULL, - CHF_CREATE_FLAG, - lpt->create_info)) + LEX_CUSTRING frm= build_frm_image(lpt->thd, lpt->table_name, + lpt->create_info, + lpt->alter_info->create_list, + lpt->key_count, lpt->key_info_buffer, + lpt->table->file); + if (!frm.str) + { + error= 1; + goto end; + } + + int error= writefrm(shadow_path, lpt->db, lpt->table_name, + !lpt->create_info->tmp_table(), frm.str, frm.length); + my_free(const_cast<uchar*>(frm.str)); + + if (error || lpt->table->file->ha_create_partitioning_metadata(shadow_path, + NULL, CHF_CREATE_FLAG, lpt->create_info)) { mysql_file_delete(key_file_frm, shadow_frm_name, MYF(0)); error= 1; @@ -3857,6 +3867,21 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } } + if (create_info->tmp_table()) + create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE; + + /* Give warnings for not supported table options */ +#if defined(WITH_ARIA_STORAGE_ENGINE) + extern handlerton *maria_hton; + if (file->ht != maria_hton) +#endif + if (create_info->transactional) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + ER(ER_ILLEGAL_HA_CREATE_OPTION), + file->engine_name()->str, + "TRANSACTIONAL=1"); + if (parse_option_list(thd, &create_info->option_struct, create_info->option_list, file->partition_ht()->table_options, FALSE, @@ -4047,70 +4072,27 @@ static bool check_if_created_table_can_be_opened(THD *thd, #endif -/* - Create a table - - SYNOPSIS - mysql_create_table_no_lock() - thd Thread object - db Database - table_name Table name - create_info Create information (like MAX_ROWS) - fields List of fields to create - keys List of keys to create - internal_tmp_table Set to 1 if this is an internal temporary table - (From ALTER TABLE) - select_field_count - is_trans identifies the type of engine where the table - was created: either trans or non-trans. - - DESCRIPTION - If one creates a temporary table, this is automatically opened - - Note that this function assumes that caller already have taken - exclusive metadata lock on table being created or used some other - way to ensure that concurrent operations won't intervene. - mysql_create_table() is a wrapper that can be used for this. - - no_log is needed for the case of CREATE ... SELECT, - as the logging will be done later in sql_insert.cc - select_field_count is also used for CREATE ... SELECT, - and must be zero for standard create of table. - - RETURN VALUES - FALSE OK - TRUE error -*/ - -bool mysql_create_table_no_lock(THD *thd, +handler *mysql_create_frm_image(THD *thd, const char *db, const char *table_name, HA_CREATE_INFO *create_info, Alter_info *alter_info, bool internal_tmp_table, - uint select_field_count, - bool *is_trans) + uint select_field_count, LEX_CUSTRING *frm) { - char path[FN_REFLEN + 1]; - uint path_length; - const char *alias; uint db_options, key_count; KEY *key_info_buffer; - handler *file; - bool error= TRUE; - DBUG_ENTER("mysql_create_table_no_lock"); - DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d", - db, table_name, internal_tmp_table)); - + handler *file; + DBUG_ENTER("mysql_create_frm_image"); /* Check for duplicate fields and check type of table to create */ if (!alter_info->create_list.elements) { my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS), MYF(0)); - DBUG_RETURN(TRUE); + DBUG_RETURN(NULL); } if (check_engine(thd, db, table_name, create_info)) - DBUG_RETURN(TRUE); + DBUG_RETURN(NULL); set_table_default_charset(thd, create_info, (char*) db); @@ -4119,12 +4101,11 @@ bool mysql_create_table_no_lock(THD *thd, create_info->row_type != ROW_TYPE_FIXED && create_info->row_type != ROW_TYPE_DEFAULT) db_options|= HA_OPTION_PACK_RECORD; - alias= table_case_name(create_info, table_name); if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, create_info->db_type))) { mem_alloc_error(sizeof(handler)); - DBUG_RETURN(TRUE); + DBUG_RETURN(NULL); } #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *part_info= thd->work_part_info; @@ -4141,7 +4122,7 @@ bool mysql_create_table_no_lock(THD *thd, if (!part_info) { mem_alloc_error(sizeof(partition_info)); - DBUG_RETURN(TRUE); + goto err; } file->set_auto_partitions(part_info); part_info->default_engine_type= create_info->db_type; @@ -4166,7 +4147,7 @@ bool mysql_create_table_no_lock(THD *thd, char *part_syntax_buf; uint syntax_len; handlerton *engine_type; - if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + if (create_info->tmp_table()) { my_error(ER_PARTITION_NO_TEMPORARY, MYF(0)); goto err; @@ -4238,9 +4219,8 @@ bool mysql_create_table_no_lock(THD *thd, delete file; create_info->db_type= partition_hton; if (!(file= get_ha_partition(part_info))) - { - DBUG_RETURN(TRUE); - } + DBUG_RETURN(NULL); + /* If we have default number of partitions or subpartitions we might require to set-up the part_info object such that it @@ -4282,65 +4262,90 @@ bool mysql_create_table_no_lock(THD *thd, engine_type))) { mem_alloc_error(sizeof(handler)); - DBUG_RETURN(TRUE); + DBUG_RETURN(NULL); } } } #endif if (mysql_prepare_create_table(thd, create_info, alter_info, - internal_tmp_table, - &db_options, file, + internal_tmp_table, &db_options, file, &key_info_buffer, &key_count, select_field_count)) goto err; + create_info->table_options=db_options; - /* Check if table exists */ - if (create_info->options & HA_LEX_CREATE_TMP_TABLE) - { - path_length= build_tmptable_filename(thd, path, sizeof(path)); - create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE; - } - else - { - path_length= build_table_filename(path, sizeof(path) - 1, db, alias, reg_ext, - internal_tmp_table ? FN_IS_TMP : 0); - } + *frm= build_frm_image(thd, table_name, create_info, + alter_info->create_list, key_count, + key_info_buffer, file); - /* Check if table already exists */ - if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) && - find_temporary_table(thd, db, table_name)) - { - if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - goto warn; - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); - goto err; - } + if (frm->str) + DBUG_RETURN(file); - /* Give warnings for not supported table options */ -#if defined(WITH_ARIA_STORAGE_ENGINE) - extern handlerton *maria_hton; - if (file->ht != maria_hton) -#endif - if (create_info->transactional) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - ER(ER_ILLEGAL_HA_CREATE_OPTION), - file->engine_name()->str, - "TRANSACTIONAL=1"); +err: + delete file; + DBUG_RETURN(NULL); +} - if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) - { - if (ha_table_exists(thd, db, table_name)) - { - if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - goto warn; - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); - goto err; - } - } - thd_proc_info(thd, "creating table"); +/* + Create a table + + SYNOPSIS + mysql_create_table_no_lock() + thd Thread object + db Database + table_name Table name + create_info Create information (like MAX_ROWS) + fields List of fields to create + keys List of keys to create + internal_tmp_table Set to 1 if this is an internal temporary table + (From ALTER TABLE) + select_field_count + is_trans identifies the type of engine where the table + was created: either trans or non-trans. + + DESCRIPTION + If one creates a temporary table, this is automatically opened + + Note that this function assumes that caller already have taken + exclusive metadata lock on table being created or used some other + way to ensure that concurrent operations won't intervene. + mysql_create_table() is a wrapper that can be used for this. + + select_field_count is also used for CREATE ... SELECT, + and must be zero for standard create of table. + + RETURN VALUES + FALSE OK + TRUE error +*/ + +bool mysql_create_table_no_lock(THD *thd, + const char *db, const char *table_name, + HA_CREATE_INFO *create_info, + Alter_info *alter_info, + bool internal_tmp_table, + uint select_field_count, + bool *is_trans) +{ + char path[FN_REFLEN + 1]; + uint path_length; + const char *alias; + handler *file; + LEX_CUSTRING frm= {0,0}; + bool error= TRUE; + DBUG_ENTER("mysql_create_table_no_lock"); + DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d", + db, table_name, internal_tmp_table)); + + alias= table_case_name(create_info, table_name); + + file= mysql_create_frm_image(thd, db, table_name, create_info, alter_info, + internal_tmp_table, select_field_count, &frm); + + if (!file) + goto err; #ifdef HAVE_READLINK { @@ -4402,15 +4407,41 @@ bool mysql_create_table_no_lock(THD *thd, "INDEX DIRECTORY"); create_info->data_file_name= create_info->index_file_name= 0; } - create_info->table_options=db_options; - path[path_length - reg_ext_length]= '\0'; // Remove .frm extension - if (rea_create_table(thd, path, db, table_name, - create_info, alter_info->create_list, - key_count, key_info_buffer, file)) + /* Check if table exists */ + if (create_info->tmp_table()) + { + path_length= build_tmptable_filename(thd, path, sizeof(path)); + path[path_length - reg_ext_length]= '\0'; // Remove .frm extension + + if (find_temporary_table(thd, db, table_name)) + { + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + goto warn; + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); + goto err; + } + } + else + { + path_length= build_table_filename(path, sizeof(path) - 1, db, alias, "", + internal_tmp_table ? FN_IS_TMP : 0); + + if (!internal_tmp_table && ha_table_exists(thd, db, table_name)) + { + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + goto warn; + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + goto err; + } + } + + thd_proc_info(thd, "creating table"); + + if (rea_create_table(thd, &frm, path, db, table_name, create_info, file)) goto err; - if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + if (create_info->tmp_table()) { /* Open a table (skipping table cache) and add it into @@ -4431,7 +4462,7 @@ bool mysql_create_table_no_lock(THD *thd, thd->thread_specific_used= TRUE; } #ifdef WITH_PARTITION_STORAGE_ENGINE - else if (part_info && create_info->frm_only) + else if (thd->work_part_info && create_info->frm_only) { /* For partitioned tables we can't find some problems with table @@ -4457,6 +4488,7 @@ bool mysql_create_table_no_lock(THD *thd, error= FALSE; err: thd_proc_info(thd, "After create"); + my_free(const_cast<uchar*>(frm.str)); delete file; DBUG_RETURN(error); @@ -4468,7 +4500,6 @@ warn: goto err; } - /** Implementation of SQLCOM_CREATE_TABLE. @@ -4514,7 +4545,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, if (!result && (!thd->is_current_stmt_binlog_format_row() || (thd->is_current_stmt_binlog_format_row() && - !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) + !(create_info->tmp_table())))) result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans); end: @@ -4727,7 +4758,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS; /* Replace type of source table with one specified in the statement. */ local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE; - local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE; + local_create_info.options|= create_info->tmp_table(); /* Reset auto-increment counter for the new table. */ local_create_info.auto_increment_value= 0; /* @@ -4745,7 +4776,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, Ensure that we have an exclusive lock on target table if we are creating non-temporary table. */ - DBUG_ASSERT((create_info->options & HA_LEX_CREATE_TMP_TABLE) || + DBUG_ASSERT((create_info->tmp_table()) || thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db, table->table_name, MDL_EXCLUSIVE)); @@ -4772,7 +4803,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, 4 temporary temporary Nothing ==== ========= ========= ============================== */ - if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) + if (!(create_info->tmp_table())) { if (src_table->table->s->tmp_table) // Case 2 { @@ -7227,7 +7258,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->is_current_stmt_binlog_format_row() && - (create_info->options & HA_LEX_CREATE_TMP_TABLE))); + (create_info->tmp_table()))); if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) DBUG_RETURN(TRUE); @@ -7852,7 +7883,7 @@ static bool check_engine(THD *thd, const char *db_name, ha_resolve_storage_engine_name(*new_engine), table_name); } - if (create_info->options & HA_LEX_CREATE_TMP_TABLE && + if (create_info->tmp_table() && ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED)) { if (create_info->used_fields & HA_CREATE_USED_ENGINE) diff --git a/sql/sql_table.h b/sql/sql_table.h index 4dc28aa4933..016260b6b26 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -25,6 +25,7 @@ struct TABLE_LIST; class THD; struct TABLE; struct handlerton; +class handler; typedef struct st_ha_check_opt HA_CHECK_OPT; struct HA_CREATE_INFO; typedef struct st_key KEY; @@ -140,6 +141,12 @@ bool mysql_create_table_no_lock(THD *thd, const char *db, Alter_info *alter_info, bool tmp_table, uint select_field_count, bool *is_trans); +handler *mysql_create_frm_image(THD *thd, + const char *db, const char *table_name, + HA_CREATE_INFO *create_info, + Alter_info *alter_info, + bool internal_tmp_table, + uint select_field_count, LEX_CUSTRING *frm); bool mysql_prepare_alter_table(THD *thd, TABLE *table, HA_CREATE_INFO *create_info, Alter_info *alter_info); diff --git a/sql/table.cc b/sql/table.cc index e47c07f3a7e..d6b109a880a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -693,9 +693,9 @@ err_not_open: */ -bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, - const uchar *frm_image, - size_t frm_length) +int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, + const uchar *frm_image, + size_t frm_length) { TABLE_SHARE *share= this; uint new_frm_ver, field_pack_length, new_field_pack_flag; @@ -729,10 +729,11 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, KEY_PART_INFO *first_key_part= NULL; uint ext_key_parts= 0; uint first_key_parts= 0; + plugin_ref se_plugin= 0; keyinfo= &first_keyinfo; share->ext_key_parts= 0; MEM_ROOT **root_ptr, *old_root; - DBUG_ENTER("open_binary_frm"); + DBUG_ENTER("TABLE_SHARE::init_from_binary_frm_image"); root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); old_root= *root_ptr; @@ -776,15 +777,13 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, DBUG_PRINT("info", ("default_part_db_type = %u", frm_image[61])); #endif legacy_db_type= (enum legacy_db_type) (uint) frm_image[3]; - DBUG_ASSERT(share->db_plugin == NULL); /* if the storage engine is dynamic, no point in resolving it by its dynamically allocated legacy_db_type. We will resolve it later by name. */ if (legacy_db_type > DB_TYPE_UNKNOWN && legacy_db_type < DB_TYPE_FIRST_DYNAMIC) - share->db_plugin= ha_lock_engine(NULL, - ha_checktype(thd, legacy_db_type, 0, 0)); + se_plugin= ha_lock_engine(NULL, ha_checktype(thd, legacy_db_type, 0, 0)); share->db_create_options= db_create_options= uint2korr(frm_image+30); share->db_options_in_use= share->db_create_options; share->mysql_version= uint4korr(frm_image+51); @@ -1045,7 +1044,7 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, name.length= str_db_type_length; plugin_ref tmp_plugin= ha_resolve_by_name(thd, &name); - if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, share->db_plugin)) + if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, se_plugin)) { if (legacy_db_type > DB_TYPE_UNKNOWN && legacy_db_type < DB_TYPE_FIRST_DYNAMIC && @@ -1057,14 +1056,11 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } /* tmp_plugin is locked with a local lock. - we unlock the old value of share->db_plugin before + we unlock the old value of se_plugin before replacing it with a globally locked version of tmp_plugin */ - plugin_unlock(NULL, share->db_plugin); - share->db_plugin= my_plugin_lock(NULL, tmp_plugin); - DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)", - str_db_type_length, next_chunk + 2, - ha_legacy_type(share->db_type()))); + plugin_unlock(NULL, se_plugin); + se_plugin= plugin_lock(NULL, tmp_plugin); } #ifdef WITH_PARTITION_STORAGE_ENGINE else if (str_db_type_length == 9 && @@ -1073,7 +1069,7 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, /* Use partition handler tmp_plugin is locked with a local lock. - we unlock the old value of share->db_plugin before + we unlock the old value of se_plugin before replacing it with a globally locked version of tmp_plugin */ /* Check if the partitioning engine is ready */ @@ -1083,11 +1079,8 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, "--skip-partition"); goto err; } - plugin_unlock(NULL, share->db_plugin); - share->db_plugin= ha_lock_engine(NULL, partition_hton); - DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)", - str_db_type_length, next_chunk + 2, - ha_legacy_type(share->db_type()))); + plugin_unlock(NULL, se_plugin); + se_plugin= ha_lock_engine(NULL, partition_hton); } #endif else if (!tmp_plugin) @@ -1284,7 +1277,7 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, /* Allocate handler */ if (!(handler_file= get_new_handler(share, thd->mem_root, - share->db_type()))) + plugin_data(se_plugin, handlerton *)))) goto err; record= share->default_values-1; /* Fieldstart = 1 */ @@ -1909,6 +1902,8 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, (void) my_hash_check(&share->name_hash); #endif + DBUG_ASSERT(!share->db_plugin || plugin_equals(share->db_plugin, se_plugin)); + share->db_plugin= se_plugin; share->error= OPEN_FRM_OK; thd->status_var.opened_shares++; *root_ptr= old_root; @@ -1918,6 +1913,7 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, share->error= OPEN_FRM_CORRUPTED; share->open_errno= my_errno; delete handler_file; + plugin_unlock(0, se_plugin); my_hash_free(&share->name_hash); if (share->ha_data_destroy) { @@ -1936,9 +1932,128 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, open_table_error(share, OPEN_FRM_CORRUPTED, share->open_errno); *root_ptr= old_root; - DBUG_RETURN(1); -} /* open_binary_frm */ + DBUG_RETURN(HA_ERR_NOT_A_TABLE); +} + + +static bool sql_unusable_for_discovery(THD *thd, const char *sql) +{ + LEX *lex= thd->lex; + HA_CREATE_INFO *create_info= &lex->create_info; + + // ... not CREATE TABLE + if (lex->sql_command != SQLCOM_CREATE_TABLE) + return 1; + // ... create like + if (create_info->options & HA_LEX_CREATE_TABLE_LIKE) + return 1; + // ... create select + if (lex->select_lex.item_list.elements) + return 1; + // ... temporary + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + return 1; + // ... if exists + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + return 1; + + // XXX error out or rather ignore the following: + // ... partitioning + if (lex->part_info) + return 1; + // ... union + if (create_info->used_fields & HA_CREATE_USED_UNION) + return 1; + // ... index/data directory + if (create_info->data_file_name || create_info->index_file_name) + return 1; + // ... engine + if (create_info->used_fields & HA_CREATE_USED_ENGINE) + return 1; + + return 0; +} + +int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, + const char *sql, size_t sql_length) +{ + ulonglong saved_mode= thd->variables.sql_mode; + CHARSET_INFO *old_cs= thd->variables.character_set_client; + Parser_state parser_state; + bool error; + char *sql_copy; + handler *file; + LEX *old_lex; + Query_arena *arena, backup; + LEX tmp_lex; + LEX_CUSTRING frm= {0,0}; + + DBUG_ENTER("TABLE_SHARE::init_from_sql_statement_string"); + + /* + Ouch. Parser may *change* the string it's working on. + Currently (2013-02-26) it is used to permanently disable + conditional comments. + Anyway, let's copy the caller's string... + */ + if (!(sql_copy= thd->strmake(sql, sql_length))) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + if (parser_state.init(thd, sql_copy, sql_length)) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + thd->variables.sql_mode= MODE_NO_ENGINE_SUBSTITUTION | MODE_NO_DIR_IN_CREATE; + thd->variables.character_set_client= system_charset_info; + tmp_disable_binlog(thd); + old_lex= thd->lex; + thd->lex= &tmp_lex; + + arena= thd->stmt_arena; + if (arena->is_conventional()) + arena= 0; + else + thd->set_n_backup_active_arena(arena, &backup); + + lex_start(thd); + if ((error= parse_sql(thd, & parser_state, NULL))) + goto ret; + + if (sql_unusable_for_discovery(thd, sql_copy)) + { + my_error(ER_SQL_DISCOVER_ERROR, MYF(0), plugin_name(db_plugin)->str, + db.str, table_name.str, sql_copy); + goto ret; + } + + thd->lex->create_info.db_type= plugin_data(db_plugin, handlerton *); + + file= mysql_create_frm_image(thd, db.str, table_name.str, + &thd->lex->create_info, &thd->lex->alter_info, + 0, 0, &frm); + error|= file == 0; + delete file; + + if (frm.str) + error= init_from_binary_frm_image(thd, write, frm.str, frm.length); + +ret: + my_free(const_cast<uchar*>(frm.str)); + lex_end(thd->lex); + thd->lex= old_lex; + if (arena) + thd->restore_active_arena(arena, &backup); + reenable_binlog(thd); + thd->variables.sql_mode= saved_mode; + thd->variables.character_set_client= old_cs; + if (thd->is_error() || error) + { + thd->clear_error(); + my_error(ER_NO_SUCH_TABLE, MYF(0), db.str, table_name.str); + DBUG_RETURN(HA_ERR_NOT_A_TABLE); + } + DBUG_RETURN(0); +} bool TABLE_SHARE::write_frm_image(const uchar *frm, size_t len) { diff --git a/sql/table.h b/sql/table.h index 562a49bfdae..a10617cc938 100644 --- a/sql/table.h +++ b/sql/table.h @@ -989,8 +989,10 @@ struct TABLE_SHARE uint actual_n_key_parts(THD *thd); LEX_CUSTRING *frm_image; ///< only during CREATE TABLE (@sa ha_create_table) - bool init_from_binary_frm_image(THD *thd, bool write, - const uchar *frm_image, size_t frm_length); + int init_from_binary_frm_image(THD *thd, bool write, + const uchar *frm_image, size_t frm_length); + int init_from_sql_statement_string(THD *thd, bool write, + const char *sql, size_t sql_length); bool write_frm_image(const uchar *frm_image, size_t frm_length); bool read_frm_image(const uchar **frm_image, size_t *frm_length); }; diff --git a/sql/unireg.cc b/sql/unireg.cc index a50ac99ed20..aa60a9e49c8 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -44,8 +44,6 @@ static uint get_interval_id(uint *,List<Create_field> &, Create_field *); static bool pack_fields(uchar *, List<Create_field> &, ulong); static size_t packed_fields_length(List<Create_field> &); static bool make_empty_rec(THD *, uchar *, uint, List<Create_field> &, uint, ulong); -static LEX_CUSTRING create_frm_image(THD *, const char *, HA_CREATE_INFO *, - List<Create_field> &, uint, KEY *, handler *); /* Create a frm (table definition) file @@ -67,27 +65,7 @@ static LEX_CUSTRING create_frm_image(THD *, const char *, HA_CREATE_INFO *, true error */ -bool mysql_create_frm(THD *thd, const char *file_name, - const char *db, const char *table, - HA_CREATE_INFO *create_info, - List<Create_field> &create_fields, - uint keys, KEY *key_info, - handler *db_file) -{ - DBUG_ENTER("mysql_create_frm"); - LEX_CUSTRING frm= create_frm_image(thd, table, create_info, - create_fields, keys, key_info, db_file); - if (!frm.str) - DBUG_RETURN(1); - - int error= writefrm(file_name, db, table, !create_info->tmp_table(), - frm.str, frm.length); - - my_free(const_cast<uchar*>(frm.str)); - DBUG_RETURN(error); -} - -LEX_CUSTRING create_frm_image(THD *thd, const char *table, +LEX_CUSTRING build_frm_image(THD *thd, const char *table, HA_CREATE_INFO *create_info, List<Create_field> &create_fields, uint keys, KEY *key_info, handler *db_file) @@ -104,7 +82,7 @@ LEX_CUSTRING create_frm_image(THD *thd, const char *table, int error; uchar *frm_ptr, *pos; LEX_CUSTRING frm= {0,0}; - DBUG_ENTER("create_frm_image"); + DBUG_ENTER("build_frm_image"); /* If fixed row records, we need one bit to check for deleted rows */ if (!(create_info->table_options & HA_OPTION_PACK_RECORD)) @@ -373,37 +351,30 @@ err: 1 error */ -int rea_create_table(THD *thd, const char *path, - const char *db, const char *table_name, - HA_CREATE_INFO *create_info, - List<Create_field> &create_fields, - uint keys, KEY *key_info, handler *file) +int rea_create_table(THD *thd, LEX_CUSTRING *frm, + const char *path, const char *db, const char *table_name, + HA_CREATE_INFO *create_info, handler *file) { DBUG_ENTER("rea_create_table"); - LEX_CUSTRING frm= create_frm_image(thd, table_name, create_info, - create_fields, keys, key_info, file); - if (!frm.str) - DBUG_RETURN(1); - if (thd->variables.keep_files_on_create) create_info->options|= HA_CREATE_KEEP_FILES; if (create_info->frm_only) { - if (writefrm(path, db, table_name, 1, frm.str, frm.length)) + if (writefrm(path, db, table_name, 1, frm->str, frm->length)) goto err_handler; } else { // TODO don't write frm for temp tables if (create_info->tmp_table() && - writefrm(path, db, table_name, 0, frm.str, frm.length)) + writefrm(path, db, table_name, 0, frm->str, frm->length)) goto err_handler; if (file->ha_create_partitioning_metadata(path, NULL, CHF_CREATE_FLAG, create_info) || - ha_create_table(thd, path, db, table_name, create_info, &frm)) + ha_create_table(thd, path, db, table_name, create_info, frm)) { file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG, create_info); @@ -411,14 +382,12 @@ int rea_create_table(THD *thd, const char *path, } } - my_free(const_cast<uchar*>(frm.str)); DBUG_RETURN(0); err_handler: char frm_name[FN_REFLEN]; strxmov(frm_name, path, reg_ext, NullS); mysql_file_delete(key_file_frm, frm_name, MYF(0)); - my_free(const_cast<uchar*>(frm.str)); DBUG_RETURN(1); } /* rea_create_table */ diff --git a/sql/unireg.h b/sql/unireg.h index 6972f90c1db..89dae6b2e97 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -167,17 +167,13 @@ #include "sql_list.h" /* List<> */ #include "field.h" /* Create_field */ -bool mysql_create_frm(THD *thd, const char *file_name, - const char *db, const char *table, - HA_CREATE_INFO *create_info, - List<Create_field> &create_field, - uint key_count,KEY *key_info,handler *db_type); -int rea_create_table(THD *thd, const char *path, - const char *db, const char *table_name, - HA_CREATE_INFO *create_info, - List<Create_field> &create_field, - uint key_count,KEY *key_info, - handler *file); +int rea_create_table(THD *thd, LEX_CUSTRING *frm, + const char *path, const char *db, const char *table_name, + HA_CREATE_INFO *create_info, handler *file); +LEX_CUSTRING build_frm_image(THD *thd, const char *table, + HA_CREATE_INFO *create_info, + List<Create_field> &create_fields, + uint keys, KEY *key_info, handler *db_file); #define FRM_HEADER_SIZE 64 #define FRM_FORMINFO_SIZE 288 |