Commit 83de46bc authored by unknown's avatar unknown

This the 4-th patch in scope of CS patch (BUG#11986).

The patch contains the following changes:
  - Introduce auxilary functions to convenient work with character sets:
    - resolve_charset();
    - resolve_collation();
    - get_default_db_collation();
  - Introduce lex_string_set();
  - Refactor Table_trigger_list::process_triggers() &
    sp_head::execute_trigger() to be consistent with other code;
  - Move reusable code from add_table_for_trigger() into
    build_trn_path(), check_trn_exists() and load_table_name_for_trigger()
    to be used in the following patch.
  - Rename triggers_file_ext and trigname_file_ext into TRN_EXT and
    TRG_EXT respectively.


include/my_sys.h:
  Introduced auxilary functions (to be used in the following patch).
mysys/charset.c:
  Introduced auxilary functions (to be used in the following patch).
sql/handler.cc:
  Rename triggers_file_ext -> TRG_EXT;
  Rename trigname_file_ext -> TRN_EXT.
sql/mysql_priv.h:
  1. Fix typo;
  2. Introduce auxilary functions (set_lex_string() will  be used
     in the following patch);
  3. Rename triggers_file_ext -> TRG_EXT;
     Rename trigname_file_ext -> TRN_EXT.
sql/sp_head.cc:
  Make sp_head::execute_trigger() consistent with
  sp_head::execute_function() and sp_head::execute_procedure().
sql/sp_head.h:
  Make sp_head::execute_trigger() consistent with
  sp_head::execute_function() and sp_head::execute_procedure().
sql/sql_db.cc:
  1. Introduce auxilary function.
  2. Polishing.
sql/sql_trigger.cc:
  1. Move common code from add_table_for_trigger() into
     - build_trn_path();
     - check_trn_exists();
     - load_table_name_for_trigger();
  2. Polishing.
sql/sql_trigger.h:
  1. Move common code from add_table_for_trigger() into
     - build_trn_path();
     - check_trn_exists();
     - load_table_name_for_trigger();
  2. Polishing.
parent c7aeb8f3
...@@ -904,6 +904,14 @@ extern CHARSET_INFO *get_charset(uint cs_number, myf flags); ...@@ -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_name(const char *cs_name, myf flags);
extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, extern CHARSET_INFO *get_charset_by_csname(const char *cs_name,
uint cs_flags, myf my_flags); 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 void free_charsets(void);
extern char *get_charsets_dir(char *buf); extern char *get_charsets_dir(char *buf);
extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2);
......
...@@ -573,6 +573,70 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name, ...@@ -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 (\) Escape string with backslashes (\)
......
...@@ -3376,8 +3376,8 @@ TYPELIB *ha_known_exts(void) ...@@ -3376,8 +3376,8 @@ TYPELIB *ha_known_exts(void)
const char **ext, *old_ext; const char **ext, *old_ext;
known_extensions_id= mysys_usage_id; known_extensions_id= mysys_usage_id;
found_exts.push_back((char*) triggers_file_ext); found_exts.push_back((char*) TRG_EXT);
found_exts.push_back((char*) trigname_file_ext); found_exts.push_back((char*) TRN_EXT);
plugin_foreach(NULL, exts_handlerton, plugin_foreach(NULL, exts_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &found_exts); MYSQL_STORAGE_ENGINE_PLUGIN, &found_exts);
......
...@@ -101,7 +101,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); ...@@ -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), \ ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
(Old), (Ver), (New)); \ (Old), (Ver), (New)); \
else \ 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)); \ "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
} while(0) } while(0)
...@@ -1590,6 +1590,7 @@ bool check_db_dir_existence(const char *db_name); ...@@ -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(THD *thd, const char *path, HA_CREATE_INFO *create);
bool load_db_opt_by_name(THD *thd, const char *db_name, bool load_db_opt_by_name(THD *thd, const char *db_name,
HA_CREATE_INFO *db_create_info); HA_CREATE_INFO *db_create_info);
CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name);
bool my_dbopt_init(void); bool my_dbopt_init(void);
void my_dbopt_cleanup(void); void my_dbopt_cleanup(void);
extern int creating_database; // How many database locks are made 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; ...@@ -1610,8 +1611,8 @@ extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */ extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str; extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond; extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
extern const char * const triggers_file_ext; extern const char * const TRG_EXT;
extern const char * const trigname_file_ext; extern const char * const TRN_EXT;
extern Eq_creator eq_creator; extern Eq_creator eq_creator;
extern Ne_creator ne_creator; extern Ne_creator ne_creator;
extern Gt_creator gt_creator; extern Gt_creator gt_creator;
...@@ -2146,6 +2147,12 @@ bool schema_table_store_record(THD *thd, TABLE *table); ...@@ -2146,6 +2147,12 @@ bool schema_table_store_record(THD *thd, TABLE *table);
int item_create_init(); int item_create_init();
void item_create_cleanup(); 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_SERVER */
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
......
...@@ -1268,30 +1268,31 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc, ...@@ -1268,30 +1268,31 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
#endif // ! NO_EMBEDDED_ACCESS_CHECKS #endif // ! NO_EMBEDDED_ACCESS_CHECKS
/* /**
Execute trigger stored program.
Execute a trigger: Execute a trigger:
- changes security context for triggers - changes security context for triggers;
- switch to new memroot - switch to new memroot;
- call sp_head::execute - call sp_head::execute;
- restore old memroot - restore old memroot;
- restores security context - 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.
SYNOPSIS @return Error status.
sp_head::execute_trigger() @retval FALSE on success.
thd Thread handle @retval TRUE on error.
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
*/ */
bool 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) GRANT_INFO *grant_info)
{ {
sp_rcontext *octx = thd->spcont; sp_rcontext *octx = thd->spcont;
...@@ -1304,6 +1305,46 @@ sp_head::execute_trigger(THD *thd, const char *db, const char *table, ...@@ -1304,6 +1305,46 @@ sp_head::execute_trigger(THD *thd, const char *db, const char *table,
DBUG_ENTER("sp_head::execute_trigger"); DBUG_ENTER("sp_head::execute_trigger");
DBUG_PRINT("info", ("trigger %s", m_name.str)); 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 Prepare arena and memroot for objects which lifetime is whole
duration of trigger call (sp_rcontext, it's tables and items, 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, ...@@ -1336,6 +1377,11 @@ sp_head::execute_trigger(THD *thd, const char *db, const char *table,
err_with_cleanup: err_with_cleanup:
thd->restore_active_arena(&call_arena, &backup_arena); 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; delete nctx;
call_arena.free_items(); call_arena.free_items();
free_root(&call_mem_root, MYF(0)); free_root(&call_mem_root, MYF(0));
......
...@@ -216,8 +216,10 @@ public: ...@@ -216,8 +216,10 @@ public:
destroy(); destroy();
bool bool
execute_trigger(THD *thd, const char *db, const char *table, execute_trigger(THD *thd,
GRANT_INFO *grant_onfo); const LEX_STRING *db_name,
const LEX_STRING *table_name,
GRANT_INFO *grant_info);
bool bool
execute_function(THD *thd, Item **args, uint argcount, Field *return_fld); execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
......
...@@ -538,6 +538,37 @@ bool load_db_opt_by_name(THD *thd, const char *db_name, ...@@ -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 Create a database
...@@ -751,10 +782,8 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) ...@@ -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))) if ((error=write_db_opt(thd, path, create_info)))
goto exit; goto exit;
/* /* Change options if current database is being altered. */
Change options if current database is being altered
TODO: Delete this code
*/
if (thd->db && !strcmp(thd->db,db)) if (thd->db && !strcmp(thd->db,db))
{ {
thd->db_charset= create_info->default_table_charset ? 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) ...@@ -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; Security_context *sctx= thd->security_ctx;
ulong db_access= sctx->db_access; ulong db_access= sctx->db_access;
CHARSET_INFO *db_default_cl;
DBUG_ENTER("mysql_change_db"); DBUG_ENTER("mysql_change_db");
DBUG_PRINT("enter",("name: '%s'", new_db_name->str)); 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) ...@@ -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(). attributes and will be freed in THD::~THD().
*/ */
{ db_default_cl= get_default_db_collation(thd, new_db_file_name.str);
HA_CREATE_INFO db_options;
load_db_opt_by_name(thd, new_db_name->str, &db_options); mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl);
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);
}
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
......
This diff is collapsed.
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
/* /*
This class holds all information about triggers of table. 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 class Table_triggers_list: public Sql_alloc
...@@ -143,6 +143,17 @@ private: ...@@ -143,6 +143,17 @@ private:
extern const LEX_STRING trg_action_time_type_names[]; extern const LEX_STRING trg_action_time_type_names[];
extern const LEX_STRING trg_event_type_names[]; extern const LEX_STRING trg_event_type_names[];
int bool add_table_for_trigger(THD *thd,
add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists, sp_name *trg_name,
TABLE_LIST **table); 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment