Commit 21189de3 authored by unknown's avatar unknown

Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-5.0

into  sanja.is.com.ua:/home/bell/mysql/bk/work-trigger-5.0

parents c15cab96 a66928bb
......@@ -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, &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
}
......
......@@ -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 @@ class sys_var_thd_sql_mode :public sys_var_thd_enum
}
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 @@ class sp_head :private Query_arena
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 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
// QQ: anything else ?
lex_end(&lex);
thd->lex= old_lex;
thd->variables.sql_mode= save_sql_mode;
DBUG_RETURN(1);
}
......@@ -657,6 +715,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
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 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
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 @@ class Table_triggers_list: public Sql_alloc
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 @@ class Table_triggers_list: public Sql_alloc
}
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)
{
......
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