diff --git a/include/my_sys.h b/include/my_sys.h index a8633982f84..d1a253e4a7f 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -904,6 +904,14 @@ extern CHARSET_INFO *get_charset(uint cs_number, myf flags); extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint cs_flags, myf my_flags); + +extern bool resolve_charset(CHARSET_INFO **cs, + const char *cs_name, + CHARSET_INFO *default_cs); +extern bool resolve_collation(CHARSET_INFO **cl, + const char *cl_name, + CHARSET_INFO *default_cl); + extern void free_charsets(void); extern char *get_charsets_dir(char *buf); extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); diff --git a/mysys/charset.c b/mysys/charset.c index c6065f87df3..5f9521eeab8 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -573,6 +573,70 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name, } +/** + Resolve character set by the character set name (utf8, latin1, ...). + + The function tries to resolve character set by the specified name. If + there is character set with the given name, it is assigned to the "cs" + parameter and FALSE is returned. If there is no such character set, + "default_cs" is assigned to the "cs" and TRUE is returned. + + @param[out] cs Variable to store character set. + @param[in] cs_name Character set name. + @param[in] default_cs Default character set. + + @return FALSE if character set was resolved successfully; TRUE if there + is no character set with given name. +*/ + +bool resolve_charset(CHARSET_INFO **cs, + const char *cs_name, + CHARSET_INFO *default_cs) +{ + *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0)); + + if (*cs == NULL) + { + *cs= default_cs; + return TRUE; + } + + return FALSE; +} + + +/** + Resolve collation by the collation name (utf8_general_ci, ...). + + The function tries to resolve collation by the specified name. If there + is collation with the given name, it is assigned to the "cl" parameter + and FALSE is returned. If there is no such collation, "default_cl" is + assigned to the "cl" and TRUE is returned. + + @param[out] cl Variable to store collation. + @param[in] cl_name Collation name. + @param[in] default_cl Default collation. + + @return FALSE if collation was resolved successfully; TRUE if there is no + collation with given name. +*/ + +bool resolve_collation(CHARSET_INFO **cl, + const char *cl_name, + CHARSET_INFO *default_cl) +{ + *cl= get_charset_by_name(cl_name, MYF(0)); + + if (*cl == NULL) + { + *cl= default_cl; + return TRUE; + } + + return FALSE; +} + + /* Escape string with backslashes (\) diff --git a/sql/handler.cc b/sql/handler.cc index afb88dc962d..79719745119 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3376,8 +3376,8 @@ TYPELIB *ha_known_exts(void) const char **ext, *old_ext; known_extensions_id= mysys_usage_id; - found_exts.push_back((char*) triggers_file_ext); - found_exts.push_back((char*) trigname_file_ext); + found_exts.push_back((char*) TRG_EXT); + found_exts.push_back((char*) TRN_EXT); plugin_foreach(NULL, exts_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &found_exts); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9b9f9340c3f..762fafdaaa7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -101,7 +101,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \ (Old), (Ver), (New)); \ else \ - sql_print_warning("The syntax %s is deprecated and will be removed " \ + sql_print_warning("The syntax '%s' is deprecated and will be removed " \ "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \ } while(0) @@ -1590,6 +1590,7 @@ bool check_db_dir_existence(const char *db_name); bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create); bool load_db_opt_by_name(THD *thd, const char *db_name, HA_CREATE_INFO *db_create_info); +CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name); bool my_dbopt_init(void); void my_dbopt_cleanup(void); extern int creating_database; // How many database locks are made @@ -1610,8 +1611,8 @@ extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword; extern const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond; -extern const char * const triggers_file_ext; -extern const char * const trigname_file_ext; +extern const char * const TRG_EXT; +extern const char * const TRN_EXT; extern Eq_creator eq_creator; extern Ne_creator ne_creator; extern Gt_creator gt_creator; @@ -2146,6 +2147,12 @@ bool schema_table_store_record(THD *thd, TABLE *table); int item_create_init(); void item_create_cleanup(); +inline void lex_string_set(LEX_STRING *lex_str, const char *c_str) +{ + lex_str->str= (char *) c_str; + lex_str->length= strlen(c_str); +} + #endif /* MYSQL_SERVER */ #endif /* MYSQL_CLIENT */ diff --git a/sql/sp_head.cc b/sql/sp_head.cc index bd38de2dd42..edfa493da9f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1268,30 +1268,31 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc, #endif // ! NO_EMBEDDED_ACCESS_CHECKS -/* - Execute a trigger: - - changes security context for triggers - - switch to new memroot - - call sp_head::execute - - restore old memroot - - restores security context +/** + Execute trigger stored program. - SYNOPSIS - sp_head::execute_trigger() - thd Thread handle - db database name - table table name - grant_info GRANT_INFO structure to be filled with - information about definer's privileges - on subject table - - RETURN - FALSE on success - TRUE on error + Execute a trigger: + - changes security context for triggers; + - switch to new memroot; + - call sp_head::execute; + - restore old memroot; + - restores security context. + + @param thd Thread context. + @param db_name Database name. + @param table_name Table name. + @param grant_info GRANT_INFO structure to be filled with information + about definer's privileges on subject table. + + @return Error status. + @retval FALSE on success. + @retval TRUE on error. */ bool -sp_head::execute_trigger(THD *thd, const char *db, const char *table, +sp_head::execute_trigger(THD *thd, + const LEX_STRING *db_name, + const LEX_STRING *table_name, GRANT_INFO *grant_info) { sp_rcontext *octx = thd->spcont; @@ -1304,6 +1305,46 @@ sp_head::execute_trigger(THD *thd, const char *db, const char *table, DBUG_ENTER("sp_head::execute_trigger"); DBUG_PRINT("info", ("trigger %s", m_name.str)); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *save_ctx= NULL; + + + if (m_chistics->suid != SP_IS_NOT_SUID && + m_security_ctx.change_security_context(thd, + &m_definer_user, + &m_definer_host, + &m_db, + &save_ctx)) + DBUG_RETURN(TRUE); + + /* + Fetch information about table-level privileges for subject table into + GRANT_INFO instance. The access check itself will happen in + Item_trigger_field, where this information will be used along with + information about column-level privileges. + */ + + fill_effective_table_privileges(thd, + grant_info, + db_name->str, + table_name->str); + + /* Check that the definer has TRIGGER privilege on the subject table. */ + + if (!(grant_info->privilege & TRIGGER_ACL)) + { + char priv_desc[128]; + get_privilege_desc(priv_desc, sizeof(priv_desc), TRIGGER_ACL); + + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc, + thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, + table_name->str); + + m_security_ctx.restore_security_context(thd, save_ctx); + DBUG_RETURN(TRUE); + } +#endif // NO_EMBEDDED_ACCESS_CHECKS + /* Prepare arena and memroot for objects which lifetime is whole duration of trigger call (sp_rcontext, it's tables and items, @@ -1336,6 +1377,11 @@ sp_head::execute_trigger(THD *thd, const char *db, const char *table, err_with_cleanup: thd->restore_active_arena(&call_arena, &backup_arena); + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + m_security_ctx.restore_security_context(thd, save_ctx); +#endif // NO_EMBEDDED_ACCESS_CHECKS + delete nctx; call_arena.free_items(); free_root(&call_mem_root, MYF(0)); diff --git a/sql/sp_head.h b/sql/sp_head.h index 89af0259706..f3c3ebfe6e8 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -216,8 +216,10 @@ public: destroy(); bool - execute_trigger(THD *thd, const char *db, const char *table, - GRANT_INFO *grant_onfo); + execute_trigger(THD *thd, + const LEX_STRING *db_name, + const LEX_STRING *table_name, + GRANT_INFO *grant_info); bool execute_function(THD *thd, Item **args, uint argcount, Field *return_fld); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 82938184245..43d84740f0b 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -538,6 +538,37 @@ bool load_db_opt_by_name(THD *thd, const char *db_name, } +/** + Return default database collation. + + @param thd Thread context. + @param db_name Database name. + + @return CHARSET_INFO object. The operation always return valid character + set, even if the database does not exist. +*/ + +CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name) +{ + HA_CREATE_INFO db_info; + + if (thd->db != NULL && strcmp(db_name, thd->db) == 0) + return thd->db_charset; + + load_db_opt_by_name(thd, db_name, &db_info); + + /* + NOTE: even if load_db_opt_by_name() fails, + db_info.default_table_charset contains valid character set + (collation_server). We should not fail if load_db_opt_by_name() fails, + because it is valid case. If a database has been created just by + "mkdir", it does not contain db.opt file, but it is valid database. + */ + + return db_info.default_table_charset; +} + + /* Create a database @@ -751,10 +782,8 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if ((error=write_db_opt(thd, path, create_info))) goto exit; - /* - Change options if current database is being altered - TODO: Delete this code - */ + /* Change options if current database is being altered. */ + if (thd->db && !strcmp(thd->db,db)) { thd->db_charset= create_info->default_table_charset ? @@ -1358,6 +1387,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) Security_context *sctx= thd->security_ctx; ulong db_access= sctx->db_access; + CHARSET_INFO *db_default_cl; DBUG_ENTER("mysql_change_db"); DBUG_PRINT("enter",("name: '%s'", new_db_name->str)); @@ -1487,16 +1517,9 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) attributes and will be freed in THD::~THD(). */ - { - HA_CREATE_INFO db_options; + db_default_cl= get_default_db_collation(thd, new_db_file_name.str); - load_db_opt_by_name(thd, new_db_name->str, &db_options); - - mysql_change_db_impl(thd, &new_db_file_name, db_access, - db_options.default_table_charset ? - db_options.default_table_charset : - thd->variables.collation_server); - } + mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl); DBUG_RETURN(FALSE); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index ded3a0a6e24..7433a3f45cd 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -23,7 +23,7 @@ static const LEX_STRING triggers_file_type= { C_STRING_WITH_LEN("TRIGGERS") }; -const char * const triggers_file_ext= ".TRG"; +const char * const TRG_EXT= ".TRG"; /* Table of .TRG file field descriptors. @@ -79,7 +79,7 @@ struct st_trigname static const LEX_STRING trigname_file_type= { C_STRING_WITH_LEN("TRIGGERNAME") }; -const char * const trigname_file_ext= ".TRN"; +const char * const TRN_EXT= ".TRN"; static File_option trigname_file_parameters[]= { @@ -132,6 +132,7 @@ private: LEX_STRING *trigger_table_value; }; + /* Create or drop trigger for table. @@ -463,14 +464,14 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, sql_create_definition_file() files handles renaming and backup of older versions */ - file.length= build_table_filename(file_buff, FN_REFLEN-1, + file.length= build_table_filename(file_buff, FN_REFLEN - 1, tables->db, tables->table_name, - triggers_file_ext, 0); + TRG_EXT, 0); file.str= file_buff; trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1, tables->db, lex->spname->m_name.str, - trigname_file_ext, 0); + TRN_EXT, 0); trigname_file.str= trigname_buff; /* Use the filesystem to enforce trigger namespace constraints. */ @@ -604,7 +605,7 @@ err_with_cleanup: static bool rm_trigger_file(char *path, const char *db, const char *table_name) { - build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext, 0); + build_table_filename(path, FN_REFLEN-1, db, table_name, TRG_EXT, 0); return my_delete(path, MYF(MY_WME)); } @@ -627,8 +628,7 @@ static bool rm_trigger_file(char *path, const char *db, static bool rm_trigname_file(char *path, const char *db, const char *trigger_name) { - build_table_filename(path, FN_REFLEN-1, - db, trigger_name, trigname_file_ext, 0); + build_table_filename(path, FN_REFLEN - 1, db, trigger_name, TRN_EXT, 0); return my_delete(path, MYF(MY_WME)); } @@ -653,8 +653,8 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db, char file_buff[FN_REFLEN]; LEX_STRING file; - file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name, - triggers_file_ext, 0); + file.length= build_table_filename(file_buff, FN_REFLEN - 1, db, table_name, + TRG_EXT, 0); file.str= file_buff; return sql_create_definition_file(NULL, &file, &triggers_file_type, (uchar*)triggers, triggers_file_parameters, @@ -834,8 +834,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_ENTER("Table_triggers_list::check_n_load"); - path.length= build_table_filename(path_buff, FN_REFLEN-1, - db, table_name, triggers_file_ext, 0); + path.length= build_table_filename(path_buff, FN_REFLEN - 1, + db, table_name, TRG_EXT, 0); path.str= path_buff; // QQ: should we analyze errno somehow ? @@ -1106,7 +1106,7 @@ err_with_lex_cleanup: be merged into .FRM anyway. */ my_error(ER_WRONG_OBJECT, MYF(0), - table_name, triggers_file_ext+1, "TRIGGER"); + table_name, TRG_EXT + 1, "TRIGGER"); DBUG_RETURN(1); } @@ -1166,83 +1166,66 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event, } -/* +/** Find trigger's table from trigger identifier and add it to the statement table list. - SYNOPSIS - mysql_table_for_trigger() - thd - current thread context - trig - identifier for trigger - if_exists - treat a not existing trigger as a warning if TRUE - table - pointer to TABLE_LIST object for the table trigger (output) + @param[in] thd Thread context. + @param[in] trg_name Trigger name. + @param[in] if_exists TRUE if SQL statement contains "IF EXISTS" clause. + That means a warning instead of error should be + thrown if trigger with given name does not exist. + @param[out] table Pointer to TABLE_LIST object for the + table trigger. - RETURN VALUE - 0 Success - 1 Error + @return Operation status + @retval FALSE On success. + @retval TRUE Otherwise. */ -int -add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists, - TABLE_LIST **table) +bool add_table_for_trigger(THD *thd, + sp_name *trg_name, + bool if_exists, + TABLE_LIST **table) { LEX *lex= thd->lex; - char path_buff[FN_REFLEN]; - LEX_STRING path; - File_parser *parser; - struct st_trigname trigname; - Handle_old_incorrect_trigger_table_hook trigger_table_hook( - path_buff, &trigname.trigger_table); - + char trn_path_buff[FN_REFLEN]; + LEX_STRING trn_path= { trn_path_buff, 0 }; + LEX_STRING tbl_name; + DBUG_ENTER("add_table_for_trigger"); - DBUG_ASSERT(table != NULL); - path.length= build_table_filename(path_buff, FN_REFLEN-1, - trig->m_db.str, trig->m_name.str, - trigname_file_ext, 0); - path.str= path_buff; + build_trn_path(thd, trg_name, &trn_path); - if (access(path_buff, F_OK)) + if (check_trn_exists(&trn_path)) { if (if_exists) { push_warning_printf(thd, - MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_TRG_DOES_NOT_EXIST, - ER(ER_TRG_DOES_NOT_EXIST)); + MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TRG_DOES_NOT_EXIST, + ER(ER_TRG_DOES_NOT_EXIST)); + *table= NULL; - DBUG_RETURN(0); + + DBUG_RETURN(FALSE); } my_error(ER_TRG_DOES_NOT_EXIST, MYF(0)); - DBUG_RETURN(1); + DBUG_RETURN(TRUE); } - if (!(parser= sql_parse_prepare(&path, thd->mem_root, 1))) - DBUG_RETURN(1); - - if (!is_equal(&trigname_file_type, parser->type())) - { - my_error(ER_WRONG_OBJECT, MYF(0), trig->m_name.str, trigname_file_ext+1, - "TRIGGERNAME"); - DBUG_RETURN(1); - } - - if (parser->parse((uchar*)&trigname, thd->mem_root, - trigname_file_parameters, 1, - &trigger_table_hook)) - DBUG_RETURN(1); + if (load_table_name_for_trigger(thd, trg_name, &trn_path, &tbl_name)) + DBUG_RETURN(TRUE); /* We need to reset statement table list to be PS/SP friendly. */ lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; - *table= sp_add_to_query_tables(thd, lex, trig->m_db.str, - trigname.trigger_table.str, TL_IGNORE); - if (! *table) - DBUG_RETURN(1); + *table= sp_add_to_query_tables(thd, lex, trg_name->m_db.str, + tbl_name.str, TL_IGNORE); - DBUG_RETURN(0); + DBUG_RETURN(*table ? FALSE : TRUE); } @@ -1426,7 +1409,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name, { trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1, db_name, trigger->str, - trigname_file_ext, 0); + TRN_EXT, 0); trigname_file.str= trigname_buff; trigname.trigger_table= *new_table_name; @@ -1535,77 +1518,54 @@ end: } -bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, +/** + Execute trigger for given (event, time) pair. + + The operation executes trigger for the specified event (insert, update, + delete) and time (after, before) if it is set. + + @param thd + @param event + @param time_type, + @param old_row_is_record1 + + @return Error status. + @retval FALSE on success. + @retval TRUE on error. +*/ + +bool Table_triggers_list::process_triggers(THD *thd, + trg_event_type event, trg_action_time_type time_type, bool old_row_is_record1) { - bool err_status= FALSE; - sp_head *sp_trigger= bodies[event][time_type]; + bool err_status; + Sub_statement_state statement_state; - if (sp_trigger) + if (!bodies[event][time_type]) + return FALSE; + + if (old_row_is_record1) { - Sub_statement_state statement_state; - - if (old_row_is_record1) - { - old_field= record1_field; - new_field= trigger_table->field; - } - else - { - new_field= record1_field; - old_field= trigger_table->field; - } -#ifndef NO_EMBEDDED_ACCESS_CHECKS - Security_context *sctx= &sp_trigger->m_security_ctx; - Security_context *save_ctx= NULL; - - - if (sp_trigger->m_chistics->suid != SP_IS_NOT_SUID && - sctx->change_security_context(thd, - &sp_trigger->m_definer_user, - &sp_trigger->m_definer_host, - &sp_trigger->m_db, - &save_ctx)) - return TRUE; - - /* - Fetch information about table-level privileges to GRANT_INFO structure for - subject table. Check of privileges that will use it and information about - column-level privileges will happen in Item_trigger_field::fix_fields(). - */ - - fill_effective_table_privileges(thd, - &subject_table_grants[event][time_type], - trigger_table->s->db.str, - trigger_table->s->table_name.str); - - /* Check that the definer has TRIGGER privilege on the subject table. */ - - if (!(subject_table_grants[event][time_type].privilege & TRIGGER_ACL)) - { - char priv_desc[128]; - get_privilege_desc(priv_desc, sizeof(priv_desc), TRIGGER_ACL); - - my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc, - thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, - trigger_table->s->table_name.str); - - sctx->restore_security_context(thd, save_ctx); - return TRUE; - } -#endif // NO_EMBEDDED_ACCESS_CHECKS - - thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); - err_status= sp_trigger->execute_trigger - (thd, trigger_table->s->db.str, trigger_table->s->table_name.str, - &subject_table_grants[event][time_type]); - thd->restore_sub_statement_state(&statement_state); - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - sctx->restore_security_context(thd, save_ctx); -#endif // NO_EMBEDDED_ACCESS_CHECKS + old_field= record1_field; + new_field= trigger_table->field; } + else + { + new_field= record1_field; + old_field= trigger_table->field; + } + + thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); + + err_status= + bodies[event][time_type]->execute_trigger( + thd, + &trigger_table->s->db, + &trigger_table->s->table_name, + &subject_table_grants[event][time_type]); + + thd->restore_sub_statement_state(&statement_state); return err_status; } @@ -1747,3 +1707,95 @@ process_unknown_string(char *&unknown_key, uchar* base, MEM_ROOT *mem_root, } DBUG_RETURN(FALSE); } + + +/** + Contruct path to TRN-file. + + @param thd[in] Thread context. + @param trg_name[in] Trigger name. + @param trn_path[out] Variable to store constructed path +*/ + +void build_trn_path(THD *thd, const sp_name *trg_name, LEX_STRING *trn_path) +{ + /* Construct path to the TRN-file. */ + + trn_path->length= build_table_filename(trn_path->str, + FN_REFLEN - 1, + trg_name->m_db.str, + trg_name->m_name.str, + TRN_EXT, + 0); +} + + +/** + Check if TRN-file exists. + + @return + @retval TRUE if TRN-file does not exist. + @retval FALSE if TRN-file exists. +*/ + +bool check_trn_exists(const LEX_STRING *trn_path) +{ + return access(trn_path->str, F_OK) != 0; +} + + +/** + Retrieve table name for given trigger. + + @param thd[in] Thread context. + @param trg_name[in] Trigger name. + @param trn_path[in] Path to the corresponding TRN-file. + @param tbl_name[out] Variable to store retrieved table name. + + @return Error status. + @retval FALSE on success. + @retval TRUE if table name could not be retrieved. +*/ + +bool load_table_name_for_trigger(THD *thd, + const sp_name *trg_name, + const LEX_STRING *trn_path, + LEX_STRING *tbl_name) +{ + File_parser *parser; + struct st_trigname trn_data; + + Handle_old_incorrect_trigger_table_hook trigger_table_hook( + trn_path->str, + &trn_data.trigger_table); + + DBUG_ENTER("load_table_name_for_trigger"); + + /* Parse the TRN-file. */ + + if (!(parser= sql_parse_prepare(trn_path, thd->mem_root, TRUE))) + DBUG_RETURN(TRUE); + + if (!is_equal(&trigname_file_type, parser->type())) + { + my_error(ER_WRONG_OBJECT, MYF(0), + trg_name->m_name.str, + TRN_EXT + 1, + "TRIGGERNAME"); + + DBUG_RETURN(TRUE); + } + + if (parser->parse((uchar*) &trn_data, thd->mem_root, + trigname_file_parameters, 1, + &trigger_table_hook)) + DBUG_RETURN(TRUE); + + /* Copy trigger table name. */ + + *tbl_name= trn_data.trigger_table; + + /* That's all. */ + + DBUG_RETURN(FALSE); +} diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 7d99dd811cd..c305efb5029 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -17,7 +17,7 @@ /* This class holds all information about triggers of table. - QQ: Will it be merged into TABLE in future ? + QQ: Will it be merged into TABLE in the future ? */ class Table_triggers_list: public Sql_alloc @@ -143,6 +143,17 @@ private: extern const LEX_STRING trg_action_time_type_names[]; extern const LEX_STRING trg_event_type_names[]; -int -add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists, - TABLE_LIST **table); +bool add_table_for_trigger(THD *thd, + sp_name *trg_name, + bool continue_if_not_exist, + TABLE_LIST **table); + +void build_trn_path(THD *thd, const sp_name *trg_name, LEX_STRING *trn_path); + +bool check_trn_exists(const LEX_STRING *trn_path); + +bool load_table_name_for_trigger(THD *thd, + const sp_name *trg_name, + const LEX_STRING *trn_path, + LEX_STRING *tbl_name); +