Merge mysql.com:/home/dlenev/src/mysql-5.0-bg13525
into mysql.com:/home/dlenev/src/mysql-5.1-merges2 client/mysqltest.c: Auto merged include/my_global.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/mysql-test-run.sh: Auto merged mysql-test/r/heap.result: Auto merged mysql-test/r/merge.result: Auto merged mysql-test/r/ps.result: Auto merged mysql-test/r/trigger.result: Auto merged mysql-test/r/view.result: Auto merged mysql-test/t/ps.test: Auto merged mysql-test/t/trigger.test: Auto merged mysql-test/t/view.test: Auto merged sql/field.cc: Auto merged sql/field.h: Auto merged sql/ha_myisammrg.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged storage/myisammrg/myrg_queue.c: Auto merged sql/sql_rename.cc: Manual merge. sql/sql_trigger.cc: Manual merge. sql/sql_yacc.yy: Manual merge.
This commit is contained in:
commit
e54ecf09be
@ -3662,8 +3662,10 @@ DYNAMIC_ARRAY patterns;
|
||||
static void init_win_path_patterns()
|
||||
{
|
||||
/* List of string patterns to match in order to find paths */
|
||||
const char* paths[] = { "$MYSQL_TEST_DIR", "./test/", 0 };
|
||||
int num_paths= 2;
|
||||
const char* paths[] = { "$MYSQL_TEST_DIR",
|
||||
"$MYSQL_TMP_DIR",
|
||||
"./test/", 0 };
|
||||
int num_paths= 3;
|
||||
int i;
|
||||
char* p;
|
||||
|
||||
|
@ -43,6 +43,15 @@
|
||||
#define HAVE_ERRNO_AS_DEFINE
|
||||
#endif /* __CYGWIN__ */
|
||||
|
||||
#if defined(__QNXNTO__) && !defined(FD_SETSIZE)
|
||||
#define FD_SETSIZE 1024 /* Max number of file descriptor bits in
|
||||
fd_set, used when calling 'select'
|
||||
Must be defined before including
|
||||
"sys/select.h" and "sys/time.h"
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
/* to make command line shorter we'll define USE_PRAGMA_INTERFACE here */
|
||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||
#define USE_PRAGMA_INTERFACE
|
||||
|
@ -1156,6 +1156,7 @@ sub environment_setup () {
|
||||
$ENV{'USE_RUNNING_SERVER'}= $glob_use_running_server;
|
||||
$ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir;
|
||||
$ENV{'MYSQLTEST_VARDIR'}= $opt_vardir;
|
||||
$ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir;
|
||||
$ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'};
|
||||
$ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'};
|
||||
$ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'};
|
||||
@ -2876,7 +2877,7 @@ sub run_mysqltest ($) {
|
||||
if ( $opt_debug )
|
||||
{
|
||||
$cmdline_mysqlcheck .=
|
||||
" --debug=d:t:A,$opt_vardir_trace/log/mysqldump.trace";
|
||||
" --debug=d:t:A,$opt_vardir_trace/log/mysqlcheck.trace";
|
||||
}
|
||||
|
||||
my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " .
|
||||
|
@ -202,6 +202,7 @@ SYST=0
|
||||
REALT=0
|
||||
FAST_START=""
|
||||
MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp
|
||||
export MYSQL_TMP_DIR
|
||||
|
||||
# Use a relative path for where the slave will find the dumps
|
||||
# generated by "LOAD DATA" on the master. The path is relative
|
||||
|
@ -402,3 +402,25 @@ explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'b
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where
|
||||
drop table t1;
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (
|
||||
a int, b int,
|
||||
filler1 char(200), filler2 char(200),
|
||||
key(a),key(b)
|
||||
);
|
||||
insert into t1 select @v:= A.a, @v, 't1', 'filler2' from t0 A, t0 B, t0 C;
|
||||
create table t2 like t1;
|
||||
create table t3 (
|
||||
a int, b int,
|
||||
filler1 char(200), filler2 char(200),
|
||||
key(a),key(b)
|
||||
) engine=merge union=(t1,t2);
|
||||
explain select * from t1 where a=1 and b=1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index_merge a,b a,b 5,5 NULL # Using intersect(a,b); Using where
|
||||
explain select * from t3 where a=1 and b=1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t3 index_merge a,b a,b 5,5 NULL # Using intersect(a,b); Using where
|
||||
drop table t3;
|
||||
drop table t0, t1, t2;
|
||||
|
@ -56,8 +56,8 @@ a b
|
||||
4 Testing
|
||||
5 table
|
||||
5 table
|
||||
6 t1
|
||||
6 t2
|
||||
6 t1
|
||||
7 Testing
|
||||
7 Testing
|
||||
8 table
|
||||
|
@ -859,6 +859,20 @@ count(*)
|
||||
5
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
prepare stmt from 'create table t1 (a varchar(10) character set utf8)';
|
||||
execute stmt;
|
||||
insert into t1 (a) values (repeat('a', 20));
|
||||
select length(a) from t1;
|
||||
length(a)
|
||||
10
|
||||
drop table t1;
|
||||
execute stmt;
|
||||
insert into t1 (a) values (repeat('a', 20));
|
||||
select length(a) from t1;
|
||||
length(a)
|
||||
10
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
create table t1 (id int);
|
||||
prepare ins_call from "insert into t1 (id) values (1)";
|
||||
execute ins_call;
|
||||
|
@ -1,4 +1,4 @@
|
||||
drop table if exists t1, t2, t3;
|
||||
drop table if exists t1, t2, t3, t4;
|
||||
drop view if exists v1;
|
||||
drop database if exists mysqltest;
|
||||
drop function if exists f1;
|
||||
@ -785,6 +785,107 @@ create trigger test.t1_bi before insert on t1 for each row set @a:=0;
|
||||
ERROR 3D000: No database selected
|
||||
drop trigger t1_bi;
|
||||
ERROR 3D000: No database selected
|
||||
create table t1 (id int);
|
||||
create trigger t1_bi before insert on t1 for each row set @a:=new.id;
|
||||
insert into t1 values (101);
|
||||
select @a;
|
||||
@a
|
||||
101
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
test t1_bi test t1 set @a:=new.id
|
||||
rename table t1 to t2;
|
||||
insert into t2 values (102);
|
||||
select @a;
|
||||
@a
|
||||
102
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
test t1_bi test t2 set @a:=new.id
|
||||
alter table t2 rename to t3;
|
||||
insert into t3 values (103);
|
||||
select @a;
|
||||
@a
|
||||
103
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
test t1_bi test t3 set @a:=new.id
|
||||
alter table t3 rename to t4, add column val int default 0;
|
||||
insert into t4 values (104, 1);
|
||||
select @a;
|
||||
@a
|
||||
104
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
test t1_bi test t4 set @a:=new.id
|
||||
drop trigger t1_bi;
|
||||
drop table t4;
|
||||
create database mysqltest;
|
||||
use mysqltest;
|
||||
create table t1 (id int);
|
||||
create trigger t1_bi before insert on t1 for each row set @a:=new.id;
|
||||
insert into t1 values (101);
|
||||
select @a;
|
||||
@a
|
||||
101
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test' or event_object_schema = 'mysqltest';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
mysqltest t1_bi mysqltest t1 set @a:=new.id
|
||||
rename table t1 to test.t2;
|
||||
ERROR HY000: Trigger in wrong schema
|
||||
insert into t1 values (102);
|
||||
select @a;
|
||||
@a
|
||||
102
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test' or event_object_schema = 'mysqltest';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
mysqltest t1_bi mysqltest t1 set @a:=new.id
|
||||
drop trigger test.t1_bi;
|
||||
ERROR HY000: Trigger does not exist
|
||||
drop trigger t1_bi;
|
||||
drop table t1;
|
||||
drop database mysqltest;
|
||||
use test;
|
||||
create table t1 (id int);
|
||||
create trigger t1_bi before insert on t1 for each row set @a:=new.id;
|
||||
create trigger t1_ai after insert on t1 for each row set @b:=new.id;
|
||||
insert into t1 values (101);
|
||||
select @a, @b;
|
||||
@a @b
|
||||
101 101
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
test t1_bi test t1 set @a:=new.id
|
||||
test t1_ai test t1 set @b:=new.id
|
||||
rename table t1 to t2;
|
||||
ERROR HY000: Can't create/write to file './test/t1_ai.TRN~' (Errcode: 13)
|
||||
insert into t1 values (102);
|
||||
select @a, @b;
|
||||
@a @b
|
||||
102 102
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
trigger_schema trigger_name event_object_schema event_object_table action_statement
|
||||
test t1_bi test t1 set @a:=new.id
|
||||
test t1_ai test t1 set @b:=new.id
|
||||
drop trigger t1_bi;
|
||||
drop trigger t1_ai;
|
||||
drop table t1;
|
||||
create table t1 (i int);
|
||||
create trigger t1_bi before insert on t1 for each row return 0;
|
||||
ERROR 42000: RETURN is only allowed in a FUNCTION
|
||||
|
@ -2529,3 +2529,13 @@ Warnings:
|
||||
Warning 1052 Column 'x' in group statement is ambiguous
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
drop table if exists t1;
|
||||
drop view if exists v1;
|
||||
create table t1 (id int);
|
||||
create view v1 as select * from t1;
|
||||
drop table t1;
|
||||
show create view v1;
|
||||
drop view v1;
|
||||
//
|
||||
View Create View
|
||||
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache `test`.`t1`.`id` AS `id` from `t1`
|
||||
|
@ -357,3 +357,29 @@ explain select * from t1 WHERE cola = 'foo' AND colb = 'bar';
|
||||
explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar';
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# BUG#17314: Index_merge/intersection not choosen by the optimizer for MERGE tables
|
||||
#
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (
|
||||
a int, b int,
|
||||
filler1 char(200), filler2 char(200),
|
||||
key(a),key(b)
|
||||
);
|
||||
insert into t1 select @v:= A.a, @v, 't1', 'filler2' from t0 A, t0 B, t0 C;
|
||||
create table t2 like t1;
|
||||
|
||||
create table t3 (
|
||||
a int, b int,
|
||||
filler1 char(200), filler2 char(200),
|
||||
key(a),key(b)
|
||||
) engine=merge union=(t1,t2);
|
||||
|
||||
--replace_column 9 #
|
||||
explain select * from t1 where a=1 and b=1;
|
||||
--replace_column 9 #
|
||||
explain select * from t3 where a=1 and b=1;
|
||||
|
||||
drop table t3;
|
||||
drop table t0, t1, t2;
|
||||
|
@ -900,6 +900,27 @@ execute stmt using @like;
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug#13134 "Length of VARCHAR() utf8 column is increasing when table is
|
||||
# recreated with PS/SP"
|
||||
#
|
||||
|
||||
prepare stmt from 'create table t1 (a varchar(10) character set utf8)';
|
||||
execute stmt;
|
||||
--disable_warnings
|
||||
insert into t1 (a) values (repeat('a', 20));
|
||||
--enable_warnings
|
||||
select length(a) from t1;
|
||||
drop table t1;
|
||||
execute stmt;
|
||||
--disable_warnings
|
||||
insert into t1 (a) values (repeat('a', 20));
|
||||
--enable_warnings
|
||||
# Check that the data is truncated to the same length
|
||||
select length(a) from t1;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2, t3;
|
||||
drop table if exists t1, t2, t3, t4;
|
||||
drop view if exists v1;
|
||||
drop database if exists mysqltest;
|
||||
drop function if exists f1;
|
||||
@ -959,6 +959,91 @@ create trigger test.t1_bi before insert on t1 for each row set @a:=0;
|
||||
drop trigger t1_bi;
|
||||
connection default;
|
||||
|
||||
#
|
||||
# Test for bug #13525 "Rename table does not keep info of triggers"
|
||||
#
|
||||
create table t1 (id int);
|
||||
create trigger t1_bi before insert on t1 for each row set @a:=new.id;
|
||||
insert into t1 values (101);
|
||||
select @a;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
rename table t1 to t2;
|
||||
# Trigger should work after rename
|
||||
insert into t2 values (102);
|
||||
select @a;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
# Let us check that the same works for simple ALTER TABLE ... RENAME
|
||||
alter table t2 rename to t3;
|
||||
insert into t3 values (103);
|
||||
select @a;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
# And for more complex ALTER TABLE
|
||||
alter table t3 rename to t4, add column val int default 0;
|
||||
insert into t4 values (104, 1);
|
||||
select @a;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
# .TRN file should be updated with new table name
|
||||
drop trigger t1_bi;
|
||||
drop table t4;
|
||||
# Rename between different databases if triggers exist should fail
|
||||
create database mysqltest;
|
||||
use mysqltest;
|
||||
create table t1 (id int);
|
||||
create trigger t1_bi before insert on t1 for each row set @a:=new.id;
|
||||
insert into t1 values (101);
|
||||
select @a;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test' or event_object_schema = 'mysqltest';
|
||||
--error ER_TRG_IN_WRONG_SCHEMA
|
||||
rename table t1 to test.t2;
|
||||
insert into t1 values (102);
|
||||
select @a;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test' or event_object_schema = 'mysqltest';
|
||||
# There should be no fantom .TRN files
|
||||
--error ER_TRG_DOES_NOT_EXIST
|
||||
drop trigger test.t1_bi;
|
||||
drop trigger t1_bi;
|
||||
drop table t1;
|
||||
drop database mysqltest;
|
||||
use test;
|
||||
# And now let us check that the properly handle rename if there is some
|
||||
# error during it (that we rollback such renames completely).
|
||||
create table t1 (id int);
|
||||
create trigger t1_bi before insert on t1 for each row set @a:=new.id;
|
||||
create trigger t1_ai after insert on t1 for each row set @b:=new.id;
|
||||
insert into t1 values (101);
|
||||
select @a, @b;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
# Trick which makes update of second .TRN file impossible
|
||||
system echo dummy >var/master-data/test/t1_ai.TRN~;
|
||||
system chmod 000 var/master-data/test/t1_ai.TRN~;
|
||||
--error 1
|
||||
rename table t1 to t2;
|
||||
# 't1' should be still there and triggers should work correctly
|
||||
insert into t1 values (102);
|
||||
select @a, @b;
|
||||
select trigger_schema, trigger_name, event_object_schema,
|
||||
event_object_table, action_statement from information_schema.triggers
|
||||
where event_object_schema = 'test';
|
||||
system chmod 600 var/master-data/test/t1_ai.TRN;
|
||||
# Let us check that updates to .TRN files were rolled back too
|
||||
drop trigger t1_bi;
|
||||
drop trigger t1_ai;
|
||||
drop table t1;
|
||||
|
||||
# Test for bug #16829 "Firing trigger with RETURN crashes the server"
|
||||
# RETURN is not supposed to be used anywhere except functions, so error
|
||||
# should be returned when one attempts to create trigger with RETURN.
|
||||
|
@ -2375,3 +2375,18 @@ SELECT IF(x IS NULL, 'blank', 'not blank') AS x FROM v1 GROUP BY x;
|
||||
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# BUG#15943: mysql_next_result hangs on invalid SHOW CREATE VIEW
|
||||
#
|
||||
|
||||
delimiter //;
|
||||
drop table if exists t1;
|
||||
drop view if exists v1;
|
||||
create table t1 (id int);
|
||||
create view v1 as select * from t1;
|
||||
drop table t1;
|
||||
show create view v1;
|
||||
drop view v1;
|
||||
//
|
||||
delimiter ;//
|
||||
|
@ -8297,13 +8297,11 @@ void Field_bit_as_char::sql_type(String &res) const
|
||||
create_field::create_length_to_internal_length()
|
||||
|
||||
DESCRIPTION
|
||||
Convert create_field::length from number of characters to number of bytes,
|
||||
save original value in chars_length.
|
||||
Convert create_field::length from number of characters to number of bytes.
|
||||
*/
|
||||
|
||||
void create_field::create_length_to_internal_length(void)
|
||||
{
|
||||
chars_length= length;
|
||||
switch (sql_type) {
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
@ -8355,7 +8353,7 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
|
||||
{
|
||||
field_name= "";
|
||||
sql_type= sql_type_arg;
|
||||
length= length_arg;;
|
||||
char_length= length= length_arg;;
|
||||
unireg_check= Field::NONE;
|
||||
interval= 0;
|
||||
charset= &my_charset_bin;
|
||||
@ -8683,6 +8681,8 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
|
||||
case FIELD_TYPE_DECIMAL:
|
||||
DBUG_ASSERT(0); /* Was obsolete */
|
||||
}
|
||||
/* Remember the value of length */
|
||||
char_length= length;
|
||||
|
||||
if (!(flags & BLOB_FLAG) &&
|
||||
((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
|
||||
@ -9023,6 +9023,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
|
||||
else
|
||||
interval=0;
|
||||
def=0;
|
||||
char_length= length;
|
||||
|
||||
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
|
||||
old_field->ptr && orig_field &&
|
||||
|
@ -1410,9 +1410,10 @@ public:
|
||||
*/
|
||||
ulong length;
|
||||
/*
|
||||
The value of 'length' before a call to create_length_to_internal_length
|
||||
The value of `length' as set by parser: is the number of characters
|
||||
for most of the types, or of bytes for BLOBs or numeric types.
|
||||
*/
|
||||
uint32 chars_length;
|
||||
uint32 char_length;
|
||||
uint decimals, flags, pack_length, key_length;
|
||||
Field::utype unireg_check;
|
||||
TYPELIB *interval; // Which interval to use
|
||||
|
@ -308,7 +308,27 @@ void ha_myisammrg::info(uint flag)
|
||||
table->s->keys_in_use.set_prefix(table->s->keys);
|
||||
table->s->db_options_in_use= info.options;
|
||||
mean_rec_length= info.reclength;
|
||||
block_size=0;
|
||||
|
||||
/*
|
||||
The handler::block_size is used all over the code in index scan cost
|
||||
calculations. It is used to get number of disk seeks required to
|
||||
retrieve a number of index tuples.
|
||||
If the merge table has N underlying tables, then (assuming underlying
|
||||
tables have equal size, the only "simple" approach we can use)
|
||||
retrieving X index records from a merge table will require N times more
|
||||
disk seeks compared to doing the same on a MyISAM table with equal
|
||||
number of records.
|
||||
In the edge case (file_tables > myisam_block_size) we'll get
|
||||
block_size==0, and index calculation code will act as if we need one
|
||||
disk seek to retrieve one index tuple.
|
||||
|
||||
TODO: In 5.2 index scan cost calculation will be factored out into a
|
||||
virtual function in class handler and we'll be able to remove this hack.
|
||||
*/
|
||||
block_size= 0;
|
||||
if (file->tables)
|
||||
block_size= myisam_block_size / file->tables;
|
||||
|
||||
update_time=0;
|
||||
#if SIZEOF_OFF_T > 4
|
||||
ref_length=6; // Should be big enough
|
||||
|
@ -4416,7 +4416,6 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
|
||||
{
|
||||
Field_iterator_table_ref it_1, it_2;
|
||||
Natural_join_column *nj_col_1, *nj_col_2;
|
||||
const char *field_name_1;
|
||||
Query_arena *arena, backup;
|
||||
bool add_columns= TRUE;
|
||||
bool result= TRUE;
|
||||
@ -4449,6 +4448,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
|
||||
{
|
||||
bool is_created_1;
|
||||
bool found= FALSE;
|
||||
const char *field_name_1;
|
||||
if (!(nj_col_1= it_1.get_or_create_column_ref(&is_created_1)))
|
||||
goto err;
|
||||
field_name_1= nj_col_1->name();
|
||||
@ -4649,7 +4649,6 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
|
||||
{
|
||||
Field_iterator_table_ref it_1, it_2;
|
||||
Natural_join_column *nj_col_1, *nj_col_2;
|
||||
bool is_created;
|
||||
Query_arena *arena, backup;
|
||||
bool result= TRUE;
|
||||
List<Natural_join_column> *non_join_columns;
|
||||
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_trigger.h"
|
||||
|
||||
|
||||
static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
|
||||
@ -173,9 +174,30 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
|
||||
if (table_type == DB_TYPE_UNKNOWN)
|
||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||
else
|
||||
rc= mysql_rename_table(ha_resolve_by_legacy_type(thd, table_type),
|
||||
ren_table->db, old_alias,
|
||||
new_table->db, new_alias);
|
||||
{
|
||||
if (!(rc= mysql_rename_table(ha_resolve_by_legacy_type(thd,
|
||||
table_type),
|
||||
ren_table->db, old_alias,
|
||||
new_table->db, new_alias)))
|
||||
{
|
||||
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
|
||||
old_alias,
|
||||
new_table->db,
|
||||
new_alias)))
|
||||
{
|
||||
/*
|
||||
We've succeeded in renaming table's .frm and in updating
|
||||
corresponding handler data, but have failed to update table's
|
||||
triggers appropriately. So let us revert operations on .frm
|
||||
and handler's data and report about failure to rename table.
|
||||
*/
|
||||
(void) mysql_rename_table(ha_resolve_by_legacy_type(thd,
|
||||
table_type),
|
||||
new_table->db, new_alias,
|
||||
ren_table->db, old_alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRMTYPE_VIEW:
|
||||
|
@ -176,7 +176,9 @@ typedef struct st_rollup
|
||||
|
||||
class JOIN :public Sql_alloc
|
||||
{
|
||||
public:
|
||||
JOIN(const JOIN &rhs); /* not implemented */
|
||||
JOIN& operator=(const JOIN &rhs); /* not implemented */
|
||||
public:
|
||||
JOIN_TAB *join_tab,**best_ref;
|
||||
JOIN_TAB **map2table; // mapping between table indexes and JOIN_TABs
|
||||
JOIN_TAB *join_tab_save; // saved join_tab for subquery reexecution
|
||||
@ -288,13 +290,6 @@ class JOIN :public Sql_alloc
|
||||
init(thd_arg, fields_arg, select_options_arg, result_arg);
|
||||
}
|
||||
|
||||
JOIN(JOIN &join)
|
||||
:Sql_alloc(), fields_list(join.fields_list)
|
||||
{
|
||||
init(join.thd, join.fields_list, join.select_options,
|
||||
join.result);
|
||||
}
|
||||
|
||||
void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
|
||||
select_result *result_arg)
|
||||
{
|
||||
|
@ -513,12 +513,15 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
/*
|
||||
Clear all messages with 'error' level status and
|
||||
issue a warning with 'warning' level status in
|
||||
case of invalid view and last error is ER_VIEW_INVALID
|
||||
*/
|
||||
mysql_reset_errors(thd, true);
|
||||
thd->clear_error();
|
||||
|
||||
push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_VIEW_INVALID,
|
||||
ER(ER_VIEW_INVALID),
|
||||
|
@ -1127,6 +1127,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
{
|
||||
CHARSET_INFO *save_cs;
|
||||
|
||||
/*
|
||||
Initialize length from its original value (number of characters),
|
||||
which was set in the parser. This is necessary if we're
|
||||
executing a prepared statement for the second time.
|
||||
*/
|
||||
sql_field->length= sql_field->char_length;
|
||||
if (!sql_field->charset)
|
||||
sql_field->charset= create_info->default_table_charset;
|
||||
/*
|
||||
@ -1311,7 +1317,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
sql_field->charset= (dup_field->charset ?
|
||||
dup_field->charset :
|
||||
create_info->default_table_charset);
|
||||
sql_field->length= dup_field->chars_length;
|
||||
sql_field->length= dup_field->char_length;
|
||||
sql_field->pack_length= dup_field->pack_length;
|
||||
sql_field->key_length= dup_field->key_length;
|
||||
sql_field->create_length_to_internal_length();
|
||||
@ -4031,6 +4037,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
close_cached_table(thd, table);
|
||||
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias))
|
||||
error= -1;
|
||||
else if (Table_triggers_list::change_table_name(thd, db, table_name,
|
||||
new_db, new_alias))
|
||||
{
|
||||
VOID(mysql_rename_table(old_db_type, new_db, new_alias, db,
|
||||
table_name));
|
||||
error= -1;
|
||||
}
|
||||
}
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
}
|
||||
@ -4933,7 +4946,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
VOID(quick_rm_table(new_db_type,new_db,tmp_name));
|
||||
}
|
||||
else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db,
|
||||
new_alias))
|
||||
new_alias) ||
|
||||
(new_name != table_name || new_db != db) && // we also do rename
|
||||
Table_triggers_list::change_table_name(thd, db, table_name,
|
||||
new_db, new_alias))
|
||||
|
||||
{ // Try to get everything back
|
||||
error=1;
|
||||
VOID(quick_rm_table(new_db_type,new_db,new_alias));
|
||||
|
@ -65,7 +65,6 @@ File_option sql_modes_parameters=
|
||||
*/
|
||||
|
||||
static const int TRG_NUM_REQUIRED_PARAMETERS= 4;
|
||||
static const int TRG_MAX_VERSIONS= 3;
|
||||
|
||||
/*
|
||||
Structure representing contents of .TRN file which are used to support
|
||||
@ -318,8 +317,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
TABLE *table= tables->table;
|
||||
char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN],
|
||||
trigname_path[FN_REFLEN];
|
||||
char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
|
||||
LEX_STRING file, trigname_file;
|
||||
LEX_STRING *trg_def, *name;
|
||||
ulonglong *trg_sql_mode;
|
||||
@ -472,12 +470,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
||||
definer_host->str, NullS) - trg_definer->str;
|
||||
|
||||
if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
|
||||
(gptr)this, triggers_file_parameters,
|
||||
TRG_MAX_VERSIONS))
|
||||
(gptr)this, triggers_file_parameters, 0))
|
||||
return 0;
|
||||
|
||||
err_with_cleanup:
|
||||
my_delete(trigname_path, MYF(MY_WME));
|
||||
my_delete(trigname_buff, MYF(MY_WME));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -497,7 +494,8 @@ err_with_cleanup:
|
||||
True - error
|
||||
*/
|
||||
|
||||
static bool rm_trigger_file(char *path, char *db, char *table_name)
|
||||
static bool rm_trigger_file(char *path, const char *db,
|
||||
const char *table_name)
|
||||
{
|
||||
build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext);
|
||||
return my_delete(path, MYF(MY_WME));
|
||||
@ -519,13 +517,43 @@ static bool rm_trigger_file(char *path, char *db, char *table_name)
|
||||
True - error
|
||||
*/
|
||||
|
||||
static bool rm_trigname_file(char *path, char *db, char *trigger_name)
|
||||
static bool rm_trigname_file(char *path, const char *db,
|
||||
const char *trigger_name)
|
||||
{
|
||||
build_table_filename(path, FN_REFLEN-1, db, trigger_name, trigname_file_ext);
|
||||
return my_delete(path, MYF(MY_WME));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Helper function that saves .TRG file for Table_triggers_list object.
|
||||
|
||||
SYNOPSIS
|
||||
save_trigger_file()
|
||||
triggers Table_triggers_list object for which file should be saved
|
||||
db Name of database for subject table
|
||||
table_name Name of subject table
|
||||
|
||||
RETURN VALUE
|
||||
FALSE Success
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
|
||||
const char *table_name)
|
||||
{
|
||||
char file_buff[FN_REFLEN];
|
||||
LEX_STRING file;
|
||||
|
||||
file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name,
|
||||
triggers_file_ext);
|
||||
file.str= file_buff;
|
||||
return sql_create_definition_file(NULL, &file, &triggers_file_type,
|
||||
(gptr)triggers, triggers_file_parameters,
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Drop trigger for table.
|
||||
|
||||
@ -579,16 +607,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
|
||||
}
|
||||
else
|
||||
{
|
||||
char file_buff[FN_REFLEN];
|
||||
LEX_STRING file;
|
||||
|
||||
file.length= build_table_filename(file_buff, FN_REFLEN-1,
|
||||
tables->db, tables->table_name,
|
||||
triggers_file_ext);
|
||||
file.str= file_buff;
|
||||
if (sql_create_definition_file(NULL, &file, &triggers_file_type,
|
||||
(gptr)this, triggers_file_parameters,
|
||||
TRG_MAX_VERSIONS))
|
||||
if (save_trigger_file(this, tables->db, tables->table_name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -827,12 +846,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
if (!names_only && triggers->prepare_record1_accessors(table))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
char *trg_name_buff;
|
||||
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
|
||||
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
|
||||
LEX *old_lex= thd->lex, lex;
|
||||
sp_rcontext *save_spcont= thd->spcont;
|
||||
ulong save_sql_mode= thd->variables.sql_mode;
|
||||
LEX_STRING *on_table_name;
|
||||
|
||||
thd->lex= &lex;
|
||||
|
||||
@ -898,6 +917,21 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
&table->mem_root))
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
if (!(on_table_name= (LEX_STRING*) alloc_root(&table->mem_root,
|
||||
sizeof(LEX_STRING))))
|
||||
goto err_with_lex_cleanup;
|
||||
*on_table_name= lex.ident;
|
||||
if (triggers->on_table_names_list.push_back(on_table_name, &table->mem_root))
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
/*
|
||||
Let us check that we correctly update trigger definitions when we
|
||||
rename tables with triggers.
|
||||
*/
|
||||
DBUG_ASSERT(!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) &&
|
||||
!my_strcasecmp(table_alias_charset, lex.query_tables->table_name,
|
||||
table_name));
|
||||
|
||||
if (names_only)
|
||||
{
|
||||
lex_end(&lex);
|
||||
@ -1063,7 +1097,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
|
||||
lex->query_tables= 0;
|
||||
lex->query_tables_last= &lex->query_tables;
|
||||
DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
|
||||
trigname.trigger_table.str, TL_WRITE));
|
||||
trigname.trigger_table.str, TL_IGNORE));
|
||||
}
|
||||
|
||||
|
||||
@ -1133,6 +1167,218 @@ end:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Update .TRG file after renaming triggers' subject table
|
||||
(change name of table in triggers' definitions).
|
||||
|
||||
SYNOPSIS
|
||||
change_table_name_in_triggers()
|
||||
thd Thread context
|
||||
db_name Database of subject table
|
||||
old_table_name Old subject table's name
|
||||
new_table_name New subject table's name
|
||||
|
||||
RETURN VALUE
|
||||
FALSE Success
|
||||
TRUE Failure
|
||||
*/
|
||||
|
||||
bool
|
||||
Table_triggers_list::change_table_name_in_triggers(THD *thd,
|
||||
const char *db_name,
|
||||
LEX_STRING *old_table_name,
|
||||
LEX_STRING *new_table_name)
|
||||
{
|
||||
char path_buff[FN_REFLEN];
|
||||
LEX_STRING *def, *on_table_name, new_def;
|
||||
ulonglong *sql_mode;
|
||||
ulong save_sql_mode= thd->variables.sql_mode;
|
||||
List_iterator_fast<LEX_STRING> it_def(definitions_list);
|
||||
List_iterator_fast<LEX_STRING> it_on_table_name(on_table_names_list);
|
||||
List_iterator_fast<ulonglong> it_mode(definition_modes_list);
|
||||
uint on_q_table_name_len, before_on_len;
|
||||
String buff;
|
||||
|
||||
DBUG_ASSERT(definitions_list.elements == on_table_names_list.elements &&
|
||||
definitions_list.elements == definition_modes_list.elements);
|
||||
|
||||
while ((def= it_def++))
|
||||
{
|
||||
on_table_name= it_on_table_name++;
|
||||
thd->variables.sql_mode= *(it_mode++);
|
||||
|
||||
/* Construct CREATE TRIGGER statement with new table name. */
|
||||
buff.length(0);
|
||||
before_on_len= on_table_name->str - def->str;
|
||||
buff.append(def->str, before_on_len);
|
||||
buff.append(STRING_WITH_LEN("ON "));
|
||||
append_identifier(thd, &buff, new_table_name->str, new_table_name->length);
|
||||
on_q_table_name_len= buff.length() - before_on_len;
|
||||
buff.append(on_table_name->str + on_table_name->length,
|
||||
def->length - (before_on_len + on_table_name->length));
|
||||
/*
|
||||
It is OK to allocate some memory on table's MEM_ROOT since this
|
||||
table instance will be thrown out at the end of rename anyway.
|
||||
*/
|
||||
new_def.str= memdup_root(&table->mem_root, buff.ptr(), buff.length());
|
||||
new_def.length= buff.length();
|
||||
on_table_name->str= new_def.str + before_on_len;
|
||||
on_table_name->length= on_q_table_name_len;
|
||||
*def= new_def;
|
||||
}
|
||||
|
||||
thd->variables.sql_mode= save_sql_mode;
|
||||
|
||||
if (thd->is_fatal_error)
|
||||
return TRUE; /* OOM */
|
||||
|
||||
if (save_trigger_file(this, db_name, new_table_name->str))
|
||||
return TRUE;
|
||||
if (rm_trigger_file(path_buff, db_name, old_table_name->str))
|
||||
{
|
||||
(void) rm_trigger_file(path_buff, db_name, new_table_name->str);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Iterate though Table_triggers_list::names_list list and update .TRN files
|
||||
after renaming triggers' subject table.
|
||||
|
||||
SYNOPSIS
|
||||
change_table_name_in_trignames()
|
||||
db_name Database of subject table
|
||||
new_table_name New subject table's name
|
||||
stopper Pointer to Table_triggers_list::names_list at
|
||||
which we should stop updating.
|
||||
|
||||
RETURN VALUE
|
||||
0 Success
|
||||
non-0 Failure, pointer to Table_triggers_list::names_list element
|
||||
for which update failed.
|
||||
*/
|
||||
|
||||
LEX_STRING*
|
||||
Table_triggers_list::change_table_name_in_trignames(const char *db_name,
|
||||
LEX_STRING *new_table_name,
|
||||
LEX_STRING *stopper)
|
||||
{
|
||||
char trigname_buff[FN_REFLEN];
|
||||
struct st_trigname trigname;
|
||||
LEX_STRING trigname_file;
|
||||
LEX_STRING *trigger;
|
||||
List_iterator_fast<LEX_STRING> it_name(names_list);
|
||||
|
||||
while ((trigger= it_name++) != stopper)
|
||||
{
|
||||
trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
|
||||
db_name, trigger->str,
|
||||
trigname_file_ext);
|
||||
trigname_file.str= trigname_buff;
|
||||
|
||||
trigname.trigger_table= *new_table_name;
|
||||
|
||||
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
|
||||
(gptr)&trigname, trigname_file_parameters,
|
||||
0))
|
||||
return trigger;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Update .TRG and .TRN files after renaming triggers' subject table.
|
||||
|
||||
SYNOPSIS
|
||||
change_table_name()
|
||||
thd Thread context
|
||||
db Old database of subject table
|
||||
old_table Old name of subject table
|
||||
new_db New database for subject table
|
||||
new_table New name of subject table
|
||||
|
||||
NOTE
|
||||
This method tries to leave trigger related files in consistent state,
|
||||
i.e. it either will complete successfully, or will fail leaving files
|
||||
in their initial state.
|
||||
|
||||
RETURN VALUE
|
||||
FALSE Success
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
bool Table_triggers_list::change_table_name(THD *thd, const char *db,
|
||||
const char *old_table,
|
||||
const char *new_db,
|
||||
const char *new_table)
|
||||
{
|
||||
TABLE table;
|
||||
bool result= 0;
|
||||
LEX_STRING *err_trigname;
|
||||
DBUG_ENTER("change_table_name");
|
||||
|
||||
bzero(&table, sizeof(table));
|
||||
init_alloc_root(&table.mem_root, 8192, 0);
|
||||
|
||||
safe_mutex_assert_owner(&LOCK_open);
|
||||
|
||||
if (Table_triggers_list::check_n_load(thd, db, old_table, &table, TRUE))
|
||||
{
|
||||
result= 1;
|
||||
goto end;
|
||||
}
|
||||
if (table.triggers)
|
||||
{
|
||||
LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
|
||||
LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
|
||||
/*
|
||||
Since triggers should be in the same schema as their subject tables
|
||||
moving table with them between two schemas raises too many questions.
|
||||
(E.g. what should happen if in new schema we already have trigger
|
||||
with same name ?).
|
||||
*/
|
||||
if (my_strcasecmp(table_alias_charset, db, new_db))
|
||||
{
|
||||
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
|
||||
result= 1;
|
||||
goto end;
|
||||
}
|
||||
if (table.triggers->change_table_name_in_triggers(thd, db,
|
||||
&old_table_name,
|
||||
&new_table_name))
|
||||
{
|
||||
result= 1;
|
||||
goto end;
|
||||
}
|
||||
if ((err_trigname= table.triggers->change_table_name_in_trignames(
|
||||
db, &new_table_name, 0)))
|
||||
{
|
||||
/*
|
||||
If we were unable to update one of .TRN files properly we will
|
||||
revert all changes that we have done and report about error.
|
||||
We assume that we will be able to undo our changes without errors
|
||||
(we can't do much if there will be an error anyway).
|
||||
*/
|
||||
(void) table.triggers->change_table_name_in_trignames(db,
|
||||
&old_table_name,
|
||||
err_trigname);
|
||||
(void) table.triggers->change_table_name_in_triggers(thd, db,
|
||||
&new_table_name,
|
||||
&old_table_name);
|
||||
result= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
end:
|
||||
delete table.triggers;
|
||||
free_root(&table.mem_root, MYF(0));
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||
trg_action_time_type time_type,
|
||||
|
@ -46,6 +46,11 @@ class Table_triggers_list: public Sql_alloc
|
||||
used in CREATE/DROP TRIGGER for looking up trigger by name.
|
||||
*/
|
||||
List<LEX_STRING> names_list;
|
||||
/*
|
||||
List of "ON table_name" parts in trigger definitions, used for
|
||||
updating trigger definitions during RENAME TABLE.
|
||||
*/
|
||||
List<LEX_STRING> on_table_names_list;
|
||||
/*
|
||||
Key representing triggers for this table in set of all stored
|
||||
routines used by statement.
|
||||
@ -97,7 +102,10 @@ public:
|
||||
static bool check_n_load(THD *thd, const char *db, const char *table_name,
|
||||
TABLE *table, bool names_only);
|
||||
static bool drop_all_triggers(THD *thd, char *db, char *table_name);
|
||||
|
||||
static bool change_table_name(THD *thd, const char *db,
|
||||
const char *old_table,
|
||||
const char *new_db,
|
||||
const char *new_table);
|
||||
bool has_delete_triggers()
|
||||
{
|
||||
return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
|
||||
@ -117,6 +125,13 @@ public:
|
||||
|
||||
private:
|
||||
bool prepare_record1_accessors(TABLE *table);
|
||||
LEX_STRING* change_table_name_in_trignames(const char *db_name,
|
||||
LEX_STRING *new_table_name,
|
||||
LEX_STRING *stopper);
|
||||
bool change_table_name_in_triggers(THD *thd,
|
||||
const char *db_name,
|
||||
LEX_STRING *old_table_name,
|
||||
LEX_STRING *new_table_name);
|
||||
};
|
||||
|
||||
extern const LEX_STRING trg_action_time_type_names[];
|
||||
|
@ -10931,7 +10931,7 @@ view_check_option:
|
||||
|
||||
trigger_tail:
|
||||
TRIGGER_SYM remember_name sp_name trg_action_time trg_event
|
||||
ON table_ident FOR_SYM EACH_SYM ROW_SYM
|
||||
ON remember_name table_ident remember_end FOR_SYM EACH_SYM ROW_SYM
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp;
|
||||
@ -10948,6 +10948,8 @@ trigger_tail:
|
||||
sp->init(lex);
|
||||
|
||||
lex->trigger_definition_begin= $2;
|
||||
lex->ident.str= $7;
|
||||
lex->ident.length= $9 - $7;
|
||||
|
||||
sp->m_type= TYPE_ENUM_TRIGGER;
|
||||
lex->sphead= sp;
|
||||
@ -10975,7 +10977,7 @@ trigger_tail:
|
||||
sp->init_strings(YYTHD, lex, $3);
|
||||
/* Restore flag if it was cleared above */
|
||||
|
||||
YYTHD->client_capabilities |= $<ulong_num>11;
|
||||
YYTHD->client_capabilities |= $<ulong_num>13;
|
||||
sp->restore_thd_mem_root(YYTHD);
|
||||
|
||||
if (sp->is_not_allowed_in_function("trigger"))
|
||||
@ -10985,15 +10987,11 @@ trigger_tail:
|
||||
We have to do it after parsing trigger body, because some of
|
||||
sp_proc_stmt alternatives are not saving/restoring LEX, so
|
||||
lex->query_tables can be wiped out.
|
||||
|
||||
QQ: What are other consequences of this?
|
||||
|
||||
QQ: Could we loosen lock type in certain cases ?
|
||||
*/
|
||||
if (!lex->select_lex.add_table_to_list(YYTHD, $7,
|
||||
if (!lex->select_lex.add_table_to_list(YYTHD, $8,
|
||||
(LEX_STRING*) 0,
|
||||
TL_OPTION_UPDATING,
|
||||
TL_WRITE))
|
||||
TL_IGNORE))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
@ -18,12 +18,26 @@
|
||||
|
||||
static int queue_key_cmp(void *keyseg, byte *a, byte *b)
|
||||
{
|
||||
MI_INFO *aa=((MYRG_TABLE *)a)->table;
|
||||
MI_INFO *bb=((MYRG_TABLE *)b)->table;
|
||||
MYRG_TABLE *ma= (MYRG_TABLE *)a;
|
||||
MYRG_TABLE *mb= (MYRG_TABLE *)b;
|
||||
MI_INFO *aa= ma->table;
|
||||
MI_INFO *bb= mb->table;
|
||||
uint not_used[2];
|
||||
int ret= ha_key_cmp((HA_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
|
||||
USE_WHOLE_KEY, SEARCH_FIND, not_used);
|
||||
return ret < 0 ? -1 : ret > 0 ? 1 : 0;
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret > 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
If index tuples have the same values, let the record with least rowid
|
||||
value be "smaller", so index scans return records ordered by (keytuple,
|
||||
rowid). This is used by index_merge access method, grep for ROR in
|
||||
sql/opt_range.cc for details.
|
||||
*/
|
||||
return (ma->file_offset < mb->file_offset)? -1 : (ma->file_offset >
|
||||
mb->file_offset) ? 1 : 0;
|
||||
} /* queue_key_cmp */
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user