mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
store/restore sql_mode which was in force during ctrigger creation (BUG#5891)
other sql_mode fixes mysql-test/r/information_schema.result: changes in information schema mysql-test/r/trigger.result: storing and restoring sql modes for triggers mysql-test/t/trigger.test: storing and restoring parsing modes for triggers sql/mysqld.cc: add length of mode names sql/parse_file.cc: new type of list (ulonglong) sql/parse_file.h: new type of list (ulonglong) sql/set_var.cc: mode output made as static method sql/set_var.h: mode output made as static method sql/sp_head.cc: added sql_mode storing/restoring during SP execution optimised sql_mode printing sql/sp_head.h: comment fixed according this changes sql/sql_show.cc: added sql_mode field sql/sql_trigger.cc: store/restore sql_mode which was in force during ctrigger creation sql/sql_trigger.h: store/restore sql_mode which was in force during ctrigger creation sql/sql_view.cc: fixed sql_mode
This commit is contained in:
parent
482cf550f9
commit
a66928bb24
14 changed files with 345 additions and 77 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, ¬_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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue