summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/information_schema.result17
-rw-r--r--mysql-test/r/trigger.result47
-rw-r--r--mysql-test/t/trigger.test36
-rw-r--r--sql/mysqld.cc45
-rw-r--r--sql/parse_file.cc68
-rw-r--r--sql/parse_file.h4
-rw-r--r--sql/set_var.cc29
-rw-r--r--sql/set_var.h2
-rw-r--r--sql/sp_head.cc44
-rw-r--r--sql/sp_head.h2
-rw-r--r--sql/sql_show.cc22
-rw-r--r--sql/sql_trigger.cc91
-rw-r--r--sql/sql_trigger.h7
-rw-r--r--sql/sql_view.cc8
14 files changed, 345 insertions, 77 deletions
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 89b3df0a83b..2cd426ea038 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -713,6 +713,7 @@ information_schema ROUTINES SQL_MODE
information_schema VIEWS VIEW_DEFINITION
information_schema TRIGGERS ACTION_CONDITION
information_schema TRIGGERS ACTION_STATEMENT
+information_schema TRIGGERS SQL_MODE
select table_name, column_name, data_type from information_schema.columns
where data_type = 'datetime';
table_name column_name data_type
@@ -790,45 +791,45 @@ set @fired:= "Yes";
end if;
end|
show triggers;
-Trigger Event Table Statement Timing Created
+Trigger Event Table Statement Timing Created sql_mode
trg1 INSERT t1
begin
if new.j > 10 then
set new.j := 10;
end if;
-end BEFORE NULL
+end BEFORE NULL
trg2 UPDATE t1
begin
if old.i % 2 = 0 then
set new.j := -1;
end if;
-end BEFORE NULL
+end BEFORE NULL
trg3 UPDATE t1
begin
if new.j = -1 then
set @fired:= "Yes";
end if;
-end AFTER NULL
+end AFTER NULL
select * from information_schema.triggers;
-TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED
+TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE
NULL test trg1 INSERT NULL test t1 0 NULL
begin
if new.j > 10 then
set new.j := 10;
end if;
-end ROW BEFORE NULL NULL OLD NEW NULL
+end ROW BEFORE NULL NULL OLD NEW NULL
NULL test trg2 UPDATE NULL test t1 0 NULL
begin
if old.i % 2 = 0 then
set new.j := -1;
end if;
-end ROW BEFORE NULL NULL OLD NEW NULL
+end ROW BEFORE NULL NULL OLD NEW NULL
NULL test trg3 UPDATE NULL test t1 0 NULL
begin
if new.j = -1 then
set @fired:= "Yes";
end if;
-end ROW AFTER NULL NULL OLD NEW NULL
+end ROW AFTER NULL NULL OLD NEW NULL
drop trigger trg1;
drop trigger trg2;
drop trigger trg3;
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 7e3a6fa65d4..d416d3c41ba 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -595,3 +595,50 @@ update t1 set col2 = 4;
ERROR 42000: FUNCTION test.bug5893 does not exist
drop trigger t1_bu;
drop table t1;
+set sql_mode='ansi';
+create table t1 ("t1 column" int);
+create trigger t1_bi before insert on t1 for each row set new."t1 column" = 5;
+set sql_mode=default;
+insert into t1 values (0);
+create trigger t1_af after insert on t1 for each row set @a=10;
+insert into t1 values (0);
+select * from t1;
+t1 column
+5
+5
+select @a;
+@a
+10
+show triggers;
+Trigger Event Table Statement Timing Created sql_mode
+t1_bi INSERT t1 set new."t1 column" = 5 BEFORE # REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
+t1_af INSERT t1 set @a=10 AFTER #
+select * from information_schema.triggers;
+TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE
+NULL test t1_bi INSERT NULL test t1 0 NULL set new."t1 column" = 5 ROW BEFORE NULL NULL OLD NEW # REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
+NULL test t1_af INSERT NULL test t1 0 NULL set @a=10 ROW AFTER NULL NULL OLD NEW #
+drop table t1;
+set sql_mode="traditional";
+create table t1 (a date);
+insert into t1 values ('2004-01-00');
+ERROR 22007: Incorrect date value: '2004-01-00' for column 'a' at row 1
+set sql_mode="";
+create trigger t1_bi before insert on t1 for each row set new.a = '2004-01-00';
+set sql_mode="traditional";
+insert into t1 values ('2004-01-01');
+select * from t1;
+a
+2004-01-00
+set sql_mode=default;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show triggers;
+Trigger Event Table Statement Timing Created sql_mode
+t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE #
+select * from information_schema.triggers;
+TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE
+NULL test t1_bi INSERT NULL test t1 0 NULL set new.a = '2004-01-00' ROW BEFORE NULL NULL OLD NEW #
+drop table t1;
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index f6b3c714d28..17f2e85f2e8 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -610,3 +610,39 @@ update t1 set col2 = 4;
# This should not crash server too.
drop trigger t1_bu;
drop table t1;
+
+#
+# storing and restoring parsing modes for triggers (BUG#5891)
+#
+set sql_mode='ansi';
+create table t1 ("t1 column" int);
+create trigger t1_bi before insert on t1 for each row set new."t1 column" = 5;
+set sql_mode=default;
+insert into t1 values (0);
+# create trigger with different sql_mode
+create trigger t1_af after insert on t1 for each row set @a=10;
+insert into t1 values (0);
+select * from t1;
+select @a;
+--replace_column 6 #
+show triggers;
+--replace_column 17 #
+select * from information_schema.triggers;
+drop table t1;
+# check that rigger preserve sql_mode during execution
+set sql_mode="traditional";
+create table t1 (a date);
+-- error 1292
+insert into t1 values ('2004-01-00');
+set sql_mode="";
+create trigger t1_bi before insert on t1 for each row set new.a = '2004-01-00';
+set sql_mode="traditional";
+insert into t1 values ('2004-01-01');
+select * from t1;
+set sql_mode=default;
+show create table t1;
+--replace_column 6 #
+show triggers;
+--replace_column 17 #
+select * from information_schema.triggers;
+drop table t1;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 798bd25fa7c..7c55b42b48e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -220,21 +220,58 @@ extern "C" int gethostname(char *name, int namelen);
/* Constants */
const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
-static const char *sql_mode_names[] =
+static const char *sql_mode_names[]=
{
"REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
"?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
"NO_DIR_IN_CREATE",
"POSTGRESQL", "ORACLE", "MSSQL", "DB2", "MAXDB", "NO_KEY_OPTIONS",
"NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
- "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES", "STRICT_ALL_TABLES",
- "NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES", "ERROR_FOR_DIVISION_BY_ZERO",
+ "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES",
+ "STRICT_ALL_TABLES",
+ "NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES",
+ "ERROR_FOR_DIVISION_BY_ZERO",
"TRADITIONAL", "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE",
"NO_ENGINE_SUBSTITUTION",
NullS
};
+static const unsigned int sql_mode_names_len[]=
+{
+ /*REAL_AS_FLOAT*/ 13,
+ /*PIPES_AS_CONCAT*/ 15,
+ /*ANSI_QUOTES*/ 11,
+ /*IGNORE_SPACE*/ 12,
+ /*?*/ 1,
+ /*ONLY_FULL_GROUP_BY*/ 18,
+ /*NO_UNSIGNED_SUBTRACTION*/ 23,
+ /*NO_DIR_IN_CREATE*/ 16,
+ /*POSTGRESQL*/ 10,
+ /*ORACLE*/ 6,
+ /*MSSQL*/ 5,
+ /*DB2*/ 3,
+ /*MAXDB*/ 5,
+ /*NO_KEY_OPTIONS*/ 14,
+ /*NO_TABLE_OPTIONS*/ 16,
+ /*NO_FIELD_OPTIONS*/ 16,
+ /*MYSQL323*/ 8,
+ /*MYSQL40*/ 7,
+ /*ANSI*/ 4,
+ /*NO_AUTO_VALUE_ON_ZERO*/ 21,
+ /*NO_BACKSLASH_ESCAPES*/ 20,
+ /*STRICT_TRANS_TABLES*/ 19,
+ /*STRICT_ALL_TABLES*/ 17,
+ /*NO_ZERO_IN_DATE*/ 15,
+ /*NO_ZERO_DATE*/ 12,
+ /*ALLOW_INVALID_DATES*/ 19,
+ /*ERROR_FOR_DIVISION_BY_ZERO*/ 26,
+ /*TRADITIONAL*/ 11,
+ /*NO_AUTO_CREATE_USER*/ 19,
+ /*HIGH_NOT_PRECEDENCE*/ 19,
+ /*NO_ENGINE_SUBSTITUTION*/ 22
+};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
- sql_mode_names, NULL };
+ sql_mode_names,
+ (unsigned int *)sql_mode_names_len };
static const char *tc_heuristic_recover_names[]=
{
"COMMIT", "ROLLBACK", NullS
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index abca8736916..82ce2f2d7b5 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -166,6 +166,25 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
}
break;
}
+ case FILE_OPTIONS_ULLLIST:
+ {
+ List_iterator_fast<ulonglong> it(*((List<ulonglong>*)
+ (base + parameter->offset)));
+ bool first= 1;
+ ulonglong *val;
+ while ((val= it++))
+ {
+ num.set(*val, &my_charset_bin);
+ // We need ' ' after string to detect list continuation
+ if ((!first && my_b_append(file, (const byte *)" ", 1)) ||
+ my_b_append(file, (const byte *)num.ptr(), num.length()))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ first= 0;
+ }
+ break;
+ }
default:
DBUG_ASSERT(0); // never should happened
}
@@ -615,6 +634,8 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
char *eol;
LEX_STRING *str;
List<LEX_STRING> *list;
+ ulonglong *num;
+ List<ulonglong> *nlist;
DBUG_ENTER("File_parser::parse");
while (ptr < end && found < required)
@@ -719,7 +740,7 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
case FILE_OPTIONS_STRLIST:
{
list= (List<LEX_STRING>*)(base + parameter->offset);
-
+
list->empty();
// list parsing
while (ptr < end)
@@ -741,17 +762,56 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
goto list_err_w_message;
}
}
- end_of_list:
+
+end_of_list:
if (*(ptr++) != '\n')
goto list_err;
break;
- list_err_w_message:
+list_err_w_message:
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
parameter->name.str, line);
- list_err:
+list_err:
DBUG_RETURN(TRUE);
}
+ case FILE_OPTIONS_ULLLIST:
+ {
+ nlist= (List<ulonglong>*)(base + parameter->offset);
+ nlist->empty();
+ // list parsing
+ while (ptr < end)
+ {
+ int not_used;
+ char *num_end= end;
+ if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) ||
+ nlist->push_back(num, mem_root))
+ goto nlist_err;
+ *num= my_strtoll10(ptr, &num_end, &not_used);
+ ptr= num_end;
+ switch (*ptr) {
+ case '\n':
+ goto end_of_nlist;
+ case ' ':
+ // we cant go over buffer bounds, because we have \0 at the end
+ ptr++;
+ break;
+ default:
+ goto nlist_err_w_message;
+ }
+ }
+
+end_of_nlist:
+ if (*(ptr++) != '\n')
+ goto nlist_err;
+ break;
+
+nlist_err_w_message:
+ my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
+ parameter->name.str, line);
+nlist_err:
+ DBUG_RETURN(TRUE);
+
+ }
default:
DBUG_ASSERT(0); // never should happened
}
diff --git a/sql/parse_file.h b/sql/parse_file.h
index 82a89dffd18..cc0aa6556f6 100644
--- a/sql/parse_file.h
+++ b/sql/parse_file.h
@@ -27,8 +27,10 @@ enum file_opt_type {
FILE_OPTIONS_REV, /* Revision version number (ulonglong) */
FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be
allocated with length 20 (19+1) */
- FILE_OPTIONS_STRLIST /* list of escaped strings
+ FILE_OPTIONS_STRLIST, /* list of escaped strings
(List<LEX_STRING>) */
+ FILE_OPTIONS_ULLLIST /* list of ulonglong values
+ (List<ulonglong>) */
};
struct File_option
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 09581aed217..d3f3f62c259 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -3196,29 +3196,46 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var)
Functions to handle sql_mode
****************************************************************************/
-byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
+/*
+ Make string representation of mode
+
+ SINOPSYS
+ thd thread handler
+ val sql_mode value
+ len pointer on length of string
+*/
+
+byte *sys_var_thd_sql_mode::symbolic_mode_representation(THD *thd, ulong val,
+ ulong *len)
{
- ulong val;
char buff[256];
String tmp(buff, sizeof(buff), &my_charset_latin1);
tmp.length(0);
- val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
- thd->variables.*offset);
for (uint i= 0; val; val>>= 1, i++)
{
if (val & 1)
{
- tmp.append(enum_names->type_names[i]);
+ tmp.append(sql_mode_typelib.type_names[i],
+ sql_mode_typelib.type_lengths[i]);
tmp.append(',');
}
}
if (tmp.length())
tmp.length(tmp.length() - 1);
+ *len= tmp.length();
return (byte*) thd->strmake(tmp.ptr(), tmp.length());
}
+byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ ulong val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
+ thd->variables.*offset);
+ ulong length_unused;
+ return symbolic_mode_representation(thd, val, &length_unused);
+}
+
void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type)
{
diff --git a/sql/set_var.h b/sql/set_var.h
index a7e680cc7fa..c8b075ddd35 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -361,6 +361,8 @@ public:
}
void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ static byte *symbolic_mode_representation(THD *thd, ulong sql_mode,
+ ulong *length);
};
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 02c006d01ee..0c3a6d04598 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -574,6 +574,7 @@ sp_head::execute(THD *thd)
sp_rcontext *ctx;
int ret= 0;
uint ip= 0;
+ ulong save_sql_mode;
Query_arena *old_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
@@ -626,6 +627,8 @@ sp_head::execute(THD *thd)
old_query_id= thd->query_id;
old_derived_tables= thd->derived_tables;
thd->derived_tables= 0;
+ save_sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode= m_sql_mode;
/*
It is also more efficient to save/restore current thd->lex once when
do it in each instruction
@@ -715,6 +718,7 @@ sp_head::execute(THD *thd)
thd->query_id= old_query_id;
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
+ thd->variables.sql_mode= save_sql_mode;
thd->current_arena= old_arena;
state= EXECUTED;
@@ -1245,8 +1249,6 @@ sp_head::show_create_procedure(THD *thd)
String buffer(buff, sizeof(buff), system_charset_info);
int res;
List<Item> field_list;
- ulong old_sql_mode;
- sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
bool full_access;
@@ -1258,19 +1260,13 @@ sp_head::show_create_procedure(THD *thd)
if (check_show_routine_access(thd, this, &full_access))
return 1;
-
- old_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= m_sql_mode;
- sql_mode_var= find_sys_var("SQL_MODE", 8);
- if (sql_mode_var)
- {
- sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0);
- sql_mode_len= strlen((char*) sql_mode_str);
- }
+ sql_mode_str=
+ sys_var_thd_sql_mode::symbolic_mode_representation(thd,
+ m_sql_mode,
+ &sql_mode_len);
field_list.push_back(new Item_empty_string("Procedure", NAME_LEN));
- if (sql_mode_var)
- field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
+ field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
// 1024 is for not to confuse old clients
field_list.push_back(new Item_empty_string("Create Procedure",
max(buffer.length(), 1024)));
@@ -1282,15 +1278,13 @@ sp_head::show_create_procedure(THD *thd)
}
protocol->prepare_for_resend();
protocol->store(m_name.str, m_name.length, system_charset_info);
- if (sql_mode_var)
- protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
if (full_access)
protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
done:
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(res);
}
@@ -1326,7 +1320,6 @@ sp_head::show_create_function(THD *thd)
String buffer(buff, sizeof(buff), system_charset_info);
int res;
List<Item> field_list;
- ulong old_sql_mode;
sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
@@ -1339,15 +1332,10 @@ sp_head::show_create_function(THD *thd)
if (check_show_routine_access(thd, this, &full_access))
return 1;
- old_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= m_sql_mode;
- sql_mode_var= find_sys_var("SQL_MODE", 8);
- if (sql_mode_var)
- {
- sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0);
- sql_mode_len= strlen((char*) sql_mode_str);
- }
-
+ sql_mode_str=
+ sys_var_thd_sql_mode::symbolic_mode_representation(thd,
+ m_sql_mode,
+ &sql_mode_len);
field_list.push_back(new Item_empty_string("Function",NAME_LEN));
if (sql_mode_var)
field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
@@ -1361,15 +1349,13 @@ sp_head::show_create_function(THD *thd)
}
protocol->prepare_for_resend();
protocol->store(m_name.str, m_name.length, system_charset_info);
- if (sql_mode_var)
- protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
if (full_access)
protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
done:
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(res);
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 32dc4449174..09b9c8f47a1 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -121,7 +121,7 @@ public:
uchar *m_tmp_query; // Temporary pointer to sub query string
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
st_sp_chistics *m_chistics;
- ulong m_sql_mode; // For SHOW CREATE
+ ulong m_sql_mode; // For SHOW CREATE and execution
LEX_STRING m_qname; // db.name
LEX_STRING m_db;
LEX_STRING m_name;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 6989eacf334..cc4677bcfa1 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2983,9 +2983,13 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db,
const char *tname, LEX_STRING *trigger_name,
enum trg_event_type event,
enum trg_action_time_type timing,
- LEX_STRING *trigger_stmt)
+ LEX_STRING *trigger_stmt,
+ ulong sql_mode)
{
CHARSET_INFO *cs= system_charset_info;
+ byte *sql_mode_str;
+ ulong sql_mode_len;
+
restore_record(table, s->default_values);
table->field[1]->store(db, strlen(db), cs);
table->field[2]->store(trigger_name->str, trigger_name->length, cs);
@@ -2999,6 +3003,12 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db,
trg_action_time_type_names[timing].length, cs);
table->field[14]->store("OLD", 3, cs);
table->field[15]->store("NEW", 3, cs);
+
+ sql_mode_str=
+ sys_var_thd_sql_mode::symbolic_mode_representation(thd,
+ sql_mode,
+ &sql_mode_len);
+ table->field[17]->store(sql_mode_str, sql_mode_len, cs);
return schema_table_store_record(thd, table);
}
@@ -3031,13 +3041,16 @@ static int get_schema_triggers_record(THD *thd, struct st_table_list *tables,
{
LEX_STRING trigger_name;
LEX_STRING trigger_stmt;
+ ulong sql_mode;
if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
(enum trg_action_time_type)timing,
- &trigger_name, &trigger_stmt))
+ &trigger_name, &trigger_stmt,
+ &sql_mode))
continue;
if (store_trigger(thd, table, base_name, file_name, &trigger_name,
(enum trg_event_type) event,
- (enum trg_action_time_type) timing, &trigger_stmt))
+ (enum trg_action_time_type) timing, &trigger_stmt,
+ sql_mode))
DBUG_RETURN(1);
}
}
@@ -3949,6 +3962,7 @@ ST_FIELD_INFO triggers_fields_info[]=
{"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"},
+ {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, "sql_mode"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -4003,7 +4017,7 @@ ST_SCHEMA_TABLE schema_tables[]=
fill_open_tables, make_old_format, 0, -1, -1, 1},
{"STATUS", variables_fields_info, create_schema_table, fill_status,
make_old_format, 0, -1, -1, 1},
- {"TRIGGERS", triggers_fields_info, create_schema_table,
+ {"TRIGGERS", triggers_fields_info, create_schema_table,
get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0},
{"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
make_old_format, 0, -1, -1, 1},
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index a7aee95197e..c739511dda0 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -32,8 +32,12 @@ const char * const triggers_file_ext= ".TRG";
*/
static File_option triggers_file_parameters[]=
{
- {{(char*)"triggers", 8}, offsetof(class Table_triggers_list, definitions_list),
- FILE_OPTIONS_STRLIST},
+ {{(char*)"triggers", 8},
+ offsetof(class Table_triggers_list, definitions_list),
+ FILE_OPTIONS_STRLIST},
+ {{(char*)"sql_modes", 13},
+ offsetof(class Table_triggers_list, definition_modes_list),
+ FILE_OPTIONS_ULLLIST},
{{0, 0}, 0, FILE_OPTIONS_STRING}
};
@@ -127,12 +131,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
/*
- We do not allow creation of triggers on views or temporary tables.
- We have to do this check here and not in
- Table_triggers_list::create_trigger() because we want to avoid messing
- with table cash for views and temporary tables.
+ We do not allow creation of triggers on temporary tables. We also don't
+ allow creation of triggers on views but fulfilment of this restriction
+ is guaranteed by open_ltable(). It is better to have this check here
+ than do it in Table_triggers_list::create_trigger() and mess with table
+ cache.
*/
- if (tables->view || table->s->tmp_table != NO_TMP_TABLE)
+ if (table->s->tmp_table != NO_TMP_TABLE)
{
my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
DBUG_RETURN(TRUE);
@@ -221,6 +226,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
trigname_path[FN_REFLEN];
LEX_STRING dir, file, trigname_file;
LEX_STRING *trg_def, *name;
+ ulonglong *trg_sql_mode;
Item_trigger_field *trg_field;
struct st_trigname trigname;
@@ -307,11 +313,15 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
*/
if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root,
sizeof(LEX_STRING))) ||
- definitions_list.push_back(trg_def, &table->mem_root))
+ definitions_list.push_back(trg_def, &table->mem_root) ||
+ !(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root,
+ sizeof(ulonglong))) ||
+ definition_modes_list.push_back(trg_sql_mode, &table->mem_root))
goto err_with_cleanup;
trg_def->str= thd->query;
trg_def->length= thd->query_length;
+ *trg_sql_mode= thd->variables.sql_mode;
if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
(gptr)this, triggers_file_parameters, 3))
@@ -390,11 +400,13 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
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);
char path[FN_REFLEN];
while ((name= it_name++))
{
it_def++;
+ it_mod++;
if (my_strcasecmp(system_charset_info, lex->spname->m_name.str,
name->str) == 0)
@@ -404,6 +416,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
clean trigger removing since table will be reopened anyway.
*/
it_def.remove();
+ it_mod.remove();
if (definitions_list.is_empty())
{
@@ -549,10 +562,48 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
if (!triggers)
DBUG_RETURN(1);
+ /*
+ We don't have sql_modes in old versions of .TRG file, so we should
+ initialize list for safety.
+ */
+ triggers->definition_modes_list.empty();
+
if (parser->parse((gptr)triggers, &table->mem_root,
- triggers_file_parameters, 1))
+ triggers_file_parameters, 2))
DBUG_RETURN(1);
+ List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
+ LEX_STRING *trg_create_str, *trg_name_str;
+ ulonglong *trg_sql_mode;
+
+ if (triggers->definition_modes_list.is_empty() &&
+ !triggers->definitions_list.is_empty())
+ {
+ /*
+ It is old file format => we should fill list of sql_modes.
+
+ 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))))
+ {
+ DBUG_RETURN(1); // EOM
+ }
+ *trg_sql_mode= global_system_variables.sql_mode;
+ while ((trg_create_str= it++))
+ {
+ if (triggers->definition_modes_list.push_back(trg_sql_mode,
+ &table->mem_root))
+ {
+ DBUG_RETURN(1); // EOM
+ }
+ }
+ it.rewind();
+ }
+
+ DBUG_ASSERT(triggers->definition_modes_list.elements ==
+ triggers->definitions_list.elements);
table->triggers= triggers;
/*
@@ -574,15 +625,17 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
if (!names_only && triggers->prepare_record1_accessors(table))
DBUG_RETURN(1);
- List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
- LEX_STRING *trg_create_str, *trg_name_str;
char *trg_name_buff;
+ List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
LEX *old_lex= thd->lex, lex;
+ ulong save_sql_mode= thd->variables.sql_mode;
thd->lex= &lex;
while ((trg_create_str= it++))
{
+ trg_sql_mode= itm++;
+ thd->variables.sql_mode= (ulong)*trg_sql_mode;
lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
if (yyparse((void *)thd) || thd->is_fatal_error)
@@ -595,9 +648,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
goto err_with_lex_cleanup;
}
+ lex.sphead->m_sql_mode= *trg_sql_mode;
triggers->bodies[lex.trg_chistics.event]
[lex.trg_chistics.action_time]= lex.sphead;
- if (triggers->names_list.push_back(&lex.sphead->m_name, &table->mem_root))
+ if (triggers->names_list.push_back(&lex.sphead->m_name,
+ &table->mem_root))
goto err_with_lex_cleanup;
if (names_only)
@@ -611,8 +666,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
in old/new versions of row in trigger to Field objects in table being
opened.
- We ignore errors here, because if even something is wrong we still will
- be willing to open table to perform some operations (e.g. SELECT)...
+ We ignore errors here, because if even something is wrong we still
+ will be willing to open table to perform some operations (e.g.
+ SELECT)...
Anyway some things can be checked only during trigger execution.
*/
for (Item_trigger_field *trg_field=
@@ -624,6 +680,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
lex_end(&lex);
}
thd->lex= old_lex;
+ thd->variables.sql_mode= save_sql_mode;
DBUG_RETURN(0);
@@ -631,6 +688,7 @@ err_with_lex_cleanup:
// QQ: anything else ?
lex_end(&lex);
thd->lex= old_lex;
+ thd->variables.sql_mode= save_sql_mode;
DBUG_RETURN(1);
}
@@ -657,6 +715,7 @@ err_with_lex_cleanup:
time_type - trigger action time
name - returns name of trigger
stmt - returns statement of trigger
+ sql_mode - returns sql_mode of trigger
RETURN VALUE
False - success
@@ -666,7 +725,8 @@ err_with_lex_cleanup:
bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
trg_action_time_type time_type,
LEX_STRING *trigger_name,
- LEX_STRING *trigger_stmt)
+ LEX_STRING *trigger_stmt,
+ ulong *sql_mode)
{
sp_head *body;
DBUG_ENTER("get_trigger_info");
@@ -674,6 +734,7 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
{
*trigger_name= body->m_name;
*trigger_stmt= body->m_body;
+ *sql_mode= body->m_sql_mode;
DBUG_RETURN(0);
}
DBUG_RETURN(1);
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index e751741fa34..ede2cb39f0e 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -60,6 +60,10 @@ public:
It have to be public because we are using it directly from parser.
*/
List<LEX_STRING> definitions_list;
+ /*
+ List of sql modes for triggers
+ */
+ List<ulonglong> definition_modes_list;
Table_triggers_list(TABLE *table_arg):
record1_field(0), table(table_arg)
@@ -123,7 +127,8 @@ public:
}
bool get_trigger_info(THD *thd, trg_event_type event,
trg_action_time_type time_type,
- LEX_STRING *trigger_name, LEX_STRING *trigger_stmt);
+ LEX_STRING *trigger_name, LEX_STRING *trigger_stmt,
+ ulong *sql_mode);
static bool check_n_load(THD *thd, const char *db, const char *table_name,
TABLE *table, bool names_only);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index a60bf80a6d8..8b9c86a0f08 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -691,7 +691,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
view_select= &lex->select_lex;
view_select->select_number= ++thd->select_number;
{
- ulong options= thd->options;
+ ulong save_mode= thd->variables.sql_mode;
/* switch off modes which can prevent normal parsing of VIEW
- MODE_REAL_AS_FLOAT affect only CREATE TABLE parsing
+ MODE_PIPES_AS_CONCAT affect expression parsing
@@ -716,13 +716,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
? MODE_NO_AUTO_VALUE_ON_ZERO affect UPDATEs
+ MODE_NO_BACKSLASH_ESCAPES affect expression parsing
*/
- thd->options&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
- MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES);
+ thd->variables.sql_mode&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES);
CHARSET_INFO *save_cs= thd->variables.character_set_client;
thd->variables.character_set_client= system_charset_info;
res= yyparse((void *)thd);
thd->variables.character_set_client= save_cs;
- thd->options= options;
+ thd->variables.sql_mode= save_mode;
}
if (!res && !thd->is_fatal_error)
{