Commit 41a895a1 authored by dlenev@mysql.com's avatar dlenev@mysql.com

Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime

into  mysql.com:/home/dlenev/mysql-5.0-bg17764
parents 6be4db9a 17785d16
...@@ -2,6 +2,7 @@ drop table if exists t1, t2, t3, t4; ...@@ -2,6 +2,7 @@ drop table if exists t1, t2, t3, t4;
drop view if exists v1; drop view if exists v1;
drop database if exists mysqltest; drop database if exists mysqltest;
drop function if exists f1; drop function if exists f1;
drop function if exists f2;
drop procedure if exists p1; drop procedure if exists p1;
create table t1 (i int); create table t1 (i int);
create trigger trg before insert on t1 for each row set @a:=1; create trigger trg before insert on t1 for each row set @a:=1;
...@@ -928,3 +929,26 @@ create trigger t1_bi before insert on t1 for each row return 0; ...@@ -928,3 +929,26 @@ create trigger t1_bi before insert on t1 for each row return 0;
ERROR 42000: RETURN is only allowed in a FUNCTION ERROR 42000: RETURN is only allowed in a FUNCTION
insert into t1 values (1); insert into t1 values (1);
drop table t1; drop table t1;
create table t1 (a varchar(64), b int);
create table t2 like t1;
create trigger t1_ai after insert on t1 for each row
set @a:= (select max(a) from t1);
insert into t1 (a) values
("Twas"),("brillig"),("and"),("the"),("slithy"),("toves"),
("Did"),("gyre"),("and"),("gimble"),("in"),("the"),("wabe");
create trigger t2_ai after insert on t2 for each row
set @a:= (select max(a) from t2);
insert into t2 select * from t1;
load data infile '../std_data_ln/words.dat' into table t1 (a);
drop trigger t1_ai;
drop trigger t2_ai;
create function f1() returns int return (select max(b) from t1);
insert into t1 values
("All",f1()),("mimsy",f1()),("were",f1()),("the",f1()),("borogoves",f1()),
("And",f1()),("the",f1()),("mome", f1()),("raths",f1()),("outgrabe",f1());
create function f2() returns int return (select max(b) from t2);
insert into t2 select a, f2() from t1;
load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1();
drop table t1;
drop function f1;
drop function f2;
...@@ -7,6 +7,7 @@ drop table if exists t1, t2, t3, t4; ...@@ -7,6 +7,7 @@ drop table if exists t1, t2, t3, t4;
drop view if exists v1; drop view if exists v1;
drop database if exists mysqltest; drop database if exists mysqltest;
drop function if exists f1; drop function if exists f1;
drop function if exists f2;
drop procedure if exists p1; drop procedure if exists p1;
--enable_warnings --enable_warnings
...@@ -1080,3 +1081,36 @@ create table t1 (i int); ...@@ -1080,3 +1081,36 @@ create table t1 (i int);
create trigger t1_bi before insert on t1 for each row return 0; create trigger t1_bi before insert on t1 for each row return 0;
insert into t1 values (1); insert into t1 values (1);
drop table t1; drop table t1;
# Test for bug #17764 "Trigger crashes MyISAM table"
#
# Table was reported as crashed when it was subject table of trigger invoked
# by insert statement which was executed with enabled bulk insert mode (which
# is actually set of optimizations enabled by handler::start_bulk_insert())
# and this trigger also explicitly referenced it.
# The same problem arose when table to which bulk insert was done was also
# referenced in function called by insert statement.
create table t1 (a varchar(64), b int);
create table t2 like t1;
create trigger t1_ai after insert on t1 for each row
set @a:= (select max(a) from t1);
insert into t1 (a) values
("Twas"),("brillig"),("and"),("the"),("slithy"),("toves"),
("Did"),("gyre"),("and"),("gimble"),("in"),("the"),("wabe");
create trigger t2_ai after insert on t2 for each row
set @a:= (select max(a) from t2);
insert into t2 select * from t1;
load data infile '../std_data_ln/words.dat' into table t1 (a);
drop trigger t1_ai;
drop trigger t2_ai;
# Test that the problem for functions is fixed as well
create function f1() returns int return (select max(b) from t1);
insert into t1 values
("All",f1()),("mimsy",f1()),("were",f1()),("the",f1()),("borogoves",f1()),
("And",f1()),("the",f1()),("mome", f1()),("raths",f1()),("outgrabe",f1());
create function f2() returns int return (select max(b) from t2);
insert into t2 select a, f2() from t1;
load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1();
drop table t1;
drop function f1;
drop function f2;
...@@ -405,11 +405,15 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -405,11 +405,15 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
let's *try* to start bulk inserts. It won't necessary let's *try* to start bulk inserts. It won't necessary
start them as values_list.elements should be greater than start them as values_list.elements should be greater than
some - handler dependent - threshold. some - handler dependent - threshold.
We should not start bulk inserts if this statement uses
functions or invokes triggers since they may access
to the same table and therefore should not see its
inconsistent state created by this optimization.
So we call start_bulk_insert to perform nesessary checks on So we call start_bulk_insert to perform nesessary checks on
values_list.elements, and - if nothing else - to initialize values_list.elements, and - if nothing else - to initialize
the code to make the call of end_bulk_insert() below safe. the code to make the call of end_bulk_insert() below safe.
*/ */
if (lock_type != TL_WRITE_DELAYED) if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode)
table->file->start_bulk_insert(values_list.elements); table->file->start_bulk_insert(values_list.elements);
thd->no_trans_update= 0; thd->no_trans_update= 0;
...@@ -535,7 +539,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -535,7 +539,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
else else
#endif #endif
{ {
if (table->file->end_bulk_insert() && !error) if (!thd->prelocked_mode && table->file->end_bulk_insert() && !error)
{ {
table->file->print_error(my_errno,MYF(0)); table->file->print_error(my_errno,MYF(0));
error=1; error=1;
...@@ -2190,7 +2194,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2190,7 +2194,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->current_select->options|= OPTION_BUFFER_RESULT; lex->current_select->options|= OPTION_BUFFER_RESULT;
lex->current_select->join->select_options|= OPTION_BUFFER_RESULT; lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
} }
else else if (!thd->prelocked_mode)
{ {
/* /*
We must not yet prepare the result table if it is the same as one of the We must not yet prepare the result table if it is the same as one of the
...@@ -2198,6 +2202,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2198,6 +2202,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
indexes on the result table, which may be used during the select, if it indexes on the result table, which may be used during the select, if it
is the same table (Bug #6034). Do the preparation after the select phase is the same table (Bug #6034). Do the preparation after the select phase
in select_insert::prepare2(). in select_insert::prepare2().
We won't start bulk inserts at all if this statement uses functions or
should invoke triggers since they may access to the same table too.
*/ */
table->file->start_bulk_insert((ha_rows) 0); table->file->start_bulk_insert((ha_rows) 0);
} }
...@@ -2238,7 +2244,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2238,7 +2244,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
int select_insert::prepare2(void) int select_insert::prepare2(void)
{ {
DBUG_ENTER("select_insert::prepare2"); DBUG_ENTER("select_insert::prepare2");
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT) if (thd->lex->current_select->options & OPTION_BUFFER_RESULT &&
!thd->prelocked_mode)
table->file->start_bulk_insert((ha_rows) 0); table->file->start_bulk_insert((ha_rows) 0);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -2341,6 +2348,7 @@ void select_insert::send_error(uint errcode,const char *err) ...@@ -2341,6 +2348,7 @@ void select_insert::send_error(uint errcode,const char *err)
*/ */
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (!thd->prelocked_mode)
table->file->end_bulk_insert(); table->file->end_bulk_insert();
/* /*
If at least one row has been inserted/modified and will stay in the table If at least one row has been inserted/modified and will stay in the table
...@@ -2376,7 +2384,7 @@ bool select_insert::send_eof() ...@@ -2376,7 +2384,7 @@ bool select_insert::send_eof()
int error,error2; int error,error2;
DBUG_ENTER("select_insert::send_eof"); DBUG_ENTER("select_insert::send_eof");
error=table->file->end_bulk_insert(); error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
/* /*
...@@ -2459,6 +2467,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2459,6 +2467,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
thd->cuted_fields=0; thd->cuted_fields=0;
if (info.ignore || info.handle_duplicates != DUP_ERROR) if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (!thd->prelocked_mode)
table->file->start_bulk_insert((ha_rows) 0); table->file->start_bulk_insert((ha_rows) 0);
thd->no_trans_update= 0; thd->no_trans_update= 0;
thd->abort_on_warning= (!info.ignore && thd->abort_on_warning= (!info.ignore &&
......
...@@ -356,6 +356,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -356,6 +356,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (ignore || if (ignore ||
handle_duplicates == DUP_REPLACE) handle_duplicates == DUP_REPLACE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (!thd->prelocked_mode)
table->file->start_bulk_insert((ha_rows) 0); table->file->start_bulk_insert((ha_rows) 0);
table->copy_blobs=1; table->copy_blobs=1;
...@@ -373,7 +374,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -373,7 +374,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
error= read_sep_field(thd, info, table_list, fields_vars, error= read_sep_field(thd, info, table_list, fields_vars,
set_fields, set_values, read_info, set_fields, set_values, read_info,
*enclosed, skip_lines, ignore); *enclosed, skip_lines, ignore);
if (table->file->end_bulk_insert() && !error) if (!thd->prelocked_mode && table->file->end_bulk_insert() && !error)
{ {
table->file->print_error(my_errno, MYF(0)); table->file->print_error(my_errno, MYF(0));
error= 1; error= 1;
......
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