summaryrefslogtreecommitdiff
path: root/sql/sql_trigger.cc
diff options
context:
space:
mode:
authorunknown <anozdrin/alik@ibm.>2007-06-28 21:34:54 +0400
committerunknown <anozdrin/alik@ibm.>2007-06-28 21:34:54 +0400
commit405f82d390f71c510a1da9f8495ae61d249504e0 (patch)
tree7d6b94b3baf75de8b22461e2161e5461fc54cbd6 /sql/sql_trigger.cc
parent1685f7480f4661e9b4664a9f1a434be862ef73c5 (diff)
downloadmariadb-git-405f82d390f71c510a1da9f8495ae61d249504e0.tar.gz
Patch for the following bugs:
- BUG#11986: Stored routines and triggers can fail if the code has a non-ascii symbol - BUG#16291: mysqldump corrupts string-constants with non-ascii-chars - BUG#19443: INFORMATION_SCHEMA does not support charsets properly - BUG#21249: Character set of SP-var can be ignored - BUG#25212: Character set of string constant is ignored (stored routines) - BUG#25221: Character set of string constant is ignored (triggers) There were a few general problems that caused these bugs: 1. Character set information of the original (definition) query for views, triggers, stored routines and events was lost. 2. mysqldump output query in client character set, which can be inappropriate to encode definition-query. 3. INFORMATION_SCHEMA used strings with mixed encodings to display object definition; 1. No query-definition-character set. In order to compile query into execution code, some extra data (such as environment variables or the database character set) is used. The problem here was that this context was not preserved. So, on the next load it can differ from the original one, thus the result will be different. The context contains the following data: - client character set; - connection collation (character set and collation); - collation of the owner database; The fix is to store this context and use it each time we parse (compile) and execute the object (stored routine, trigger, ...). 2. Wrong mysqldump-output. The original query can contain several encodings (by means of character set introducers). The problem here was that we tried to convert original query to the mysqldump-client character set. Moreover, we stored queries in different character sets for different objects (views, for one, used UTF8, triggers used original character set). The solution is - to store definition queries in the original character set; - to change SHOW CREATE statement to output definition query in the binary character set (i.e. without any conversion); - introduce SHOW CREATE TRIGGER statement; - to dump special statements to switch the context to the original one before dumping and restore it afterwards. Note, in order to preserve the database collation at the creation time, additional ALTER DATABASE might be used (to temporary switch the database collation back to the original value). In this case, ALTER DATABASE privilege will be required. This is a backward-incompatible change. 3. INFORMATION_SCHEMA showed non-UTF8 strings The fix is to generate UTF8-query during the parsing, store it in the object and show it in the INFORMATION_SCHEMA. Basically, the idea is to create a copy of the original query convert it to UTF8. Character set introducers are removed and all text literals are converted to UTF8. This UTF8 query is intended to provide user-readable output. It must not be used to recreate the object. Specialized SHOW CREATE statements should be used for this. The reason for this limitation is the following: the original query can contain symbols from several character sets (by means of character set introducers). Example: - original query: CREATE VIEW v1 AS SELECT _cp1251 'Hello' AS c1; - UTF8 query (for INFORMATION_SCHEMA): CREATE VIEW v1 AS SELECT 'Hello' AS c1; client/mysqldump.c: Set original character set and collation before dumping definition query. include/my_sys.h: Move out-parameter to the end of list. mysql-test/lib/mtr_report.pl: Ignore server-warnings during the test case. mysql-test/r/create.result: Update result file. mysql-test/r/ctype_cp932_binlog_stm.result: Update result file. mysql-test/r/events.result: Update result file. mysql-test/r/events_bugs.result: Update result file. mysql-test/r/events_grant.result: Update result file. mysql-test/r/func_in.result: Update result file. mysql-test/r/gis.result: Update result file. mysql-test/r/grant.result: Update result file. mysql-test/r/information_schema.result: Update result file. mysql-test/r/information_schema_db.result: Update result file. mysql-test/r/lowercase_view.result: Update result file. mysql-test/r/mysqldump.result: Update result file. mysql-test/r/ndb_sp.result: Update result file. mysql-test/r/ps.result: Update result file. mysql-test/r/rpl_replicate_do.result: Update result file. mysql-test/r/rpl_sp.result: Update result file. mysql-test/r/rpl_trigger.result: Update result file. mysql-test/r/rpl_view.result: Update result file. mysql-test/r/show_check.result: Update result file. mysql-test/r/skip_grants.result: Update result file. mysql-test/r/sp-destruct.result: Update result file. mysql-test/r/sp-error.result: Update result file. mysql-test/r/sp-security.result: Update result file. mysql-test/r/sp.result: Update result file. mysql-test/r/sql_mode.result: Update result file. mysql-test/r/system_mysql_db.result: Update result file. mysql-test/r/temp_table.result: Update result file. mysql-test/r/trigger-compat.result: Update result file. mysql-test/r/trigger-grant.result: Update result file. mysql-test/r/trigger.result: Update result file. mysql-test/r/view.result: Update result file. mysql-test/r/view_grant.result: Update result file. mysql-test/t/events.test: Update test case (new columns added). mysql-test/t/information_schema.test: Update test case (new columns added). mysql-test/t/show_check.test: Test case for SHOW CREATE TRIGGER in prepared statements and stored routines. mysql-test/t/sp-destruct.test: Update test case (new columns added). mysql-test/t/sp.test: Update test case (new columns added). mysql-test/t/view.test: Update test. mysys/charset.c: Move out-parameter to the end of list. scripts/mysql_system_tables.sql: Add new columns to mysql.proc and mysql.event. scripts/mysql_system_tables_fix.sql: Add new columns to mysql.proc and mysql.event. sql/event_data_objects.cc: Support new attributes for events. sql/event_data_objects.h: Support new attributes for events. sql/event_db_repository.cc: Support new attributes for events. sql/event_db_repository.h: Support new attributes for events. sql/events.cc: Add new columns to SHOW CREATE event resultset. sql/mysql_priv.h: 1. Introduce Object_creation_ctx; 2. Introduce SHOW CREATE TRIGGER; 3. Introduce auxilary functions. sql/sp.cc: Add support for new store routines attributes. sql/sp_head.cc: Add support for new store routines attributes. sql/sp_head.h: Add support for new store routines attributes. sql/sql_lex.cc: Generate UTF8-body on parsing/lexing. sql/sql_lex.h: 1. Generate UTF8-body on parsing/lexing. 2. Introduce SHOW CREATE TRIGGER. sql/sql_parse.cc: Introduce SHOW CREATE TRIGGER. sql/sql_partition.cc: Update parse_sql(). sql/sql_prepare.cc: Update parse_sql(). sql/sql_show.cc: Support new attributes for views sql/sql_trigger.cc: Support new attributes for views sql/sql_trigger.h: Support new attributes for views sql/sql_view.cc: Support new attributes for views sql/sql_yacc.yy: 1. Add SHOW CREATE TRIGGER statement. 2. Generate UTF8-body for views, stored routines, triggers and events. sql/table.cc: Introduce Object_creation_ctx. sql/table.h: Introduce Object_creation_ctx. sql/share/errmsg.txt: Add new errors. mysql-test/include/ddl_i18n.check_events.inc: Aux file for test suite. mysql-test/include/ddl_i18n.check_sp.inc: Aux file for test suite. mysql-test/include/ddl_i18n.check_triggers.inc: Aux file for test suite. mysql-test/include/ddl_i18n.check_views.inc: Aux file for test suite. mysql-test/include/have_cp1251.inc: Aux file for test suite. mysql-test/include/have_cp866.inc: Aux file for test suite. mysql-test/include/have_koi8r.inc: Aux file for test suite. mysql-test/include/have_utf8.inc: Aux file for test suite. mysql-test/r/ddl_i18n_koi8r.result: Result file. mysql-test/r/ddl_i18n_utf8.result: Result file. mysql-test/r/have_cp1251.require: Aux file for test suite. mysql-test/r/have_cp866.require: Aux file for test suite. mysql-test/r/have_koi8r.require: Aux file for test suite. mysql-test/r/have_utf8.require: Aux file for test suite. mysql-test/t/ddl_i18n_koi8r.test: Complete koi8r test case for the CS patch. mysql-test/t/ddl_i18n_utf8.test: Complete utf8 test case for the CS patch.
Diffstat (limited to 'sql/sql_trigger.cc')
-rw-r--r--sql/sql_trigger.cc417
1 files changed, 387 insertions, 30 deletions
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 7c28dff850a..06dd0dded43 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -20,6 +20,149 @@
#include "sql_trigger.h"
#include "parse_file.h"
+/*************************************************************************/
+
+template <class T>
+inline T *alloc_type(MEM_ROOT *m)
+{
+ return (T *) alloc_root(m, sizeof (T));
+}
+
+/*
+ NOTE: Since alloc_type() is declared as inline, alloc_root() calls should
+ be inlined by the compiler. So, implementation of alloc_root() is not
+ needed. However, let's put the implementation in object file just in case
+ of stupid MS or other old compilers.
+*/
+
+template LEX_STRING *alloc_type<LEX_STRING>(MEM_ROOT *m);
+template ulonglong *alloc_type<ulonglong>(MEM_ROOT *m);
+
+inline LEX_STRING *alloc_lex_string(MEM_ROOT *m)
+{
+ return alloc_type<LEX_STRING>(m);
+}
+
+/*************************************************************************/
+/**
+ Trigger_creation_ctx -- creation context of triggers.
+*/
+
+class Trigger_creation_ctx : public Stored_program_creation_ctx,
+ public Sql_alloc
+{
+public:
+ static Trigger_creation_ctx *create(THD *thd,
+ const char *db_name,
+ const char *table_name,
+ const LEX_STRING *client_cs_name,
+ const LEX_STRING *connection_cl_name,
+ const LEX_STRING *db_cl_name);
+
+public:
+ virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root)
+ {
+ return new (mem_root) Trigger_creation_ctx(m_client_cs,
+ m_connection_cl,
+ m_db_cl);
+ }
+
+protected:
+ virtual Object_creation_ctx *create_backup_ctx(THD *thd) const
+ {
+ return new Trigger_creation_ctx(thd);
+ }
+
+private:
+ Trigger_creation_ctx(THD *thd)
+ :Stored_program_creation_ctx(thd)
+ { }
+
+ Trigger_creation_ctx(CHARSET_INFO *client_cs,
+ CHARSET_INFO *connection_cl,
+ CHARSET_INFO *db_cl)
+ :Stored_program_creation_ctx(client_cs, connection_cl, db_cl)
+ { }
+};
+
+/**************************************************************************
+ Trigger_creation_ctx implementation.
+**************************************************************************/
+
+Trigger_creation_ctx *
+Trigger_creation_ctx::create(THD *thd,
+ const char *db_name,
+ const char *table_name,
+ const LEX_STRING *client_cs_name,
+ const LEX_STRING *connection_cl_name,
+ const LEX_STRING *db_cl_name)
+{
+ CHARSET_INFO *client_cs;
+ CHARSET_INFO *connection_cl;
+ CHARSET_INFO *db_cl;
+
+ bool invalid_creation_ctx= FALSE;
+
+ if (resolve_charset(client_cs_name->str,
+ thd->variables.character_set_client,
+ &client_cs))
+ {
+ sql_print_warning("Trigger for table '%s'.'%s': "
+ "invalid character_set_client value (%s).",
+ (const char *) db_name,
+ (const char *) table_name,
+ (const char *) client_cs_name->str);
+
+ invalid_creation_ctx= TRUE;
+ }
+
+ if (resolve_collation(connection_cl_name->str,
+ thd->variables.collation_connection,
+ &connection_cl))
+ {
+ sql_print_warning("Trigger for table '%s'.'%s': "
+ "invalid collation_connection value (%s).",
+ (const char *) db_name,
+ (const char *) table_name,
+ (const char *) connection_cl_name->str);
+
+ invalid_creation_ctx= TRUE;
+ }
+
+ if (resolve_collation(db_cl_name->str, NULL, &db_cl))
+ {
+ sql_print_warning("Trigger for table '%s'.'%s': "
+ "invalid database_collation value (%s).",
+ (const char *) db_name,
+ (const char *) table_name,
+ (const char *) db_cl_name->str);
+
+ invalid_creation_ctx= TRUE;
+ }
+
+ if (invalid_creation_ctx)
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_INVALID_CREATION_CTX,
+ ER(ER_TRG_INVALID_CREATION_CTX),
+ (const char *) db_name,
+ (const char *) table_name);
+ }
+
+ /*
+ If we failed to resolve the database collation, load the default one
+ from the disk.
+ */
+
+ if (!db_cl)
+ db_cl= get_default_db_collation(thd, db_name);
+
+ return new Trigger_creation_ctx(client_cs, connection_cl, db_cl);
+}
+
+/*************************************************************************/
+
static const LEX_STRING triggers_file_type=
{ C_STRING_WITH_LEN("TRIGGERS") };
@@ -48,6 +191,21 @@ static File_option triggers_file_parameters[]=
my_offsetof(class Table_triggers_list, definers_list),
FILE_OPTIONS_STRLIST
},
+ {
+ { C_STRING_WITH_LEN("client_cs_names") },
+ my_offsetof(class Table_triggers_list, client_cs_names),
+ FILE_OPTIONS_STRLIST
+ },
+ {
+ { C_STRING_WITH_LEN("connection_cl_names") },
+ my_offsetof(class Table_triggers_list, connection_cl_names),
+ FILE_OPTIONS_STRLIST
+ },
+ {
+ { C_STRING_WITH_LEN("db_cl_names") },
+ my_offsetof(class Table_triggers_list, db_cl_names),
+ FILE_OPTIONS_STRLIST
+ },
{ { 0, 0 }, 0, FILE_OPTIONS_STRING }
};
@@ -64,7 +222,7 @@ File_option sql_modes_parameters=
.trg file.
*/
-static const int TRG_NUM_REQUIRED_PARAMETERS= 4;
+static const int TRG_NUM_REQUIRED_PARAMETERS= 6;
/*
Structure representing contents of .TRN file which are used to support
@@ -118,6 +276,7 @@ public:
MEM_ROOT *mem_root, char *end);
};
+
class Handle_old_incorrect_trigger_table_hook: public Unknown_key_hook
{
public:
@@ -359,6 +518,9 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
LEX_STRING *trg_definer;
Item_trigger_field *trg_field;
struct st_trigname trigname;
+ LEX_STRING *trg_client_cs_name;
+ LEX_STRING *trg_connection_cl_name;
+ LEX_STRING *trg_db_cl_name;
/* Trigger must be in the same schema as target table. */
@@ -489,16 +651,26 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
QQ: Hmm... probably we should not care about setting up active thread
mem_root too.
*/
- if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root,
- sizeof(LEX_STRING))) ||
+ if (!(trg_def= alloc_lex_string(&table->mem_root)) ||
definitions_list.push_back(trg_def, &table->mem_root) ||
- !(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root,
- sizeof(ulonglong))) ||
+
+ !(trg_sql_mode= alloc_type<ulonglong>(&table->mem_root)) ||
definition_modes_list.push_back(trg_sql_mode, &table->mem_root) ||
- !(trg_definer= (LEX_STRING*) alloc_root(&table->mem_root,
- sizeof(LEX_STRING))) ||
- definers_list.push_back(trg_definer, &table->mem_root))
+
+ !(trg_definer= alloc_lex_string(&table->mem_root)) ||
+ definers_list.push_back(trg_definer, &table->mem_root) ||
+
+ !(trg_client_cs_name= alloc_lex_string(&table->mem_root)) ||
+ client_cs_names.push_back(trg_client_cs_name, &table->mem_root) ||
+
+ !(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) ||
+ connection_cl_names.push_back(trg_connection_cl_name, &table->mem_root) ||
+
+ !(trg_db_cl_name= alloc_lex_string(&table->mem_root)) ||
+ db_cl_names.push_back(trg_db_cl_name, &table->mem_root))
+ {
goto err_with_cleanup;
+ }
*trg_sql_mode= thd->variables.sql_mode;
@@ -541,6 +713,21 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
}
/*
+ Fill character set information:
+ - client character set contains charset info only;
+ - connection collation contains pair {character set, collation};
+ - database collation contains pair {character set, collation};
+ */
+
+ lex_string_set(trg_client_cs_name, thd->charset()->csname);
+
+ lex_string_set(trg_connection_cl_name,
+ thd->variables.collation_connection->name);
+
+ lex_string_set(trg_db_cl_name,
+ get_default_db_collation(thd, tables->db)->name);
+
+ /*
Create well-formed trigger definition query. Original query is not
appropriated, because definer-clause can be not truncated.
*/
@@ -674,14 +861,20 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables,
String *stmt_query)
{
- LEX *lex= thd->lex;
+ const char *sp_name= thd->lex->spname->m_name.str; // alias
+
LEX_STRING *name;
- List_iterator_fast<LEX_STRING> it_name(names_list);
- List_iterator<LEX_STRING> it_def(definitions_list);
- List_iterator<ulonglong> it_mod(definition_modes_list);
- List_iterator<LEX_STRING> it_definer(definers_list);
char path[FN_REFLEN];
+ List_iterator_fast<LEX_STRING> it_name(names_list);
+
+ List_iterator<ulonglong> it_mod(definition_modes_list);
+ List_iterator<LEX_STRING> it_def(definitions_list);
+ List_iterator<LEX_STRING> it_definer(definers_list);
+ List_iterator<LEX_STRING> it_client_cs_name(client_cs_names);
+ List_iterator<LEX_STRING> it_connection_cl_name(connection_cl_names);
+ List_iterator<LEX_STRING> it_db_cl_name(db_cl_names);
+
stmt_query->append(thd->query, thd->query_length);
while ((name= it_name++))
@@ -689,9 +882,11 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables,
it_def++;
it_mod++;
it_definer++;
+ it_client_cs_name++;
+ it_connection_cl_name++;
+ it_db_cl_name++;
- if (my_strcasecmp(table_alias_charset, lex->spname->m_name.str,
- name->str) == 0)
+ if (my_strcasecmp(table_alias_charset, sp_name, name->str) == 0)
{
/*
Again we don't care much about other things required for
@@ -700,6 +895,9 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables,
it_def.remove();
it_mod.remove();
it_definer.remove();
+ it_client_cs_name.remove();
+ it_connection_cl_name.remove();
+ it_db_cl_name.remove();
if (definitions_list.is_empty())
{
@@ -718,7 +916,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables,
return 1;
}
- if (rm_trigname_file(path, tables->db, lex->spname->m_name.str))
+ if (rm_trigname_file(path, tables->db, sp_name))
return 1;
return 0;
}
@@ -857,9 +1055,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
we should initialize the list for safety:
- sql_modes;
- definers;
+ - character sets (client, connection, database);
*/
triggers->definition_modes_list.empty();
triggers->definers_list.empty();
+ triggers->client_cs_names.empty();
+ triggers->connection_cl_names.empty();
+ triggers->db_cl_names.empty();
if (parser->parse((uchar*)triggers, &table->mem_root,
triggers_file_parameters,
@@ -880,8 +1082,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
We use one mode (current) for all triggers, because we have not
information about mode in old format.
*/
- if (!(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root,
- sizeof(ulonglong))))
+ if (!(trg_sql_mode= alloc_type<ulonglong>(&table->mem_root)))
{
DBUG_RETURN(1); // EOM
}
@@ -910,8 +1111,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
LEX_STRING *trg_definer;
- if (! (trg_definer= (LEX_STRING*)alloc_root(&table->mem_root,
- sizeof(LEX_STRING))))
+ if (!(trg_definer= alloc_lex_string(&table->mem_root)))
DBUG_RETURN(1); // EOM
trg_definer->str= (char*) "";
@@ -929,10 +1129,85 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
it.rewind();
}
+ if (!triggers->definitions_list.is_empty() &&
+ (triggers->client_cs_names.is_empty() ||
+ triggers->connection_cl_names.is_empty() ||
+ triggers->db_cl_names.is_empty()))
+ {
+ /*
+ It is old file format => we should fill lists of character sets.
+ */
+
+ LEX_STRING *trg_client_cs_name;
+ LEX_STRING *trg_connection_cl_name;
+ LEX_STRING *trg_db_cl_name;
+
+ if (!triggers->client_cs_names.is_empty() ||
+ !triggers->connection_cl_names.is_empty() ||
+ !triggers->db_cl_names.is_empty())
+ {
+ my_error(ER_TRG_CORRUPTED_FILE, MYF(0),
+ (const char *) db,
+ (const char *) table_name);
+
+ DBUG_RETURN(1); // EOM
+ }
+
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_NO_CREATION_CTX,
+ ER(ER_TRG_NO_CREATION_CTX),
+ (const char*) db,
+ (const char*) table_name);
+
+ if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) ||
+ !(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) ||
+ !(trg_db_cl_name= alloc_lex_string(&table->mem_root)))
+ {
+ DBUG_RETURN(1); // EOM
+ }
+
+ /*
+ Backward compatibility: assume that the query is in the current
+ character set.
+ */
+
+ lex_string_set(trg_client_cs_name,
+ thd->variables.character_set_client->csname);
+
+ lex_string_set(trg_connection_cl_name,
+ thd->variables.collation_connection->name);
+
+ lex_string_set(trg_db_cl_name,
+ thd->variables.collation_database->name);
+
+ while (it++)
+ {
+ if (triggers->client_cs_names.push_back(trg_client_cs_name,
+ &table->mem_root) ||
+
+ triggers->connection_cl_names.push_back(trg_connection_cl_name,
+ &table->mem_root) ||
+
+ triggers->db_cl_names.push_back(trg_db_cl_name,
+ &table->mem_root))
+ {
+ DBUG_RETURN(1); // EOM
+ }
+ }
+
+ it.rewind();
+ }
+
DBUG_ASSERT(triggers->definition_modes_list.elements ==
triggers->definitions_list.elements);
DBUG_ASSERT(triggers->definers_list.elements ==
triggers->definitions_list.elements);
+ DBUG_ASSERT(triggers->client_cs_names.elements ==
+ triggers->definitions_list.elements);
+ DBUG_ASSERT(triggers->connection_cl_names.elements ==
+ triggers->definitions_list.elements);
+ DBUG_ASSERT(triggers->db_cl_names.elements ==
+ triggers->definitions_list.elements);
table->triggers= triggers;
@@ -956,6 +1231,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
+ List_iterator_fast<LEX_STRING> it_client_cs_name(triggers->client_cs_names);
+ List_iterator_fast<LEX_STRING> it_connection_cl_name(triggers->connection_cl_names);
+ List_iterator_fast<LEX_STRING> it_db_cl_name(triggers->db_cl_names);
LEX *old_lex= thd->lex, lex;
sp_rcontext *save_spcont= thd->spcont;
ulong save_sql_mode= thd->variables.sql_mode;
@@ -974,10 +1252,19 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
thd->variables.sql_mode= (ulong)*trg_sql_mode;
Lex_input_stream lip(thd, trg_create_str->str, trg_create_str->length);
+
+ Trigger_creation_ctx *creation_ctx=
+ Trigger_creation_ctx::create(thd,
+ db,
+ table_name,
+ it_client_cs_name++,
+ it_connection_cl_name++,
+ it_db_cl_name++);
+
lex_start(thd);
- thd->spcont= 0;
+ thd->spcont= NULL;
- if (parse_sql(thd, &lip))
+ if (parse_sql(thd, &lip, creation_ctx))
{
/* Currently sphead is always deleted in case of a parse error */
DBUG_ASSERT(lex.sphead == 0);
@@ -986,8 +1273,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode);
- triggers->bodies[lex.trg_chistics.event]
- [lex.trg_chistics.action_time]= lex.sphead;
+ int event= lex.trg_chistics.event;
+ int action_time= lex.trg_chistics.action_time;
+
+ lex.sphead->set_creation_ctx(creation_ctx);
+ triggers->bodies[event][action_time]= lex.sphead;
if (!trg_definer->length)
{
@@ -1023,8 +1313,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
&table->mem_root))
goto err_with_lex_cleanup;
- if (!(on_table_name= (LEX_STRING*) alloc_root(&table->mem_root,
- sizeof(LEX_STRING))))
+ if (!(on_table_name= alloc_lex_string(&table->mem_root)))
goto err_with_lex_cleanup;
on_table_name->str= (char*) lex.raw_trg_on_table_name_begin;
@@ -1070,7 +1359,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
trg_field;
trg_field= trg_field->next_trg_field)
{
- trg_field->setup_field(thd, table,
+ trg_field->setup_field(thd, table,
&triggers->subject_table_grants[lex.trg_chistics.event]
[lex.trg_chistics.action_time]);
}
@@ -1132,14 +1421,20 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
LEX_STRING *trigger_name,
LEX_STRING *trigger_stmt,
ulong *sql_mode,
- LEX_STRING *definer)
+ LEX_STRING *definer,
+ LEX_STRING *client_cs_name,
+ LEX_STRING *connection_cl_name,
+ LEX_STRING *db_cl_name)
{
sp_head *body;
DBUG_ENTER("get_trigger_info");
if ((body= bodies[event][time_type]))
{
+ Stored_program_creation_ctx *creation_ctx=
+ bodies[event][time_type]->get_creation_ctx();
+
*trigger_name= body->m_name;
- *trigger_stmt= body->m_body;
+ *trigger_stmt= body->m_body_utf8;
*sql_mode= body->m_sql_mode;
if (body->m_chistics->suid == SP_IS_NOT_SUID)
@@ -1153,12 +1448,74 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
body->m_definer_host.str, NullS) - definer->str;
}
+ lex_string_set(client_cs_name,
+ creation_ctx->get_client_cs()->csname);
+
+ lex_string_set(connection_cl_name,
+ creation_ctx->get_connection_cl()->name);
+
+ lex_string_set(db_cl_name,
+ creation_ctx->get_db_cl()->name);
+
DBUG_RETURN(0);
}
DBUG_RETURN(1);
}
+void Table_triggers_list::get_trigger_info(THD *thd,
+ int trigger_idx,
+ LEX_STRING *trigger_name,
+ ulonglong *sql_mode,
+ LEX_STRING *sql_original_stmt,
+ LEX_STRING *client_cs_name,
+ LEX_STRING *connection_cl_name,
+ LEX_STRING *db_cl_name)
+{
+ List_iterator_fast<LEX_STRING> it_trigger_name(names_list);
+ List_iterator_fast<ulonglong> it_sql_mode(definition_modes_list);
+ List_iterator_fast<LEX_STRING> it_sql_orig_stmt(definitions_list);
+ List_iterator_fast<LEX_STRING> it_client_cs_name(client_cs_names);
+ List_iterator_fast<LEX_STRING> it_connection_cl_name(connection_cl_names);
+ List_iterator_fast<LEX_STRING> it_db_cl_name(db_cl_names);
+
+ for (int i = 0; i < trigger_idx; ++i)
+ {
+ it_trigger_name.next_fast();
+ it_sql_mode.next_fast();
+ it_sql_orig_stmt.next_fast();
+
+ it_client_cs_name.next_fast();
+ it_connection_cl_name.next_fast();
+ it_db_cl_name.next_fast();
+ }
+
+ *trigger_name= *(it_trigger_name++);
+ *sql_mode= *(it_sql_mode++);
+ *sql_original_stmt= *(it_sql_orig_stmt++);
+
+ *client_cs_name= *(it_client_cs_name++);
+ *connection_cl_name= *(it_connection_cl_name++);
+ *db_cl_name= *(it_db_cl_name++);
+}
+
+
+int Table_triggers_list::find_trigger_by_name(const LEX_STRING *trg_name)
+{
+ List_iterator_fast<LEX_STRING> it(names_list);
+
+ for (int i = 0; ; ++i)
+ {
+ LEX_STRING *cur_name= it++;
+
+ if (!cur_name)
+ return -1;
+
+ if (strcmp(cur_name->str, trg_name->str) == 0)
+ return i;
+ }
+}
+
/**
Find trigger's table from trigger identifier and add it to
the statement table list.
@@ -1177,7 +1534,7 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
*/
bool add_table_for_trigger(THD *thd,
- sp_name *trg_name,
+ const sp_name *trg_name,
bool if_exists,
TABLE_LIST **table)
{