mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
Merge aivanov@bk-internal.mysql.com:/home/bk/mysql-5.1-new
into mysql.com:/home/alexi/innodb/mysql-5.1 sql/ha_innodb.cc: Auto merged mysql-test/r/innodb.result: Hand-merge mysql-test/t/innodb.test: Hand_merge
This commit is contained in:
@@ -1295,22 +1295,14 @@ insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
29267
|
||||
explain select * from t1 where c between 1 and 10000;
|
||||
623
|
||||
explain select * from t1 where c between 1 and 2500;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range c c 5 NULL # Using where
|
||||
update t1 set c=a;
|
||||
explain select * from t1 where c between 1 and 10000;
|
||||
explain select * from t1 where c between 1 and 2500;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL c NULL NULL NULL # Using where
|
||||
drop table t1,t2;
|
||||
@@ -1775,21 +1767,6 @@ select count(*) from t1 where x = 18446744073709551601;
|
||||
count(*)
|
||||
1
|
||||
drop table t1;
|
||||
show status like "Innodb_buffer_pool_pages_total";
|
||||
Variable_name Value
|
||||
Innodb_buffer_pool_pages_total 512
|
||||
show status like "Innodb_page_size";
|
||||
Variable_name Value
|
||||
Innodb_page_size 16384
|
||||
show status like "Innodb_rows_deleted";
|
||||
Variable_name Value
|
||||
Innodb_rows_deleted 2070
|
||||
show status like "Innodb_rows_inserted";
|
||||
Variable_name Value
|
||||
Innodb_rows_inserted 31727
|
||||
show status like "Innodb_rows_updated";
|
||||
Variable_name Value
|
||||
Innodb_rows_updated 29530
|
||||
show status like "Innodb_row_lock_waits";
|
||||
Variable_name Value
|
||||
Innodb_row_lock_waits 0
|
||||
@@ -3233,15 +3210,6 @@ drop trigger t2t;
|
||||
drop trigger t3t;
|
||||
drop trigger t4t;
|
||||
drop table t1, t2, t3, t4, t5;
|
||||
create table t1(a date) engine=innodb;
|
||||
create table t2(a date, key(a)) engine=innodb;
|
||||
insert into t1 values('2005-10-01');
|
||||
insert into t2 values('2005-10-01');
|
||||
select * from t1, t2
|
||||
where t2.a between t1.a - interval 2 day and t1.a + interval 2 day;
|
||||
a a
|
||||
2005-10-01 2005-10-01
|
||||
drop table t1, t2;
|
||||
CREATE TABLE t1 (
|
||||
field1 varchar(8) NOT NULL DEFAULT '',
|
||||
field2 varchar(8) NOT NULL DEFAULT '',
|
||||
@@ -3291,3 +3259,141 @@ t1 CREATE TABLE `t1` (
|
||||
UNIQUE KEY `c2` (`c2`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1, t2;
|
||||
create table t1(a date) engine=innodb;
|
||||
create table t2(a date, key(a)) engine=innodb;
|
||||
insert into t1 values('2005-10-01');
|
||||
insert into t2 values('2005-10-01');
|
||||
select * from t1, t2
|
||||
where t2.a between t1.a - interval 2 day and t1.a + interval 2 day;
|
||||
a a
|
||||
2005-10-01 2005-10-01
|
||||
drop table t1, t2;
|
||||
create table t1 (id int not null, f_id int not null, f int not null,
|
||||
primary key(f_id, id)) engine=innodb;
|
||||
create table t2 (id int not null,s_id int not null,s varchar(200),
|
||||
primary key(id)) engine=innodb;
|
||||
INSERT INTO t1 VALUES (8, 1, 3);
|
||||
INSERT INTO t1 VALUES (1, 2, 1);
|
||||
INSERT INTO t2 VALUES (1, 0, '');
|
||||
INSERT INTO t2 VALUES (8, 1, '');
|
||||
commit;
|
||||
DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
|
||||
WHERE mm.id IS NULL;
|
||||
select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id)
|
||||
where mm.id is null lock in share mode;
|
||||
id f_id f
|
||||
drop table t1,t2;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
update t1 set b = 5 where b = 1;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
select * from t1 where a = 7 and b = 3 for update;
|
||||
a b
|
||||
7 3
|
||||
commit;
|
||||
commit;
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t1 lock in share mode;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
3 1
|
||||
4 2
|
||||
5 1
|
||||
6 2
|
||||
update t1 set b = 5 where b = 1;
|
||||
set autocommit = 0;
|
||||
select * from t1 where a = 2 and b = 2 for update;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
commit;
|
||||
commit;
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
d e
|
||||
3 1
|
||||
8 6
|
||||
12 1
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
insert into t1 select * from t2;
|
||||
update t1 set b = (select e from t2 where a = d);
|
||||
create table t3(d int not null, e int, primary key(d)) engine=innodb
|
||||
select * from t2;
|
||||
commit;
|
||||
commit;
|
||||
drop table t1, t2, t3;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
create table t3(d int not null, b int, primary key(d)) engine=innodb;
|
||||
insert into t3 values (8,6),(12,1),(3,1);
|
||||
create table t5(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t5 values (1,2),(5,3),(4,2);
|
||||
create table t6(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t6 values (8,6),(12,1),(3,1);
|
||||
create table t8(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t8 values (1,2),(5,3),(4,2);
|
||||
create table t9(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t9 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
a b
|
||||
3 1
|
||||
8 6
|
||||
12 1
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
insert into t1 select * from t2;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
update t3 set b = (select b from t2 where a = d);
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
insert into t5 (select * from t2 lock in share mode);
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
update t6 set e = (select b from t2 where a = d lock in share mode);
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
insert into t8 (select * from t2 for update);
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
update t9 set e = (select b from t2 where a = d for update);
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
commit;
|
||||
drop table t1, t2, t3, t5, t6, t8, t9;
|
||||
CREATE TABLE t1 (DB_ROW_ID int) engine=innodb;
|
||||
ERROR HY000: Can't create table 'test.t1' (errno: -1)
|
||||
|
@@ -15,7 +15,7 @@ where mm.id is null lock in share mode;
|
||||
id f_id f
|
||||
drop table t1,t2;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t1 lock in share mode;
|
||||
@@ -26,6 +26,7 @@ a b
|
||||
4 2
|
||||
5 1
|
||||
6 2
|
||||
7 3
|
||||
update t1 set b = 5 where b = 1;
|
||||
set autocommit = 0;
|
||||
select * from t1 where a = 2 and b = 2 for update;
|
||||
@@ -33,3 +34,87 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
commit;
|
||||
commit;
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
update t1 set b = 5 where b = 1;
|
||||
set autocommit = 0;
|
||||
select * from t1 where a = 7 and b = 3 for update;
|
||||
a b
|
||||
7 3
|
||||
commit;
|
||||
commit;
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
d e
|
||||
3 1
|
||||
8 6
|
||||
12 1
|
||||
set autocommit = 0;
|
||||
insert into t1 select * from t2;
|
||||
update t1 set b = (select e from t2 where a = d);
|
||||
create table t3(d int not null, e int, primary key(d)) engine=innodb
|
||||
select * from t2;
|
||||
commit;
|
||||
commit;
|
||||
drop table t1, t2, t3;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
create table t3(d int not null, b int, primary key(d)) engine=innodb;
|
||||
insert into t3 values (8,6),(12,1),(3,1);
|
||||
create table t5(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t5 values (1,2),(5,3),(4,2);
|
||||
create table t6(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t6 values (8,6),(12,1),(3,1);
|
||||
create table t8(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t8 values (1,2),(5,3),(4,2);
|
||||
create table t9(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t9 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
a b
|
||||
3 1
|
||||
8 6
|
||||
12 1
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
insert into t1 select * from t2;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
update t3 set b = (select b from t2 where a = d);
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
|
||||
set autocommit = 0;
|
||||
insert into t5 (select * from t2 lock in share mode);
|
||||
set autocommit = 0;
|
||||
update t6 set e = (select b from t2 where a = d lock in share mode);
|
||||
set autocommit = 0;
|
||||
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
|
||||
set autocommit = 0;
|
||||
insert into t8 (select * from t2 for update);
|
||||
set autocommit = 0;
|
||||
update t9 set e = (select b from t2 where a = d for update);
|
||||
set autocommit = 0;
|
||||
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
commit;
|
||||
drop table t1, t2, t3, t5, t6, t8, t9;
|
||||
|
@@ -1 +1 @@
|
||||
--binlog_cache_size=32768
|
||||
--binlog_cache_size=32768 --innodb_lock_wait_timeout=1
|
||||
|
@@ -891,20 +891,12 @@ insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
insert into t2 (a) select b from t1;
|
||||
insert into t1 (a) select b from t2;
|
||||
select count(*) from t1;
|
||||
--replace_column 9 #
|
||||
explain select * from t1 where c between 1 and 10000;
|
||||
explain select * from t1 where c between 1 and 2500;
|
||||
update t1 set c=a;
|
||||
--replace_column 9 #
|
||||
explain select * from t1 where c between 1 and 10000;
|
||||
explain select * from t1 where c between 1 and 2500;
|
||||
drop table t1,t2;
|
||||
|
||||
#
|
||||
@@ -1290,15 +1282,6 @@ select * from t1 where x > -16;
|
||||
select count(*) from t1 where x = 18446744073709551601;
|
||||
drop table t1;
|
||||
|
||||
|
||||
# Test for testable InnoDB status variables. This test
|
||||
# uses previous ones(pages_created, rows_deleted, ...).
|
||||
show status like "Innodb_buffer_pool_pages_total";
|
||||
show status like "Innodb_page_size";
|
||||
show status like "Innodb_rows_deleted";
|
||||
show status like "Innodb_rows_inserted";
|
||||
show status like "Innodb_rows_updated";
|
||||
|
||||
# Test for row locks InnoDB status variables.
|
||||
show status like "Innodb_row_lock_waits";
|
||||
show status like "Innodb_row_lock_current_waits";
|
||||
@@ -2193,3 +2176,268 @@ alter table t1 drop foreign key c2_fk;
|
||||
show create table t1;
|
||||
#
|
||||
drop table t1, t2;
|
||||
#
|
||||
# Bug #14360: problem with intervals
|
||||
#
|
||||
|
||||
create table t1(a date) engine=innodb;
|
||||
create table t2(a date, key(a)) engine=innodb;
|
||||
insert into t1 values('2005-10-01');
|
||||
insert into t2 values('2005-10-01');
|
||||
select * from t1, t2
|
||||
where t2.a between t1.a - interval 2 day and t1.a + interval 2 day;
|
||||
drop table t1, t2;
|
||||
|
||||
create table t1 (id int not null, f_id int not null, f int not null,
|
||||
primary key(f_id, id)) engine=innodb;
|
||||
create table t2 (id int not null,s_id int not null,s varchar(200),
|
||||
primary key(id)) engine=innodb;
|
||||
INSERT INTO t1 VALUES (8, 1, 3);
|
||||
INSERT INTO t1 VALUES (1, 2, 1);
|
||||
INSERT INTO t2 VALUES (1, 0, '');
|
||||
INSERT INTO t2 VALUES (8, 1, '');
|
||||
commit;
|
||||
DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
|
||||
WHERE mm.id IS NULL;
|
||||
select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id)
|
||||
where mm.id is null lock in share mode;
|
||||
drop table t1,t2;
|
||||
|
||||
#
|
||||
# Test case where X-locks on unused rows should be released in a
|
||||
# update (because READ COMMITTED isolation level)
|
||||
#
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
update t1 set b = 5 where b = 1;
|
||||
connection b;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
#
|
||||
# X-lock to record (7,3) should be released in a update
|
||||
#
|
||||
select * from t1 where a = 7 and b = 3 for update;
|
||||
connection a;
|
||||
commit;
|
||||
connection b;
|
||||
commit;
|
||||
drop table t1;
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
|
||||
#
|
||||
# Test case where no locks should be released (because we are not
|
||||
# using READ COMMITTED isolation level)
|
||||
#
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t1 lock in share mode;
|
||||
update t1 set b = 5 where b = 1;
|
||||
connection b;
|
||||
set autocommit = 0;
|
||||
#
|
||||
# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update
|
||||
#
|
||||
--error 1205
|
||||
select * from t1 where a = 2 and b = 2 for update;
|
||||
#
|
||||
# X-lock to record (1,1),(3,1),(5,1) should not be released in a update
|
||||
#
|
||||
--error 1205
|
||||
connection a;
|
||||
commit;
|
||||
connection b;
|
||||
commit;
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Consistent read should be used in following selects
|
||||
#
|
||||
# 1) INSERT INTO ... SELECT
|
||||
# 2) UPDATE ... = ( SELECT ...)
|
||||
# 3) CREATE ... SELECT
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
connection b;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
insert into t1 select * from t2;
|
||||
update t1 set b = (select e from t2 where a = d);
|
||||
create table t3(d int not null, e int, primary key(d)) engine=innodb
|
||||
select * from t2;
|
||||
commit;
|
||||
connection a;
|
||||
commit;
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
drop table t1, t2, t3;
|
||||
|
||||
#
|
||||
# Consistent read should not be used if
|
||||
#
|
||||
# (a) isolation level is serializable OR
|
||||
# (b) select ... lock in share mode OR
|
||||
# (c) select ... for update
|
||||
#
|
||||
# in following queries:
|
||||
#
|
||||
# 1) INSERT INTO ... SELECT
|
||||
# 2) UPDATE ... = ( SELECT ...)
|
||||
# 3) CREATE ... SELECT
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connect (c,localhost,root,,);
|
||||
connect (d,localhost,root,,);
|
||||
connect (e,localhost,root,,);
|
||||
connect (f,localhost,root,,);
|
||||
connect (g,localhost,root,,);
|
||||
connect (h,localhost,root,,);
|
||||
connect (i,localhost,root,,);
|
||||
connect (j,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
create table t3(d int not null, b int, primary key(d)) engine=innodb;
|
||||
insert into t3 values (8,6),(12,1),(3,1);
|
||||
create table t5(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t5 values (1,2),(5,3),(4,2);
|
||||
create table t6(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t6 values (8,6),(12,1),(3,1);
|
||||
create table t8(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t8 values (1,2),(5,3),(4,2);
|
||||
create table t9(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t9 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
connection b;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
--send
|
||||
insert into t1 select * from t2;
|
||||
connection c;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
--send
|
||||
update t3 set b = (select b from t2 where a = d);
|
||||
connection d;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
--send
|
||||
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
|
||||
connection e;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
--send
|
||||
insert into t5 (select * from t2 lock in share mode);
|
||||
connection f;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
--send
|
||||
update t6 set e = (select b from t2 where a = d lock in share mode);
|
||||
connection g;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
--send
|
||||
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
|
||||
connection h;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
--send
|
||||
insert into t8 (select * from t2 for update);
|
||||
connection i;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
--send
|
||||
update t9 set e = (select b from t2 where a = d for update);
|
||||
connection j;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
--send
|
||||
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
|
||||
|
||||
connection b;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection c;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection d;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection e;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection f;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection g;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection h;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection i;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection j;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection a;
|
||||
commit;
|
||||
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
disconnect c;
|
||||
disconnect d;
|
||||
disconnect e;
|
||||
disconnect f;
|
||||
disconnect g;
|
||||
disconnect h;
|
||||
disconnect i;
|
||||
disconnect j;
|
||||
drop table t1, t2, t3, t5, t6, t8, t9;
|
||||
|
||||
# bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID"
|
||||
--error 1005
|
||||
CREATE TABLE t1 (DB_ROW_ID int) engine=innodb;
|
||||
|
@@ -1 +1 @@
|
||||
--innodb_locks_unsafe_for_binlog=true
|
||||
--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=1
|
||||
|
@@ -1,7 +1,9 @@
|
||||
-- source include/have_innodb.inc
|
||||
#
|
||||
# Note that these tests uses a innodb_locks_unsafe_for_binlog option.
|
||||
#
|
||||
# Note that these tests uses options
|
||||
# innodb_locks_unsafe_for_binlog = true
|
||||
# innodb_lock_timeout = 5
|
||||
|
||||
#
|
||||
# Test cases for a bug #15650
|
||||
#
|
||||
@@ -33,7 +35,7 @@ connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t1 lock in share mode;
|
||||
@@ -50,6 +52,197 @@ commit;
|
||||
connection b;
|
||||
commit;
|
||||
drop table t1;
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
|
||||
#
|
||||
# unlock row test
|
||||
#
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
update t1 set b = 5 where b = 1;
|
||||
connection b;
|
||||
set autocommit = 0;
|
||||
#
|
||||
# X-lock to record (7,3) should be released in a update
|
||||
#
|
||||
select * from t1 where a = 7 and b = 3 for update;
|
||||
commit;
|
||||
connection a;
|
||||
commit;
|
||||
drop table t1;
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
|
||||
|
||||
#
|
||||
# Consistent read should be used in following selects
|
||||
#
|
||||
# 1) INSERT INTO ... SELECT
|
||||
# 2) UPDATE ... = ( SELECT ...)
|
||||
# 3) CREATE ... SELECT
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
connection b;
|
||||
set autocommit = 0;
|
||||
insert into t1 select * from t2;
|
||||
update t1 set b = (select e from t2 where a = d);
|
||||
create table t3(d int not null, e int, primary key(d)) engine=innodb
|
||||
select * from t2;
|
||||
commit;
|
||||
connection a;
|
||||
commit;
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
drop table t1, t2, t3;
|
||||
|
||||
#
|
||||
# Consistent read should not be used if
|
||||
#
|
||||
# (a) isolation level is serializable OR
|
||||
# (b) select ... lock in share mode OR
|
||||
# (c) select ... for update
|
||||
#
|
||||
# in following queries:
|
||||
#
|
||||
# 1) INSERT INTO ... SELECT
|
||||
# 2) UPDATE ... = ( SELECT ...)
|
||||
# 3) CREATE ... SELECT
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connect (c,localhost,root,,);
|
||||
connect (d,localhost,root,,);
|
||||
connect (e,localhost,root,,);
|
||||
connect (f,localhost,root,,);
|
||||
connect (g,localhost,root,,);
|
||||
connect (h,localhost,root,,);
|
||||
connect (i,localhost,root,,);
|
||||
connect (j,localhost,root,,);
|
||||
connection a;
|
||||
create table t1(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t1 values (1,2),(5,3),(4,2);
|
||||
create table t2(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t2 values (8,6),(12,1),(3,1);
|
||||
create table t3(d int not null, b int, primary key(d)) engine=innodb;
|
||||
insert into t3 values (8,6),(12,1),(3,1);
|
||||
create table t5(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t5 values (1,2),(5,3),(4,2);
|
||||
create table t6(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t6 values (8,6),(12,1),(3,1);
|
||||
create table t8(a int not null, b int, primary key(a)) engine=innodb;
|
||||
insert into t8 values (1,2),(5,3),(4,2);
|
||||
create table t9(d int not null, e int, primary key(d)) engine=innodb;
|
||||
insert into t9 values (8,6),(12,1),(3,1);
|
||||
commit;
|
||||
set autocommit = 0;
|
||||
select * from t2 for update;
|
||||
connection b;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
--send
|
||||
insert into t1 select * from t2;
|
||||
connection c;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
--send
|
||||
update t3 set b = (select b from t2 where a = d);
|
||||
connection d;
|
||||
set autocommit = 0;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
--send
|
||||
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
|
||||
connection e;
|
||||
set autocommit = 0;
|
||||
--send
|
||||
insert into t5 (select * from t2 lock in share mode);
|
||||
connection f;
|
||||
set autocommit = 0;
|
||||
--send
|
||||
update t6 set e = (select b from t2 where a = d lock in share mode);
|
||||
connection g;
|
||||
set autocommit = 0;
|
||||
--send
|
||||
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
|
||||
connection h;
|
||||
set autocommit = 0;
|
||||
--send
|
||||
insert into t8 (select * from t2 for update);
|
||||
connection i;
|
||||
set autocommit = 0;
|
||||
--send
|
||||
update t9 set e = (select b from t2 where a = d for update);
|
||||
connection j;
|
||||
set autocommit = 0;
|
||||
--send
|
||||
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
|
||||
|
||||
connection b;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection c;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection d;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection e;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection f;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection g;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection h;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection i;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection j;
|
||||
--error 1205
|
||||
reap;
|
||||
|
||||
connection a;
|
||||
commit;
|
||||
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
disconnect c;
|
||||
disconnect d;
|
||||
disconnect e;
|
||||
disconnect f;
|
||||
disconnect g;
|
||||
disconnect h;
|
||||
disconnect i;
|
||||
disconnect j;
|
||||
drop table t1, t2, t3, t5, t6, t8, t9;
|
||||
|
@@ -132,6 +132,7 @@ extern "C" {
|
||||
#include "../storage/innobase/include/sync0sync.h"
|
||||
#include "../storage/innobase/include/fil0fil.h"
|
||||
#include "../storage/innobase/include/trx0xa.h"
|
||||
#include "../storage/innobase/include/thr0loc.h"
|
||||
}
|
||||
|
||||
#define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
|
||||
@@ -1014,7 +1015,6 @@ innobase_query_caching_of_table_permitted(
|
||||
mutex_enter_noninline(&kernel_mutex);
|
||||
trx_print(stderr, trx, 1024);
|
||||
mutex_exit_noninline(&kernel_mutex);
|
||||
ut_error;
|
||||
}
|
||||
|
||||
innobase_release_stat_resources(trx);
|
||||
@@ -1840,7 +1840,6 @@ innobase_commit_complete(
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
Rolls back a transaction or the latest SQL statement. */
|
||||
|
||||
@@ -2066,6 +2065,7 @@ innobase_close_connection(
|
||||
|
||||
innobase_rollback_trx(trx);
|
||||
|
||||
thr_local_free(trx->mysql_thread_id);
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
return(0);
|
||||
@@ -2086,7 +2086,7 @@ ha_innobase::get_row_type() const
|
||||
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||
|
||||
if (prebuilt && prebuilt->table) {
|
||||
if (innodb_dict_table_is_comp(prebuilt->table)) {
|
||||
if (dict_table_is_comp_noninline(prebuilt->table)) {
|
||||
return(ROW_TYPE_COMPACT);
|
||||
} else {
|
||||
return(ROW_TYPE_REDUNDANT);
|
||||
@@ -3479,7 +3479,8 @@ calc_row_difference(
|
||||
TRUE,
|
||||
new_mysql_row_col,
|
||||
col_pack_len,
|
||||
innodb_dict_table_is_comp(prebuilt->table));
|
||||
dict_table_is_comp_noninline(
|
||||
prebuilt->table));
|
||||
ufield->new_val.data = dfield.data;
|
||||
ufield->new_val.len = dfield.len;
|
||||
} else {
|
||||
@@ -3639,9 +3640,17 @@ ha_innobase::unlock_row(void)
|
||||
ut_error;
|
||||
}
|
||||
|
||||
/* Consistent read does not take any locks, thus there is
|
||||
nothing to unlock. */
|
||||
|
||||
if (prebuilt->select_lock_type == LOCK_NONE) {
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
switch (prebuilt->row_read_type) {
|
||||
case ROW_READ_WITH_LOCKS:
|
||||
if (!srv_locks_unsafe_for_binlog) {
|
||||
if (!srv_locks_unsafe_for_binlog
|
||||
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
@@ -3673,7 +3682,13 @@ ha_innobase::try_semi_consistent_read(bool yes)
|
||||
{
|
||||
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||
|
||||
if (yes && srv_locks_unsafe_for_binlog) {
|
||||
/* Row read type is set to semi consistent read if this was
|
||||
requested by the MySQL and either innodb_locks_unsafe_for_binlog
|
||||
option is used or this session is using READ COMMITTED isolation
|
||||
level. */
|
||||
|
||||
if (yes && (srv_locks_unsafe_for_binlog
|
||||
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
|
||||
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
|
||||
} else {
|
||||
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
|
||||
@@ -6156,12 +6171,6 @@ ha_innobase::external_lock(
|
||||
trx->n_mysql_tables_in_use++;
|
||||
prebuilt->mysql_has_locked = TRUE;
|
||||
|
||||
if (trx->n_mysql_tables_in_use == 1) {
|
||||
trx->isolation_level = innobase_map_isolation_level(
|
||||
(enum_tx_isolation)
|
||||
thd->variables.tx_isolation);
|
||||
}
|
||||
|
||||
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
|
||||
&& prebuilt->select_lock_type == LOCK_NONE
|
||||
&& (thd->options
|
||||
@@ -6635,11 +6644,22 @@ ha_innobase::store_lock(
|
||||
TL_IGNORE */
|
||||
{
|
||||
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||
trx_t* trx = prebuilt->trx;
|
||||
|
||||
/* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
|
||||
Be careful to ignore TL_IGNORE if we are going to do something with
|
||||
only 'real' locks! */
|
||||
|
||||
/* If no MySQL tables is use we need to set isolation level
|
||||
of the transaction. */
|
||||
|
||||
if (lock_type != TL_IGNORE
|
||||
&& trx->n_mysql_tables_in_use == 0) {
|
||||
trx->isolation_level = innobase_map_isolation_level(
|
||||
(enum_tx_isolation)
|
||||
thd->variables.tx_isolation);
|
||||
}
|
||||
|
||||
if ((lock_type == TL_READ && thd->in_lock_tables) ||
|
||||
(lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) ||
|
||||
lock_type == TL_READ_WITH_SHARED_LOCKS ||
|
||||
@@ -6664,18 +6684,26 @@ ha_innobase::store_lock(
|
||||
unexpected if an obsolete consistent read view would be
|
||||
used. */
|
||||
|
||||
if (srv_locks_unsafe_for_binlog &&
|
||||
prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE &&
|
||||
(lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) &&
|
||||
(thd->lex->sql_command == SQLCOM_INSERT_SELECT ||
|
||||
thd->lex->sql_command == SQLCOM_UPDATE)) {
|
||||
ulint isolation_level;
|
||||
|
||||
/* In case we have innobase_locks_unsafe_for_binlog
|
||||
option set and isolation level of the transaction
|
||||
isolation_level = trx->isolation_level;
|
||||
|
||||
if ((srv_locks_unsafe_for_binlog
|
||||
|| isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& isolation_level != TRX_ISO_SERIALIZABLE
|
||||
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
|
||||
&& (thd->lex->sql_command == SQLCOM_INSERT_SELECT
|
||||
|| thd->lex->sql_command == SQLCOM_UPDATE
|
||||
|| thd->lex->sql_command == SQLCOM_CREATE_TABLE)) {
|
||||
|
||||
/* If we either have innobase_locks_unsafe_for_binlog
|
||||
option set or this session is using READ COMMITTED
|
||||
isolation level and isolation level of the transaction
|
||||
is not set to serializable and MySQL is doing
|
||||
INSERT INTO...SELECT or UPDATE ... = (SELECT ...)
|
||||
without FOR UPDATE or IN SHARE MODE in select, then
|
||||
we use consistent read for select. */
|
||||
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
|
||||
CREATE ... SELECT... without FOR UPDATE or
|
||||
IN SHARE MODE in select, then we use consistent
|
||||
read for select. */
|
||||
|
||||
prebuilt->select_lock_type = LOCK_NONE;
|
||||
prebuilt->stored_select_lock_type = LOCK_NONE;
|
||||
@@ -6729,8 +6757,9 @@ ha_innobase::store_lock(
|
||||
< TL_WRITE_CONCURRENT_INSERT.
|
||||
|
||||
We especially allow multiple writers if MySQL is at the
|
||||
start of a stored procedure call (SQLCOM_CALL)
|
||||
(MySQL does have thd->in_lock_tables TRUE there). */
|
||||
start of a stored procedure call (SQLCOM_CALL) or a
|
||||
stored function call (MySQL does have thd->in_lock_tables
|
||||
TRUE there). */
|
||||
|
||||
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
|
||||
&& lock_type <= TL_WRITE)
|
||||
|
@@ -76,8 +76,7 @@ EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr
|
||||
include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \
|
||||
include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \
|
||||
include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \
|
||||
include/ut0sort.h include/ut0ut.h include/ut0ut.ic \
|
||||
cmakelists.txt
|
||||
include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic
|
||||
|
||||
# Don't update the files from bitkeeper
|
||||
%::SCCS/s.%
|
||||
|
@@ -144,7 +144,7 @@ btr_root_get(
|
||||
|
||||
root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
|
||||
ut_a((ibool)!!page_is_comp(root) ==
|
||||
dict_table_is_comp(UT_LIST_GET_FIRST(tree->tree_indexes)->table));
|
||||
dict_table_is_comp(tree->tree_index->table));
|
||||
|
||||
return(root);
|
||||
}
|
||||
@@ -259,7 +259,7 @@ btr_page_create(
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
|
||||
MTR_MEMO_PAGE_X_FIX));
|
||||
page_create(page, mtr,
|
||||
dict_table_is_comp(UT_LIST_GET_FIRST(tree->tree_indexes)->table));
|
||||
dict_table_is_comp(tree->tree_index->table));
|
||||
buf_block_align(page)->check_index_page_at_flush = TRUE;
|
||||
|
||||
btr_page_set_index_id(page, tree->id, mtr);
|
||||
@@ -574,7 +574,7 @@ btr_page_get_father_for_rec(
|
||||
|
||||
tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap,
|
||||
btr_page_get_level(page, mtr));
|
||||
index = UT_LIST_GET_FIRST(tree->tree_indexes);
|
||||
index = tree->tree_index;
|
||||
|
||||
/* In the following, we choose just any index from the tree as the
|
||||
first parameter for btr_cur_search_to_nth_level. */
|
||||
@@ -1073,8 +1073,7 @@ btr_root_raise_and_insert(
|
||||
/* fprintf(stderr, "Root raise new page no %lu\n",
|
||||
buf_frame_get_page_no(new_page)); */
|
||||
|
||||
ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
|
||||
new_page);
|
||||
ibuf_reset_free_bits(tree->tree_index, new_page);
|
||||
/* Reposition the cursor to the child node */
|
||||
page_cur_search(new_page, cursor->index, tuple,
|
||||
PAGE_CUR_LE, page_cursor);
|
||||
@@ -1415,7 +1414,7 @@ btr_insert_on_non_leaf_level(
|
||||
/* In the following, choose just any index from the tree as the
|
||||
first parameter for btr_cur_search_to_nth_level. */
|
||||
|
||||
btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes),
|
||||
btr_cur_search_to_nth_level(tree->tree_index,
|
||||
level, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE,
|
||||
&cursor, 0, mtr);
|
||||
|
||||
@@ -1479,7 +1478,7 @@ btr_attach_half_pages(
|
||||
|
||||
btr_node_ptr_set_child_page_no(node_ptr,
|
||||
rec_get_offsets(node_ptr,
|
||||
UT_LIST_GET_FIRST(tree->tree_indexes),
|
||||
tree->tree_index,
|
||||
NULL, ULINT_UNDEFINED, &heap),
|
||||
lower_page_no, mtr);
|
||||
mem_heap_empty(heap);
|
||||
@@ -1768,8 +1767,8 @@ func_start:
|
||||
buf_frame_get_page_no(left_page),
|
||||
buf_frame_get_page_no(right_page)); */
|
||||
|
||||
ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
|
||||
ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
|
||||
ut_ad(page_validate(left_page, tree->tree_index));
|
||||
ut_ad(page_validate(right_page, tree->tree_index));
|
||||
|
||||
mem_heap_free(heap);
|
||||
return(rec);
|
||||
@@ -1910,8 +1909,7 @@ btr_node_ptr_delete(
|
||||
|
||||
node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
|
||||
|
||||
btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr,
|
||||
&cursor);
|
||||
btr_cur_position(tree->tree_index, node_ptr, &cursor);
|
||||
compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
|
||||
mtr);
|
||||
ut_a(err == DB_SUCCESS);
|
||||
@@ -1947,7 +1945,7 @@ btr_lift_page_up(
|
||||
btr_page_get_father_node_ptr(tree, page, mtr));
|
||||
|
||||
page_level = btr_page_get_level(page, mtr);
|
||||
index = UT_LIST_GET_FIRST(tree->tree_indexes);
|
||||
index = tree->tree_index;
|
||||
|
||||
btr_search_drop_page_hash_index(page);
|
||||
|
||||
@@ -2180,8 +2178,7 @@ btr_discard_only_page_on_level(
|
||||
btr_page_empty(father_page, mtr);
|
||||
|
||||
/* We play safe and reset the free bits for the father */
|
||||
ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
|
||||
father_page);
|
||||
ibuf_reset_free_bits(tree->tree_index, father_page);
|
||||
} else {
|
||||
ut_ad(page_get_n_recs(father_page) == 1);
|
||||
|
||||
@@ -2449,7 +2446,7 @@ btr_check_node_ptr(
|
||||
|
||||
ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr,
|
||||
rec_get_offsets(node_ptr,
|
||||
dict_tree_find_index(tree, node_ptr),
|
||||
tree->tree_index,
|
||||
NULL, ULINT_UNDEFINED, &heap)) == 0);
|
||||
|
||||
mem_heap_free(heap);
|
||||
@@ -2692,7 +2689,7 @@ btr_validate_level(
|
||||
|
||||
space = buf_frame_get_space_id(page);
|
||||
|
||||
index = UT_LIST_GET_FIRST(tree->tree_indexes);
|
||||
index = tree->tree_index;
|
||||
|
||||
while (level != btr_page_get_level(page, &mtr)) {
|
||||
|
||||
|
@@ -1606,7 +1606,7 @@ btr_cur_optimistic_update(
|
||||
new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
|
||||
|
||||
row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
|
||||
NULL);
|
||||
FALSE, NULL);
|
||||
old_rec_size = rec_offs_size(offsets);
|
||||
new_rec_size = rec_get_converted_size(index, new_entry);
|
||||
|
||||
@@ -1846,7 +1846,7 @@ btr_cur_pessimistic_update(
|
||||
new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
|
||||
|
||||
row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
|
||||
heap);
|
||||
FALSE, heap);
|
||||
if (!(flags & BTR_KEEP_SYS_FLAG)) {
|
||||
row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
|
||||
roll_ptr);
|
||||
@@ -1915,13 +1915,13 @@ btr_cur_pessimistic_update(
|
||||
ut_a(rec || optim_err != DB_UNDERFLOW);
|
||||
|
||||
if (rec) {
|
||||
offsets = rec_get_offsets(rec, index, offsets,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
lock_rec_restore_from_page_infimum(rec, page);
|
||||
rec_set_field_extern_bits(rec, index,
|
||||
ext_vect, n_ext_vect, mtr);
|
||||
|
||||
offsets = rec_get_offsets(rec, index, offsets,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
|
||||
/* The new inserted record owns its possible externally
|
||||
stored fields */
|
||||
@@ -2371,8 +2371,7 @@ btr_cur_compress(
|
||||
ut_ad(mtr_memo_contains(mtr,
|
||||
dict_tree_get_lock(btr_cur_get_tree(cursor)),
|
||||
MTR_MEMO_X_LOCK));
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(
|
||||
btr_cur_get_page(cursor)),
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
|
||||
MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0);
|
||||
|
||||
@@ -2398,8 +2397,7 @@ btr_cur_compress_if_useful(
|
||||
ut_ad(mtr_memo_contains(mtr,
|
||||
dict_tree_get_lock(btr_cur_get_tree(cursor)),
|
||||
MTR_MEMO_X_LOCK));
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(
|
||||
btr_cur_get_page(cursor)),
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
|
||||
MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
if (btr_cur_compress_recommendation(cursor, mtr)) {
|
||||
@@ -2437,7 +2435,7 @@ btr_cur_optimistic_delete(
|
||||
ibool no_compress_needed;
|
||||
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_page(cursor)),
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
|
||||
MTR_MEMO_PAGE_X_FIX));
|
||||
/* This is intended only for leaf page deletions */
|
||||
|
||||
@@ -3330,7 +3328,10 @@ btr_store_big_rec_extern_fields(
|
||||
dict_index_t* index, /* in: index of rec; the index tree
|
||||
MUST be X-latched */
|
||||
rec_t* rec, /* in: record */
|
||||
const ulint* offsets, /* in: rec_get_offsets(rec, index) */
|
||||
const ulint* offsets, /* in: rec_get_offsets(rec, index);
|
||||
the "external storage" flags in offsets
|
||||
will not correspond to rec when
|
||||
this function returns */
|
||||
big_rec_t* big_rec_vec, /* in: vector containing fields
|
||||
to be stored externally */
|
||||
mtr_t* local_mtr __attribute__((unused))) /* in: mtr
|
||||
|
@@ -259,10 +259,7 @@ btr_pcur_restore_position(
|
||||
cursor->latch_mode = latch_mode;
|
||||
#ifdef UNIV_DEBUG
|
||||
rec = btr_pcur_get_rec(cursor);
|
||||
index = dict_tree_find_index(
|
||||
btr_cur_get_tree(
|
||||
btr_pcur_get_btr_cur(cursor)),
|
||||
rec);
|
||||
index = btr_pcur_get_btr_cur(cursor)->index;
|
||||
|
||||
heap = mem_heap_create(256);
|
||||
offsets1 = rec_get_offsets(cursor->old_rec,
|
||||
|
@@ -24,8 +24,8 @@ ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the
|
||||
|
||||
#ifdef UNIV_SEARCH_PERF_STAT
|
||||
ulint btr_search_n_succ = 0;
|
||||
#endif /* UNIV_SEARCH_PERF_STAT */
|
||||
ulint btr_search_n_hash_fail = 0;
|
||||
#endif /* UNIV_SEARCH_PERF_STAT */
|
||||
|
||||
byte btr_sea_pad1[64]; /* padding to prevent other memory update
|
||||
hotspots from residing on the same memory
|
||||
@@ -59,9 +59,6 @@ before hash index building is started */
|
||||
|
||||
#define BTR_SEARCH_BUILD_LIMIT 100
|
||||
|
||||
/* How many cells to check before temporarily releasing btr_search_latch */
|
||||
#define BTR_CHUNK_SIZE 10000
|
||||
|
||||
/************************************************************************
|
||||
Builds a hash index on a page with the given parameters. If the page already
|
||||
has a hash index with different parameters, the old hash index is removed.
|
||||
@@ -172,10 +169,12 @@ btr_search_info_create(
|
||||
|
||||
info->last_hash_succ = FALSE;
|
||||
|
||||
#ifdef UNIV_SEARCH_PERF_STAT
|
||||
info->n_hash_succ = 0;
|
||||
info->n_hash_fail = 0;
|
||||
info->n_patt_succ = 0;
|
||||
info->n_searches = 0;
|
||||
#endif /* UNIV_SEARCH_PERF_STAT */
|
||||
|
||||
/* Set some sensible values */
|
||||
info->n_fields = 1;
|
||||
@@ -487,7 +486,9 @@ btr_search_info_update_slow(
|
||||
if (cursor->flag == BTR_CUR_HASH_FAIL) {
|
||||
/* Update the hash node reference, if appropriate */
|
||||
|
||||
#ifdef UNIV_SEARCH_PERF_STAT
|
||||
btr_search_n_hash_fail++;
|
||||
#endif /* UNIV_SEARCH_PERF_STAT */
|
||||
|
||||
rw_lock_x_lock(&btr_search_latch);
|
||||
|
||||
@@ -872,11 +873,11 @@ failure_unlock:
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
}
|
||||
failure:
|
||||
info->n_hash_fail++;
|
||||
|
||||
cursor->flag = BTR_CUR_HASH_FAIL;
|
||||
|
||||
#ifdef UNIV_SEARCH_PERF_STAT
|
||||
info->n_hash_fail++;
|
||||
|
||||
if (info->n_hash_succ > 0) {
|
||||
info->n_hash_succ--;
|
||||
}
|
||||
@@ -1607,6 +1608,11 @@ btr_search_validate(void)
|
||||
mem_heap_t* heap = NULL;
|
||||
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
ulint* offsets = offsets_;
|
||||
|
||||
/* How many cells to check before temporarily releasing
|
||||
btr_search_latch. */
|
||||
ulint chunk_size = 10000;
|
||||
|
||||
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
|
||||
|
||||
rw_lock_x_lock(&btr_search_latch);
|
||||
@@ -1616,7 +1622,7 @@ btr_search_validate(void)
|
||||
for (i = 0; i < cell_count; i++) {
|
||||
/* We release btr_search_latch every once in a while to
|
||||
give other queries a chance to run. */
|
||||
if ((i != 0) && ((i % BTR_CHUNK_SIZE) == 0)) {
|
||||
if ((i != 0) && ((i % chunk_size) == 0)) {
|
||||
rw_lock_x_unlock(&btr_search_latch);
|
||||
os_thread_yield();
|
||||
rw_lock_x_lock(&btr_search_latch);
|
||||
@@ -1675,8 +1681,8 @@ btr_search_validate(void)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < cell_count; i += BTR_CHUNK_SIZE) {
|
||||
ulint end_index = ut_min(i + BTR_CHUNK_SIZE - 1, cell_count - 1);
|
||||
for (i = 0; i < cell_count; i += chunk_size) {
|
||||
ulint end_index = ut_min(i + chunk_size - 1, cell_count - 1);
|
||||
|
||||
/* We release btr_search_latch every once in a while to
|
||||
give other queries a chance to run. */
|
||||
|
@@ -294,14 +294,14 @@ buf_LRU_try_free_flushed_blocks(void)
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Returns TRUE if less than 15 % of the buffer pool is available. This can be
|
||||
Returns TRUE if less than 25 % of the buffer pool is available. This can be
|
||||
used in heuristics to prevent huge transactions eating up the whole buffer
|
||||
pool for their locks. */
|
||||
|
||||
ibool
|
||||
buf_LRU_buf_pool_running_out(void)
|
||||
/*==============================*/
|
||||
/* out: TRUE if less than 15 % of buffer pool
|
||||
/* out: TRUE if less than 25 % of buffer pool
|
||||
left */
|
||||
{
|
||||
ibool ret = FALSE;
|
||||
@@ -309,7 +309,7 @@ buf_LRU_buf_pool_running_out(void)
|
||||
mutex_enter(&(buf_pool->mutex));
|
||||
|
||||
if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
|
||||
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 7) {
|
||||
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) {
|
||||
|
||||
ret = TRUE;
|
||||
}
|
||||
@@ -340,11 +340,11 @@ loop:
|
||||
mutex_enter(&(buf_pool->mutex));
|
||||
|
||||
if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
|
||||
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 10) {
|
||||
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 20) {
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fprintf(stderr,
|
||||
" InnoDB: ERROR: over 9 / 10 of the buffer pool is occupied by\n"
|
||||
" InnoDB: ERROR: over 95 percent of the buffer pool is occupied by\n"
|
||||
"InnoDB: lock heaps or the adaptive hash index! Check that your\n"
|
||||
"InnoDB: transactions do not set too many row locks.\n"
|
||||
"InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n"
|
||||
@@ -356,17 +356,17 @@ loop:
|
||||
ut_error;
|
||||
|
||||
} else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
|
||||
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) {
|
||||
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 3) {
|
||||
|
||||
if (!buf_lru_switched_on_innodb_mon) {
|
||||
|
||||
/* Over 80 % of the buffer pool is occupied by lock
|
||||
/* Over 67 % of the buffer pool is occupied by lock
|
||||
heaps or the adaptive hash index. This may be a memory
|
||||
leak! */
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n"
|
||||
" InnoDB: WARNING: over 67 percent of the buffer pool is occupied by\n"
|
||||
"InnoDB: lock heaps or the adaptive hash index! Check that your\n"
|
||||
"InnoDB: transactions do not set too many row locks.\n"
|
||||
"InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n"
|
||||
@@ -881,10 +881,10 @@ buf_LRU_block_remove_hashed_page(
|
||||
if (buf_page_hash_get(block->space, block->offset)) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: From hash table we find block %p of %lu %lu which is not %p\n",
|
||||
buf_page_hash_get(block->space, block->offset),
|
||||
(void*) buf_page_hash_get(block->space, block->offset),
|
||||
(ulong) buf_page_hash_get(block->space, block->offset)->space,
|
||||
(ulong) buf_page_hash_get(block->space, block->offset)->offset,
|
||||
block);
|
||||
(void*) block);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
|
@@ -32,4 +32,4 @@ ADD_LIBRARY(innobase btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
|
||||
thr/thr0loc.c
|
||||
trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
|
||||
usr/usr0sess.c
|
||||
ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c)
|
||||
ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c)
|
||||
|
@@ -89,6 +89,25 @@ else
|
||||
CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS -DDEBUG_OFF"
|
||||
fi
|
||||
|
||||
# NOTE: The flags below are disabled by default since we can't easily get
|
||||
# rid of the "string over 509 characters in length" warnings, and thus can't
|
||||
# add -Werror. But it's a good idea to enable these for a test compile
|
||||
# before shipping a new snapshot to MySQL to catch errors that could make
|
||||
# the compile fail on non-C99 compilers.
|
||||
|
||||
# If using gcc, disallow usage of C99 features to avoid accidentally
|
||||
# introducing problems on compilers that only implement C89.
|
||||
#if test "$ac_cv_prog_gcc" = "yes"
|
||||
#then
|
||||
# CFLAGS="$CFLAGS -std=c89 -ansi -pedantic -Wno-long-long"
|
||||
#fi
|
||||
|
||||
# If using gcc, add some extra warning flags.
|
||||
if test "$ac_cv_prog_gcc" = "yes"
|
||||
then
|
||||
CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
|
||||
fi
|
||||
|
||||
case "$target_os" in
|
||||
lin*)
|
||||
CFLAGS="$CFLAGS -DUNIV_LINUX";;
|
||||
|
@@ -216,20 +216,43 @@ dtype_print(
|
||||
|
||||
mtype = type->mtype;
|
||||
prtype = type->prtype;
|
||||
if (mtype == DATA_VARCHAR) {
|
||||
|
||||
switch (mtype) {
|
||||
case DATA_VARCHAR:
|
||||
fputs("DATA_VARCHAR", stderr);
|
||||
} else if (mtype == DATA_CHAR) {
|
||||
break;
|
||||
|
||||
case DATA_CHAR:
|
||||
fputs("DATA_CHAR", stderr);
|
||||
} else if (mtype == DATA_BINARY) {
|
||||
break;
|
||||
|
||||
case DATA_BINARY:
|
||||
fputs("DATA_BINARY", stderr);
|
||||
} else if (mtype == DATA_INT) {
|
||||
break;
|
||||
|
||||
case DATA_FIXBINARY:
|
||||
fputs("DATA_FIXBINARY", stderr);
|
||||
break;
|
||||
|
||||
case DATA_BLOB:
|
||||
fputs("DATA_BLOB", stderr);
|
||||
break;
|
||||
|
||||
case DATA_INT:
|
||||
fputs("DATA_INT", stderr);
|
||||
} else if (mtype == DATA_MYSQL) {
|
||||
break;
|
||||
|
||||
case DATA_MYSQL:
|
||||
fputs("DATA_MYSQL", stderr);
|
||||
} else if (mtype == DATA_SYS) {
|
||||
break;
|
||||
|
||||
case DATA_SYS:
|
||||
fputs("DATA_SYS", stderr);
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "type %lu", (ulong) mtype);
|
||||
break;
|
||||
}
|
||||
|
||||
len = type->len;
|
||||
@@ -254,6 +277,18 @@ dtype_print(
|
||||
} else {
|
||||
fprintf(stderr, "prtype %lu", (ulong) prtype);
|
||||
}
|
||||
} else {
|
||||
if (prtype & DATA_UNSIGNED) {
|
||||
fputs(" DATA_UNSIGNED", stderr);
|
||||
}
|
||||
|
||||
if (prtype & DATA_BINARY_TYPE) {
|
||||
fputs(" DATA_BINARY_TYPE", stderr);
|
||||
}
|
||||
|
||||
if (prtype & DATA_NOT_NULL) {
|
||||
fputs(" DATA_NOT_NULL", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec);
|
||||
|
@@ -24,6 +24,7 @@ Created 1/8/1996 Heikki Tuuri
|
||||
#include "pars0pars.h"
|
||||
#include "trx0roll.h"
|
||||
#include "usr0sess.h"
|
||||
#include "ut0vec.h"
|
||||
|
||||
/*********************************************************************
|
||||
Based on a table object, this function builds the entry to be inserted
|
||||
@@ -74,14 +75,14 @@ dict_create_sys_tables_tuple(
|
||||
dfield = dtuple_get_nth_field(entry, 3);
|
||||
|
||||
ptr = mem_heap_alloc(heap, 4);
|
||||
mach_write_to_4(ptr, table->type);
|
||||
mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
|
||||
|
||||
dfield_set_data(dfield, ptr, 4);
|
||||
/* 6: MIX_ID ---------------------------*/
|
||||
dfield = dtuple_get_nth_field(entry, 4);
|
||||
|
||||
ptr = mem_heap_alloc(heap, 8);
|
||||
mach_write_to_8(ptr, table->mix_id);
|
||||
memset(ptr, 0, 8);
|
||||
|
||||
dfield_set_data(dfield, ptr, 8);
|
||||
/* 7: MIX_LEN --------------------------*/
|
||||
@@ -89,19 +90,13 @@ dict_create_sys_tables_tuple(
|
||||
dfield = dtuple_get_nth_field(entry, 5);
|
||||
|
||||
ptr = mem_heap_alloc(heap, 4);
|
||||
mach_write_to_4(ptr, table->mix_len);
|
||||
memset(ptr, 0, 4);
|
||||
|
||||
dfield_set_data(dfield, ptr, 4);
|
||||
/* 8: CLUSTER_NAME ---------------------*/
|
||||
dfield = dtuple_get_nth_field(entry, 6);
|
||||
dfield_set_data(dfield, NULL, UNIV_SQL_NULL); /* not supported */
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
dfield_set_data(dfield, table->cluster_name,
|
||||
ut_strlen(table->cluster_name));
|
||||
ut_error; /* Oracle-style clusters are not supported yet */
|
||||
} else {
|
||||
dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
|
||||
}
|
||||
/* 9: SPACE ----------------------------*/
|
||||
dfield = dtuple_get_nth_field(entry, 7);
|
||||
|
||||
@@ -207,7 +202,6 @@ dict_build_table_def_step(
|
||||
tab_node_t* node) /* in: table create node */
|
||||
{
|
||||
dict_table_t* table;
|
||||
dict_table_t* cluster_table;
|
||||
dtuple_t* row;
|
||||
ulint error;
|
||||
const char* path_or_name;
|
||||
@@ -235,23 +229,6 @@ dict_build_table_def_step(
|
||||
return(DB_TOO_BIG_RECORD);
|
||||
}
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
|
||||
cluster_table = dict_table_get_low(table->cluster_name);
|
||||
|
||||
if (cluster_table == NULL) {
|
||||
|
||||
return(DB_CLUSTER_NOT_FOUND);
|
||||
}
|
||||
|
||||
/* Inherit space and mix len from the cluster */
|
||||
|
||||
table->space = cluster_table->space;
|
||||
table->mix_len = cluster_table->mix_len;
|
||||
|
||||
table->mix_id = dict_hdr_get_new_id(DICT_HDR_MIX_ID);
|
||||
}
|
||||
|
||||
if (srv_file_per_table) {
|
||||
/* We create a new single-table tablespace for the table.
|
||||
We initially let it be 4 pages:
|
||||
@@ -614,15 +591,6 @@ dict_create_index_tree_step(
|
||||
|
||||
sys_indexes = dict_sys->sys_indexes;
|
||||
|
||||
if (index->type & DICT_CLUSTERED
|
||||
&& table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
|
||||
/* Do not create a new index tree: entries are put to the
|
||||
cluster tree */
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/* Run a mini-transaction in which the index tree is allocated for
|
||||
the index and its root address is written to the index entry in
|
||||
sys_indexes */
|
||||
@@ -1159,11 +1127,8 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
{
|
||||
dict_table_t* table1;
|
||||
dict_table_t* table2;
|
||||
que_thr_t* thr;
|
||||
que_t* graph;
|
||||
ulint error;
|
||||
trx_t* trx;
|
||||
const char* str;
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
@@ -1215,7 +1180,7 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
VARBINARY, like in other InnoDB system tables, to get a clean
|
||||
design. */
|
||||
|
||||
str =
|
||||
error = que_eval_sql(NULL,
|
||||
"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
|
||||
"BEGIN\n"
|
||||
"CREATE TABLE\n"
|
||||
@@ -1227,22 +1192,8 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
"SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n";
|
||||
|
||||
graph = pars_sql(str);
|
||||
|
||||
ut_a(graph);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
error = trx->error_state;
|
||||
"END;\n"
|
||||
, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
fprintf(stderr, "InnoDB: error %lu in creation\n",
|
||||
@@ -1261,8 +1212,6 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
error = DB_MUST_GET_MORE_FILE_SPACE;
|
||||
}
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
@@ -1277,150 +1226,23 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
return(error);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Adds foreign key definitions to data dictionary tables in the database. We
|
||||
look at table->foreign_list, and also generate names to constraints that were
|
||||
not named by the user. A generated constraint has a name of the format
|
||||
databasename/tablename_ibfk_<number>, where the numbers start from 1, and are
|
||||
given locally for this table, that is, the number is not global, as in the
|
||||
old format constraints < 4.0.18 it used to be. */
|
||||
/********************************************************************
|
||||
Evaluate the given foreign key SQL statement. */
|
||||
|
||||
ulint
|
||||
dict_create_add_foreigns_to_dictionary(
|
||||
/*===================================*/
|
||||
dict_foreign_eval_sql(
|
||||
/*==================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
ulint start_id,/* in: if we are actually doing ALTER TABLE
|
||||
ADD CONSTRAINT, we want to generate constraint
|
||||
numbers which are bigger than in the table so
|
||||
far; we number the constraints from
|
||||
start_id + 1 up; start_id should be set to 0 if
|
||||
we are creating a new table, or if the table
|
||||
so far has no constraints for which the name
|
||||
was generated here */
|
||||
pars_info_t* info, /* in: info struct, or NULL */
|
||||
const char* sql, /* in: SQL string to evaluate */
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_foreign_t* foreign,/* in: foreign */
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
que_thr_t* thr;
|
||||
que_t* graph;
|
||||
ulint number = start_id + 1;
|
||||
ulint len;
|
||||
ulint error;
|
||||
FILE* ef = dict_foreign_err_file;
|
||||
ulint i;
|
||||
char* sql;
|
||||
char* sqlend;
|
||||
/* This procedure builds an InnoDB stored procedure which will insert
|
||||
the necessary rows into SYS_FOREIGN and SYS_FOREIGN_COLS. */
|
||||
static const char str1[] = "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n"
|
||||
"BEGIN\n"
|
||||
"INSERT INTO SYS_FOREIGN VALUES(";
|
||||
static const char str2[] = ");\n";
|
||||
static const char str3[] =
|
||||
"INSERT INTO SYS_FOREIGN_COLS VALUES(";
|
||||
static const char str4[] =
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n";
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
if (NULL == dict_table_get_low("SYS_FOREIGN")) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
loop:
|
||||
if (foreign == NULL) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
if (foreign->id == NULL) {
|
||||
/* Generate a new constraint id */
|
||||
ulint namelen = strlen(table->name);
|
||||
char* id = mem_heap_alloc(foreign->heap, namelen + 20);
|
||||
/* no overflow if number < 1e13 */
|
||||
sprintf(id, "%s_ibfk_%lu", table->name, (ulong) number++);
|
||||
foreign->id = id;
|
||||
}
|
||||
|
||||
len = (sizeof str1) + (sizeof str2) + (sizeof str4) - 3
|
||||
+ 9/* ' and , chars */ + 10/* 32-bit integer */
|
||||
+ ut_strlenq(foreign->id, '\'') * (foreign->n_fields + 1)
|
||||
+ ut_strlenq(table->name, '\'')
|
||||
+ ut_strlenq(foreign->referenced_table_name, '\'');
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
len += 9/* ' and , chars */ + 10/* 32-bit integer */
|
||||
+ (sizeof str3) + (sizeof str2) - 2
|
||||
+ ut_strlenq(foreign->foreign_col_names[i], '\'')
|
||||
+ ut_strlenq(foreign->referenced_col_names[i], '\'');
|
||||
}
|
||||
|
||||
sql = sqlend = mem_alloc(len + 1);
|
||||
|
||||
/* INSERT INTO SYS_FOREIGN VALUES(...); */
|
||||
memcpy(sqlend, str1, (sizeof str1) - 1);
|
||||
sqlend += (sizeof str1) - 1;
|
||||
*sqlend++ = '\'';
|
||||
sqlend = ut_strcpyq(sqlend, '\'', foreign->id);
|
||||
*sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\'';
|
||||
sqlend = ut_strcpyq(sqlend, '\'', table->name);
|
||||
*sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\'';
|
||||
sqlend = ut_strcpyq(sqlend, '\'', foreign->referenced_table_name);
|
||||
*sqlend++ = '\'', *sqlend++ = ',';
|
||||
sqlend += sprintf(sqlend, "%010lu",
|
||||
foreign->n_fields + (foreign->type << 24));
|
||||
memcpy(sqlend, str2, (sizeof str2) - 1);
|
||||
sqlend += (sizeof str2) - 1;
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
/* INSERT INTO SYS_FOREIGN_COLS VALUES(...); */
|
||||
memcpy(sqlend, str3, (sizeof str3) - 1);
|
||||
sqlend += (sizeof str3) - 1;
|
||||
*sqlend++ = '\'';
|
||||
sqlend = ut_strcpyq(sqlend, '\'', foreign->id);
|
||||
*sqlend++ = '\''; *sqlend++ = ',';
|
||||
sqlend += sprintf(sqlend, "%010lu", (ulong) i);
|
||||
*sqlend++ = ','; *sqlend++ = '\'';
|
||||
sqlend = ut_strcpyq(sqlend, '\'',
|
||||
foreign->foreign_col_names[i]);
|
||||
*sqlend++ = '\''; *sqlend++ = ','; *sqlend++ = '\'';
|
||||
sqlend = ut_strcpyq(sqlend, '\'',
|
||||
foreign->referenced_col_names[i]);
|
||||
*sqlend++ = '\'';
|
||||
memcpy(sqlend, str2, (sizeof str2) - 1);
|
||||
sqlend += (sizeof str2) - 1;
|
||||
}
|
||||
|
||||
memcpy(sqlend, str4, sizeof str4);
|
||||
sqlend += sizeof str4;
|
||||
|
||||
ut_a(sqlend == sql + len + 1);
|
||||
|
||||
graph = pars_sql(sql);
|
||||
|
||||
ut_a(graph);
|
||||
|
||||
mem_free(sql);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
error = trx->error_state;
|
||||
|
||||
que_graph_free(graph);
|
||||
error = que_eval_sql(info, sql, trx);
|
||||
|
||||
if (error == DB_DUPLICATE_KEY) {
|
||||
mutex_enter(&dict_foreign_err_mutex);
|
||||
@@ -1466,7 +1288,163 @@ loop:
|
||||
return(error);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||
|
||||
goto loop;
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Add a single foreign key field definition to the data dictionary tables in
|
||||
the database. */
|
||||
static
|
||||
ulint
|
||||
dict_create_add_foreign_field_to_dictionary(
|
||||
/*========================================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
ulint field_nr, /* in: foreign field number */
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_foreign_t* foreign, /* in: foreign */
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
pars_info_t* info = pars_info_create();
|
||||
|
||||
pars_info_add_str_literal(info, "id", foreign->id);
|
||||
|
||||
pars_info_add_int4_literal(info, "pos", field_nr);
|
||||
|
||||
pars_info_add_str_literal(info, "for_col_name",
|
||||
foreign->foreign_col_names[field_nr]);
|
||||
|
||||
pars_info_add_str_literal(info, "ref_col_name",
|
||||
foreign->referenced_col_names[field_nr]);
|
||||
|
||||
return dict_foreign_eval_sql(info,
|
||||
"PROCEDURE P () IS\n"
|
||||
"BEGIN\n"
|
||||
"INSERT INTO SYS_FOREIGN_COLS VALUES"
|
||||
"(:id, :pos, :for_col_name, :ref_col_name);\n"
|
||||
"END;\n"
|
||||
, table, foreign, trx);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Add a single foreign key definition to the data dictionary tables in the
|
||||
database. We also generate names to constraints that were not named by the
|
||||
user. A generated constraint has a name of the format
|
||||
databasename/tablename_ibfk_<number>, where the numbers start from 1, and
|
||||
are given locally for this table, that is, the number is not global, as in
|
||||
the old format constraints < 4.0.18 it used to be. */
|
||||
static
|
||||
ulint
|
||||
dict_create_add_foreign_to_dictionary(
|
||||
/*==================================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
ulint* id_nr, /* in/out: number to use in id generation;
|
||||
incremented if used */
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_foreign_t* foreign,/* in: foreign */
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
ulint error;
|
||||
ulint i;
|
||||
|
||||
pars_info_t* info = pars_info_create();
|
||||
|
||||
if (foreign->id == NULL) {
|
||||
/* Generate a new constraint id */
|
||||
ulint namelen = strlen(table->name);
|
||||
char* id = mem_heap_alloc(foreign->heap, namelen + 20);
|
||||
/* no overflow if number < 1e13 */
|
||||
sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
|
||||
foreign->id = id;
|
||||
}
|
||||
|
||||
pars_info_add_str_literal(info, "id", foreign->id);
|
||||
|
||||
pars_info_add_str_literal(info, "for_name", table->name);
|
||||
|
||||
pars_info_add_str_literal(info, "ref_name",
|
||||
foreign->referenced_table_name);
|
||||
|
||||
pars_info_add_int4_literal(info, "n_cols",
|
||||
foreign->n_fields + (foreign->type << 24));
|
||||
|
||||
error = dict_foreign_eval_sql(info,
|
||||
"PROCEDURE P () IS\n"
|
||||
"BEGIN\n"
|
||||
"INSERT INTO SYS_FOREIGN VALUES"
|
||||
"(:id, :for_name, :ref_name, :n_cols);\n"
|
||||
"END;\n"
|
||||
, table, foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
error = dict_create_add_foreign_field_to_dictionary(i,
|
||||
table, foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
return(error);
|
||||
}
|
||||
}
|
||||
|
||||
error = dict_foreign_eval_sql(NULL,
|
||||
"PROCEDURE P () IS\n"
|
||||
"BEGIN\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n"
|
||||
, table, foreign, trx);
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Adds foreign key definitions to data dictionary tables in the database. */
|
||||
|
||||
ulint
|
||||
dict_create_add_foreigns_to_dictionary(
|
||||
/*===================================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
ulint start_id,/* in: if we are actually doing ALTER TABLE
|
||||
ADD CONSTRAINT, we want to generate constraint
|
||||
numbers which are bigger than in the table so
|
||||
far; we number the constraints from
|
||||
start_id + 1 up; start_id should be set to 0 if
|
||||
we are creating a new table, or if the table
|
||||
so far has no constraints for which the name
|
||||
was generated here */
|
||||
dict_table_t* table, /* in: table */
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
ulint number = start_id + 1;
|
||||
ulint error;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
if (NULL == dict_table_get_low("SYS_FOREIGN")) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
foreign;
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
|
||||
|
||||
error = dict_create_add_foreign_to_dictionary(&number,
|
||||
table, foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
return(error);
|
||||
}
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
@@ -657,6 +657,19 @@ dict_table_get_nth_col_pos(
|
||||
n));
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Check whether the table uses the compact page format. */
|
||||
|
||||
ibool
|
||||
dict_table_is_comp_noninline(
|
||||
/*=========================*/
|
||||
/* out: TRUE if table uses the
|
||||
compact page format */
|
||||
const dict_table_t* table) /* in: table */
|
||||
{
|
||||
return(dict_table_is_comp(table));
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Checks if a column is in the ordering columns of the clustered index of a
|
||||
table. Column prefixes are treated like whole columns. */
|
||||
@@ -870,13 +883,6 @@ dict_table_add_to_cache(
|
||||
ut_a(table2 == NULL);
|
||||
}
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
|
||||
table->mix_id_len = mach_dulint_get_compressed_size(
|
||||
table->mix_id);
|
||||
mach_dulint_write_compressed(table->mix_id_buf, table->mix_id);
|
||||
}
|
||||
|
||||
/* Add the columns to the column hash table */
|
||||
for (i = 0; i < table->n_cols; i++) {
|
||||
dict_col_add_to_cache(table, dict_table_get_nth_col(table, i));
|
||||
@@ -1251,15 +1257,13 @@ dict_table_remove_from_cache(
|
||||
/* Remove table from LRU list of tables */
|
||||
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
|
||||
|
||||
mutex_free(&(table->autoinc_mutex));
|
||||
|
||||
size = mem_heap_get_size(table->heap);
|
||||
|
||||
ut_ad(dict_sys->size >= size);
|
||||
|
||||
dict_sys->size -= size;
|
||||
|
||||
mem_heap_free(table->heap);
|
||||
dict_mem_table_free(table);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@@ -1380,6 +1384,38 @@ dict_col_reposition_in_cache(
|
||||
HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
If the given column name is reserved for InnoDB system columns, return
|
||||
TRUE. */
|
||||
|
||||
ibool
|
||||
dict_col_name_is_reserved(
|
||||
/*======================*/
|
||||
/* out: TRUE if name is reserved */
|
||||
const char* name) /* in: column name */
|
||||
{
|
||||
/* This check reminds that if a new system column is added to
|
||||
the program, it should be dealt with here. */
|
||||
#if DATA_N_SYS_COLS != 4
|
||||
#error "DATA_N_SYS_COLS != 4"
|
||||
#endif
|
||||
|
||||
static const char* reserved_names[] = {
|
||||
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR", "DB_MIX_ID"
|
||||
};
|
||||
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
|
||||
if (strcmp(name, reserved_names[i]) == 0) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Adds an index to the dictionary cache. */
|
||||
|
||||
@@ -1394,7 +1430,6 @@ dict_index_add_to_cache(
|
||||
{
|
||||
dict_index_t* new_index;
|
||||
dict_tree_t* tree;
|
||||
dict_table_t* cluster;
|
||||
dict_field_t* field;
|
||||
ulint n_ord;
|
||||
ibool success;
|
||||
@@ -1468,21 +1503,11 @@ dict_index_add_to_cache(
|
||||
dict_field_get_col(field)->ord_part++;
|
||||
}
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
/* The index tree is found from the cluster object */
|
||||
|
||||
cluster = dict_table_get_low(table->cluster_name);
|
||||
|
||||
tree = dict_index_get_tree(
|
||||
UT_LIST_GET_FIRST(cluster->indexes));
|
||||
new_index->tree = tree;
|
||||
} else {
|
||||
/* Create an index tree memory object for the index */
|
||||
tree = dict_tree_create(new_index, page_no);
|
||||
ut_ad(tree);
|
||||
|
||||
new_index->tree = tree;
|
||||
}
|
||||
|
||||
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
|
||||
|
||||
@@ -1500,7 +1525,7 @@ dict_index_add_to_cache(
|
||||
}
|
||||
|
||||
/* Add the index to the list of indexes stored in the tree */
|
||||
UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index);
|
||||
tree->tree_index = new_index;
|
||||
|
||||
/* If the dictionary cache grows too big, trim the table LRU list */
|
||||
|
||||
@@ -1532,7 +1557,7 @@ dict_index_remove_from_cache(
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1);
|
||||
ut_ad(index->tree->tree_index);
|
||||
dict_tree_free(index->tree);
|
||||
|
||||
/* Decrement the ord_part counts in columns which are ordering */
|
||||
@@ -1553,7 +1578,7 @@ dict_index_remove_from_cache(
|
||||
|
||||
dict_sys->size -= size;
|
||||
|
||||
mem_heap_free(index->heap);
|
||||
dict_mem_index_free(index);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -1699,8 +1724,6 @@ dict_table_copy_types(
|
||||
dtype_t* type;
|
||||
ulint i;
|
||||
|
||||
ut_ad(!(table->type & DICT_UNIVERSAL));
|
||||
|
||||
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
|
||||
|
||||
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
|
||||
@@ -1749,22 +1772,8 @@ dict_index_build_internal_clust(
|
||||
|
||||
new_index->id = index->id;
|
||||
|
||||
if (table->type != DICT_TABLE_ORDINARY) {
|
||||
/* The index is mixed: copy common key prefix fields */
|
||||
|
||||
dict_index_copy(new_index, index, 0, table->mix_len);
|
||||
|
||||
/* Add the mix id column */
|
||||
dict_index_add_col(new_index,
|
||||
dict_table_get_sys_col(table, DATA_MIX_ID), 0);
|
||||
|
||||
/* Copy the rest of fields */
|
||||
dict_index_copy(new_index, index, table->mix_len,
|
||||
index->n_fields);
|
||||
} else {
|
||||
/* Copy the fields of index */
|
||||
dict_index_copy(new_index, index, 0, index->n_fields);
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
|
||||
/* No fixed number of fields determines an entry uniquely */
|
||||
@@ -3641,7 +3650,7 @@ dict_tree_create(
|
||||
|
||||
tree->id = index->id;
|
||||
|
||||
UT_LIST_INIT(tree->tree_indexes);
|
||||
tree->tree_index = NULL;
|
||||
|
||||
tree->magic_n = DICT_TREE_MAGIC_N;
|
||||
|
||||
@@ -3667,135 +3676,7 @@ dict_tree_free(
|
||||
mem_free(tree);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
In an index tree, finds the index corresponding to a record in the tree. */
|
||||
UNIV_INLINE
|
||||
dict_index_t*
|
||||
dict_tree_find_index_low(
|
||||
/*=====================*/
|
||||
/* out: index */
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
rec_t* rec) /* in: record for which to find correct
|
||||
index */
|
||||
{
|
||||
dict_index_t* index;
|
||||
dict_table_t* table;
|
||||
dulint mix_id;
|
||||
ulint len;
|
||||
|
||||
index = UT_LIST_GET_FIRST(tree->tree_indexes);
|
||||
ut_ad(index);
|
||||
table = index->table;
|
||||
|
||||
if ((index->type & DICT_CLUSTERED)
|
||||
&& UNIV_UNLIKELY(table->type != DICT_TABLE_ORDINARY)) {
|
||||
|
||||
/* Get the mix id of the record */
|
||||
ut_a(!dict_table_is_comp(table));
|
||||
|
||||
mix_id = mach_dulint_read_compressed(
|
||||
rec_get_nth_field_old(rec, table->mix_len, &len));
|
||||
|
||||
while (ut_dulint_cmp(table->mix_id, mix_id) != 0) {
|
||||
|
||||
index = UT_LIST_GET_NEXT(tree_indexes, index);
|
||||
table = index->table;
|
||||
ut_ad(index);
|
||||
}
|
||||
}
|
||||
|
||||
return(index);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
In an index tree, finds the index corresponding to a record in the tree. */
|
||||
|
||||
dict_index_t*
|
||||
dict_tree_find_index(
|
||||
/*=================*/
|
||||
/* out: index */
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
rec_t* rec) /* in: record for which to find correct
|
||||
index */
|
||||
{
|
||||
dict_index_t* index;
|
||||
|
||||
index = dict_tree_find_index_low(tree, rec);
|
||||
|
||||
return(index);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
In an index tree, finds the index corresponding to a dtuple which is used
|
||||
in a search to a tree. */
|
||||
|
||||
dict_index_t*
|
||||
dict_tree_find_index_for_tuple(
|
||||
/*===========================*/
|
||||
/* out: index; NULL if the tuple does not
|
||||
contain the mix id field in a mixed tree */
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
dtuple_t* tuple) /* in: tuple for which to find index */
|
||||
{
|
||||
dict_index_t* index;
|
||||
dict_table_t* table;
|
||||
dulint mix_id;
|
||||
|
||||
ut_ad(dtuple_check_typed(tuple));
|
||||
|
||||
if (UT_LIST_GET_LEN(tree->tree_indexes) == 1) {
|
||||
|
||||
return(UT_LIST_GET_FIRST(tree->tree_indexes));
|
||||
}
|
||||
|
||||
index = UT_LIST_GET_FIRST(tree->tree_indexes);
|
||||
ut_ad(index);
|
||||
table = index->table;
|
||||
|
||||
if (dtuple_get_n_fields(tuple) <= table->mix_len) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Get the mix id of the record */
|
||||
|
||||
mix_id = mach_dulint_read_compressed(
|
||||
dfield_get_data(
|
||||
dtuple_get_nth_field(tuple, table->mix_len)));
|
||||
|
||||
while (ut_dulint_cmp(table->mix_id, mix_id) != 0) {
|
||||
|
||||
index = UT_LIST_GET_NEXT(tree_indexes, index);
|
||||
table = index->table;
|
||||
ut_ad(index);
|
||||
}
|
||||
|
||||
return(index);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Checks if a table which is a mixed cluster member owns a record. */
|
||||
|
||||
ibool
|
||||
dict_is_mixed_table_rec(
|
||||
/*====================*/
|
||||
/* out: TRUE if the record belongs to this
|
||||
table */
|
||||
dict_table_t* table, /* in: table in a mixed cluster */
|
||||
rec_t* rec) /* in: user record in the clustered index */
|
||||
{
|
||||
byte* mix_id_field;
|
||||
ulint len;
|
||||
|
||||
ut_ad(!dict_table_is_comp(table));
|
||||
|
||||
mix_id_field = rec_get_nth_field_old(rec,
|
||||
table->mix_len, &len);
|
||||
|
||||
return(len == table->mix_id_len
|
||||
&& !ut_memcmp(table->mix_id_buf, mix_id_field, len));
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/**************************************************************************
|
||||
Checks that a tuple has n_fields_cmp value in a sensible range, so that
|
||||
no comparison can occur with the page number field in a node pointer. */
|
||||
@@ -3807,19 +3688,14 @@ dict_tree_check_search_tuple(
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
dtuple_t* tuple) /* in: tuple used in a search */
|
||||
{
|
||||
dict_index_t* index;
|
||||
|
||||
index = dict_tree_find_index_for_tuple(tree, tuple);
|
||||
|
||||
if (index == NULL) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
dict_index_t* index = tree->tree_index;
|
||||
|
||||
ut_a(index);
|
||||
ut_a(dtuple_get_n_fields_cmp(tuple)
|
||||
<= dict_index_get_n_unique_in_tree(index));
|
||||
return(TRUE);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/**************************************************************************
|
||||
Builds a node pointer out of a physical record and a page number. */
|
||||
@@ -3842,7 +3718,7 @@ dict_tree_build_node_ptr(
|
||||
byte* buf;
|
||||
ulint n_unique;
|
||||
|
||||
ind = dict_tree_find_index_low(tree, rec);
|
||||
ind = tree->tree_index;
|
||||
|
||||
if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
|
||||
/* In a universal index tree, we take the whole record as
|
||||
@@ -3910,7 +3786,7 @@ dict_tree_copy_rec_order_prefix(
|
||||
ulint n;
|
||||
|
||||
UNIV_PREFETCH_R(rec);
|
||||
index = dict_tree_find_index_low(tree, rec);
|
||||
index = tree->tree_index;
|
||||
|
||||
if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
|
||||
ut_a(!dict_table_is_comp(index->table));
|
||||
@@ -3938,7 +3814,7 @@ dict_tree_build_data_tuple(
|
||||
dtuple_t* tuple;
|
||||
dict_index_t* ind;
|
||||
|
||||
ind = dict_tree_find_index_low(tree, rec);
|
||||
ind = tree->tree_index;
|
||||
|
||||
ut_ad(dict_table_is_comp(ind->table)
|
||||
|| n_fields <= rec_get_n_fields_old(rec));
|
||||
@@ -4096,6 +3972,18 @@ dict_update_statistics(
|
||||
dict_update_statistics_low(table, FALSE);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
A noninlined version of dict_table_get_low. */
|
||||
|
||||
dict_table_t*
|
||||
dict_table_get_low_noninlined(
|
||||
/*==========================*/
|
||||
/* out: table, NULL if not found */
|
||||
const char* table_name) /* in: table name */
|
||||
{
|
||||
return(dict_table_get_low(table_name));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Prints info of a foreign key constraint. */
|
||||
static
|
||||
@@ -4520,15 +4408,3 @@ dict_index_name_print(
|
||||
fputs(" of table ", file);
|
||||
ut_print_name(file, trx, index->table_name);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Export an inlined function for use in ha_innodb.c. */
|
||||
ibool
|
||||
innodb_dict_table_is_comp(
|
||||
/*===============*/
|
||||
/* out: TRUE if table uses the
|
||||
compact page format */
|
||||
const dict_table_t* table) /* in: table */
|
||||
{
|
||||
return dict_table_is_comp(table);
|
||||
}
|
||||
|
@@ -768,7 +768,7 @@ dict_load_table(
|
||||
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
|
||||
|| rec_get_deleted_flag(rec, 0)) {
|
||||
/* Not found */
|
||||
|
||||
err_exit:
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
@@ -780,11 +780,8 @@ dict_load_table(
|
||||
|
||||
/* Check if the table name in record is the searched one */
|
||||
if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(NULL);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
ut_a(0 == ut_strcmp("SPACE",
|
||||
@@ -848,36 +845,17 @@ dict_load_table(
|
||||
table->id = mach_read_from_8(field);
|
||||
|
||||
field = rec_get_nth_field_old(rec, 5, &len);
|
||||
table->type = mach_read_from_4(field);
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
ut_error;
|
||||
#if 0 /* clustered tables have not been implemented yet */
|
||||
field = rec_get_nth_field_old(rec, 6, &len);
|
||||
table->mix_id = mach_read_from_8(field);
|
||||
|
||||
field = rec_get_nth_field_old(rec, 8, &len);
|
||||
table->cluster_name = mem_heap_strdupl(heap, (char*) field, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((table->type == DICT_TABLE_CLUSTER)
|
||||
|| (table->type == DICT_TABLE_CLUSTER_MEMBER)) {
|
||||
|
||||
field = rec_get_nth_field_old(rec, 7, &len);
|
||||
ut_a(len == 4);
|
||||
table->mix_len = mach_read_from_4(field);
|
||||
if (UNIV_UNLIKELY(mach_read_from_4(field) != DICT_TABLE_ORDINARY)) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: table %s: unknown table type %lu\n",
|
||||
name, (ulong) mach_read_from_4(field));
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
/* Load the cluster table definition if not yet in
|
||||
memory cache */
|
||||
dict_table_get_low(table->cluster_name);
|
||||
}
|
||||
|
||||
dict_load_columns(table, heap);
|
||||
|
||||
dict_table_add_to_cache(table);
|
||||
|
@@ -50,7 +50,6 @@ dict_mem_table_create(
|
||||
|
||||
table->heap = heap;
|
||||
|
||||
table->type = DICT_TABLE_ORDINARY;
|
||||
table->flags = flags;
|
||||
table->name = mem_heap_strdup(heap, name);
|
||||
table->dir_path_of_temp_table = NULL;
|
||||
@@ -66,9 +65,6 @@ dict_mem_table_create(
|
||||
|
||||
table->cached = FALSE;
|
||||
|
||||
table->mix_id = ut_dulint_zero;
|
||||
table->mix_len = 0;
|
||||
|
||||
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
|
||||
* sizeof(dict_col_t));
|
||||
UT_LIST_INIT(table->indexes);
|
||||
@@ -97,42 +93,19 @@ dict_mem_table_create(
|
||||
return(table);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Creates a cluster memory object. */
|
||||
|
||||
dict_table_t*
|
||||
dict_mem_cluster_create(
|
||||
/*====================*/
|
||||
/* out, own: cluster object */
|
||||
const char* name, /* in: cluster name */
|
||||
ulint space, /* in: space where the clustered indexes
|
||||
of the member tables are placed */
|
||||
ulint n_cols, /* in: number of columns */
|
||||
ulint mix_len)/* in: length of the common key prefix in the
|
||||
cluster */
|
||||
{
|
||||
dict_table_t* cluster;
|
||||
|
||||
/* Clustered tables cannot work with the compact record format. */
|
||||
cluster = dict_mem_table_create(name, space, n_cols, 0);
|
||||
|
||||
cluster->type = DICT_TABLE_CLUSTER;
|
||||
cluster->mix_len = mix_len;
|
||||
|
||||
return(cluster);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Declares a non-published table as a member in a cluster. */
|
||||
/********************************************************************
|
||||
Free a table memory object. */
|
||||
|
||||
void
|
||||
dict_mem_table_make_cluster_member(
|
||||
/*===============================*/
|
||||
dict_table_t* table, /* in: non-published table */
|
||||
const char* cluster_name) /* in: cluster name */
|
||||
dict_mem_table_free(
|
||||
/*================*/
|
||||
dict_table_t* table) /* in: table */
|
||||
{
|
||||
table->type = DICT_TABLE_CLUSTER_MEMBER;
|
||||
table->cluster_name = cluster_name;
|
||||
ut_ad(table);
|
||||
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
||||
|
||||
mutex_free(&(table->autoinc_mutex));
|
||||
mem_heap_free(table->heap);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@@ -286,5 +259,8 @@ dict_mem_index_free(
|
||||
/*================*/
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
ut_ad(index);
|
||||
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
||||
|
||||
mem_heap_free(index->heap);
|
||||
}
|
||||
|
@@ -212,6 +212,38 @@ for_step(
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of an exit statement node. */
|
||||
|
||||
que_thr_t*
|
||||
exit_step(
|
||||
/*======*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
exit_node_t* node;
|
||||
que_node_t* loop_node;
|
||||
|
||||
ut_ad(thr);
|
||||
|
||||
node = thr->run_node;
|
||||
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_EXIT);
|
||||
|
||||
/* Loops exit by setting thr->run_node as the loop node's parent, so
|
||||
find our containing loop node and get its parent. */
|
||||
|
||||
loop_node = que_node_get_containing_loop_node(node);
|
||||
|
||||
/* If someone uses an EXIT statement outside of a loop, this will
|
||||
trigger. */
|
||||
ut_a(loop_node);
|
||||
|
||||
thr->run_node = que_node_get_parent(loop_node);
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of a return-statement node. */
|
||||
|
||||
|
@@ -1170,9 +1170,9 @@ ibuf_dummy_index_free(
|
||||
dict_index_t* index) /* in: dummy index */
|
||||
{
|
||||
dict_table_t* table = index->table;
|
||||
mem_heap_free(index->heap);
|
||||
mutex_free(&(table->autoinc_mutex));
|
||||
mem_heap_free(table->heap);
|
||||
|
||||
dict_mem_index_free(index);
|
||||
dict_mem_table_free(table);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
@@ -459,7 +459,10 @@ btr_store_big_rec_extern_fields(
|
||||
dict_index_t* index, /* in: index of rec; the index tree
|
||||
MUST be X-latched */
|
||||
rec_t* rec, /* in: record */
|
||||
const ulint* offsets, /* in: rec_get_offsets(rec, index) */
|
||||
const ulint* offsets, /* in: rec_get_offsets(rec, index);
|
||||
the "external storage" flags in offsets
|
||||
will not correspond to rec when
|
||||
this function returns */
|
||||
big_rec_t* big_rec_vec, /* in: vector containing fields
|
||||
to be stored externally */
|
||||
mtr_t* local_mtr); /* in: mtr containing the latch to
|
||||
|
@@ -98,8 +98,7 @@ btr_cur_compress_recommendation(
|
||||
{
|
||||
page_t* page;
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(
|
||||
btr_cur_get_page(cursor)),
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
|
||||
MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
page = btr_cur_get_page(cursor);
|
||||
@@ -142,8 +141,7 @@ btr_cur_can_delete_without_compress(
|
||||
{
|
||||
page_t* page;
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(
|
||||
btr_cur_get_page(cursor)),
|
||||
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
|
||||
MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
page = btr_cur_get_page(cursor);
|
||||
|
@@ -180,12 +180,14 @@ struct btr_search_struct{
|
||||
the same prefix should be indexed in the
|
||||
hash index */
|
||||
/*----------------------*/
|
||||
#ifdef UNIV_SEARCH_PERF_STAT
|
||||
ulint n_hash_succ; /* number of successful hash searches thus
|
||||
far */
|
||||
ulint n_hash_fail; /* number of failed hash searches */
|
||||
ulint n_patt_succ; /* number of successful pattern searches thus
|
||||
far */
|
||||
ulint n_searches; /* number of searches */
|
||||
#endif /* UNIV_SEARCH_PERF_STAT */
|
||||
};
|
||||
|
||||
#define BTR_SEARCH_MAGIC_N 1112765
|
||||
@@ -218,8 +220,8 @@ extern rw_lock_t* btr_search_latch_temp;
|
||||
|
||||
#ifdef UNIV_SEARCH_PERF_STAT
|
||||
extern ulint btr_search_n_succ;
|
||||
#endif /* UNIV_SEARCH_PERF_STAT */
|
||||
extern ulint btr_search_n_hash_fail;
|
||||
#endif /* UNIV_SEARCH_PERF_STAT */
|
||||
|
||||
/* After change in n_fields or n_bytes in info, this many rounds are waited
|
||||
before starting the hash analysis again: this is to save CPU time when there
|
||||
|
@@ -26,14 +26,14 @@ void
|
||||
buf_LRU_try_free_flushed_blocks(void);
|
||||
/*==================================*/
|
||||
/**********************************************************************
|
||||
Returns TRUE if less than 15 % of the buffer pool is available. This can be
|
||||
Returns TRUE if less than 25 % of the buffer pool is available. This can be
|
||||
used in heuristics to prevent huge transactions eating up the whole buffer
|
||||
pool for their locks. */
|
||||
|
||||
ibool
|
||||
buf_LRU_buf_pool_running_out(void);
|
||||
/*==============================*/
|
||||
/* out: TRUE if less than 15 % of buffer pool
|
||||
/* out: TRUE if less than 25 % of buffer pool
|
||||
left */
|
||||
|
||||
/*#######################################################################
|
||||
|
@@ -100,6 +100,15 @@ ulint
|
||||
dict_col_get_clust_pos(
|
||||
/*===================*/
|
||||
dict_col_t* col);
|
||||
/********************************************************************
|
||||
If the given column name is reserved for InnoDB system columns, return
|
||||
TRUE. */
|
||||
|
||||
ibool
|
||||
dict_col_name_is_reserved(
|
||||
/*======================*/
|
||||
/* out: TRUE if name is reserved */
|
||||
const char* name); /* in: column name */
|
||||
/************************************************************************
|
||||
Initializes the autoinc counter. It is not an error to initialize an already
|
||||
initialized counter. */
|
||||
@@ -321,6 +330,14 @@ dict_table_get_low(
|
||||
/* out: table, NULL if not found */
|
||||
const char* table_name); /* in: table name */
|
||||
/**************************************************************************
|
||||
A noninlined version of dict_table_get_low. */
|
||||
|
||||
dict_table_t*
|
||||
dict_table_get_low_noninlined(
|
||||
/*==========================*/
|
||||
/* out: table, NULL if not found */
|
||||
const char* table_name); /* in: table name */
|
||||
/**************************************************************************
|
||||
Returns an index object. */
|
||||
UNIV_INLINE
|
||||
dict_index_t*
|
||||
@@ -496,10 +513,11 @@ dict_table_is_comp(
|
||||
compact page format */
|
||||
const dict_table_t* table); /* in: table */
|
||||
/************************************************************************
|
||||
Non inlined version of 'dict_table_is_comp' above. */
|
||||
Check whether the table uses the compact page format. */
|
||||
|
||||
ibool
|
||||
innodb_dict_table_is_comp(
|
||||
/*===============*/
|
||||
dict_table_is_comp_noninline(
|
||||
/*=========================*/
|
||||
/* out: TRUE if table uses the
|
||||
compact page format */
|
||||
const dict_table_t* table); /* in: table */
|
||||
@@ -725,33 +743,6 @@ dict_tree_free(
|
||||
/**************************************************************************
|
||||
In an index tree, finds the index corresponding to a record in the tree. */
|
||||
|
||||
dict_index_t*
|
||||
dict_tree_find_index(
|
||||
/*=================*/
|
||||
/* out: index */
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
rec_t* rec); /* in: record for which to find correct index */
|
||||
/**************************************************************************
|
||||
In an index tree, finds the index corresponding to a dtuple which is used
|
||||
in a search to a tree. */
|
||||
|
||||
dict_index_t*
|
||||
dict_tree_find_index_for_tuple(
|
||||
/*===========================*/
|
||||
/* out: index; NULL if the tuple does not
|
||||
contain the mix id field in a mixed tree */
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
dtuple_t* tuple); /* in: tuple for which to find index */
|
||||
/***********************************************************************
|
||||
Checks if a table which is a mixed cluster member owns a record. */
|
||||
|
||||
ibool
|
||||
dict_is_mixed_table_rec(
|
||||
/*====================*/
|
||||
/* out: TRUE if the record belongs to this
|
||||
table */
|
||||
dict_table_t* table, /* in: table in a mixed cluster */
|
||||
rec_t* rec); /* in: user record in the clustered index */
|
||||
/**************************************************************************
|
||||
Returns an index object if it is found in the dictionary cache. */
|
||||
|
||||
@@ -760,6 +751,7 @@ dict_index_get_if_in_cache(
|
||||
/*=======================*/
|
||||
/* out: index, NULL if not found */
|
||||
dulint index_id); /* in: index id */
|
||||
#ifdef UNIV_DEBUG
|
||||
/**************************************************************************
|
||||
Checks that a tuple has n_fields_cmp value in a sensible range, so that
|
||||
no comparison can occur with the page number field in a node pointer. */
|
||||
@@ -770,6 +762,7 @@ dict_tree_check_search_tuple(
|
||||
/* out: TRUE if ok */
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
dtuple_t* tuple); /* in: tuple used in a search */
|
||||
#endif /* UNIV_DEBUG */
|
||||
/**************************************************************************
|
||||
Builds a node pointer out of a physical record and a page number. */
|
||||
|
||||
@@ -916,7 +909,6 @@ dict_tables_have_same_db(
|
||||
dbname '/' tablename */
|
||||
const char* name2); /* in: table name in the form
|
||||
dbname '/' tablename */
|
||||
|
||||
/*************************************************************************
|
||||
Scans from pointer onwards. Stops if is at the start of a copy of
|
||||
'string' where characters are compared without case sensitivity. Stops
|
||||
@@ -928,7 +920,6 @@ dict_scan_to(
|
||||
/* out: scanned up to this */
|
||||
const char* ptr, /* in: scan from */
|
||||
const char* string);/* in: look for this */
|
||||
|
||||
/* Buffers for storing detailed information about the latest foreign key
|
||||
and unique key errors */
|
||||
extern FILE* dict_foreign_err_file;
|
||||
|
@@ -92,7 +92,6 @@ dict_table_get_n_user_cols(
|
||||
{
|
||||
ut_ad(table);
|
||||
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
||||
ut_ad(table->cached);
|
||||
|
||||
return(table->n_cols - DATA_N_SYS_COLS);
|
||||
}
|
||||
@@ -126,7 +125,6 @@ dict_table_get_n_cols(
|
||||
{
|
||||
ut_ad(table);
|
||||
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
||||
ut_ad(table->cached);
|
||||
|
||||
return(table->n_cols);
|
||||
}
|
||||
|
@@ -35,9 +35,11 @@ combination of types */
|
||||
|
||||
/* Types for a table object */
|
||||
#define DICT_TABLE_ORDINARY 1
|
||||
#if 0 /* not implemented */
|
||||
#define DICT_TABLE_CLUSTER_MEMBER 2
|
||||
#define DICT_TABLE_CLUSTER 3 /* this means that the table is
|
||||
really a cluster definition */
|
||||
#endif
|
||||
|
||||
/* Table flags */
|
||||
#define DICT_TF_COMPACT 1 /* compact page format */
|
||||
@@ -56,29 +58,13 @@ dict_mem_table_create(
|
||||
a member of a cluster */
|
||||
ulint n_cols, /* in: number of columns */
|
||||
ulint flags); /* in: table flags */
|
||||
/**************************************************************************
|
||||
Creates a cluster memory object. */
|
||||
|
||||
dict_cluster_t*
|
||||
dict_mem_cluster_create(
|
||||
/*====================*/
|
||||
/* out, own: cluster object (where the
|
||||
type dict_cluster_t == dict_table_t) */
|
||||
const char* name, /* in: cluster name */
|
||||
ulint space, /* in: space where the clustered
|
||||
indexes of the member tables are
|
||||
placed */
|
||||
ulint n_cols, /* in: number of columns */
|
||||
ulint mix_len); /* in: length of the common key prefix
|
||||
in the cluster */
|
||||
/**************************************************************************
|
||||
Declares a non-published table as a member in a cluster. */
|
||||
/********************************************************************
|
||||
Free a table memory object. */
|
||||
|
||||
void
|
||||
dict_mem_table_make_cluster_member(
|
||||
/*===============================*/
|
||||
dict_table_t* table, /* in: non-published table */
|
||||
const char* cluster_name); /* in: cluster name */
|
||||
dict_mem_table_free(
|
||||
/*================*/
|
||||
dict_table_t* table); /* in: table */
|
||||
/**************************************************************************
|
||||
Adds a column definition to a table. */
|
||||
|
||||
@@ -176,9 +162,7 @@ struct dict_field_struct{
|
||||
/* Data structure for an index tree */
|
||||
struct dict_tree_struct{
|
||||
ulint type; /* tree type */
|
||||
dulint id; /* id of the index stored in the tree, in the
|
||||
case of a mixed index, the id of the clustered
|
||||
index of the cluster table */
|
||||
dulint id; /* id of the index stored in the tree */
|
||||
ulint space; /* space of index tree */
|
||||
ulint page; /* index tree root page number */
|
||||
byte pad[64];/* Padding to prevent other memory hotspots on
|
||||
@@ -189,13 +173,8 @@ struct dict_tree_struct{
|
||||
struct has been memoryfixed (by mini-
|
||||
transactions wanting to access the index
|
||||
tree) */
|
||||
UT_LIST_BASE_NODE_T(dict_index_t)
|
||||
tree_indexes; /* list of indexes stored in the
|
||||
index tree: if the tree is not of the
|
||||
mixed type there is only one index in
|
||||
the list; if the tree is of the mixed
|
||||
type, the first index in the list is the
|
||||
index of the cluster which owns the tree */
|
||||
dict_index_t* tree_index; /* the index stored in the
|
||||
index tree */
|
||||
ulint magic_n;/* magic number */
|
||||
};
|
||||
|
||||
@@ -301,8 +280,7 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */
|
||||
|
||||
/* Data structure for a database table */
|
||||
struct dict_table_struct{
|
||||
dulint id; /* id of the table or cluster */
|
||||
ulint type; /* DICT_TABLE_ORDINARY, ... */
|
||||
dulint id; /* id of the table */
|
||||
ulint flags; /* DICT_TF_COMPACT, ... */
|
||||
mem_heap_t* heap; /* memory heap */
|
||||
const char* name; /* table name */
|
||||
@@ -371,17 +349,6 @@ struct dict_table_struct{
|
||||
UT_LIST_BASE_NODE_T(lock_t)
|
||||
locks; /* list of locks on the table */
|
||||
/*----------------------*/
|
||||
dulint mix_id; /* if the table is a member in a cluster,
|
||||
this is its mix id */
|
||||
ulint mix_len;/* if the table is a cluster or a member
|
||||
this is the common key prefix lenght */
|
||||
ulint mix_id_len;/* mix id length in a compressed form */
|
||||
byte mix_id_buf[12];
|
||||
/* mix id of a mixed table written in
|
||||
a compressed form */
|
||||
const char* cluster_name; /* if the table is a member in a
|
||||
cluster, this is the name of the cluster */
|
||||
/*----------------------*/
|
||||
ibool does_not_fit_in_memory;
|
||||
/* this field is used to specify in simulations
|
||||
tables which are so big that disk should be
|
||||
|
@@ -63,6 +63,14 @@ proc_eval_step(
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr); /* in: query thread */
|
||||
/**************************************************************************
|
||||
Performs an execution step of an exit statement node. */
|
||||
|
||||
que_thr_t*
|
||||
exit_step(
|
||||
/*======*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr); /* in: query thread */
|
||||
/**************************************************************************
|
||||
Performs an execution step of a return-statement node. */
|
||||
|
||||
que_thr_t*
|
||||
|
@@ -222,6 +222,32 @@ do {\
|
||||
mem_heap_free_top(hash_get_heap(TABLE, fold111), sizeof(TYPE));\
|
||||
} while (0)
|
||||
|
||||
/********************************************************************
|
||||
Move all hash table entries from OLD_TABLE to NEW_TABLE.*/
|
||||
|
||||
#define HASH_MIGRATE(OLD_TABLE, NEW_TABLE, NODE_TYPE, PTR_NAME, FOLD_FUNC) \
|
||||
do {\
|
||||
ulint i2222;\
|
||||
ulint cell_count2222;\
|
||||
\
|
||||
cell_count2222 = hash_get_n_cells(OLD_TABLE);\
|
||||
\
|
||||
for (i2222 = 0; i2222 < cell_count2222; i2222++) {\
|
||||
NODE_TYPE* node2222 = HASH_GET_FIRST((OLD_TABLE), i2222);\
|
||||
\
|
||||
while (node2222) {\
|
||||
NODE_TYPE* next2222 = node2222->PTR_NAME;\
|
||||
ulint fold2222 = FOLD_FUNC(node2222);\
|
||||
\
|
||||
HASH_INSERT(NODE_TYPE, PTR_NAME, (NEW_TABLE),\
|
||||
fold2222, node2222);\
|
||||
\
|
||||
node2222 = next2222;\
|
||||
}\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
|
||||
/****************************************************************
|
||||
Gets the mutex index for a fold value in a hash table. */
|
||||
UNIV_INLINE
|
||||
|
@@ -595,6 +595,15 @@ ibool
|
||||
lock_validate(void);
|
||||
/*===============*/
|
||||
/* out: TRUE if ok */
|
||||
/*************************************************************************
|
||||
Return approximate number or record locks (bits set in the bitmap) for
|
||||
this transaction. Since delete-marked records ma ybe removed, the
|
||||
record count will not be precise. */
|
||||
|
||||
ulint
|
||||
lock_number_of_rows_locked(
|
||||
/*=======================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
|
||||
/* The lock system */
|
||||
extern lock_sys_t* lock_sys;
|
||||
|
@@ -311,6 +311,17 @@ mem_heap_strdupl(
|
||||
const char* str, /* in: string to be copied */
|
||||
ulint len); /* in: length of str, in bytes */
|
||||
|
||||
/**************************************************************************
|
||||
Concatenate two strings and return the result, using a memory heap. */
|
||||
|
||||
char*
|
||||
mem_heap_strcat(
|
||||
/*============*/
|
||||
/* out, own: the result */
|
||||
mem_heap_t* heap, /* in: memory heap where string is allocated */
|
||||
const char* s1, /* in: string 1 */
|
||||
const char* s2); /* in: string 2 */
|
||||
|
||||
#ifdef MEM_PERIODIC_CHECK
|
||||
/**********************************************************************
|
||||
Goes through the list of all allocated mem blocks, checks their magic
|
||||
|
@@ -175,19 +175,6 @@ page_rec_is_comp(
|
||||
/* out: nonzero if in compact format */
|
||||
const rec_t* rec) /* in: record */
|
||||
{
|
||||
#ifdef UNIV_RELEASE_NOT_YET_STABLE
|
||||
if (UNIV_UNLIKELY((ulint)rec < (ulint)(buf_pool->frame_zero))
|
||||
|| UNIV_UNLIKELY((ulint)rec >= (ulint)(buf_pool->high_end))) {
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to read a stray page rec %p\n"
|
||||
"InnoDB: buf pool start is at %p, end at %p\n",
|
||||
rec, buf_pool->frame_zero,
|
||||
buf_pool->high_end);
|
||||
ut_error;
|
||||
}
|
||||
#endif
|
||||
return(page_is_comp(ut_align_down((rec_t*) rec, UNIV_PAGE_SIZE)));
|
||||
}
|
||||
|
||||
|
@@ -32,177 +32,187 @@
|
||||
PARS_INT_LIT = 258,
|
||||
PARS_FLOAT_LIT = 259,
|
||||
PARS_STR_LIT = 260,
|
||||
PARS_NULL_LIT = 261,
|
||||
PARS_ID_TOKEN = 262,
|
||||
PARS_AND_TOKEN = 263,
|
||||
PARS_OR_TOKEN = 264,
|
||||
PARS_NOT_TOKEN = 265,
|
||||
PARS_GE_TOKEN = 266,
|
||||
PARS_LE_TOKEN = 267,
|
||||
PARS_NE_TOKEN = 268,
|
||||
PARS_PROCEDURE_TOKEN = 269,
|
||||
PARS_IN_TOKEN = 270,
|
||||
PARS_OUT_TOKEN = 271,
|
||||
PARS_BINARY_TOKEN = 272,
|
||||
PARS_BLOB_TOKEN = 273,
|
||||
PARS_INT_TOKEN = 274,
|
||||
PARS_INTEGER_TOKEN = 275,
|
||||
PARS_FLOAT_TOKEN = 276,
|
||||
PARS_CHAR_TOKEN = 277,
|
||||
PARS_IS_TOKEN = 278,
|
||||
PARS_BEGIN_TOKEN = 279,
|
||||
PARS_END_TOKEN = 280,
|
||||
PARS_IF_TOKEN = 281,
|
||||
PARS_THEN_TOKEN = 282,
|
||||
PARS_ELSE_TOKEN = 283,
|
||||
PARS_ELSIF_TOKEN = 284,
|
||||
PARS_LOOP_TOKEN = 285,
|
||||
PARS_WHILE_TOKEN = 286,
|
||||
PARS_RETURN_TOKEN = 287,
|
||||
PARS_SELECT_TOKEN = 288,
|
||||
PARS_SUM_TOKEN = 289,
|
||||
PARS_COUNT_TOKEN = 290,
|
||||
PARS_DISTINCT_TOKEN = 291,
|
||||
PARS_FROM_TOKEN = 292,
|
||||
PARS_WHERE_TOKEN = 293,
|
||||
PARS_FOR_TOKEN = 294,
|
||||
PARS_DDOT_TOKEN = 295,
|
||||
PARS_CONSISTENT_TOKEN = 296,
|
||||
PARS_READ_TOKEN = 297,
|
||||
PARS_ORDER_TOKEN = 298,
|
||||
PARS_BY_TOKEN = 299,
|
||||
PARS_ASC_TOKEN = 300,
|
||||
PARS_DESC_TOKEN = 301,
|
||||
PARS_INSERT_TOKEN = 302,
|
||||
PARS_INTO_TOKEN = 303,
|
||||
PARS_VALUES_TOKEN = 304,
|
||||
PARS_UPDATE_TOKEN = 305,
|
||||
PARS_SET_TOKEN = 306,
|
||||
PARS_DELETE_TOKEN = 307,
|
||||
PARS_CURRENT_TOKEN = 308,
|
||||
PARS_OF_TOKEN = 309,
|
||||
PARS_CREATE_TOKEN = 310,
|
||||
PARS_TABLE_TOKEN = 311,
|
||||
PARS_INDEX_TOKEN = 312,
|
||||
PARS_UNIQUE_TOKEN = 313,
|
||||
PARS_CLUSTERED_TOKEN = 314,
|
||||
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315,
|
||||
PARS_ON_TOKEN = 316,
|
||||
PARS_ASSIGN_TOKEN = 317,
|
||||
PARS_DECLARE_TOKEN = 318,
|
||||
PARS_CURSOR_TOKEN = 319,
|
||||
PARS_SQL_TOKEN = 320,
|
||||
PARS_OPEN_TOKEN = 321,
|
||||
PARS_FETCH_TOKEN = 322,
|
||||
PARS_CLOSE_TOKEN = 323,
|
||||
PARS_NOTFOUND_TOKEN = 324,
|
||||
PARS_TO_CHAR_TOKEN = 325,
|
||||
PARS_TO_NUMBER_TOKEN = 326,
|
||||
PARS_TO_BINARY_TOKEN = 327,
|
||||
PARS_BINARY_TO_NUMBER_TOKEN = 328,
|
||||
PARS_SUBSTR_TOKEN = 329,
|
||||
PARS_REPLSTR_TOKEN = 330,
|
||||
PARS_CONCAT_TOKEN = 331,
|
||||
PARS_INSTR_TOKEN = 332,
|
||||
PARS_LENGTH_TOKEN = 333,
|
||||
PARS_SYSDATE_TOKEN = 334,
|
||||
PARS_PRINTF_TOKEN = 335,
|
||||
PARS_ASSERT_TOKEN = 336,
|
||||
PARS_RND_TOKEN = 337,
|
||||
PARS_RND_STR_TOKEN = 338,
|
||||
PARS_ROW_PRINTF_TOKEN = 339,
|
||||
PARS_COMMIT_TOKEN = 340,
|
||||
PARS_ROLLBACK_TOKEN = 341,
|
||||
PARS_WORK_TOKEN = 342,
|
||||
NEG = 343
|
||||
PARS_FIXBINARY_LIT = 261,
|
||||
PARS_BLOB_LIT = 262,
|
||||
PARS_NULL_LIT = 263,
|
||||
PARS_ID_TOKEN = 264,
|
||||
PARS_AND_TOKEN = 265,
|
||||
PARS_OR_TOKEN = 266,
|
||||
PARS_NOT_TOKEN = 267,
|
||||
PARS_GE_TOKEN = 268,
|
||||
PARS_LE_TOKEN = 269,
|
||||
PARS_NE_TOKEN = 270,
|
||||
PARS_PROCEDURE_TOKEN = 271,
|
||||
PARS_IN_TOKEN = 272,
|
||||
PARS_OUT_TOKEN = 273,
|
||||
PARS_BINARY_TOKEN = 274,
|
||||
PARS_BLOB_TOKEN = 275,
|
||||
PARS_INT_TOKEN = 276,
|
||||
PARS_INTEGER_TOKEN = 277,
|
||||
PARS_FLOAT_TOKEN = 278,
|
||||
PARS_CHAR_TOKEN = 279,
|
||||
PARS_IS_TOKEN = 280,
|
||||
PARS_BEGIN_TOKEN = 281,
|
||||
PARS_END_TOKEN = 282,
|
||||
PARS_IF_TOKEN = 283,
|
||||
PARS_THEN_TOKEN = 284,
|
||||
PARS_ELSE_TOKEN = 285,
|
||||
PARS_ELSIF_TOKEN = 286,
|
||||
PARS_LOOP_TOKEN = 287,
|
||||
PARS_WHILE_TOKEN = 288,
|
||||
PARS_RETURN_TOKEN = 289,
|
||||
PARS_SELECT_TOKEN = 290,
|
||||
PARS_SUM_TOKEN = 291,
|
||||
PARS_COUNT_TOKEN = 292,
|
||||
PARS_DISTINCT_TOKEN = 293,
|
||||
PARS_FROM_TOKEN = 294,
|
||||
PARS_WHERE_TOKEN = 295,
|
||||
PARS_FOR_TOKEN = 296,
|
||||
PARS_DDOT_TOKEN = 297,
|
||||
PARS_CONSISTENT_TOKEN = 298,
|
||||
PARS_READ_TOKEN = 299,
|
||||
PARS_ORDER_TOKEN = 300,
|
||||
PARS_BY_TOKEN = 301,
|
||||
PARS_ASC_TOKEN = 302,
|
||||
PARS_DESC_TOKEN = 303,
|
||||
PARS_INSERT_TOKEN = 304,
|
||||
PARS_INTO_TOKEN = 305,
|
||||
PARS_VALUES_TOKEN = 306,
|
||||
PARS_UPDATE_TOKEN = 307,
|
||||
PARS_SET_TOKEN = 308,
|
||||
PARS_DELETE_TOKEN = 309,
|
||||
PARS_CURRENT_TOKEN = 310,
|
||||
PARS_OF_TOKEN = 311,
|
||||
PARS_CREATE_TOKEN = 312,
|
||||
PARS_TABLE_TOKEN = 313,
|
||||
PARS_INDEX_TOKEN = 314,
|
||||
PARS_UNIQUE_TOKEN = 315,
|
||||
PARS_CLUSTERED_TOKEN = 316,
|
||||
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317,
|
||||
PARS_ON_TOKEN = 318,
|
||||
PARS_ASSIGN_TOKEN = 319,
|
||||
PARS_DECLARE_TOKEN = 320,
|
||||
PARS_CURSOR_TOKEN = 321,
|
||||
PARS_SQL_TOKEN = 322,
|
||||
PARS_OPEN_TOKEN = 323,
|
||||
PARS_FETCH_TOKEN = 324,
|
||||
PARS_CLOSE_TOKEN = 325,
|
||||
PARS_NOTFOUND_TOKEN = 326,
|
||||
PARS_TO_CHAR_TOKEN = 327,
|
||||
PARS_TO_NUMBER_TOKEN = 328,
|
||||
PARS_TO_BINARY_TOKEN = 329,
|
||||
PARS_BINARY_TO_NUMBER_TOKEN = 330,
|
||||
PARS_SUBSTR_TOKEN = 331,
|
||||
PARS_REPLSTR_TOKEN = 332,
|
||||
PARS_CONCAT_TOKEN = 333,
|
||||
PARS_INSTR_TOKEN = 334,
|
||||
PARS_LENGTH_TOKEN = 335,
|
||||
PARS_SYSDATE_TOKEN = 336,
|
||||
PARS_PRINTF_TOKEN = 337,
|
||||
PARS_ASSERT_TOKEN = 338,
|
||||
PARS_RND_TOKEN = 339,
|
||||
PARS_RND_STR_TOKEN = 340,
|
||||
PARS_ROW_PRINTF_TOKEN = 341,
|
||||
PARS_COMMIT_TOKEN = 342,
|
||||
PARS_ROLLBACK_TOKEN = 343,
|
||||
PARS_WORK_TOKEN = 344,
|
||||
PARS_UNSIGNED_TOKEN = 345,
|
||||
PARS_EXIT_TOKEN = 346,
|
||||
PARS_FUNCTION_TOKEN = 347,
|
||||
NEG = 348
|
||||
};
|
||||
#endif
|
||||
#define PARS_INT_LIT 258
|
||||
#define PARS_FLOAT_LIT 259
|
||||
#define PARS_STR_LIT 260
|
||||
#define PARS_NULL_LIT 261
|
||||
#define PARS_ID_TOKEN 262
|
||||
#define PARS_AND_TOKEN 263
|
||||
#define PARS_OR_TOKEN 264
|
||||
#define PARS_NOT_TOKEN 265
|
||||
#define PARS_GE_TOKEN 266
|
||||
#define PARS_LE_TOKEN 267
|
||||
#define PARS_NE_TOKEN 268
|
||||
#define PARS_PROCEDURE_TOKEN 269
|
||||
#define PARS_IN_TOKEN 270
|
||||
#define PARS_OUT_TOKEN 271
|
||||
#define PARS_BINARY_TOKEN 272
|
||||
#define PARS_BLOB_TOKEN 273
|
||||
#define PARS_INT_TOKEN 274
|
||||
#define PARS_INTEGER_TOKEN 275
|
||||
#define PARS_FLOAT_TOKEN 276
|
||||
#define PARS_CHAR_TOKEN 277
|
||||
#define PARS_IS_TOKEN 278
|
||||
#define PARS_BEGIN_TOKEN 279
|
||||
#define PARS_END_TOKEN 280
|
||||
#define PARS_IF_TOKEN 281
|
||||
#define PARS_THEN_TOKEN 282
|
||||
#define PARS_ELSE_TOKEN 283
|
||||
#define PARS_ELSIF_TOKEN 284
|
||||
#define PARS_LOOP_TOKEN 285
|
||||
#define PARS_WHILE_TOKEN 286
|
||||
#define PARS_RETURN_TOKEN 287
|
||||
#define PARS_SELECT_TOKEN 288
|
||||
#define PARS_SUM_TOKEN 289
|
||||
#define PARS_COUNT_TOKEN 290
|
||||
#define PARS_DISTINCT_TOKEN 291
|
||||
#define PARS_FROM_TOKEN 292
|
||||
#define PARS_WHERE_TOKEN 293
|
||||
#define PARS_FOR_TOKEN 294
|
||||
#define PARS_DDOT_TOKEN 295
|
||||
#define PARS_CONSISTENT_TOKEN 296
|
||||
#define PARS_READ_TOKEN 297
|
||||
#define PARS_ORDER_TOKEN 298
|
||||
#define PARS_BY_TOKEN 299
|
||||
#define PARS_ASC_TOKEN 300
|
||||
#define PARS_DESC_TOKEN 301
|
||||
#define PARS_INSERT_TOKEN 302
|
||||
#define PARS_INTO_TOKEN 303
|
||||
#define PARS_VALUES_TOKEN 304
|
||||
#define PARS_UPDATE_TOKEN 305
|
||||
#define PARS_SET_TOKEN 306
|
||||
#define PARS_DELETE_TOKEN 307
|
||||
#define PARS_CURRENT_TOKEN 308
|
||||
#define PARS_OF_TOKEN 309
|
||||
#define PARS_CREATE_TOKEN 310
|
||||
#define PARS_TABLE_TOKEN 311
|
||||
#define PARS_INDEX_TOKEN 312
|
||||
#define PARS_UNIQUE_TOKEN 313
|
||||
#define PARS_CLUSTERED_TOKEN 314
|
||||
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315
|
||||
#define PARS_ON_TOKEN 316
|
||||
#define PARS_ASSIGN_TOKEN 317
|
||||
#define PARS_DECLARE_TOKEN 318
|
||||
#define PARS_CURSOR_TOKEN 319
|
||||
#define PARS_SQL_TOKEN 320
|
||||
#define PARS_OPEN_TOKEN 321
|
||||
#define PARS_FETCH_TOKEN 322
|
||||
#define PARS_CLOSE_TOKEN 323
|
||||
#define PARS_NOTFOUND_TOKEN 324
|
||||
#define PARS_TO_CHAR_TOKEN 325
|
||||
#define PARS_TO_NUMBER_TOKEN 326
|
||||
#define PARS_TO_BINARY_TOKEN 327
|
||||
#define PARS_BINARY_TO_NUMBER_TOKEN 328
|
||||
#define PARS_SUBSTR_TOKEN 329
|
||||
#define PARS_REPLSTR_TOKEN 330
|
||||
#define PARS_CONCAT_TOKEN 331
|
||||
#define PARS_INSTR_TOKEN 332
|
||||
#define PARS_LENGTH_TOKEN 333
|
||||
#define PARS_SYSDATE_TOKEN 334
|
||||
#define PARS_PRINTF_TOKEN 335
|
||||
#define PARS_ASSERT_TOKEN 336
|
||||
#define PARS_RND_TOKEN 337
|
||||
#define PARS_RND_STR_TOKEN 338
|
||||
#define PARS_ROW_PRINTF_TOKEN 339
|
||||
#define PARS_COMMIT_TOKEN 340
|
||||
#define PARS_ROLLBACK_TOKEN 341
|
||||
#define PARS_WORK_TOKEN 342
|
||||
#define NEG 343
|
||||
#define PARS_FIXBINARY_LIT 261
|
||||
#define PARS_BLOB_LIT 262
|
||||
#define PARS_NULL_LIT 263
|
||||
#define PARS_ID_TOKEN 264
|
||||
#define PARS_AND_TOKEN 265
|
||||
#define PARS_OR_TOKEN 266
|
||||
#define PARS_NOT_TOKEN 267
|
||||
#define PARS_GE_TOKEN 268
|
||||
#define PARS_LE_TOKEN 269
|
||||
#define PARS_NE_TOKEN 270
|
||||
#define PARS_PROCEDURE_TOKEN 271
|
||||
#define PARS_IN_TOKEN 272
|
||||
#define PARS_OUT_TOKEN 273
|
||||
#define PARS_BINARY_TOKEN 274
|
||||
#define PARS_BLOB_TOKEN 275
|
||||
#define PARS_INT_TOKEN 276
|
||||
#define PARS_INTEGER_TOKEN 277
|
||||
#define PARS_FLOAT_TOKEN 278
|
||||
#define PARS_CHAR_TOKEN 279
|
||||
#define PARS_IS_TOKEN 280
|
||||
#define PARS_BEGIN_TOKEN 281
|
||||
#define PARS_END_TOKEN 282
|
||||
#define PARS_IF_TOKEN 283
|
||||
#define PARS_THEN_TOKEN 284
|
||||
#define PARS_ELSE_TOKEN 285
|
||||
#define PARS_ELSIF_TOKEN 286
|
||||
#define PARS_LOOP_TOKEN 287
|
||||
#define PARS_WHILE_TOKEN 288
|
||||
#define PARS_RETURN_TOKEN 289
|
||||
#define PARS_SELECT_TOKEN 290
|
||||
#define PARS_SUM_TOKEN 291
|
||||
#define PARS_COUNT_TOKEN 292
|
||||
#define PARS_DISTINCT_TOKEN 293
|
||||
#define PARS_FROM_TOKEN 294
|
||||
#define PARS_WHERE_TOKEN 295
|
||||
#define PARS_FOR_TOKEN 296
|
||||
#define PARS_DDOT_TOKEN 297
|
||||
#define PARS_CONSISTENT_TOKEN 298
|
||||
#define PARS_READ_TOKEN 299
|
||||
#define PARS_ORDER_TOKEN 300
|
||||
#define PARS_BY_TOKEN 301
|
||||
#define PARS_ASC_TOKEN 302
|
||||
#define PARS_DESC_TOKEN 303
|
||||
#define PARS_INSERT_TOKEN 304
|
||||
#define PARS_INTO_TOKEN 305
|
||||
#define PARS_VALUES_TOKEN 306
|
||||
#define PARS_UPDATE_TOKEN 307
|
||||
#define PARS_SET_TOKEN 308
|
||||
#define PARS_DELETE_TOKEN 309
|
||||
#define PARS_CURRENT_TOKEN 310
|
||||
#define PARS_OF_TOKEN 311
|
||||
#define PARS_CREATE_TOKEN 312
|
||||
#define PARS_TABLE_TOKEN 313
|
||||
#define PARS_INDEX_TOKEN 314
|
||||
#define PARS_UNIQUE_TOKEN 315
|
||||
#define PARS_CLUSTERED_TOKEN 316
|
||||
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317
|
||||
#define PARS_ON_TOKEN 318
|
||||
#define PARS_ASSIGN_TOKEN 319
|
||||
#define PARS_DECLARE_TOKEN 320
|
||||
#define PARS_CURSOR_TOKEN 321
|
||||
#define PARS_SQL_TOKEN 322
|
||||
#define PARS_OPEN_TOKEN 323
|
||||
#define PARS_FETCH_TOKEN 324
|
||||
#define PARS_CLOSE_TOKEN 325
|
||||
#define PARS_NOTFOUND_TOKEN 326
|
||||
#define PARS_TO_CHAR_TOKEN 327
|
||||
#define PARS_TO_NUMBER_TOKEN 328
|
||||
#define PARS_TO_BINARY_TOKEN 329
|
||||
#define PARS_BINARY_TO_NUMBER_TOKEN 330
|
||||
#define PARS_SUBSTR_TOKEN 331
|
||||
#define PARS_REPLSTR_TOKEN 332
|
||||
#define PARS_CONCAT_TOKEN 333
|
||||
#define PARS_INSTR_TOKEN 334
|
||||
#define PARS_LENGTH_TOKEN 335
|
||||
#define PARS_SYSDATE_TOKEN 336
|
||||
#define PARS_PRINTF_TOKEN 337
|
||||
#define PARS_ASSERT_TOKEN 338
|
||||
#define PARS_RND_TOKEN 339
|
||||
#define PARS_RND_STR_TOKEN 340
|
||||
#define PARS_ROW_PRINTF_TOKEN 341
|
||||
#define PARS_COMMIT_TOKEN 342
|
||||
#define PARS_ROLLBACK_TOKEN 343
|
||||
#define PARS_WORK_TOKEN 344
|
||||
#define PARS_UNSIGNED_TOKEN 345
|
||||
#define PARS_EXIT_TOKEN 346
|
||||
#define PARS_FUNCTION_TOKEN 347
|
||||
#define NEG 348
|
||||
|
||||
|
||||
|
||||
|
@@ -15,6 +15,13 @@ Created 11/19/1996 Heikki Tuuri
|
||||
#include "pars0types.h"
|
||||
#include "row0types.h"
|
||||
#include "trx0types.h"
|
||||
#include "ut0vec.h"
|
||||
|
||||
/* Type of the user functions. The first argument is always InnoDB-supplied
|
||||
and varies in type, while 'user_arg' is a user-supplied argument. The
|
||||
meaning of the return type also varies. See the individual use cases, e.g.
|
||||
the FETCH statement, for details on them. */
|
||||
typedef void* (*pars_user_func_cb_t)(void* arg, void* user_arg);
|
||||
|
||||
extern int yydebug;
|
||||
|
||||
@@ -77,6 +84,7 @@ que_t*
|
||||
pars_sql(
|
||||
/*=====*/
|
||||
/* out, own: the query graph */
|
||||
pars_info_t* info, /* in: extra information, or NULL */
|
||||
const char* str); /* in: SQL string */
|
||||
/*****************************************************************
|
||||
Retrieves characters to the lexical analyzer. */
|
||||
@@ -157,6 +165,15 @@ pars_cursor_declaration(
|
||||
table */
|
||||
sel_node_t* select_node); /* in: select node */
|
||||
/*************************************************************************
|
||||
Parses a function declaration. */
|
||||
|
||||
que_node_t*
|
||||
pars_function_declaration(
|
||||
/*======================*/
|
||||
/* out: sym_node */
|
||||
sym_node_t* sym_node); /* in: function id node in the symbol
|
||||
table */
|
||||
/*************************************************************************
|
||||
Parses a select statement. */
|
||||
|
||||
sel_node_t*
|
||||
@@ -269,6 +286,13 @@ pars_while_statement(
|
||||
que_node_t* cond, /* in: while-condition */
|
||||
que_node_t* stat_list); /* in: statement list */
|
||||
/*************************************************************************
|
||||
Parses an exit statement. */
|
||||
|
||||
exit_node_t*
|
||||
pars_exit_statement(void);
|
||||
/*=====================*/
|
||||
/* out: exit statement node */
|
||||
/*************************************************************************
|
||||
Parses a return-statement. */
|
||||
|
||||
return_node_t*
|
||||
@@ -294,14 +318,16 @@ pars_assignment_statement(
|
||||
sym_node_t* var, /* in: variable to assign */
|
||||
que_node_t* val); /* in: value to assign */
|
||||
/*************************************************************************
|
||||
Parses a fetch statement. */
|
||||
Parses a fetch statement. into_list or user_func (but not both) must be
|
||||
non-NULL. */
|
||||
|
||||
fetch_node_t*
|
||||
pars_fetch_statement(
|
||||
/*=================*/
|
||||
/* out: fetch statement node */
|
||||
sym_node_t* cursor, /* in: cursor node */
|
||||
sym_node_t* into_list); /* in: variables to set */
|
||||
sym_node_t* into_list, /* in: variables to set, or NULL */
|
||||
sym_node_t* user_func); /* in: user function name, or NULL */
|
||||
/*************************************************************************
|
||||
Parses an open or close cursor statement. */
|
||||
|
||||
@@ -345,6 +371,8 @@ pars_column_def(
|
||||
pars_res_word_t* type, /* in: data type */
|
||||
sym_node_t* len, /* in: length of column, or
|
||||
NULL */
|
||||
void* is_unsigned, /* in: if not NULL, column
|
||||
is of type UNSIGNED. */
|
||||
void* is_not_null); /* in: if not NULL, column
|
||||
is of type NOT NULL. */
|
||||
/*************************************************************************
|
||||
@@ -418,6 +446,142 @@ pars_complete_graph_for_exec(
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
mem_heap_t* heap); /* in: memory heap from which allocated */
|
||||
|
||||
/********************************************************************
|
||||
Create parser info struct.*/
|
||||
|
||||
pars_info_t*
|
||||
pars_info_create(void);
|
||||
/*==================*/
|
||||
/* out, own: info struct */
|
||||
|
||||
/********************************************************************
|
||||
Free info struct and everything it contains.*/
|
||||
|
||||
void
|
||||
pars_info_free(
|
||||
/*===========*/
|
||||
pars_info_t* info); /* in: info struct */
|
||||
|
||||
/********************************************************************
|
||||
Add bound literal. */
|
||||
|
||||
void
|
||||
pars_info_add_literal(
|
||||
/*==================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
const void* address, /* in: address */
|
||||
ulint length, /* in: length of data */
|
||||
ulint type, /* in: type, e.g. DATA_FIXBINARY */
|
||||
ulint prtype); /* in: precise type, e.g.
|
||||
DATA_UNSIGNED */
|
||||
|
||||
/********************************************************************
|
||||
Equivalent to pars_info_add_literal(info, name, str, strlen(str),
|
||||
DATA_VARCHAR, DATA_ENGLISH). */
|
||||
|
||||
void
|
||||
pars_info_add_str_literal(
|
||||
/*======================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
const char* str); /* in: string */
|
||||
|
||||
/********************************************************************
|
||||
Equivalent to:
|
||||
|
||||
char buf[4];
|
||||
mach_write_to_4(buf, val);
|
||||
pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
|
||||
|
||||
except that the buffer is dynamically allocated from the info struct's
|
||||
heap. */
|
||||
|
||||
void
|
||||
pars_info_add_int4_literal(
|
||||
/*=======================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
lint val); /* in: value */
|
||||
|
||||
/********************************************************************
|
||||
Equivalent to:
|
||||
|
||||
char buf[8];
|
||||
mach_write_to_8(buf, val);
|
||||
pars_info_add_literal(info, name, buf, 8, DATA_BINARY, 0);
|
||||
|
||||
except that the buffer is dynamically allocated from the info struct's
|
||||
heap. */
|
||||
|
||||
void
|
||||
pars_info_add_dulint_literal(
|
||||
/*=========================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
dulint val); /* in: value */
|
||||
/********************************************************************
|
||||
Add user function. */
|
||||
|
||||
void
|
||||
pars_info_add_function(
|
||||
/*===================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: function name */
|
||||
pars_user_func_cb_t func, /* in: function address */
|
||||
void* arg); /* in: user-supplied argument */
|
||||
|
||||
/********************************************************************
|
||||
Get user function with the given name.*/
|
||||
|
||||
pars_user_func_t*
|
||||
pars_info_get_user_func(
|
||||
/*====================*/
|
||||
/* out: user func, or NULL if not
|
||||
found */
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name); /* in: function name to find*/
|
||||
|
||||
/********************************************************************
|
||||
Get bound literal with the given name.*/
|
||||
|
||||
pars_bound_lit_t*
|
||||
pars_info_get_bound_lit(
|
||||
/*====================*/
|
||||
/* out: bound literal, or NULL if
|
||||
not found */
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name); /* in: bound literal name to find */
|
||||
|
||||
|
||||
/* Extra information supplied for pars_sql(). */
|
||||
struct pars_info_struct {
|
||||
mem_heap_t* heap; /* our own memory heap */
|
||||
|
||||
ib_vector_t* funcs; /* user functions, or NUll
|
||||
(pars_user_func_t*) */
|
||||
ib_vector_t* bound_lits; /* bound literals, or NULL
|
||||
(pars_bound_lit_t*) */
|
||||
|
||||
ibool graph_owns_us; /* if TRUE (which is the default),
|
||||
que_graph_free() will free us */
|
||||
};
|
||||
|
||||
/* User-supplied function and argument. */
|
||||
struct pars_user_func_struct {
|
||||
const char* name; /* function name */
|
||||
pars_user_func_cb_t func; /* function address */
|
||||
void* arg; /* user-supplied argument */
|
||||
};
|
||||
|
||||
/* Bound literal. */
|
||||
struct pars_bound_lit_struct {
|
||||
const char* name; /* name */
|
||||
const void* address; /* address */
|
||||
ulint length; /* length of data */
|
||||
ulint type; /* type, e.g. DATA_FIXBINARY */
|
||||
ulint prtype; /* precise type, e.g. DATA_UNSIGNED */
|
||||
};
|
||||
|
||||
/* Struct used to denote a reserved word in a parsing tree */
|
||||
struct pars_res_word_struct{
|
||||
@@ -498,6 +662,11 @@ struct for_node_struct{
|
||||
que_node_t* stat_list; /* statement list */
|
||||
};
|
||||
|
||||
/* exit statement node */
|
||||
struct exit_node_struct{
|
||||
que_common_t common; /* type: QUE_NODE_EXIT */
|
||||
};
|
||||
|
||||
/* return-statement node */
|
||||
struct return_node_struct{
|
||||
que_common_t common; /* type: QUE_NODE_RETURN */
|
||||
|
@@ -54,6 +54,16 @@ sym_tab_add_str_lit(
|
||||
it */
|
||||
ulint len); /* in: string length */
|
||||
/**********************************************************************
|
||||
Add a bound literal to a symbol table. */
|
||||
|
||||
sym_node_t*
|
||||
sym_tab_add_bound_lit(
|
||||
/*==================*/
|
||||
/* out: symbol table node */
|
||||
sym_tab_t* sym_tab, /* in: symbol table */
|
||||
const char* name, /* in: name of bound literal */
|
||||
ulint* lit_type); /* out: type of literal (PARS_*_LIT) */
|
||||
/**********************************************************************
|
||||
Adds an SQL null literal to a symbol table. */
|
||||
|
||||
sym_node_t*
|
||||
@@ -83,6 +93,19 @@ struct sym_node_struct{
|
||||
been allocated from dynamic memory and it should be freed when the
|
||||
symbol table is discarded */
|
||||
|
||||
/* 'alias' and 'indirection' are almost the same, but not quite.
|
||||
'alias' always points to the primary instance of the variable, while
|
||||
'indirection' does the same only if we should use the primary
|
||||
instance's values for the node's data. This is usually the case, but
|
||||
when initializing a cursor (e.g., "DECLARE CURSOR c IS SELECT * FROM
|
||||
t WHERE id = x;"), we copy the values from the primary instance to
|
||||
the cursor's instance so that they are fixed for the duration of the
|
||||
cursor, and set 'indirection' to NULL. If we did not, the value of
|
||||
'x' could change between fetches and things would break horribly.
|
||||
|
||||
TODO: It would be cleaner to make 'indirection' a boolean field and
|
||||
always use 'alias' to refer to the primary node. */
|
||||
|
||||
sym_node_t* indirection; /* pointer to
|
||||
another symbol table
|
||||
node which contains
|
||||
@@ -158,6 +181,7 @@ struct sym_tab_struct{
|
||||
/* position of the next character in
|
||||
sql_string to give to the lexical
|
||||
analyzer */
|
||||
pars_info_t* info; /* extra information, or NULL */
|
||||
sym_node_list_t sym_list;
|
||||
/* list of symbol nodes in the symbol
|
||||
table */
|
||||
@@ -180,6 +204,7 @@ struct sym_tab_struct{
|
||||
#define SYM_CURSOR 96 /* named cursor */
|
||||
#define SYM_PROCEDURE_NAME 97 /* stored procedure name */
|
||||
#define SYM_INDEX 98 /* database index name */
|
||||
#define SYM_FUNCTION 99 /* user function name */
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "pars0sym.ic"
|
||||
|
@@ -9,6 +9,9 @@ Created 1/11/1998 Heikki Tuuri
|
||||
#ifndef pars0types_h
|
||||
#define pars0types_h
|
||||
|
||||
typedef struct pars_info_struct pars_info_t;
|
||||
typedef struct pars_user_func_struct pars_user_func_t;
|
||||
typedef struct pars_bound_lit_struct pars_bound_lit_t;
|
||||
typedef struct sym_node_struct sym_node_t;
|
||||
typedef struct sym_tab_struct sym_tab_t;
|
||||
typedef struct pars_res_word_struct pars_res_word_t;
|
||||
@@ -19,6 +22,7 @@ typedef struct elsif_node_struct elsif_node_t;
|
||||
typedef struct if_node_struct if_node_t;
|
||||
typedef struct while_node_struct while_node_t;
|
||||
typedef struct for_node_struct for_node_t;
|
||||
typedef struct exit_node_struct exit_node_t;
|
||||
typedef struct return_node_struct return_node_t;
|
||||
typedef struct assign_node_struct assign_node_t;
|
||||
typedef struct col_assign_node_struct col_assign_node_t;
|
||||
|
@@ -277,6 +277,15 @@ que_node_get_parent(
|
||||
/*================*/
|
||||
/* out: parent node or NULL */
|
||||
que_node_t* node); /* in: node */
|
||||
/********************************************************************
|
||||
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
|
||||
given node, or NULL if the node is not within a loop. */
|
||||
|
||||
que_node_t*
|
||||
que_node_get_containing_loop_node(
|
||||
/*==============================*/
|
||||
/* out: containing loop node, or NULL. */
|
||||
que_node_t* node); /* in: node */
|
||||
/*************************************************************************
|
||||
Catenates a query graph node to a list of them, possible empty list. */
|
||||
UNIV_INLINE
|
||||
@@ -322,8 +331,15 @@ void
|
||||
que_node_print_info(
|
||||
/*================*/
|
||||
que_node_t* node); /* in: query graph node */
|
||||
/*************************************************************************
|
||||
Evaluate the given SQL */
|
||||
|
||||
|
||||
ulint
|
||||
que_eval_sql(
|
||||
/*=========*/
|
||||
pars_info_t* info, /* out: error code or DB_SUCCESS */
|
||||
const char* sql, /* in: info struct, or NULL */
|
||||
trx_t* trx); /* in: trx */
|
||||
/* Query graph query thread node: the fields are protected by the kernel
|
||||
mutex with the exceptions named below */
|
||||
|
||||
@@ -388,6 +404,7 @@ struct que_fork_struct{
|
||||
sym_tab_t* sym_tab; /* symbol table of the query,
|
||||
generated by the parser, or NULL
|
||||
if the graph was created 'by hand' */
|
||||
pars_info_t* info; /* in: info struct, or NULL */
|
||||
/* The following cur_... fields are relevant only in a select graph */
|
||||
|
||||
ulint cur_end; /* QUE_CUR_NOT_DEFINED, QUE_CUR_START,
|
||||
@@ -469,6 +486,7 @@ struct que_fork_struct{
|
||||
#define QUE_NODE_ROW_PRINTF 29
|
||||
#define QUE_NODE_ELSIF 30
|
||||
#define QUE_NODE_CALL 31
|
||||
#define QUE_NODE_EXIT 32
|
||||
|
||||
/* Query thread states */
|
||||
#define QUE_THR_RUNNING 1
|
||||
|
@@ -244,7 +244,8 @@ row_update_for_mysql(
|
||||
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
||||
handle */
|
||||
/*************************************************************************
|
||||
This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
|
||||
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
|
||||
session is using a READ COMMITTED isolation level. Before
|
||||
calling this function we must use trx_reset_new_rec_lock_info() and
|
||||
trx_register_new_rec_lock() to store the information which new record locks
|
||||
really were set. This function removes a newly set lock under prebuilt->pcur,
|
||||
|
@@ -78,6 +78,26 @@ fetch_step(
|
||||
/*=======*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr); /* in: query thread */
|
||||
/********************************************************************
|
||||
Sample callback function for fetch that prints each row.*/
|
||||
|
||||
void*
|
||||
row_fetch_print(
|
||||
/*============*/
|
||||
/* out: always returns non-NULL */
|
||||
void* row, /* in: sel_node_t* */
|
||||
void* user_arg); /* in: not used */
|
||||
/********************************************************************
|
||||
Callback function for fetch that stores an unsigned 4 byte integer to the
|
||||
location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
|
||||
= 4. */
|
||||
|
||||
void*
|
||||
row_fetch_store_uint4(
|
||||
/*==================*/
|
||||
/* out: always returns NULL */
|
||||
void* row, /* in: sel_node_t* */
|
||||
void* user_arg); /* in: data pointer */
|
||||
/***************************************************************
|
||||
Prints a row in a select result. */
|
||||
|
||||
@@ -204,8 +224,6 @@ struct plan_struct{
|
||||
ulint first_prefetched;/* index of the first cached row in
|
||||
select buffer arrays for each column */
|
||||
ibool no_prefetch; /* no prefetch for this table */
|
||||
ibool mixed_index; /* TRUE if index is a clustered index
|
||||
in a mixed cluster */
|
||||
sym_node_list_t columns; /* symbol table nodes for the columns
|
||||
to retrieve from the table */
|
||||
UT_LIST_BASE_NODE_T(func_node_t)
|
||||
@@ -311,6 +329,20 @@ struct fetch_node_struct{
|
||||
que_common_t common; /* type: QUE_NODE_FETCH */
|
||||
sel_node_t* cursor_def; /* cursor definition */
|
||||
sym_node_t* into_list; /* variables to set */
|
||||
|
||||
pars_user_func_t*
|
||||
func; /* User callback function or NULL.
|
||||
The first argument to the function
|
||||
is a sel_node_t*, containing the
|
||||
results of the SELECT operation for
|
||||
one row. If the function returns
|
||||
NULL, it is not interested in
|
||||
further rows and the cursor is
|
||||
modified so (cursor % NOTFOUND) is
|
||||
true. If it returns not-NULL,
|
||||
continue normally. See
|
||||
row_fetch_print() for an example
|
||||
(and a useful debugging tool). */
|
||||
};
|
||||
|
||||
/* Open or close cursor statement node */
|
||||
|
@@ -185,6 +185,10 @@ row_upd_index_replace_new_col_vals_index_pos(
|
||||
upd_t* update, /* in: an update vector built for the index so
|
||||
that the field number in an upd_field is the
|
||||
index position */
|
||||
ibool order_only,
|
||||
/* in: if TRUE, limit the replacement to
|
||||
ordering fields of index; note that this
|
||||
does not work for non-clustered indexes. */
|
||||
mem_heap_t* heap); /* in: memory heap to which we allocate and
|
||||
copy the new values, set this as NULL if you
|
||||
do not want allocation */
|
||||
|
@@ -544,7 +544,9 @@ struct trx_struct{
|
||||
the transaction; note that it is also
|
||||
in the lock list trx_locks */
|
||||
dict_index_t* new_rec_locks[2];/* these are normally NULL; if
|
||||
srv_locks_unsafe_for_binlog is TRUE,
|
||||
srv_locks_unsafe_for_binlog is TRUE
|
||||
or session is using READ COMMITTED
|
||||
isolation level,
|
||||
in a cursor search, if we set a new
|
||||
record lock on an index, this is set
|
||||
to point to the index; this is
|
||||
|
@@ -82,10 +82,6 @@ memory is read outside the allocated blocks. */
|
||||
|
||||
/* Make a non-inline debug version */
|
||||
|
||||
/* You can remove this define when the release is stable. This define adds
|
||||
some consistency checks to code. They use a little CPU time. */
|
||||
#define UNIV_RELEASE_NOT_YET_STABLE
|
||||
|
||||
/*
|
||||
#define UNIV_DEBUG
|
||||
#define UNIV_MEM_DEBUG
|
||||
@@ -128,7 +124,7 @@ by one. */
|
||||
#ifdef __WIN__
|
||||
#define UNIV_INLINE __inline
|
||||
#else
|
||||
#define UNIV_INLINE static inline
|
||||
#define UNIV_INLINE static __inline__
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -178,6 +174,16 @@ management to ensure correct alignment for doubles etc. */
|
||||
/* Note that inside MySQL 'byte' is defined as char on Linux! */
|
||||
#define byte unsigned char
|
||||
|
||||
/* Define an unsigned integer type that is exactly 32 bits. */
|
||||
|
||||
#if SIZEOF_INT == 4
|
||||
typedef unsigned int ib_uint32_t;
|
||||
#elif SIZEOF_LONG == 4
|
||||
typedef unsigned long ib_uint32_t;
|
||||
#else
|
||||
#error "Neither int or long is 4 bytes"
|
||||
#endif
|
||||
|
||||
/* Another basic type we use is unsigned long integer which should be equal to
|
||||
the word size of the machine, that is on a 32-bit platform 32 bits, and on a
|
||||
64-bit platform 64 bits. We also give the printf format for the type as a
|
||||
@@ -205,9 +211,6 @@ typedef longlong ib_longlong;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The following type should be at least a 64-bit floating point number */
|
||||
typedef double utfloat;
|
||||
|
||||
/* The 'undefined' value for a ulint */
|
||||
#define ULINT_UNDEFINED ((ulint)(-1))
|
||||
|
||||
|
@@ -181,6 +181,30 @@ ut_memcpyq(
|
||||
const char* src, /* in: string to be quoted */
|
||||
ulint len); /* in: length of src */
|
||||
|
||||
/**************************************************************************
|
||||
Return the number of times s2 occurs in s1. Overlapping instances of s2
|
||||
are only counted once. */
|
||||
|
||||
ulint
|
||||
ut_strcount(
|
||||
/*========*/
|
||||
/* out: the number of times s2 occurs in s1 */
|
||||
const char* s1, /* in: string to search in */
|
||||
const char* s2); /* in: string to search for */
|
||||
|
||||
/**************************************************************************
|
||||
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
|
||||
are only replaced once. */
|
||||
|
||||
char *
|
||||
ut_strreplace(
|
||||
/*==========*/
|
||||
/* out, own: modified string, must be
|
||||
freed with mem_free() */
|
||||
const char* str, /* in: string to operate on */
|
||||
const char* s1, /* in: string to replace */
|
||||
const char* s2); /* in: string to replace s1 with */
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "ut0mem.ic"
|
||||
#endif
|
||||
|
73
storage/innobase/include/ut0vec.h
Normal file
73
storage/innobase/include/ut0vec.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef IB_VECTOR_H
|
||||
#define IB_VECTOR_H
|
||||
|
||||
#include "univ.i"
|
||||
#include "mem0mem.h"
|
||||
|
||||
typedef struct ib_vector_struct ib_vector_t;
|
||||
|
||||
/* An automatically resizing vector datatype with the following properties:
|
||||
|
||||
-Contains void* items.
|
||||
|
||||
-The items are owned by the caller.
|
||||
|
||||
-All memory allocation is done through a heap owned by the caller, who is
|
||||
responsible for freeing it when done with the vector.
|
||||
|
||||
-When the vector is resized, the old memory area is left allocated since it
|
||||
uses the same heap as the new memory area, so this is best used for
|
||||
relatively small or short-lived uses.
|
||||
*/
|
||||
|
||||
/********************************************************************
|
||||
Create a new vector with the given initial size. */
|
||||
|
||||
ib_vector_t*
|
||||
ib_vector_create(
|
||||
/*=============*/
|
||||
/* out: vector */
|
||||
mem_heap_t* heap, /* in: heap */
|
||||
ulint size); /* in: initial size */
|
||||
|
||||
/********************************************************************
|
||||
Push a new element to the vector, increasing its size if necessary. */
|
||||
|
||||
void
|
||||
ib_vector_push(
|
||||
/*===========*/
|
||||
ib_vector_t* vec, /* in: vector */
|
||||
void* elem); /* in: data element */
|
||||
|
||||
/********************************************************************
|
||||
Get the number of elements in the vector. */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
ib_vector_size(
|
||||
/*===========*/
|
||||
/* out: number of elements in vector */
|
||||
ib_vector_t* vec); /* in: vector */
|
||||
|
||||
/********************************************************************
|
||||
Get the n'th element. */
|
||||
UNIV_INLINE
|
||||
void*
|
||||
ib_vector_get(
|
||||
/*==========*/
|
||||
/* out: n'th element */
|
||||
ib_vector_t* vec, /* in: vector */
|
||||
ulint n); /* in: element index to get */
|
||||
|
||||
/* See comment at beginning of file. */
|
||||
struct ib_vector_struct {
|
||||
mem_heap_t* heap; /* heap */
|
||||
void** data; /* data elements */
|
||||
ulint used; /* number of elements currently used */
|
||||
ulint total; /* number of elements allocated */
|
||||
};
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "ut0vec.ic"
|
||||
#endif
|
||||
|
||||
#endif
|
26
storage/innobase/include/ut0vec.ic
Normal file
26
storage/innobase/include/ut0vec.ic
Normal file
@@ -0,0 +1,26 @@
|
||||
/********************************************************************
|
||||
Get number of elements in vector. */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
ib_vector_size(
|
||||
/*===========*/
|
||||
/* out: number of elements in vector */
|
||||
ib_vector_t* vec) /* in: vector */
|
||||
{
|
||||
return(vec->used);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Get n'th element. */
|
||||
UNIV_INLINE
|
||||
void*
|
||||
ib_vector_get(
|
||||
/*==========*/
|
||||
/* out: n'th element */
|
||||
ib_vector_t* vec, /* in: vector */
|
||||
ulint n) /* in: element index to get */
|
||||
{
|
||||
ut_a(n < vec->used);
|
||||
|
||||
return(vec->data[n]);
|
||||
}
|
@@ -1698,6 +1698,40 @@ lock_sec_rec_some_has_impl_off_kernel(
|
||||
return(row_vers_impl_x_locked_off_kernel(rec, index, offsets));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Return approximate number or record locks (bits set in the bitmap) for
|
||||
this transaction. Since delete-marked records may be removed, the
|
||||
record count will not be precise. */
|
||||
|
||||
ulint
|
||||
lock_number_of_rows_locked(
|
||||
/*=======================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
lock_t* lock;
|
||||
ulint n_records = 0;
|
||||
ulint n_bits;
|
||||
ulint n_bit;
|
||||
|
||||
lock = UT_LIST_GET_FIRST(trx->trx_locks);
|
||||
|
||||
while (lock) {
|
||||
if (lock_get_type(lock) == LOCK_REC) {
|
||||
n_bits = lock_rec_get_n_bits(lock);
|
||||
|
||||
for (n_bit = 0; n_bit < n_bits; n_bit++) {
|
||||
if (lock_rec_get_nth_bit(lock, n_bit)) {
|
||||
n_records++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lock = UT_LIST_GET_NEXT(trx_locks, lock);
|
||||
}
|
||||
|
||||
return (n_records);
|
||||
}
|
||||
|
||||
/*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/
|
||||
|
||||
/*************************************************************************
|
||||
@@ -2001,7 +2035,8 @@ lock_rec_lock_fast(
|
||||
if (!impl) {
|
||||
lock_rec_create(mode, rec, index, trx);
|
||||
|
||||
if (srv_locks_unsafe_for_binlog) {
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
trx_register_new_rec_lock(trx, index);
|
||||
}
|
||||
}
|
||||
@@ -2027,7 +2062,8 @@ lock_rec_lock_fast(
|
||||
|
||||
if (!lock_rec_get_nth_bit(lock, heap_no)) {
|
||||
lock_rec_set_nth_bit(lock, heap_no);
|
||||
if (srv_locks_unsafe_for_binlog) {
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
trx_register_new_rec_lock(trx, index);
|
||||
}
|
||||
}
|
||||
@@ -2087,7 +2123,8 @@ lock_rec_lock_slow(
|
||||
|
||||
err = lock_rec_enqueue_waiting(mode, rec, index, thr);
|
||||
|
||||
if (srv_locks_unsafe_for_binlog) {
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
trx_register_new_rec_lock(trx, index);
|
||||
}
|
||||
} else {
|
||||
@@ -2096,7 +2133,8 @@ lock_rec_lock_slow(
|
||||
|
||||
lock_rec_add_to_queue(LOCK_REC | mode, rec, index,
|
||||
trx);
|
||||
if (srv_locks_unsafe_for_binlog) {
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
trx_register_new_rec_lock(trx, index);
|
||||
}
|
||||
}
|
||||
@@ -2436,14 +2474,17 @@ lock_rec_inherit_to_gap(
|
||||
|
||||
lock = lock_rec_get_first(rec);
|
||||
|
||||
/* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set
|
||||
/* If srv_locks_unsafe_for_binlog is TRUE or session is using
|
||||
READ COMMITTED isolation level, we do not want locks set
|
||||
by an UPDATE or a DELETE to be inherited as gap type locks. But we
|
||||
DO want S-locks set by a consistency constraint to be inherited also
|
||||
then. */
|
||||
|
||||
while (lock != NULL) {
|
||||
if (!lock_rec_get_insert_intention(lock)
|
||||
&& !(srv_locks_unsafe_for_binlog
|
||||
&& !((srv_locks_unsafe_for_binlog
|
||||
|| lock->trx->isolation_level ==
|
||||
TRX_ISO_READ_COMMITTED)
|
||||
&& lock_get_mode(lock) == LOCK_X)) {
|
||||
|
||||
lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock)
|
||||
@@ -4320,6 +4361,10 @@ loop:
|
||||
(ulong) ut_dulint_get_low(trx->read_view->up_limit_id));
|
||||
}
|
||||
|
||||
fprintf(file,
|
||||
"Trx has approximately %lu row locks\n",
|
||||
(ulong) lock_number_of_rows_locked(trx));
|
||||
|
||||
if (trx->que_state == TRX_QUE_LOCK_WAIT) {
|
||||
fprintf(file,
|
||||
"------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:\n",
|
||||
@@ -5167,3 +5212,4 @@ lock_clust_rec_read_check_and_lock_alt(
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
@@ -897,9 +897,9 @@ recv_parse_or_apply_log_rec_body(
|
||||
ut_ad(!page || ptr);
|
||||
if (index) {
|
||||
dict_table_t* table = index->table;
|
||||
mem_heap_free(index->heap);
|
||||
mutex_free(&(table->autoinc_mutex));
|
||||
mem_heap_free(table->heap);
|
||||
|
||||
dict_mem_index_free(index);
|
||||
dict_mem_table_free(table);
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
|
@@ -445,7 +445,7 @@ mem_heap_validate_or_print(
|
||||
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", block,
|
||||
"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", (void*) block,
|
||||
(ulong) mem_block_get_len(block));
|
||||
/* error */
|
||||
|
||||
|
@@ -114,6 +114,31 @@ mem_heap_strdup(
|
||||
return(memcpy(mem_heap_alloc(heap, len), str, len));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Concatenate two strings and return the result, using a memory heap. */
|
||||
|
||||
char*
|
||||
mem_heap_strcat(
|
||||
/*============*/
|
||||
/* out, own: the result */
|
||||
mem_heap_t* heap, /* in: memory heap where string is allocated */
|
||||
const char* s1, /* in: string 1 */
|
||||
const char* s2) /* in: string 2 */
|
||||
{
|
||||
char* s;
|
||||
ulint s1_len = strlen(s1);
|
||||
ulint s2_len = strlen(s2);
|
||||
|
||||
s = mem_heap_alloc(heap, s1_len + s2_len + 1);
|
||||
|
||||
memcpy(s, s1, s1_len);
|
||||
memcpy(s + s1_len, s2, s2_len);
|
||||
|
||||
s[s1_len + s2_len] = '\0';
|
||||
|
||||
return(s);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Creates a memory heap block where data can be allocated. */
|
||||
|
||||
|
@@ -641,7 +641,7 @@ os_fast_mutex_free(
|
||||
" InnoDB: error: return value %lu when calling\n"
|
||||
"InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
|
||||
fprintf(stderr,
|
||||
"InnoDB: Byte contents of the pthread mutex at %p:\n", fast_mutex);
|
||||
"InnoDB: Byte contents of the pthread mutex at %p:\n", (void*) fast_mutex);
|
||||
ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# regenerate parser from bison input files as documented at the top of
|
||||
# pars0lex.l.
|
||||
# generate parser files from bison input files.
|
||||
|
||||
set -eu
|
||||
|
||||
|
20
storage/innobase/pars/make_flex.sh
Executable file
20
storage/innobase/pars/make_flex.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# generate lexer files from flex input files.
|
||||
|
||||
set -eu
|
||||
|
||||
TMPFILE=_flex_tmp.c
|
||||
OUTFILE=lexyy.c
|
||||
|
||||
flex -o $TMPFILE pars0lex.l
|
||||
|
||||
# AIX needs its includes done in a certain order, so include "univ.i" first
|
||||
# to be sure we get it right.
|
||||
echo '#include "univ.i"' > $OUTFILE
|
||||
|
||||
# flex assigns a pointer to an int in one place without a cast, resulting in
|
||||
# a warning on Win64. this adds the cast.
|
||||
sed -e 's/int offset = (yy_c_buf_p) - (yytext_ptr);/int offset = (int)((yy_c_buf_p) - (yytext_ptr));/;' < $TMPFILE >> $OUTFILE
|
||||
|
||||
rm $TMPFILE
|
File diff suppressed because it is too large
Load Diff
@@ -32,177 +32,187 @@
|
||||
PARS_INT_LIT = 258,
|
||||
PARS_FLOAT_LIT = 259,
|
||||
PARS_STR_LIT = 260,
|
||||
PARS_NULL_LIT = 261,
|
||||
PARS_ID_TOKEN = 262,
|
||||
PARS_AND_TOKEN = 263,
|
||||
PARS_OR_TOKEN = 264,
|
||||
PARS_NOT_TOKEN = 265,
|
||||
PARS_GE_TOKEN = 266,
|
||||
PARS_LE_TOKEN = 267,
|
||||
PARS_NE_TOKEN = 268,
|
||||
PARS_PROCEDURE_TOKEN = 269,
|
||||
PARS_IN_TOKEN = 270,
|
||||
PARS_OUT_TOKEN = 271,
|
||||
PARS_BINARY_TOKEN = 272,
|
||||
PARS_BLOB_TOKEN = 273,
|
||||
PARS_INT_TOKEN = 274,
|
||||
PARS_INTEGER_TOKEN = 275,
|
||||
PARS_FLOAT_TOKEN = 276,
|
||||
PARS_CHAR_TOKEN = 277,
|
||||
PARS_IS_TOKEN = 278,
|
||||
PARS_BEGIN_TOKEN = 279,
|
||||
PARS_END_TOKEN = 280,
|
||||
PARS_IF_TOKEN = 281,
|
||||
PARS_THEN_TOKEN = 282,
|
||||
PARS_ELSE_TOKEN = 283,
|
||||
PARS_ELSIF_TOKEN = 284,
|
||||
PARS_LOOP_TOKEN = 285,
|
||||
PARS_WHILE_TOKEN = 286,
|
||||
PARS_RETURN_TOKEN = 287,
|
||||
PARS_SELECT_TOKEN = 288,
|
||||
PARS_SUM_TOKEN = 289,
|
||||
PARS_COUNT_TOKEN = 290,
|
||||
PARS_DISTINCT_TOKEN = 291,
|
||||
PARS_FROM_TOKEN = 292,
|
||||
PARS_WHERE_TOKEN = 293,
|
||||
PARS_FOR_TOKEN = 294,
|
||||
PARS_DDOT_TOKEN = 295,
|
||||
PARS_CONSISTENT_TOKEN = 296,
|
||||
PARS_READ_TOKEN = 297,
|
||||
PARS_ORDER_TOKEN = 298,
|
||||
PARS_BY_TOKEN = 299,
|
||||
PARS_ASC_TOKEN = 300,
|
||||
PARS_DESC_TOKEN = 301,
|
||||
PARS_INSERT_TOKEN = 302,
|
||||
PARS_INTO_TOKEN = 303,
|
||||
PARS_VALUES_TOKEN = 304,
|
||||
PARS_UPDATE_TOKEN = 305,
|
||||
PARS_SET_TOKEN = 306,
|
||||
PARS_DELETE_TOKEN = 307,
|
||||
PARS_CURRENT_TOKEN = 308,
|
||||
PARS_OF_TOKEN = 309,
|
||||
PARS_CREATE_TOKEN = 310,
|
||||
PARS_TABLE_TOKEN = 311,
|
||||
PARS_INDEX_TOKEN = 312,
|
||||
PARS_UNIQUE_TOKEN = 313,
|
||||
PARS_CLUSTERED_TOKEN = 314,
|
||||
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315,
|
||||
PARS_ON_TOKEN = 316,
|
||||
PARS_ASSIGN_TOKEN = 317,
|
||||
PARS_DECLARE_TOKEN = 318,
|
||||
PARS_CURSOR_TOKEN = 319,
|
||||
PARS_SQL_TOKEN = 320,
|
||||
PARS_OPEN_TOKEN = 321,
|
||||
PARS_FETCH_TOKEN = 322,
|
||||
PARS_CLOSE_TOKEN = 323,
|
||||
PARS_NOTFOUND_TOKEN = 324,
|
||||
PARS_TO_CHAR_TOKEN = 325,
|
||||
PARS_TO_NUMBER_TOKEN = 326,
|
||||
PARS_TO_BINARY_TOKEN = 327,
|
||||
PARS_BINARY_TO_NUMBER_TOKEN = 328,
|
||||
PARS_SUBSTR_TOKEN = 329,
|
||||
PARS_REPLSTR_TOKEN = 330,
|
||||
PARS_CONCAT_TOKEN = 331,
|
||||
PARS_INSTR_TOKEN = 332,
|
||||
PARS_LENGTH_TOKEN = 333,
|
||||
PARS_SYSDATE_TOKEN = 334,
|
||||
PARS_PRINTF_TOKEN = 335,
|
||||
PARS_ASSERT_TOKEN = 336,
|
||||
PARS_RND_TOKEN = 337,
|
||||
PARS_RND_STR_TOKEN = 338,
|
||||
PARS_ROW_PRINTF_TOKEN = 339,
|
||||
PARS_COMMIT_TOKEN = 340,
|
||||
PARS_ROLLBACK_TOKEN = 341,
|
||||
PARS_WORK_TOKEN = 342,
|
||||
NEG = 343
|
||||
PARS_FIXBINARY_LIT = 261,
|
||||
PARS_BLOB_LIT = 262,
|
||||
PARS_NULL_LIT = 263,
|
||||
PARS_ID_TOKEN = 264,
|
||||
PARS_AND_TOKEN = 265,
|
||||
PARS_OR_TOKEN = 266,
|
||||
PARS_NOT_TOKEN = 267,
|
||||
PARS_GE_TOKEN = 268,
|
||||
PARS_LE_TOKEN = 269,
|
||||
PARS_NE_TOKEN = 270,
|
||||
PARS_PROCEDURE_TOKEN = 271,
|
||||
PARS_IN_TOKEN = 272,
|
||||
PARS_OUT_TOKEN = 273,
|
||||
PARS_BINARY_TOKEN = 274,
|
||||
PARS_BLOB_TOKEN = 275,
|
||||
PARS_INT_TOKEN = 276,
|
||||
PARS_INTEGER_TOKEN = 277,
|
||||
PARS_FLOAT_TOKEN = 278,
|
||||
PARS_CHAR_TOKEN = 279,
|
||||
PARS_IS_TOKEN = 280,
|
||||
PARS_BEGIN_TOKEN = 281,
|
||||
PARS_END_TOKEN = 282,
|
||||
PARS_IF_TOKEN = 283,
|
||||
PARS_THEN_TOKEN = 284,
|
||||
PARS_ELSE_TOKEN = 285,
|
||||
PARS_ELSIF_TOKEN = 286,
|
||||
PARS_LOOP_TOKEN = 287,
|
||||
PARS_WHILE_TOKEN = 288,
|
||||
PARS_RETURN_TOKEN = 289,
|
||||
PARS_SELECT_TOKEN = 290,
|
||||
PARS_SUM_TOKEN = 291,
|
||||
PARS_COUNT_TOKEN = 292,
|
||||
PARS_DISTINCT_TOKEN = 293,
|
||||
PARS_FROM_TOKEN = 294,
|
||||
PARS_WHERE_TOKEN = 295,
|
||||
PARS_FOR_TOKEN = 296,
|
||||
PARS_DDOT_TOKEN = 297,
|
||||
PARS_CONSISTENT_TOKEN = 298,
|
||||
PARS_READ_TOKEN = 299,
|
||||
PARS_ORDER_TOKEN = 300,
|
||||
PARS_BY_TOKEN = 301,
|
||||
PARS_ASC_TOKEN = 302,
|
||||
PARS_DESC_TOKEN = 303,
|
||||
PARS_INSERT_TOKEN = 304,
|
||||
PARS_INTO_TOKEN = 305,
|
||||
PARS_VALUES_TOKEN = 306,
|
||||
PARS_UPDATE_TOKEN = 307,
|
||||
PARS_SET_TOKEN = 308,
|
||||
PARS_DELETE_TOKEN = 309,
|
||||
PARS_CURRENT_TOKEN = 310,
|
||||
PARS_OF_TOKEN = 311,
|
||||
PARS_CREATE_TOKEN = 312,
|
||||
PARS_TABLE_TOKEN = 313,
|
||||
PARS_INDEX_TOKEN = 314,
|
||||
PARS_UNIQUE_TOKEN = 315,
|
||||
PARS_CLUSTERED_TOKEN = 316,
|
||||
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317,
|
||||
PARS_ON_TOKEN = 318,
|
||||
PARS_ASSIGN_TOKEN = 319,
|
||||
PARS_DECLARE_TOKEN = 320,
|
||||
PARS_CURSOR_TOKEN = 321,
|
||||
PARS_SQL_TOKEN = 322,
|
||||
PARS_OPEN_TOKEN = 323,
|
||||
PARS_FETCH_TOKEN = 324,
|
||||
PARS_CLOSE_TOKEN = 325,
|
||||
PARS_NOTFOUND_TOKEN = 326,
|
||||
PARS_TO_CHAR_TOKEN = 327,
|
||||
PARS_TO_NUMBER_TOKEN = 328,
|
||||
PARS_TO_BINARY_TOKEN = 329,
|
||||
PARS_BINARY_TO_NUMBER_TOKEN = 330,
|
||||
PARS_SUBSTR_TOKEN = 331,
|
||||
PARS_REPLSTR_TOKEN = 332,
|
||||
PARS_CONCAT_TOKEN = 333,
|
||||
PARS_INSTR_TOKEN = 334,
|
||||
PARS_LENGTH_TOKEN = 335,
|
||||
PARS_SYSDATE_TOKEN = 336,
|
||||
PARS_PRINTF_TOKEN = 337,
|
||||
PARS_ASSERT_TOKEN = 338,
|
||||
PARS_RND_TOKEN = 339,
|
||||
PARS_RND_STR_TOKEN = 340,
|
||||
PARS_ROW_PRINTF_TOKEN = 341,
|
||||
PARS_COMMIT_TOKEN = 342,
|
||||
PARS_ROLLBACK_TOKEN = 343,
|
||||
PARS_WORK_TOKEN = 344,
|
||||
PARS_UNSIGNED_TOKEN = 345,
|
||||
PARS_EXIT_TOKEN = 346,
|
||||
PARS_FUNCTION_TOKEN = 347,
|
||||
NEG = 348
|
||||
};
|
||||
#endif
|
||||
#define PARS_INT_LIT 258
|
||||
#define PARS_FLOAT_LIT 259
|
||||
#define PARS_STR_LIT 260
|
||||
#define PARS_NULL_LIT 261
|
||||
#define PARS_ID_TOKEN 262
|
||||
#define PARS_AND_TOKEN 263
|
||||
#define PARS_OR_TOKEN 264
|
||||
#define PARS_NOT_TOKEN 265
|
||||
#define PARS_GE_TOKEN 266
|
||||
#define PARS_LE_TOKEN 267
|
||||
#define PARS_NE_TOKEN 268
|
||||
#define PARS_PROCEDURE_TOKEN 269
|
||||
#define PARS_IN_TOKEN 270
|
||||
#define PARS_OUT_TOKEN 271
|
||||
#define PARS_BINARY_TOKEN 272
|
||||
#define PARS_BLOB_TOKEN 273
|
||||
#define PARS_INT_TOKEN 274
|
||||
#define PARS_INTEGER_TOKEN 275
|
||||
#define PARS_FLOAT_TOKEN 276
|
||||
#define PARS_CHAR_TOKEN 277
|
||||
#define PARS_IS_TOKEN 278
|
||||
#define PARS_BEGIN_TOKEN 279
|
||||
#define PARS_END_TOKEN 280
|
||||
#define PARS_IF_TOKEN 281
|
||||
#define PARS_THEN_TOKEN 282
|
||||
#define PARS_ELSE_TOKEN 283
|
||||
#define PARS_ELSIF_TOKEN 284
|
||||
#define PARS_LOOP_TOKEN 285
|
||||
#define PARS_WHILE_TOKEN 286
|
||||
#define PARS_RETURN_TOKEN 287
|
||||
#define PARS_SELECT_TOKEN 288
|
||||
#define PARS_SUM_TOKEN 289
|
||||
#define PARS_COUNT_TOKEN 290
|
||||
#define PARS_DISTINCT_TOKEN 291
|
||||
#define PARS_FROM_TOKEN 292
|
||||
#define PARS_WHERE_TOKEN 293
|
||||
#define PARS_FOR_TOKEN 294
|
||||
#define PARS_DDOT_TOKEN 295
|
||||
#define PARS_CONSISTENT_TOKEN 296
|
||||
#define PARS_READ_TOKEN 297
|
||||
#define PARS_ORDER_TOKEN 298
|
||||
#define PARS_BY_TOKEN 299
|
||||
#define PARS_ASC_TOKEN 300
|
||||
#define PARS_DESC_TOKEN 301
|
||||
#define PARS_INSERT_TOKEN 302
|
||||
#define PARS_INTO_TOKEN 303
|
||||
#define PARS_VALUES_TOKEN 304
|
||||
#define PARS_UPDATE_TOKEN 305
|
||||
#define PARS_SET_TOKEN 306
|
||||
#define PARS_DELETE_TOKEN 307
|
||||
#define PARS_CURRENT_TOKEN 308
|
||||
#define PARS_OF_TOKEN 309
|
||||
#define PARS_CREATE_TOKEN 310
|
||||
#define PARS_TABLE_TOKEN 311
|
||||
#define PARS_INDEX_TOKEN 312
|
||||
#define PARS_UNIQUE_TOKEN 313
|
||||
#define PARS_CLUSTERED_TOKEN 314
|
||||
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315
|
||||
#define PARS_ON_TOKEN 316
|
||||
#define PARS_ASSIGN_TOKEN 317
|
||||
#define PARS_DECLARE_TOKEN 318
|
||||
#define PARS_CURSOR_TOKEN 319
|
||||
#define PARS_SQL_TOKEN 320
|
||||
#define PARS_OPEN_TOKEN 321
|
||||
#define PARS_FETCH_TOKEN 322
|
||||
#define PARS_CLOSE_TOKEN 323
|
||||
#define PARS_NOTFOUND_TOKEN 324
|
||||
#define PARS_TO_CHAR_TOKEN 325
|
||||
#define PARS_TO_NUMBER_TOKEN 326
|
||||
#define PARS_TO_BINARY_TOKEN 327
|
||||
#define PARS_BINARY_TO_NUMBER_TOKEN 328
|
||||
#define PARS_SUBSTR_TOKEN 329
|
||||
#define PARS_REPLSTR_TOKEN 330
|
||||
#define PARS_CONCAT_TOKEN 331
|
||||
#define PARS_INSTR_TOKEN 332
|
||||
#define PARS_LENGTH_TOKEN 333
|
||||
#define PARS_SYSDATE_TOKEN 334
|
||||
#define PARS_PRINTF_TOKEN 335
|
||||
#define PARS_ASSERT_TOKEN 336
|
||||
#define PARS_RND_TOKEN 337
|
||||
#define PARS_RND_STR_TOKEN 338
|
||||
#define PARS_ROW_PRINTF_TOKEN 339
|
||||
#define PARS_COMMIT_TOKEN 340
|
||||
#define PARS_ROLLBACK_TOKEN 341
|
||||
#define PARS_WORK_TOKEN 342
|
||||
#define NEG 343
|
||||
#define PARS_FIXBINARY_LIT 261
|
||||
#define PARS_BLOB_LIT 262
|
||||
#define PARS_NULL_LIT 263
|
||||
#define PARS_ID_TOKEN 264
|
||||
#define PARS_AND_TOKEN 265
|
||||
#define PARS_OR_TOKEN 266
|
||||
#define PARS_NOT_TOKEN 267
|
||||
#define PARS_GE_TOKEN 268
|
||||
#define PARS_LE_TOKEN 269
|
||||
#define PARS_NE_TOKEN 270
|
||||
#define PARS_PROCEDURE_TOKEN 271
|
||||
#define PARS_IN_TOKEN 272
|
||||
#define PARS_OUT_TOKEN 273
|
||||
#define PARS_BINARY_TOKEN 274
|
||||
#define PARS_BLOB_TOKEN 275
|
||||
#define PARS_INT_TOKEN 276
|
||||
#define PARS_INTEGER_TOKEN 277
|
||||
#define PARS_FLOAT_TOKEN 278
|
||||
#define PARS_CHAR_TOKEN 279
|
||||
#define PARS_IS_TOKEN 280
|
||||
#define PARS_BEGIN_TOKEN 281
|
||||
#define PARS_END_TOKEN 282
|
||||
#define PARS_IF_TOKEN 283
|
||||
#define PARS_THEN_TOKEN 284
|
||||
#define PARS_ELSE_TOKEN 285
|
||||
#define PARS_ELSIF_TOKEN 286
|
||||
#define PARS_LOOP_TOKEN 287
|
||||
#define PARS_WHILE_TOKEN 288
|
||||
#define PARS_RETURN_TOKEN 289
|
||||
#define PARS_SELECT_TOKEN 290
|
||||
#define PARS_SUM_TOKEN 291
|
||||
#define PARS_COUNT_TOKEN 292
|
||||
#define PARS_DISTINCT_TOKEN 293
|
||||
#define PARS_FROM_TOKEN 294
|
||||
#define PARS_WHERE_TOKEN 295
|
||||
#define PARS_FOR_TOKEN 296
|
||||
#define PARS_DDOT_TOKEN 297
|
||||
#define PARS_CONSISTENT_TOKEN 298
|
||||
#define PARS_READ_TOKEN 299
|
||||
#define PARS_ORDER_TOKEN 300
|
||||
#define PARS_BY_TOKEN 301
|
||||
#define PARS_ASC_TOKEN 302
|
||||
#define PARS_DESC_TOKEN 303
|
||||
#define PARS_INSERT_TOKEN 304
|
||||
#define PARS_INTO_TOKEN 305
|
||||
#define PARS_VALUES_TOKEN 306
|
||||
#define PARS_UPDATE_TOKEN 307
|
||||
#define PARS_SET_TOKEN 308
|
||||
#define PARS_DELETE_TOKEN 309
|
||||
#define PARS_CURRENT_TOKEN 310
|
||||
#define PARS_OF_TOKEN 311
|
||||
#define PARS_CREATE_TOKEN 312
|
||||
#define PARS_TABLE_TOKEN 313
|
||||
#define PARS_INDEX_TOKEN 314
|
||||
#define PARS_UNIQUE_TOKEN 315
|
||||
#define PARS_CLUSTERED_TOKEN 316
|
||||
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317
|
||||
#define PARS_ON_TOKEN 318
|
||||
#define PARS_ASSIGN_TOKEN 319
|
||||
#define PARS_DECLARE_TOKEN 320
|
||||
#define PARS_CURSOR_TOKEN 321
|
||||
#define PARS_SQL_TOKEN 322
|
||||
#define PARS_OPEN_TOKEN 323
|
||||
#define PARS_FETCH_TOKEN 324
|
||||
#define PARS_CLOSE_TOKEN 325
|
||||
#define PARS_NOTFOUND_TOKEN 326
|
||||
#define PARS_TO_CHAR_TOKEN 327
|
||||
#define PARS_TO_NUMBER_TOKEN 328
|
||||
#define PARS_TO_BINARY_TOKEN 329
|
||||
#define PARS_BINARY_TO_NUMBER_TOKEN 330
|
||||
#define PARS_SUBSTR_TOKEN 331
|
||||
#define PARS_REPLSTR_TOKEN 332
|
||||
#define PARS_CONCAT_TOKEN 333
|
||||
#define PARS_INSTR_TOKEN 334
|
||||
#define PARS_LENGTH_TOKEN 335
|
||||
#define PARS_SYSDATE_TOKEN 336
|
||||
#define PARS_PRINTF_TOKEN 337
|
||||
#define PARS_ASSERT_TOKEN 338
|
||||
#define PARS_RND_TOKEN 339
|
||||
#define PARS_RND_STR_TOKEN 340
|
||||
#define PARS_ROW_PRINTF_TOKEN 341
|
||||
#define PARS_COMMIT_TOKEN 342
|
||||
#define PARS_ROLLBACK_TOKEN 343
|
||||
#define PARS_WORK_TOKEN 344
|
||||
#define PARS_UNSIGNED_TOKEN 345
|
||||
#define PARS_EXIT_TOKEN 346
|
||||
#define PARS_FUNCTION_TOKEN 347
|
||||
#define NEG 348
|
||||
|
||||
|
||||
|
||||
|
@@ -33,6 +33,8 @@ yylex(void);
|
||||
%token PARS_INT_LIT
|
||||
%token PARS_FLOAT_LIT
|
||||
%token PARS_STR_LIT
|
||||
%token PARS_FIXBINARY_LIT
|
||||
%token PARS_BLOB_LIT
|
||||
%token PARS_NULL_LIT
|
||||
%token PARS_ID_TOKEN
|
||||
%token PARS_AND_TOKEN
|
||||
@@ -115,6 +117,9 @@ yylex(void);
|
||||
%token PARS_COMMIT_TOKEN
|
||||
%token PARS_ROLLBACK_TOKEN
|
||||
%token PARS_WORK_TOKEN
|
||||
%token PARS_UNSIGNED_TOKEN
|
||||
%token PARS_EXIT_TOKEN
|
||||
%token PARS_FUNCTION_TOKEN
|
||||
|
||||
%left PARS_AND_TOKEN PARS_OR_TOKEN
|
||||
%left PARS_NOT_TOKEN
|
||||
@@ -133,6 +138,7 @@ statement:
|
||||
| predefined_procedure_call ';'
|
||||
| while_statement ';'
|
||||
| for_statement ';'
|
||||
| exit_statement ';'
|
||||
| if_statement ';'
|
||||
| return_statement ';'
|
||||
| assignment_statement ';'
|
||||
@@ -165,6 +171,8 @@ exp:
|
||||
| PARS_INT_LIT { $$ = $1;}
|
||||
| PARS_FLOAT_LIT { $$ = $1;}
|
||||
| PARS_STR_LIT { $$ = $1;}
|
||||
| PARS_FIXBINARY_LIT { $$ = $1;}
|
||||
| PARS_BLOB_LIT { $$ = $1;}
|
||||
| PARS_NULL_LIT { $$ = $1;}
|
||||
| PARS_SQL_TOKEN { $$ = $1;}
|
||||
| exp '+' exp { $$ = pars_op('+', $1, $3); }
|
||||
@@ -225,6 +233,10 @@ predefined_procedure_name:
|
||||
| PARS_ASSERT_TOKEN { $$ = &pars_assert_token; }
|
||||
;
|
||||
|
||||
user_function_call:
|
||||
PARS_ID_TOKEN '(' ')' { $$ = $1; }
|
||||
;
|
||||
|
||||
table_list:
|
||||
PARS_ID_TOKEN { $$ = que_node_list_add_last(NULL, $1); }
|
||||
| table_list ',' PARS_ID_TOKEN
|
||||
@@ -428,6 +440,10 @@ for_statement:
|
||||
{ $$ = pars_for_statement($2, $4, $6, $8); }
|
||||
;
|
||||
|
||||
exit_statement:
|
||||
PARS_EXIT_TOKEN { $$ = pars_exit_statement(); }
|
||||
;
|
||||
|
||||
return_statement:
|
||||
PARS_RETURN_TOKEN { $$ = pars_return_statement(); }
|
||||
;
|
||||
@@ -446,12 +462,14 @@ close_cursor_statement:
|
||||
|
||||
fetch_statement:
|
||||
PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN variable_list
|
||||
{ $$ = pars_fetch_statement($2, $4); }
|
||||
{ $$ = pars_fetch_statement($2, $4, NULL); }
|
||||
| PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN user_function_call
|
||||
{ $$ = pars_fetch_statement($2, NULL, $4); }
|
||||
;
|
||||
|
||||
column_def:
|
||||
PARS_ID_TOKEN type_name opt_column_len opt_not_null
|
||||
{ $$ = pars_column_def($1, $2, $3, $4); }
|
||||
PARS_ID_TOKEN type_name opt_column_len opt_unsigned opt_not_null
|
||||
{ $$ = pars_column_def($1, $2, $3, $4, $5); }
|
||||
;
|
||||
|
||||
column_def_list:
|
||||
@@ -466,6 +484,13 @@ opt_column_len:
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
opt_unsigned:
|
||||
/* Nothing */ { $$ = NULL; }
|
||||
| PARS_UNSIGNED_TOKEN
|
||||
{ $$ = &pars_int_token;
|
||||
/* pass any non-NULL pointer */ }
|
||||
;
|
||||
|
||||
opt_not_null:
|
||||
/* Nothing */ { $$ = NULL; }
|
||||
| PARS_NOT_TOKEN PARS_NULL_LIT
|
||||
@@ -561,10 +586,20 @@ cursor_declaration:
|
||||
{ $$ = pars_cursor_declaration($3, $5); }
|
||||
;
|
||||
|
||||
function_declaration:
|
||||
PARS_DECLARE_TOKEN PARS_FUNCTION_TOKEN PARS_ID_TOKEN ';'
|
||||
{ $$ = pars_function_declaration($3); }
|
||||
;
|
||||
|
||||
declaration:
|
||||
cursor_declaration
|
||||
| function_declaration
|
||||
;
|
||||
|
||||
declaration_list:
|
||||
/* Nothing */
|
||||
| cursor_declaration
|
||||
| declaration_list cursor_declaration
|
||||
| declaration
|
||||
| declaration_list declaration
|
||||
;
|
||||
|
||||
procedure_definition:
|
||||
|
@@ -12,27 +12,11 @@ not automatically generate them from pars0grm.y and pars0lex.l.
|
||||
|
||||
How to make the InnoDB parser and lexer C files:
|
||||
|
||||
1. First do
|
||||
bison -d pars0grm.y
|
||||
That generates pars0grm.tab.c and pars0grm.tab.h.
|
||||
1. Run ./make_flex.sh to generate lexer files.
|
||||
|
||||
2. Rename pars0grm.tab.c to pars0grm.c and pars0grm.tab.h to pars0grm.h.
|
||||
2. Run ./make_bison.sh to generate parser files.
|
||||
|
||||
3. Copy pars0grm.h also to /innobase/include
|
||||
|
||||
4. Do
|
||||
flex pars0lex.l
|
||||
That generates lex.yy.c.
|
||||
|
||||
5. Rename lex.yy.c to lexyy.c.
|
||||
|
||||
6. Add '#include "univ.i"' before #include <stdio.h> in lexyy.c
|
||||
(Needed for AIX)
|
||||
|
||||
7. Add a type cast to int to the assignment below the comment
|
||||
'need more input.' (Removes a warning on Win64)
|
||||
|
||||
These instructions seem to work at least with bison-1.28 and flex-2.5.4 on
|
||||
These instructions seem to work at least with bison-1.875d and flex-2.5.31 on
|
||||
Linux.
|
||||
*******************************************************/
|
||||
|
||||
@@ -99,8 +83,11 @@ string_append(
|
||||
|
||||
DIGIT [0-9]
|
||||
ID [a-z_A-Z][a-z_A-Z0-9]*
|
||||
BOUND_LIT \:[a-z_A-Z0-9]+
|
||||
|
||||
%x comment
|
||||
%x quoted
|
||||
%x id
|
||||
%%
|
||||
|
||||
{DIGIT}+ {
|
||||
@@ -115,6 +102,15 @@ ID [a-z_A-Z][a-z_A-Z0-9]*
|
||||
return(PARS_FLOAT_LIT);
|
||||
}
|
||||
|
||||
{BOUND_LIT} {
|
||||
ulint type;
|
||||
|
||||
yylval = sym_tab_add_bound_lit(pars_sym_tab_global,
|
||||
yytext + 1, &type);
|
||||
|
||||
return(type);
|
||||
}
|
||||
|
||||
"'" {
|
||||
/* Quoted character string literals are handled in an explicit
|
||||
start state 'quoted'. This state is entered and the buffer for
|
||||
@@ -153,6 +149,45 @@ In the state 'quoted', only two actions are possible (defined below). */
|
||||
}
|
||||
}
|
||||
|
||||
\" {
|
||||
/* Quoted identifiers are handled in an explicit start state 'id'.
|
||||
This state is entered and the buffer for the scanned string is emptied
|
||||
upon encountering a starting quote.
|
||||
|
||||
In the state 'id', only two actions are possible (defined below). */
|
||||
BEGIN(id);
|
||||
stringbuf_len = 0;
|
||||
}
|
||||
<id>[^\"]+ {
|
||||
/* Got a sequence of characters other than '"':
|
||||
append to string buffer */
|
||||
string_append(yytext, yyleng);
|
||||
}
|
||||
<id>\"+ {
|
||||
/* Got a sequence of '"' characters:
|
||||
append half of them to string buffer,
|
||||
as '""' represents a single '"'.
|
||||
We apply truncating division,
|
||||
so that '"""' will result in '"'. */
|
||||
|
||||
string_append(yytext, yyleng / 2);
|
||||
|
||||
/* If we got an odd number of quotes, then the
|
||||
last quote we got is the terminating quote.
|
||||
At the end of the string, we return to the
|
||||
initial start state and report the scanned
|
||||
identifier. */
|
||||
|
||||
if (yyleng % 2) {
|
||||
BEGIN(INITIAL);
|
||||
yylval = sym_tab_add_id(
|
||||
pars_sym_tab_global,
|
||||
(byte*) stringbuf, stringbuf_len);
|
||||
|
||||
return(PARS_ID_TOKEN);
|
||||
}
|
||||
}
|
||||
|
||||
"NULL" {
|
||||
yylval = sym_tab_add_null_lit(pars_sym_tab_global);
|
||||
|
||||
@@ -462,6 +497,18 @@ In the state 'quoted', only two actions are possible (defined below). */
|
||||
return(PARS_WORK_TOKEN);
|
||||
}
|
||||
|
||||
"UNSIGNED" {
|
||||
return(PARS_UNSIGNED_TOKEN);
|
||||
}
|
||||
|
||||
"EXIT" {
|
||||
return(PARS_EXIT_TOKEN);
|
||||
}
|
||||
|
||||
"FUNCTION" {
|
||||
return(PARS_FUNCTION_TOKEN);
|
||||
}
|
||||
|
||||
{ID} {
|
||||
yylval = sym_tab_add_id(pars_sym_tab_global,
|
||||
(byte*)yytext,
|
||||
|
@@ -313,7 +313,6 @@ opt_calc_index_goodness(
|
||||
ulint goodness;
|
||||
ulint n_fields;
|
||||
ulint col_no;
|
||||
ulint mix_id_col_no;
|
||||
ulint op;
|
||||
ulint j;
|
||||
|
||||
@@ -326,8 +325,6 @@ opt_calc_index_goodness(
|
||||
|
||||
n_fields = dict_index_get_n_unique_in_tree(index);
|
||||
|
||||
mix_id_col_no = dict_table_get_sys_col_no(index->table, DATA_MIX_ID);
|
||||
|
||||
for (j = 0; j < n_fields; j++) {
|
||||
|
||||
col_no = dict_index_get_nth_col_no(index, j);
|
||||
@@ -335,13 +332,7 @@ opt_calc_index_goodness(
|
||||
exp = opt_look_for_col_in_cond_before(OPT_EQUAL, col_no,
|
||||
sel_node->search_cond,
|
||||
sel_node, nth_table, &op);
|
||||
if (col_no == mix_id_col_no) {
|
||||
ut_ad(exp == NULL);
|
||||
|
||||
index_plan[j] = NULL;
|
||||
*last_op = '=';
|
||||
goodness += 4;
|
||||
} else if (exp) {
|
||||
if (exp) {
|
||||
/* The value for this column is exactly known already
|
||||
at this stage of the join */
|
||||
|
||||
@@ -531,7 +522,6 @@ opt_search_plan_for_table(
|
||||
warning */
|
||||
ulint best_goodness;
|
||||
ulint best_last_op = 0; /* remove warning */
|
||||
ulint mix_id_pos;
|
||||
que_node_t* index_plan[256];
|
||||
que_node_t* best_index_plan[256];
|
||||
|
||||
@@ -601,26 +591,6 @@ opt_search_plan_for_table(
|
||||
plan->unique_search = FALSE;
|
||||
}
|
||||
|
||||
if ((table->type != DICT_TABLE_ORDINARY)
|
||||
&& (best_index->type & DICT_CLUSTERED)) {
|
||||
|
||||
plan->mixed_index = TRUE;
|
||||
|
||||
mix_id_pos = table->mix_len;
|
||||
|
||||
if (mix_id_pos < n_fields) {
|
||||
/* We have to add the mix id as a (string) literal
|
||||
expression to the tuple_exps */
|
||||
|
||||
plan->tuple_exps[mix_id_pos] =
|
||||
sym_tab_add_str_lit(pars_sym_tab_global,
|
||||
table->mix_id_buf,
|
||||
table->mix_id_len);
|
||||
}
|
||||
} else {
|
||||
plan->mixed_index = FALSE;
|
||||
}
|
||||
|
||||
plan->old_vers_heap = NULL;
|
||||
|
||||
btr_pcur_init(&(plan->pcur));
|
||||
@@ -1055,7 +1025,6 @@ opt_clust_access(
|
||||
dict_table_t* table;
|
||||
dict_index_t* clust_index;
|
||||
dict_index_t* index;
|
||||
dfield_t* dfield;
|
||||
mem_heap_t* heap;
|
||||
ulint n_fields;
|
||||
ulint pos;
|
||||
@@ -1109,22 +1078,7 @@ opt_clust_access(
|
||||
|
||||
*(plan->clust_map + i) = pos;
|
||||
|
||||
ut_ad((pos != ULINT_UNDEFINED)
|
||||
|| ((table->type == DICT_TABLE_CLUSTER_MEMBER)
|
||||
&& (i == table->mix_len)));
|
||||
}
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
|
||||
/* Preset the mix id field to the mix id constant */
|
||||
|
||||
dfield = dtuple_get_nth_field(plan->clust_ref, table->mix_len);
|
||||
|
||||
dfield_set_data(dfield, mem_heap_alloc(heap,
|
||||
table->mix_id_len),
|
||||
table->mix_id_len);
|
||||
ut_memcpy(dfield_get_data(dfield), table->mix_id_buf,
|
||||
table->mix_id_len);
|
||||
ut_ad(pos != ULINT_UNDEFINED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -373,14 +373,15 @@ pars_resolve_exp_variables_and_types(
|
||||
}
|
||||
|
||||
/* Not resolved yet: look in the symbol table for a variable
|
||||
or a cursor with the same name */
|
||||
or a cursor or a function with the same name */
|
||||
|
||||
node = UT_LIST_GET_FIRST(pars_sym_tab_global->sym_list);
|
||||
|
||||
while (node) {
|
||||
if (node->resolved
|
||||
&& ((node->token_type == SYM_VAR)
|
||||
|| (node->token_type == SYM_CURSOR))
|
||||
|| (node->token_type == SYM_CURSOR)
|
||||
|| (node->token_type == SYM_FUNCTION))
|
||||
&& node->name
|
||||
&& (sym_node->name_len == node->name_len)
|
||||
&& (ut_memcmp(sym_node->name, node->name,
|
||||
@@ -486,7 +487,7 @@ pars_resolve_exp_columns(
|
||||
while (t_node) {
|
||||
table = t_node->table;
|
||||
|
||||
n_cols = dict_table_get_n_user_cols(table);
|
||||
n_cols = dict_table_get_n_cols(table);
|
||||
|
||||
for (i = 0; i < n_cols; i++) {
|
||||
col = dict_table_get_nth_col(table, i);
|
||||
@@ -786,6 +787,26 @@ pars_cursor_declaration(
|
||||
return(sym_node);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Parses a function declaration. */
|
||||
|
||||
que_node_t*
|
||||
pars_function_declaration(
|
||||
/*======================*/
|
||||
/* out: sym_node */
|
||||
sym_node_t* sym_node) /* in: function id node in the symbol
|
||||
table */
|
||||
{
|
||||
sym_node->resolved = TRUE;
|
||||
sym_node->token_type = SYM_FUNCTION;
|
||||
|
||||
/* Check that the function exists. */
|
||||
ut_a(pars_info_get_user_func(pars_sym_tab_global->info,
|
||||
sym_node->name));
|
||||
|
||||
return(sym_node);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Parses a delete or update statement start. */
|
||||
|
||||
@@ -1085,6 +1106,8 @@ pars_set_dfield_type(
|
||||
pars_res_word_t* type, /* in: pointer to a type
|
||||
token */
|
||||
ulint len, /* in: length, or 0 */
|
||||
ibool is_unsigned, /* in: if TRUE, column is
|
||||
UNSIGNED. */
|
||||
ibool is_not_null) /* in: if TRUE, column is
|
||||
NOT NULL. */
|
||||
{
|
||||
@@ -1094,48 +1117,30 @@ pars_set_dfield_type(
|
||||
flags |= DATA_NOT_NULL;
|
||||
}
|
||||
|
||||
if (type == &pars_int_token) {
|
||||
if (len != 0) {
|
||||
ut_error;
|
||||
if (is_unsigned) {
|
||||
flags |= DATA_UNSIGNED;
|
||||
}
|
||||
|
||||
if (type == &pars_int_token) {
|
||||
ut_a(len == 0);
|
||||
|
||||
dtype_set(dfield_get_type(dfield), DATA_INT, flags, 4, 0);
|
||||
|
||||
} else if (type == &pars_char_token) {
|
||||
if (len != 0) {
|
||||
ut_error;
|
||||
}
|
||||
ut_a(len == 0);
|
||||
|
||||
dtype_set(dfield_get_type(dfield), DATA_VARCHAR,
|
||||
DATA_ENGLISH | flags, 0, 0);
|
||||
} else if (type == &pars_binary_token) {
|
||||
if (len == 0) {
|
||||
ut_error;
|
||||
}
|
||||
ut_a(len != 0);
|
||||
|
||||
dtype_set(dfield_get_type(dfield), DATA_FIXBINARY,
|
||||
DATA_BINARY_TYPE | flags, len, 0);
|
||||
} else if (type == &pars_blob_token) {
|
||||
if (len != 0) {
|
||||
ut_error;
|
||||
}
|
||||
ut_a(len == 0);
|
||||
|
||||
dtype_set(dfield_get_type(dfield), DATA_BLOB,
|
||||
DATA_BINARY_TYPE | flags, 0, 0);
|
||||
} else if (type == &pars_binary_token) {
|
||||
if (len == 0) {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
dtype_set(dfield_get_type(dfield), DATA_FIXBINARY,
|
||||
DATA_BINARY_TYPE, len, 0);
|
||||
} else if (type == &pars_blob_token) {
|
||||
if (len != 0) {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
dtype_set(dfield_get_type(dfield), DATA_BLOB,
|
||||
DATA_BINARY_TYPE, 0, 0);
|
||||
} else {
|
||||
ut_error;
|
||||
}
|
||||
@@ -1158,7 +1163,7 @@ pars_variable_declaration(
|
||||
|
||||
node->param_type = PARS_NOT_PARAM;
|
||||
|
||||
pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE);
|
||||
pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE, FALSE);
|
||||
|
||||
return(node);
|
||||
}
|
||||
@@ -1346,6 +1351,22 @@ pars_for_statement(
|
||||
return(node);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Parses an exit statement. */
|
||||
|
||||
exit_node_t*
|
||||
pars_exit_statement(void)
|
||||
/*=====================*/
|
||||
/* out: exit statement node */
|
||||
{
|
||||
exit_node_t* node;
|
||||
|
||||
node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(exit_node_t));
|
||||
node->common.type = QUE_NODE_EXIT;
|
||||
|
||||
return(node);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Parses a return-statement. */
|
||||
|
||||
@@ -1411,26 +1432,42 @@ pars_procedure_call(
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Parses a fetch statement. */
|
||||
Parses a fetch statement. into_list or user_func (but not both) must be
|
||||
non-NULL. */
|
||||
|
||||
fetch_node_t*
|
||||
pars_fetch_statement(
|
||||
/*=================*/
|
||||
/* out: fetch statement node */
|
||||
sym_node_t* cursor, /* in: cursor node */
|
||||
sym_node_t* into_list) /* in: variables to set */
|
||||
sym_node_t* into_list, /* in: variables to set, or NULL */
|
||||
sym_node_t* user_func) /* in: user function name, or NULL */
|
||||
{
|
||||
sym_node_t* cursor_decl;
|
||||
fetch_node_t* node;
|
||||
|
||||
/* Logical XOR. */
|
||||
ut_a(!into_list != !user_func);
|
||||
|
||||
node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(fetch_node_t));
|
||||
|
||||
node->common.type = QUE_NODE_FETCH;
|
||||
|
||||
pars_resolve_exp_variables_and_types(NULL, cursor);
|
||||
pars_resolve_exp_list_variables_and_types(NULL, into_list);
|
||||
|
||||
if (into_list) {
|
||||
pars_resolve_exp_list_variables_and_types(NULL, into_list);
|
||||
node->into_list = into_list;
|
||||
node->func = NULL;
|
||||
} else {
|
||||
pars_resolve_exp_variables_and_types(NULL, user_func);
|
||||
|
||||
node->func = pars_info_get_user_func(pars_sym_tab_global->info,
|
||||
user_func->name);
|
||||
ut_a(node->func);
|
||||
|
||||
node->into_list = NULL;
|
||||
}
|
||||
|
||||
cursor_decl = cursor->alias;
|
||||
|
||||
@@ -1438,8 +1475,11 @@ pars_fetch_statement(
|
||||
|
||||
node->cursor_def = cursor_decl->cursor_def;
|
||||
|
||||
if (into_list) {
|
||||
ut_a(que_node_list_get_len(into_list)
|
||||
== que_node_list_get_len(node->cursor_def->select_list));
|
||||
== que_node_list_get_len(
|
||||
node->cursor_def->select_list));
|
||||
}
|
||||
|
||||
return(node);
|
||||
}
|
||||
@@ -1529,6 +1569,8 @@ pars_column_def(
|
||||
pars_res_word_t* type, /* in: data type */
|
||||
sym_node_t* len, /* in: length of column, or
|
||||
NULL */
|
||||
void* is_unsigned, /* in: if not NULL, column
|
||||
is of type UNSIGNED. */
|
||||
void* is_not_null) /* in: if not NULL, column
|
||||
is of type NOT NULL. */
|
||||
{
|
||||
@@ -1541,7 +1583,7 @@ pars_column_def(
|
||||
}
|
||||
|
||||
pars_set_dfield_type(que_node_get_val(sym_node), type, len2,
|
||||
is_not_null != NULL);
|
||||
is_unsigned != NULL, is_not_null != NULL);
|
||||
|
||||
return(sym_node);
|
||||
}
|
||||
@@ -1798,6 +1840,7 @@ que_t*
|
||||
pars_sql(
|
||||
/*=====*/
|
||||
/* out, own: the query graph */
|
||||
pars_info_t* info, /* in: extra information, or NULL */
|
||||
const char* str) /* in: SQL string */
|
||||
{
|
||||
sym_node_t* sym_node;
|
||||
@@ -1817,6 +1860,7 @@ pars_sql(
|
||||
pars_sym_tab_global->sql_string = mem_heap_strdup(heap, str);
|
||||
pars_sym_tab_global->string_len = strlen(str);
|
||||
pars_sym_tab_global->next_char_pos = 0;
|
||||
pars_sym_tab_global->info = info;
|
||||
|
||||
yyparse();
|
||||
|
||||
@@ -1831,6 +1875,7 @@ pars_sql(
|
||||
graph = pars_sym_tab_global->query_graph;
|
||||
|
||||
graph->sym_tab = pars_sym_tab_global;
|
||||
graph->info = info;
|
||||
|
||||
/* fprintf(stderr, "SQL graph size %lu\n", mem_heap_get_size(heap)); */
|
||||
|
||||
@@ -1867,3 +1912,222 @@ pars_complete_graph_for_exec(
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Create parser info struct.*/
|
||||
|
||||
pars_info_t*
|
||||
pars_info_create(void)
|
||||
/*==================*/
|
||||
/* out, own: info struct */
|
||||
{
|
||||
pars_info_t* info;
|
||||
mem_heap_t* heap;
|
||||
|
||||
heap = mem_heap_create(512);
|
||||
|
||||
info = mem_heap_alloc(heap, sizeof(*info));
|
||||
|
||||
info->heap = heap;
|
||||
info->funcs = NULL;
|
||||
info->bound_lits = NULL;
|
||||
info->graph_owns_us = TRUE;
|
||||
|
||||
return(info);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Free info struct and everything it contains.*/
|
||||
|
||||
void
|
||||
pars_info_free(
|
||||
/*===========*/
|
||||
pars_info_t* info) /* in: info struct */
|
||||
{
|
||||
mem_heap_free(info->heap);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Add bound literal. */
|
||||
|
||||
void
|
||||
pars_info_add_literal(
|
||||
/*==================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
const void* address, /* in: address */
|
||||
ulint length, /* in: length of data */
|
||||
ulint type, /* in: type, e.g. DATA_FIXBINARY */
|
||||
ulint prtype) /* in: precise type, e.g.
|
||||
DATA_UNSIGNED */
|
||||
{
|
||||
pars_bound_lit_t* pbl;
|
||||
|
||||
ut_ad(!pars_info_get_bound_lit(info, name));
|
||||
|
||||
pbl = mem_heap_alloc(info->heap, sizeof(*pbl));
|
||||
|
||||
pbl->name = name;
|
||||
pbl->address = address;
|
||||
pbl->length = length;
|
||||
pbl->type = type;
|
||||
pbl->prtype = prtype;
|
||||
|
||||
if (!info->bound_lits) {
|
||||
info->bound_lits = ib_vector_create(info->heap, 8);
|
||||
}
|
||||
|
||||
ib_vector_push(info->bound_lits, pbl);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Equivalent to pars_info_add_literal(info, name, str, strlen(str),
|
||||
DATA_VARCHAR, DATA_ENGLISH). */
|
||||
|
||||
void
|
||||
pars_info_add_str_literal(
|
||||
/*======================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
const char* str) /* in: string */
|
||||
{
|
||||
pars_info_add_literal(info, name, str, strlen(str),
|
||||
DATA_VARCHAR, DATA_ENGLISH);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Equivalent to:
|
||||
|
||||
char buf[4];
|
||||
mach_write_to_4(buf, val);
|
||||
pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
|
||||
|
||||
except that the buffer is dynamically allocated from the info struct's
|
||||
heap. */
|
||||
|
||||
void
|
||||
pars_info_add_int4_literal(
|
||||
/*=======================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
lint val) /* in: value */
|
||||
{
|
||||
byte* buf = mem_heap_alloc(info->heap, 4);
|
||||
|
||||
mach_write_to_4(buf, val);
|
||||
pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Equivalent to:
|
||||
|
||||
char buf[8];
|
||||
mach_write_to_8(buf, val);
|
||||
pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0);
|
||||
|
||||
except that the buffer is dynamically allocated from the info struct's
|
||||
heap. */
|
||||
|
||||
void
|
||||
pars_info_add_dulint_literal(
|
||||
/*=========================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: name */
|
||||
dulint val) /* in: value */
|
||||
{
|
||||
byte* buf = mem_heap_alloc(info->heap, 8);
|
||||
|
||||
mach_write_to_8(buf, val);
|
||||
|
||||
pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Add user function. */
|
||||
|
||||
void
|
||||
pars_info_add_function(
|
||||
/*===================*/
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name, /* in: function name */
|
||||
pars_user_func_cb_t func, /* in: function address */
|
||||
void* arg) /* in: user-supplied argument */
|
||||
{
|
||||
pars_user_func_t* puf;
|
||||
|
||||
ut_ad(!pars_info_get_user_func(info, name));
|
||||
|
||||
puf = mem_heap_alloc(info->heap, sizeof(*puf));
|
||||
|
||||
puf->name = name;
|
||||
puf->func = func;
|
||||
puf->arg = arg;
|
||||
|
||||
if (!info->funcs) {
|
||||
info->funcs = ib_vector_create(info->heap, 8);
|
||||
}
|
||||
|
||||
ib_vector_push(info->funcs, puf);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Get user function with the given name.*/
|
||||
|
||||
pars_user_func_t*
|
||||
pars_info_get_user_func(
|
||||
/*====================*/
|
||||
/* out: user func, or NULL if not
|
||||
found */
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name) /* in: function name to find*/
|
||||
{
|
||||
ulint i;
|
||||
ib_vector_t* vec;
|
||||
|
||||
if (!info || !info->funcs) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
vec = info->funcs;
|
||||
|
||||
for (i = 0; i < ib_vector_size(vec); i++) {
|
||||
pars_user_func_t* puf = ib_vector_get(vec, i);
|
||||
|
||||
if (strcmp(puf->name, name) == 0) {
|
||||
return(puf);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Get bound literal with the given name.*/
|
||||
|
||||
pars_bound_lit_t*
|
||||
pars_info_get_bound_lit(
|
||||
/*====================*/
|
||||
/* out: bound literal, or NULL if
|
||||
not found */
|
||||
pars_info_t* info, /* in: info struct */
|
||||
const char* name) /* in: bound literal name to find */
|
||||
{
|
||||
ulint i;
|
||||
ib_vector_t* vec;
|
||||
|
||||
if (!info || !info->bound_lits) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
vec = info->bound_lits;
|
||||
|
||||
for (i = 0; i < ib_vector_size(vec); i++) {
|
||||
pars_bound_lit_t* pbl = ib_vector_get(vec, i);
|
||||
|
||||
if (strcmp(pbl->name, name) == 0) {
|
||||
return(pbl);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ Created 12/15/1997 Heikki Tuuri
|
||||
#include "mem0mem.h"
|
||||
#include "data0type.h"
|
||||
#include "data0data.h"
|
||||
#include "pars0grm.h"
|
||||
#include "pars0pars.h"
|
||||
#include "que0que.h"
|
||||
#include "eval0eval.h"
|
||||
@@ -165,6 +166,74 @@ sym_tab_add_str_lit(
|
||||
return(node);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Add a bound literal to a symbol table. */
|
||||
|
||||
sym_node_t*
|
||||
sym_tab_add_bound_lit(
|
||||
/*==================*/
|
||||
/* out: symbol table node */
|
||||
sym_tab_t* sym_tab, /* in: symbol table */
|
||||
const char* name, /* in: name of bound literal */
|
||||
ulint* lit_type) /* out: type of literal (PARS_*_LIT) */
|
||||
{
|
||||
sym_node_t* node;
|
||||
pars_bound_lit_t* blit;
|
||||
ulint len = 0;
|
||||
|
||||
blit = pars_info_get_bound_lit(sym_tab->info, name);
|
||||
ut_a(blit);
|
||||
|
||||
node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t));
|
||||
|
||||
node->common.type = QUE_NODE_SYMBOL;
|
||||
|
||||
node->resolved = TRUE;
|
||||
node->token_type = SYM_LIT;
|
||||
|
||||
node->indirection = NULL;
|
||||
|
||||
switch (blit->type) {
|
||||
case DATA_FIXBINARY:
|
||||
len = blit->length;
|
||||
*lit_type = PARS_FIXBINARY_LIT;
|
||||
break;
|
||||
|
||||
case DATA_BLOB:
|
||||
*lit_type = PARS_BLOB_LIT;
|
||||
break;
|
||||
|
||||
case DATA_VARCHAR:
|
||||
*lit_type = PARS_STR_LIT;
|
||||
break;
|
||||
|
||||
case DATA_INT:
|
||||
ut_a(blit->length > 0);
|
||||
ut_a(blit->length <= 8);
|
||||
|
||||
len = blit->length;
|
||||
*lit_type = PARS_INT_LIT;
|
||||
break;
|
||||
|
||||
default:
|
||||
ut_error;
|
||||
}
|
||||
|
||||
dtype_set(&(node->common.val.type), blit->type, blit->prtype, len, 0);
|
||||
|
||||
dfield_set_data(&(node->common.val), blit->address, blit->length);
|
||||
|
||||
node->common.val_buf_size = 0;
|
||||
node->prefetch_buf = NULL;
|
||||
node->cursor_def = NULL;
|
||||
|
||||
UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node);
|
||||
|
||||
node->sym_table = sym_tab;
|
||||
|
||||
return(node);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Adds an SQL null literal to a symbol table. */
|
||||
|
||||
@@ -220,7 +289,7 @@ sym_tab_add_id(
|
||||
node->resolved = FALSE;
|
||||
node->indirection = NULL;
|
||||
|
||||
node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len + 1);
|
||||
node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len);
|
||||
node->name_len = len;
|
||||
|
||||
UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node);
|
||||
|
@@ -25,6 +25,7 @@ Created 5/27/1996 Heikki Tuuri
|
||||
#include "log0log.h"
|
||||
#include "eval0proc.h"
|
||||
#include "eval0eval.h"
|
||||
#include "pars0types.h"
|
||||
|
||||
#define QUE_PARALLELIZE_LIMIT (64 * 256 * 256 * 256)
|
||||
#define QUE_ROUND_ROBIN_LIMIT (64 * 256 * 256 * 256)
|
||||
@@ -36,6 +37,50 @@ ibool que_trace_on = FALSE;
|
||||
|
||||
ibool que_always_false = FALSE;
|
||||
|
||||
/* Short introduction to query graphs
|
||||
==================================
|
||||
|
||||
A query graph consists of nodes linked to each other in various ways. The
|
||||
execution starts at que_run_threads() which takes a que_thr_t parameter.
|
||||
que_thr_t contains two fields that control query graph execution: run_node
|
||||
and prev_node. run_node is the next node to execute and prev_node is the
|
||||
last node executed.
|
||||
|
||||
Each node has a pointer to a 'next' statement, i.e., its brother, and a
|
||||
pointer to its parent node. The next pointer is NULL in the last statement
|
||||
of a block.
|
||||
|
||||
Loop nodes contain a link to the first statement of the enclosed statement
|
||||
list. While the loop runs, que_thr_step() checks if execution to the loop
|
||||
node came from its parent or from one of the statement nodes in the loop. If
|
||||
it came from the parent of the loop node it starts executing the first
|
||||
statement node in the loop. If it came from one of the statement nodes in
|
||||
the loop, then it checks if the statement node has another statement node
|
||||
following it, and runs it if so.
|
||||
|
||||
To signify loop ending, the loop statements (see e.g. while_step()) set
|
||||
que_thr_t->run_node to the loop node's parent node. This is noticed on the
|
||||
next call of que_thr_step() and execution proceeds to the node pointed to by
|
||||
the loop node's 'next' pointer.
|
||||
|
||||
For example, the code:
|
||||
|
||||
X := 1;
|
||||
WHILE X < 5 LOOP
|
||||
X := X + 1;
|
||||
X := X + 1;
|
||||
X := 5
|
||||
|
||||
will result in the following node hierarchy, with the X-axis indicating
|
||||
'next' links and the Y-axis indicating parent/child links:
|
||||
|
||||
A - W - A
|
||||
|
|
||||
|
|
||||
A - A
|
||||
|
||||
A = assign_node_t, W = while_node_t. */
|
||||
|
||||
/* How a stored procedure containing COMMIT or ROLLBACK commands
|
||||
is executed?
|
||||
|
||||
@@ -128,6 +173,7 @@ que_fork_create(
|
||||
UT_LIST_INIT(fork->thrs);
|
||||
|
||||
fork->sym_tab = NULL;
|
||||
fork->info = NULL;
|
||||
|
||||
fork->heap = heap;
|
||||
|
||||
@@ -583,6 +629,7 @@ que_graph_free_recursive(
|
||||
break;
|
||||
|
||||
case QUE_NODE_ASSIGNMENT:
|
||||
case QUE_NODE_EXIT:
|
||||
case QUE_NODE_RETURN:
|
||||
case QUE_NODE_COMMIT:
|
||||
case QUE_NODE_ROLLBACK:
|
||||
@@ -626,6 +673,10 @@ que_graph_free(
|
||||
sym_tab_free_private(graph->sym_tab);
|
||||
}
|
||||
|
||||
if (graph->info && graph->info->graph_owns_us) {
|
||||
pars_info_free(graph->info);
|
||||
}
|
||||
|
||||
que_graph_free_recursive(graph);
|
||||
|
||||
mem_heap_free(graph->heap);
|
||||
@@ -1040,6 +1091,37 @@ que_thr_stop_for_mysql_no_error(
|
||||
trx->n_active_thrs--;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
|
||||
given node, or NULL if the node is not within a loop. */
|
||||
|
||||
que_node_t*
|
||||
que_node_get_containing_loop_node(
|
||||
/*==============================*/
|
||||
/* out: containing loop node, or NULL. */
|
||||
que_node_t* node) /* in: node */
|
||||
{
|
||||
ut_ad(node);
|
||||
|
||||
for (;;) {
|
||||
ulint type;
|
||||
|
||||
node = que_node_get_parent(node);
|
||||
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
|
||||
type = que_node_get_type(node);
|
||||
|
||||
if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(node);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Prints info of an SQL query graph node. */
|
||||
|
||||
@@ -1093,6 +1175,8 @@ que_node_print_info(
|
||||
str = "FOR LOOP";
|
||||
} else if (type == QUE_NODE_RETURN) {
|
||||
str = "RETURN";
|
||||
} else if (type == QUE_NODE_EXIT) {
|
||||
str = "EXIT";
|
||||
} else {
|
||||
str = "UNKNOWN NODE TYPE";
|
||||
}
|
||||
@@ -1120,8 +1204,8 @@ que_thr_step(
|
||||
|
||||
thr->resource++;
|
||||
|
||||
type = que_node_get_type(thr->run_node);
|
||||
node = thr->run_node;
|
||||
type = que_node_get_type(node);
|
||||
|
||||
old_thr = thr;
|
||||
|
||||
@@ -1160,6 +1244,8 @@ que_thr_step(
|
||||
proc_step(thr);
|
||||
} else if (type == QUE_NODE_WHILE) {
|
||||
while_step(thr);
|
||||
} else {
|
||||
ut_error;
|
||||
}
|
||||
} else if (type == QUE_NODE_ASSIGNMENT) {
|
||||
assign_step(thr);
|
||||
@@ -1192,6 +1278,8 @@ que_thr_step(
|
||||
thr = row_purge_step(thr);
|
||||
} else if (type == QUE_NODE_RETURN) {
|
||||
thr = return_step(thr);
|
||||
} else if (type == QUE_NODE_EXIT) {
|
||||
thr = exit_step(thr);
|
||||
} else if (type == QUE_NODE_ROLLBACK) {
|
||||
thr = trx_rollback_step(thr);
|
||||
} else if (type == QUE_NODE_CREATE_TABLE) {
|
||||
@@ -1204,7 +1292,11 @@ que_thr_step(
|
||||
ut_error;
|
||||
}
|
||||
|
||||
if (type == QUE_NODE_EXIT) {
|
||||
old_thr->prev_node = que_node_get_containing_loop_node(node);
|
||||
} else {
|
||||
old_thr->prev_node = node;
|
||||
}
|
||||
|
||||
return(thr);
|
||||
}
|
||||
@@ -1274,3 +1366,33 @@ loop:
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Evaluate the given SQL */
|
||||
|
||||
ulint
|
||||
que_eval_sql(
|
||||
/*=========*/
|
||||
pars_info_t* info, /* out: error code or DB_SUCCESS */
|
||||
const char* sql, /* in: info struct, or NULL */
|
||||
trx_t* trx) /* in: trx */
|
||||
{
|
||||
que_thr_t* thr;
|
||||
que_t* graph;
|
||||
|
||||
graph = pars_sql(info, sql);
|
||||
ut_a(graph);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
return(trx->error_state);
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ Created 4/20/1996 Heikki Tuuri
|
||||
#include "eval0eval.h"
|
||||
#include "data0data.h"
|
||||
#include "usr0sess.h"
|
||||
#include "buf0lru.h"
|
||||
|
||||
#define ROW_INS_PREV 1
|
||||
#define ROW_INS_NEXT 2
|
||||
@@ -139,7 +140,6 @@ row_ins_alloc_sys_fields(
|
||||
mem_heap_t* heap;
|
||||
dict_col_t* col;
|
||||
dfield_t* dfield;
|
||||
ulint len;
|
||||
byte* ptr;
|
||||
|
||||
row = node->row;
|
||||
@@ -161,21 +161,6 @@ row_ins_alloc_sys_fields(
|
||||
|
||||
node->row_id_buf = ptr;
|
||||
|
||||
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
|
||||
|
||||
/* 2. Fill in the dfield for mix id */
|
||||
|
||||
col = dict_table_get_sys_col(table, DATA_MIX_ID);
|
||||
|
||||
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
|
||||
|
||||
len = mach_dulint_get_compressed_size(table->mix_id);
|
||||
ptr = mem_heap_alloc(heap, DATA_MIX_ID_LEN);
|
||||
|
||||
mach_dulint_write_compressed(ptr, table->mix_id);
|
||||
dfield_set_data(dfield, ptr, len);
|
||||
}
|
||||
|
||||
/* 3. Allocate buffer for trx id */
|
||||
|
||||
col = dict_table_get_sys_col(table, DATA_TRX_ID);
|
||||
@@ -279,10 +264,17 @@ row_ins_sec_index_entry_by_modify(
|
||||
}
|
||||
} else {
|
||||
ut_a(mode == BTR_MODIFY_TREE);
|
||||
if (buf_LRU_buf_pool_running_out()) {
|
||||
|
||||
err = DB_LOCK_TABLE_FULL;
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor,
|
||||
&dummy_big_rec, update, 0, thr, mtr);
|
||||
}
|
||||
|
||||
func_exit:
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(err);
|
||||
@@ -344,10 +336,16 @@ row_ins_clust_index_entry_by_modify(
|
||||
}
|
||||
} else {
|
||||
ut_a(mode == BTR_MODIFY_TREE);
|
||||
if (buf_LRU_buf_pool_running_out()) {
|
||||
|
||||
err = DB_LOCK_TABLE_FULL;
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
err = btr_cur_pessimistic_update(0, cursor, big_rec, update,
|
||||
0, thr, mtr);
|
||||
}
|
||||
|
||||
func_exit:
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(err);
|
||||
@@ -1882,7 +1880,6 @@ row_ins_duplicate_error_in_clust(
|
||||
err = DB_DUPLICATE_KEY;
|
||||
goto func_exit;
|
||||
}
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
|
||||
ut_a(!(cursor->index->type & DICT_CLUSTERED));
|
||||
@@ -1891,6 +1888,9 @@ row_ins_duplicate_error_in_clust(
|
||||
|
||||
err = DB_SUCCESS;
|
||||
func_exit:
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
return(err);
|
||||
#else /* UNIV_HOTBACKUP */
|
||||
/* This function depends on MySQL code that is not included in
|
||||
@@ -2091,6 +2091,12 @@ row_ins_index_entry_low(
|
||||
&insert_rec, &big_rec, thr, &mtr);
|
||||
} else {
|
||||
ut_a(mode == BTR_MODIFY_TREE);
|
||||
if (buf_LRU_buf_pool_running_out()) {
|
||||
|
||||
err = DB_LOCK_TABLE_FULL;
|
||||
|
||||
goto function_exit;
|
||||
}
|
||||
err = btr_cur_pessimistic_insert(0, &cursor, entry,
|
||||
&insert_rec, &big_rec, thr, &mtr);
|
||||
}
|
||||
@@ -2429,7 +2435,15 @@ row_ins_step(
|
||||
|
||||
/* If this is the first time this node is executed (or when
|
||||
execution resumes after wait for the table IX lock), set an
|
||||
IX lock on the table and reset the possible select node. */
|
||||
IX lock on the table and reset the possible select node. MySQL's
|
||||
partitioned table code may also call an insert within the same
|
||||
SQL statement AFTER it has used this table handle to do a search.
|
||||
This happens, for example, when a row update moves it to another
|
||||
partition. In that case, we have already set the IX lock on the
|
||||
table during the search operation, and there is no need to set
|
||||
it again here. But we must write trx->id to node->trx_id_buf. */
|
||||
|
||||
trx_write_trx_id(node->trx_id_buf, trx->id);
|
||||
|
||||
if (node->state == INS_NODE_SET_IX_LOCK) {
|
||||
|
||||
@@ -2437,13 +2451,11 @@ row_ins_step(
|
||||
its transaction, or it has been committed: */
|
||||
|
||||
if (UT_DULINT_EQ(trx->id, node->trx_id)) {
|
||||
/* No need to do IX-locking or write trx id to buf */
|
||||
/* No need to do IX-locking */
|
||||
|
||||
goto same_trx;
|
||||
}
|
||||
|
||||
trx_write_trx_id(node->trx_id_buf, trx->id);
|
||||
|
||||
err = lock_table(0, node->table, LOCK_IX, thr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
@@ -85,9 +85,11 @@ row_mysql_is_system_table(
|
||||
system table name */
|
||||
const char* name)
|
||||
{
|
||||
if (memcmp(name, "mysql/", 6)) {
|
||||
if (strncmp(name, "mysql/", 6) != 0) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
return(0 == strcmp(name + 6, "host")
|
||||
|| 0 == strcmp(name + 6, "user")
|
||||
|| 0 == strcmp(name + 6, "db"));
|
||||
@@ -1435,7 +1437,8 @@ run_again:
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
|
||||
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
|
||||
this session is using a READ COMMITTED isolation level. Before
|
||||
calling this function we must use trx_reset_new_rec_lock_info() and
|
||||
trx_register_new_rec_lock() to store the information which new record locks
|
||||
really were set. This function removes a newly set lock under prebuilt->pcur,
|
||||
@@ -1466,11 +1469,13 @@ row_unlock_for_mysql(
|
||||
ut_ad(prebuilt && trx);
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
if (!srv_locks_unsafe_for_binlog) {
|
||||
if (!(srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: calling row_unlock_for_mysql though\n"
|
||||
"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n");
|
||||
"InnoDB: srv_locks_unsafe_for_binlog is FALSE and\n"
|
||||
"InnoDB: this session is not using READ COMMITTED isolation level.\n");
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
@@ -1670,7 +1675,9 @@ row_mysql_recover_tmp_table(
|
||||
|
||||
if (!ptr) {
|
||||
/* table name does not begin with "/rsql" */
|
||||
dict_mem_table_free(table);
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
else {
|
||||
@@ -1782,6 +1789,7 @@ row_create_table_for_mysql(
|
||||
const char* table_name;
|
||||
ulint table_name_len;
|
||||
ulint err;
|
||||
ulint i;
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
@@ -1799,6 +1807,7 @@ row_create_table_for_mysql(
|
||||
"InnoDB: with raw, and innodb_force_... is removed.\n",
|
||||
stderr);
|
||||
|
||||
dict_mem_table_free(table);
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
return(DB_ERROR);
|
||||
@@ -1813,11 +1822,25 @@ row_create_table_for_mysql(
|
||||
"InnoDB: MySQL system tables must be of the MyISAM type!\n",
|
||||
table->name);
|
||||
|
||||
dict_mem_table_free(table);
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
/* Check that no reserved column names are used. */
|
||||
for (i = 0; i < dict_table_get_n_user_cols(table); i++) {
|
||||
dict_col_t* col = dict_table_get_nth_col(table, i);
|
||||
|
||||
if (dict_col_name_is_reserved(col->name)) {
|
||||
|
||||
dict_mem_table_free(table);
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
trx_start_if_not_started(trx);
|
||||
|
||||
if (row_mysql_is_recovered_tmp_table(table->name)) {
|
||||
@@ -2361,11 +2384,9 @@ row_discard_tablespace_for_mysql(
|
||||
dict_foreign_t* foreign;
|
||||
dulint new_id;
|
||||
dict_table_t* table;
|
||||
que_thr_t* thr;
|
||||
que_t* graph = NULL;
|
||||
ibool success;
|
||||
ulint err;
|
||||
char* buf;
|
||||
pars_info_t* info = NULL;
|
||||
|
||||
/* How do we prevent crashes caused by ongoing operations on the table? Old
|
||||
operations could try to access non-existent pages.
|
||||
@@ -2387,36 +2408,6 @@ discard ongoing operations.
|
||||
5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we
|
||||
do not allow the discard. We also reserve the data dictionary latch. */
|
||||
|
||||
static const char discard_tablespace_proc1[] =
|
||||
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
|
||||
"old_id CHAR;\n"
|
||||
"new_id CHAR;\n"
|
||||
"new_id_low INT;\n"
|
||||
"new_id_high INT;\n"
|
||||
"table_name CHAR;\n"
|
||||
"BEGIN\n"
|
||||
"table_name := '";
|
||||
static const char discard_tablespace_proc2[] =
|
||||
"';\n"
|
||||
"new_id_high := %lu;\n"
|
||||
"new_id_low := %lu;\n"
|
||||
"new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n"
|
||||
"SELECT ID INTO old_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = table_name;\n"
|
||||
"IF (SQL %% NOTFOUND) THEN\n"
|
||||
" COMMIT WORK;\n"
|
||||
" RETURN;\n"
|
||||
"END IF;\n"
|
||||
"UPDATE SYS_TABLES SET ID = new_id\n"
|
||||
"WHERE ID = old_id;\n"
|
||||
"UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n"
|
||||
"WHERE TABLE_ID = old_id;\n"
|
||||
"UPDATE SYS_INDEXES SET TABLE_ID = new_id\n"
|
||||
"WHERE TABLE_ID = old_id;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n";
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
trx->op_info = "discarding tablespace";
|
||||
@@ -2496,35 +2487,34 @@ do not allow the discard. We also reserve the data dictionary latch. */
|
||||
|
||||
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
|
||||
|
||||
buf = mem_alloc((sizeof discard_tablespace_proc1) +
|
||||
(sizeof discard_tablespace_proc2) +
|
||||
20 + ut_strlenq(name, '\''));
|
||||
|
||||
memcpy(buf, discard_tablespace_proc1, sizeof discard_tablespace_proc1);
|
||||
sprintf(ut_strcpyq(buf + (sizeof discard_tablespace_proc1 - 1),
|
||||
'\'', name),
|
||||
discard_tablespace_proc2,
|
||||
(ulong) ut_dulint_get_high(new_id),
|
||||
(ulong) ut_dulint_get_low(new_id));
|
||||
|
||||
graph = pars_sql(buf);
|
||||
|
||||
ut_a(graph);
|
||||
|
||||
/* Remove any locks there are on the table or its records */
|
||||
|
||||
lock_reset_all_on_table(table);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
info = pars_info_create();
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
pars_info_add_str_literal(info, "table_name", name);
|
||||
pars_info_add_dulint_literal(info, "new_id", new_id);
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
err = trx->error_state;
|
||||
err = que_eval_sql(info,
|
||||
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
|
||||
"old_id CHAR;\n"
|
||||
"BEGIN\n"
|
||||
"SELECT ID INTO old_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = :table_name;\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" COMMIT WORK;\n"
|
||||
" RETURN;\n"
|
||||
"END IF;\n"
|
||||
"UPDATE SYS_TABLES SET ID = :new_id\n"
|
||||
" WHERE ID = old_id;\n"
|
||||
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
|
||||
" WHERE TABLE_ID = old_id;\n"
|
||||
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
|
||||
" WHERE TABLE_ID = old_id;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n"
|
||||
, trx);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
trx->error_state = DB_SUCCESS;
|
||||
@@ -2548,13 +2538,10 @@ do not allow the discard. We also reserve the data dictionary latch. */
|
||||
table->ibd_file_missing = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
funct_exit:
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
if (graph) {
|
||||
que_graph_free(graph);
|
||||
}
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
trx->op_info = "";
|
||||
@@ -2715,9 +2702,7 @@ row_truncate_table_for_mysql(
|
||||
btr_pcur_t pcur;
|
||||
mtr_t mtr;
|
||||
dulint new_id;
|
||||
char* sql;
|
||||
que_thr_t* thr;
|
||||
que_t* graph = NULL;
|
||||
pars_info_t* info = NULL;
|
||||
|
||||
/* How do we prevent crashes caused by ongoing operations on the table? Old
|
||||
operations could try to access non-existent pages.
|
||||
@@ -2745,30 +2730,6 @@ by DISCARD TABLESPACE.)
|
||||
5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we
|
||||
do not allow the TRUNCATE. We also reserve the data dictionary latch. */
|
||||
|
||||
static const char renumber_tablespace_proc[] =
|
||||
"PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
|
||||
"old_id CHAR;\n"
|
||||
"new_id CHAR;\n"
|
||||
"old_id_low INT;\n"
|
||||
"old_id_high INT;\n"
|
||||
"new_id_low INT;\n"
|
||||
"new_id_high INT;\n"
|
||||
"BEGIN\n"
|
||||
"old_id_high := %lu;\n"
|
||||
"old_id_low := %lu;\n"
|
||||
"new_id_high := %lu;\n"
|
||||
"new_id_low := %lu;\n"
|
||||
"old_id := CONCAT(TO_BINARY(old_id_high, 4), TO_BINARY(old_id_low, 4));\n"
|
||||
"new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n"
|
||||
"UPDATE SYS_TABLES SET ID = new_id\n"
|
||||
"WHERE ID = old_id;\n"
|
||||
"UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n"
|
||||
"WHERE TABLE_ID = old_id;\n"
|
||||
"UPDATE SYS_INDEXES SET TABLE_ID = new_id\n"
|
||||
"WHERE TABLE_ID = old_id;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n";
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
ut_ad(table);
|
||||
|
||||
@@ -2929,35 +2890,27 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
|
||||
|
||||
mem_heap_empty(heap);
|
||||
sql = mem_heap_alloc(heap, (sizeof renumber_tablespace_proc) + 40);
|
||||
sprintf(sql, renumber_tablespace_proc,
|
||||
(ulong) ut_dulint_get_high(table->id),
|
||||
(ulong) ut_dulint_get_low(table->id),
|
||||
(ulong) ut_dulint_get_high(new_id),
|
||||
(ulong) ut_dulint_get_low(new_id));
|
||||
|
||||
graph = pars_sql(sql);
|
||||
|
||||
ut_a(graph);
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
info = pars_info_create();
|
||||
|
||||
thr = que_fork_start_command(graph);
|
||||
ut_a(thr);
|
||||
pars_info_add_dulint_literal(info, "old_id", table->id);
|
||||
pars_info_add_dulint_literal(info, "new_id", new_id);
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
err = trx->error_state;
|
||||
err = que_eval_sql(info,
|
||||
"PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
|
||||
"BEGIN\n"
|
||||
"UPDATE SYS_TABLES SET ID = :new_id\n"
|
||||
" WHERE ID = :old_id;\n"
|
||||
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
|
||||
" WHERE TABLE_ID = :old_id;\n"
|
||||
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
|
||||
" WHERE TABLE_ID = :old_id;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n"
|
||||
, trx);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
trx->error_state = DB_SUCCESS;
|
||||
@@ -3007,83 +2960,13 @@ row_drop_table_for_mysql(
|
||||
dict_foreign_t* foreign;
|
||||
dict_table_t* table;
|
||||
ulint space_id;
|
||||
que_thr_t* thr;
|
||||
que_t* graph;
|
||||
ulint err;
|
||||
const char* table_name;
|
||||
ulint namelen;
|
||||
char* dir_path_of_temp_table = NULL;
|
||||
ibool success;
|
||||
ibool locked_dictionary = FALSE;
|
||||
char* quoted_name;
|
||||
char* sql;
|
||||
|
||||
/* We use the private SQL parser of Innobase to generate the
|
||||
query graphs needed in deleting the dictionary data from system
|
||||
tables in Innobase. Deleting a row from SYS_INDEXES table also
|
||||
frees the file segments of the B-tree associated with the index. */
|
||||
|
||||
static const char str1[] =
|
||||
"PROCEDURE DROP_TABLE_PROC () IS\n"
|
||||
"table_name CHAR;\n"
|
||||
"sys_foreign_id CHAR;\n"
|
||||
"table_id CHAR;\n"
|
||||
"index_id CHAR;\n"
|
||||
"foreign_id CHAR;\n"
|
||||
"found INT;\n"
|
||||
"BEGIN\n"
|
||||
"table_name := ";
|
||||
static const char str2[] =
|
||||
";\n"
|
||||
"SELECT ID INTO table_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = table_name;\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" COMMIT WORK;\n"
|
||||
" RETURN;\n"
|
||||
"END IF;\n"
|
||||
"found := 1;\n"
|
||||
"SELECT ID INTO sys_foreign_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = 'SYS_FOREIGN';\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"IF (table_name = 'SYS_FOREIGN') THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"IF (table_name = 'SYS_FOREIGN_COLS') THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO foreign_id\n"
|
||||
" FROM SYS_FOREIGN\n"
|
||||
" WHERE FOR_NAME = table_name\n"
|
||||
" AND TO_BINARY(FOR_NAME) = TO_BINARY(table_name);\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE"
|
||||
" DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;\n"
|
||||
" DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;\n"
|
||||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"found := 1;\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO index_id\n"
|
||||
" FROM SYS_INDEXES\n"
|
||||
" WHERE TABLE_ID = table_id;\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE"
|
||||
" DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n"
|
||||
" DELETE FROM SYS_INDEXES WHERE ID = index_id\n"
|
||||
" AND TABLE_ID = table_id;\n"
|
||||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n"
|
||||
"DELETE FROM SYS_TABLES WHERE ID = table_id;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n";
|
||||
pars_info_t* info = NULL;
|
||||
|
||||
ut_a(name != NULL);
|
||||
|
||||
@@ -3138,14 +3021,6 @@ row_drop_table_for_mysql(
|
||||
srv_print_innodb_table_monitor = FALSE;
|
||||
}
|
||||
|
||||
quoted_name = mem_strdupq(name, '\'');
|
||||
namelen = strlen(quoted_name);
|
||||
sql = mem_alloc((sizeof str1) + (sizeof str2) - 2 + 1 + namelen);
|
||||
memcpy(sql, str1, (sizeof str1) - 1);
|
||||
memcpy(sql + (sizeof str1) - 1, quoted_name, namelen);
|
||||
memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2);
|
||||
mem_free(quoted_name);
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
@@ -3163,16 +3038,6 @@ row_drop_table_for_mysql(
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
graph = pars_sql(sql);
|
||||
|
||||
ut_a(graph);
|
||||
mem_free(sql);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
table = dict_table_get_low(name);
|
||||
|
||||
if (!table) {
|
||||
@@ -3296,18 +3161,80 @@ fputs(" InnoDB: You are trying to drop table ", stderr);
|
||||
trx->dict_operation = TRUE;
|
||||
trx->table_id = table->id;
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph));
|
||||
/* We use the private SQL parser of Innobase to generate the
|
||||
query graphs needed in deleting the dictionary data from system
|
||||
tables in Innobase. Deleting a row from SYS_INDEXES table also
|
||||
frees the file segments of the B-tree associated with the index. */
|
||||
|
||||
que_run_threads(thr);
|
||||
info = pars_info_create();
|
||||
|
||||
err = trx->error_state;
|
||||
pars_info_add_str_literal(info, "table_name", name);
|
||||
|
||||
err = que_eval_sql(info,
|
||||
"PROCEDURE DROP_TABLE_PROC () IS\n"
|
||||
"sys_foreign_id CHAR;\n"
|
||||
"table_id CHAR;\n"
|
||||
"index_id CHAR;\n"
|
||||
"foreign_id CHAR;\n"
|
||||
"found INT;\n"
|
||||
"BEGIN\n"
|
||||
"SELECT ID INTO table_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = :table_name;\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" COMMIT WORK;\n"
|
||||
" RETURN;\n"
|
||||
"END IF;\n"
|
||||
"found := 1;\n"
|
||||
"SELECT ID INTO sys_foreign_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = 'SYS_FOREIGN';\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"IF (:table_name = 'SYS_FOREIGN') THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO foreign_id\n"
|
||||
" FROM SYS_FOREIGN\n"
|
||||
" WHERE FOR_NAME = :table_name\n"
|
||||
" AND TO_BINARY(FOR_NAME) = TO_BINARY(:table_name);\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE"
|
||||
" DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;\n"
|
||||
" DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;\n"
|
||||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"found := 1;\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO index_id\n"
|
||||
" FROM SYS_INDEXES\n"
|
||||
" WHERE TABLE_ID = table_id;\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE"
|
||||
" DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n"
|
||||
" DELETE FROM SYS_INDEXES WHERE ID = index_id\n"
|
||||
" AND TABLE_ID = table_id;\n"
|
||||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n"
|
||||
"DELETE FROM SYS_TABLES WHERE ID = table_id;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n"
|
||||
, trx);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
ut_a(err == DB_OUT_OF_FILE_SPACE);
|
||||
|
||||
err = DB_MUST_GET_MORE_FILE_SPACE;
|
||||
|
||||
row_mysql_handle_errors(&err, trx, thr, NULL);
|
||||
row_mysql_handle_errors(&err, trx, NULL, NULL);
|
||||
|
||||
ut_error;
|
||||
} else {
|
||||
@@ -3385,8 +3312,6 @@ funct_exit:
|
||||
mem_free(dir_path_of_temp_table);
|
||||
}
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
trx->op_info = "";
|
||||
@@ -3491,6 +3416,62 @@ row_is_mysql_tmp_table_name(
|
||||
return(strstr(name, "/@0023sql") != NULL);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Delete a single constraint. */
|
||||
static
|
||||
int
|
||||
row_delete_constraint_low(
|
||||
/*======================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* id, /* in: constraint id */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
{
|
||||
pars_info_t* info = pars_info_create();
|
||||
|
||||
pars_info_add_str_literal(info, "id", id);
|
||||
|
||||
return(que_eval_sql(info,
|
||||
"PROCEDURE DELETE_CONSTRAINT () IS\n"
|
||||
"BEGIN\n"
|
||||
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
|
||||
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
|
||||
"END;\n"
|
||||
, trx));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Delete a single constraint. */
|
||||
static
|
||||
int
|
||||
row_delete_constraint(
|
||||
/*==================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* id, /* in: constraint id */
|
||||
const char* database_name, /* in: database name, with the
|
||||
trailing '/' */
|
||||
mem_heap_t* heap, /* in: memory heap */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
{
|
||||
ulint err;
|
||||
|
||||
/* New format constraints have ids <databasename>/<constraintname>. */
|
||||
err = row_delete_constraint_low(
|
||||
mem_heap_strcat(heap, database_name, id), trx);
|
||||
|
||||
if ((err == DB_SUCCESS) && !strchr(id, '/')) {
|
||||
/* Old format < 4.0.18 constraints have constraint ids
|
||||
<number>_<number>. We only try deleting them if the
|
||||
constraint name does not contain a '/' character, otherwise
|
||||
deleting a new format constraint named 'foo/bar' from
|
||||
database 'baz' would remove constraint 'bar' from database
|
||||
'foo', if it existed. */
|
||||
|
||||
err = row_delete_constraint_low(id, trx);
|
||||
}
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Renames a table for MySQL. */
|
||||
|
||||
@@ -3503,100 +3484,13 @@ row_rename_table_for_mysql(
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
{
|
||||
dict_table_t* table;
|
||||
que_thr_t* thr;
|
||||
que_t* graph = NULL;
|
||||
ulint err;
|
||||
/* We use the private SQL parser of Innobase to generate the
|
||||
query graphs needed in deleting the dictionary data from system
|
||||
tables in Innobase. Deleting a row from SYS_INDEXES table also
|
||||
frees the file segments of the B-tree associated with the index. */
|
||||
static const char str1[] =
|
||||
"PROCEDURE RENAME_TABLE_PROC () IS\n"
|
||||
"new_table_name CHAR;\n"
|
||||
"old_table_name CHAR;\n"
|
||||
"gen_constr_prefix CHAR;\n"
|
||||
"new_db_name CHAR;\n"
|
||||
"foreign_id CHAR;\n"
|
||||
"new_foreign_id CHAR;\n"
|
||||
"old_db_name_len INT;\n"
|
||||
"old_t_name_len INT;\n"
|
||||
"new_db_name_len INT;\n"
|
||||
"id_len INT;\n"
|
||||
"found INT;\n"
|
||||
"BEGIN\n"
|
||||
"new_table_name := '";
|
||||
static const char str2[] =
|
||||
"';\nold_table_name := '";
|
||||
static const char str3[] =
|
||||
"';\n"
|
||||
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
|
||||
"WHERE NAME = old_table_name;\n";
|
||||
static const char str4a1[] = /* drop some constraints of tmp tables */
|
||||
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = '";
|
||||
static const char str4a2[] = "';\n"
|
||||
"DELETE FROM SYS_FOREIGN WHERE ID = '";
|
||||
static const char str4a3[] = "';\n";
|
||||
static const char str4b[] = /* rename all constraints */
|
||||
"found := 1;\n"
|
||||
"old_db_name_len := INSTR(old_table_name, '/') - 1;\n"
|
||||
"new_db_name_len := INSTR(new_table_name, '/') - 1;\n"
|
||||
"new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);\n"
|
||||
"old_t_name_len := LENGTH(old_table_name);\n"
|
||||
"gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO foreign_id\n"
|
||||
" FROM SYS_FOREIGN\n"
|
||||
" WHERE FOR_NAME = old_table_name\n"
|
||||
" AND TO_BINARY(FOR_NAME) = TO_BINARY(old_table_name);\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE\n"
|
||||
" UPDATE SYS_FOREIGN\n"
|
||||
" SET FOR_NAME = new_table_name\n"
|
||||
" WHERE ID = foreign_id;\n"
|
||||
" id_len := LENGTH(foreign_id);\n"
|
||||
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
|
||||
" IF (INSTR(foreign_id,\n"
|
||||
" gen_constr_prefix) > 0)\n"
|
||||
" THEN\n"
|
||||
" new_foreign_id :=\n"
|
||||
" CONCAT(new_table_name,\n"
|
||||
" SUBSTR(foreign_id, old_t_name_len,\n"
|
||||
" id_len - old_t_name_len));\n"
|
||||
" ELSE\n"
|
||||
" new_foreign_id :=\n"
|
||||
" CONCAT(new_db_name,\n"
|
||||
" SUBSTR(foreign_id,\n"
|
||||
" old_db_name_len,\n"
|
||||
" id_len - old_db_name_len));\n"
|
||||
" END IF;\n"
|
||||
" UPDATE SYS_FOREIGN\n"
|
||||
" SET ID = new_foreign_id\n"
|
||||
" WHERE ID = foreign_id;\n"
|
||||
" UPDATE SYS_FOREIGN_COLS\n"
|
||||
" SET ID = new_foreign_id\n"
|
||||
" WHERE ID = foreign_id;\n"
|
||||
" END IF;\n"
|
||||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n"
|
||||
"WHERE REF_NAME = old_table_name\n"
|
||||
" AND TO_BINARY(REF_NAME) = TO_BINARY(old_table_name);\n";
|
||||
static const char str5[] =
|
||||
"END;\n";
|
||||
|
||||
mem_heap_t* heap = NULL;
|
||||
const char** constraints_to_drop = NULL;
|
||||
ulint n_constraints_to_drop = 0;
|
||||
ibool recovering_temp_table = FALSE;
|
||||
ibool old_is_tmp, new_is_tmp;
|
||||
ulint len;
|
||||
ulint i;
|
||||
ibool success;
|
||||
/* length of database name; 0 if not renaming to a temporary table */
|
||||
ulint db_name_len;
|
||||
char* sql;
|
||||
char* sqlend;
|
||||
pars_info_t* info = NULL;
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
ut_a(old_name != NULL);
|
||||
@@ -3674,13 +3568,7 @@ row_rename_table_for_mysql(
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
/* calculate the length of the SQL string */
|
||||
len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4
|
||||
+ ut_strlenq(new_name, '\'') + ut_strlenq(old_name, '\'');
|
||||
|
||||
if (new_is_tmp) {
|
||||
db_name_len = dict_get_db_name_len(old_name) + 1;
|
||||
|
||||
/* MySQL is doing an ALTER TABLE command and it renames the
|
||||
original table to a temporary table name. We want to preserve
|
||||
the original foreign key constraint definitions despite the
|
||||
@@ -3690,110 +3578,124 @@ row_rename_table_for_mysql(
|
||||
heap = mem_heap_create(100);
|
||||
|
||||
err = dict_foreign_parse_drop_constraints(heap, trx,
|
||||
table,
|
||||
&n_constraints_to_drop,
|
||||
&constraints_to_drop);
|
||||
table, &n_constraints_to_drop, &constraints_to_drop);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
goto funct_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* reserve space for all database names */
|
||||
len += 2 * n_constraints_to_drop
|
||||
* (ut_strlenq(old_name, '\'')
|
||||
- ut_strlenq(old_name + db_name_len, '\''));
|
||||
/* We use the private SQL parser of Innobase to generate the query
|
||||
graphs needed in deleting the dictionary data from system tables in
|
||||
Innobase. Deleting a row from SYS_INDEXES table also frees the file
|
||||
segments of the B-tree associated with the index. */
|
||||
|
||||
info = pars_info_create();
|
||||
|
||||
pars_info_add_str_literal(info, "new_table_name", new_name);
|
||||
pars_info_add_str_literal(info, "old_table_name", old_name);
|
||||
|
||||
err = que_eval_sql(info,
|
||||
"PROCEDURE RENAME_TABLE () IS\n"
|
||||
"BEGIN\n"
|
||||
"UPDATE SYS_TABLES SET NAME = :new_table_name\n"
|
||||
" WHERE NAME = :old_table_name;\n"
|
||||
"END;\n"
|
||||
, trx);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!new_is_tmp) {
|
||||
/* Rename all constraints. */
|
||||
|
||||
info = pars_info_create();
|
||||
|
||||
pars_info_add_str_literal(info, "new_table_name", new_name);
|
||||
pars_info_add_str_literal(info, "old_table_name", old_name);
|
||||
|
||||
err = que_eval_sql(info,
|
||||
"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
|
||||
"gen_constr_prefix CHAR;\n"
|
||||
"new_db_name CHAR;\n"
|
||||
"foreign_id CHAR;\n"
|
||||
"new_foreign_id CHAR;\n"
|
||||
"old_db_name_len INT;\n"
|
||||
"old_t_name_len INT;\n"
|
||||
"new_db_name_len INT;\n"
|
||||
"id_len INT;\n"
|
||||
"found INT;\n"
|
||||
"BEGIN\n"
|
||||
"found := 1;\n"
|
||||
"old_db_name_len := INSTR(:old_table_name, '/') - 1;\n"
|
||||
"new_db_name_len := INSTR(:new_table_name, '/') - 1;\n"
|
||||
"new_db_name := SUBSTR(:new_table_name, 0, new_db_name_len);\n"
|
||||
"old_t_name_len := LENGTH(:old_table_name);\n"
|
||||
"gen_constr_prefix := CONCAT(:old_table_name, '_ibfk_');\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO foreign_id\n"
|
||||
" FROM SYS_FOREIGN\n"
|
||||
" WHERE FOR_NAME = :old_table_name\n"
|
||||
" AND TO_BINARY(FOR_NAME) = TO_BINARY(:old_table_name);\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE\n"
|
||||
" UPDATE SYS_FOREIGN\n"
|
||||
" SET FOR_NAME = :new_table_name\n"
|
||||
" WHERE ID = foreign_id;\n"
|
||||
" id_len := LENGTH(foreign_id);\n"
|
||||
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
|
||||
" IF (INSTR(foreign_id,\n"
|
||||
" gen_constr_prefix) > 0)\n"
|
||||
" THEN\n"
|
||||
" new_foreign_id :=\n"
|
||||
" CONCAT(:new_table_name,\n"
|
||||
" SUBSTR(foreign_id, old_t_name_len,\n"
|
||||
" id_len - old_t_name_len));\n"
|
||||
" ELSE\n"
|
||||
" new_foreign_id :=\n"
|
||||
" CONCAT(new_db_name,\n"
|
||||
" SUBSTR(foreign_id,\n"
|
||||
" old_db_name_len,\n"
|
||||
" id_len - old_db_name_len));\n"
|
||||
" END IF;\n"
|
||||
" UPDATE SYS_FOREIGN\n"
|
||||
" SET ID = new_foreign_id\n"
|
||||
" WHERE ID = foreign_id;\n"
|
||||
" UPDATE SYS_FOREIGN_COLS\n"
|
||||
" SET ID = new_foreign_id\n"
|
||||
" WHERE ID = foreign_id;\n"
|
||||
" END IF;\n"
|
||||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
|
||||
"WHERE REF_NAME = :old_table_name\n"
|
||||
" AND TO_BINARY(REF_NAME) = TO_BINARY(:old_table_name);\n"
|
||||
"END;\n"
|
||||
, trx);
|
||||
|
||||
} else if (n_constraints_to_drop > 0) {
|
||||
/* Drop some constraints of tmp tables. */
|
||||
|
||||
ulint db_name_len = dict_get_db_name_len(old_name) + 1;
|
||||
char* db_name = mem_heap_strdupl(heap, old_name,
|
||||
db_name_len);
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < n_constraints_to_drop; i++) {
|
||||
ulint addlen
|
||||
= 2 * ut_strlenq(constraints_to_drop[i], '\'')
|
||||
+ ((sizeof str4a1) + (sizeof str4a2)
|
||||
+ (sizeof str4a3) - 3);
|
||||
if (!strchr(constraints_to_drop[i], '/')) {
|
||||
addlen *= 2;
|
||||
}
|
||||
len += addlen;
|
||||
}
|
||||
} else {
|
||||
db_name_len = 0;
|
||||
len += (sizeof str4b) - 1;
|
||||
}
|
||||
err = row_delete_constraint(constraints_to_drop[i],
|
||||
db_name, heap, trx);
|
||||
|
||||
sql = sqlend = mem_alloc(len + 1);
|
||||
memcpy(sql, str1, (sizeof str1) - 1);
|
||||
sqlend += (sizeof str1) - 1;
|
||||
sqlend = ut_strcpyq(sqlend, '\'', new_name);
|
||||
memcpy(sqlend, str2, (sizeof str2) - 1);
|
||||
sqlend += (sizeof str2) - 1;
|
||||
sqlend = ut_strcpyq(sqlend, '\'', old_name);
|
||||
memcpy(sqlend, str3, (sizeof str3) - 1);
|
||||
sqlend += (sizeof str3) - 1;
|
||||
|
||||
if (db_name_len) {
|
||||
/* Internally, old format < 4.0.18 constraints have as the
|
||||
constraint id <number>_<number>, while new format constraints
|
||||
have <databasename>/<constraintname>. */
|
||||
|
||||
for (i = 0; i < n_constraints_to_drop; i++) {
|
||||
memcpy(sqlend, str4a1, (sizeof str4a1) - 1);
|
||||
sqlend += (sizeof str4a1) - 1;
|
||||
sqlend = ut_memcpyq(sqlend, '\'',
|
||||
old_name, db_name_len);
|
||||
sqlend = ut_strcpyq(sqlend, '\'',
|
||||
constraints_to_drop[i]);
|
||||
memcpy(sqlend, str4a2, (sizeof str4a2) - 1);
|
||||
sqlend += (sizeof str4a2) - 1;
|
||||
sqlend = ut_memcpyq(sqlend, '\'',
|
||||
old_name, db_name_len);
|
||||
sqlend = ut_strcpyq(sqlend, '\'',
|
||||
constraints_to_drop[i]);
|
||||
memcpy(sqlend, str4a3, (sizeof str4a3) - 1);
|
||||
sqlend += (sizeof str4a3) - 1;
|
||||
|
||||
if (!strchr(constraints_to_drop[i], '/')) {
|
||||
/* If this happens to be an old format
|
||||
constraint, let us delete it. Since all new
|
||||
format constraints contain '/', it does no
|
||||
harm to run these DELETEs anyway. */
|
||||
|
||||
memcpy(sqlend, str4a1, (sizeof str4a1) - 1);
|
||||
sqlend += (sizeof str4a1) - 1;
|
||||
sqlend = ut_strcpyq(sqlend, '\'',
|
||||
constraints_to_drop[i]);
|
||||
memcpy(sqlend, str4a2, (sizeof str4a2) - 1);
|
||||
sqlend += (sizeof str4a2) - 1;
|
||||
sqlend = ut_strcpyq(sqlend, '\'',
|
||||
constraints_to_drop[i]);
|
||||
memcpy(sqlend, str4a3, (sizeof str4a3) - 1);
|
||||
sqlend += (sizeof str4a3) - 1;
|
||||
if (err != DB_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
memcpy(sqlend, str4b, (sizeof str4b) - 1);
|
||||
sqlend += (sizeof str4b) - 1;
|
||||
}
|
||||
|
||||
memcpy(sqlend, str5, sizeof str5);
|
||||
sqlend += sizeof str5;
|
||||
|
||||
ut_a(sqlend == sql + len + 1);
|
||||
|
||||
graph = pars_sql(sql);
|
||||
|
||||
ut_a(graph);
|
||||
mem_free(sql);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
err = trx->error_state;
|
||||
|
||||
end:
|
||||
if (err != DB_SUCCESS) {
|
||||
if (err == DB_DUPLICATE_KEY) {
|
||||
ut_print_timestamp(stderr);
|
||||
@@ -3830,8 +3732,9 @@ row_rename_table_for_mysql(
|
||||
/* The following call will also rename the .ibd data file if
|
||||
the table is stored in a single-table tablespace */
|
||||
|
||||
success = dict_table_rename_in_cache(table, new_name,
|
||||
ibool success = dict_table_rename_in_cache(table, new_name,
|
||||
!new_is_tmp);
|
||||
|
||||
if (!success) {
|
||||
trx->error_state = DB_SUCCESS;
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
@@ -3879,20 +3782,16 @@ row_rename_table_for_mysql(
|
||||
ut_a(dict_table_rename_in_cache(table,
|
||||
old_name, FALSE));
|
||||
trx->error_state = DB_SUCCESS;
|
||||
trx_general_rollback_for_mysql(trx, FALSE,
|
||||
NULL);
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
trx->error_state = DB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
funct_exit:
|
||||
if (!recovering_temp_table) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (graph) {
|
||||
que_graph_free(graph);
|
||||
}
|
||||
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
|
@@ -710,12 +710,17 @@ row_sel_get_clust_rec(
|
||||
if (!node->read_view) {
|
||||
/* Try to place a lock on the index record */
|
||||
|
||||
/* If innodb_locks_unsafe_for_binlog option is used,
|
||||
/* If innodb_locks_unsafe_for_binlog option is used
|
||||
or this session is using READ COMMITTED isolation level
|
||||
we lock only the record, i.e., next-key locking is
|
||||
not used. */
|
||||
ulint lock_type;
|
||||
trx_t* trx;
|
||||
|
||||
if (srv_locks_unsafe_for_binlog) {
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
lock_type = LOCK_REC_NOT_GAP;
|
||||
} else {
|
||||
lock_type = LOCK_ORDINARY;
|
||||
@@ -1307,16 +1312,22 @@ rec_loop:
|
||||
|
||||
if (!consistent_read) {
|
||||
|
||||
/* If innodb_locks_unsafe_for_binlog option is used,
|
||||
we lock only the record, i.e., next-key locking is
|
||||
not used. */
|
||||
/* If innodb_locks_unsafe_for_binlog option is used
|
||||
or this session is using READ COMMITTED isolation
|
||||
level, we lock only the record, i.e., next-key
|
||||
locking is not used. */
|
||||
|
||||
rec_t* next_rec = page_rec_get_next(rec);
|
||||
ulint lock_type;
|
||||
trx_t* trx;
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
offsets = rec_get_offsets(next_rec, index, offsets,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
if (srv_locks_unsafe_for_binlog) {
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
lock_type = LOCK_REC_NOT_GAP;
|
||||
} else {
|
||||
lock_type = LOCK_ORDINARY;
|
||||
@@ -1350,15 +1361,21 @@ rec_loop:
|
||||
if (!consistent_read) {
|
||||
/* Try to place a lock on the index record */
|
||||
|
||||
/* If innodb_locks_unsafe_for_binlog option is used,
|
||||
/* If innodb_locks_unsafe_for_binlog option is used
|
||||
or this session is using READ COMMITTED isolation level,
|
||||
we lock only the record, i.e., next-key locking is
|
||||
not used. */
|
||||
|
||||
ulint lock_type;
|
||||
trx_t* trx;
|
||||
|
||||
offsets = rec_get_offsets(rec, index, offsets,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
if (srv_locks_unsafe_for_binlog) {
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
|
||||
lock_type = LOCK_REC_NOT_GAP;
|
||||
} else {
|
||||
lock_type = LOCK_ORDINARY;
|
||||
@@ -1413,14 +1430,6 @@ rec_loop:
|
||||
|
||||
/* Ok, no need to test end_conds or mix id */
|
||||
|
||||
} else if (plan->mixed_index) {
|
||||
/* We have to check if the record in a mixed cluster belongs
|
||||
to this table */
|
||||
|
||||
if (!dict_is_mixed_table_rec(plan->table, rec)) {
|
||||
|
||||
goto next_rec;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are ready to look at a possible new index entry in the result
|
||||
@@ -1958,7 +1967,18 @@ fetch_step(
|
||||
|
||||
if (sel_node->state != SEL_NODE_NO_MORE_ROWS) {
|
||||
|
||||
sel_assign_into_var_values(node->into_list, sel_node);
|
||||
if (node->into_list) {
|
||||
sel_assign_into_var_values(node->into_list,
|
||||
sel_node);
|
||||
} else {
|
||||
void* ret = (*node->func->func)(sel_node,
|
||||
node->func->arg);
|
||||
|
||||
if (!ret) {
|
||||
sel_node->state =
|
||||
SEL_NODE_NO_MORE_ROWS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thr->run_node = que_node_get_parent(node);
|
||||
@@ -1974,8 +1994,8 @@ fetch_step(
|
||||
sel_node->common.parent = node;
|
||||
|
||||
if (sel_node->state == SEL_NODE_CLOSED) {
|
||||
/* SQL error detected */
|
||||
fprintf(stderr, "SQL error %lu\n", (ulong)DB_ERROR);
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: fetch called on a closed cursor\n");
|
||||
|
||||
que_thr_handle_error(thr, DB_ERROR, NULL, 0);
|
||||
|
||||
@@ -1987,6 +2007,76 @@ fetch_step(
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Sample callback function for fetch that prints each row.*/
|
||||
|
||||
void*
|
||||
row_fetch_print(
|
||||
/*============*/
|
||||
/* out: always returns non-NULL */
|
||||
void* row, /* in: sel_node_t* */
|
||||
void* user_arg) /* in: not used */
|
||||
{
|
||||
sel_node_t* node = row;
|
||||
que_node_t* exp;
|
||||
ulint i = 0;
|
||||
|
||||
UT_NOT_USED(user_arg);
|
||||
|
||||
fprintf(stderr, "row_fetch_print: row %p\n", row);
|
||||
|
||||
exp = node->select_list;
|
||||
|
||||
while (exp) {
|
||||
dfield_t* dfield = que_node_get_val(exp);
|
||||
dtype_t* type = dfield_get_type(dfield);
|
||||
|
||||
fprintf(stderr, " column %lu:\n", (ulong)i);
|
||||
|
||||
dtype_print(type);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
ut_print_buf(stderr, dfield_get_data(dfield),
|
||||
dfield_get_len(dfield));
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exp = que_node_get_next(exp);
|
||||
i++;
|
||||
}
|
||||
|
||||
return((void*)42);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Callback function for fetch that stores an unsigned 4 byte integer to the
|
||||
location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
|
||||
= 4. */
|
||||
|
||||
void*
|
||||
row_fetch_store_uint4(
|
||||
/*==================*/
|
||||
/* out: always returns NULL */
|
||||
void* row, /* in: sel_node_t* */
|
||||
void* user_arg) /* in: data pointer */
|
||||
{
|
||||
sel_node_t* node = row;
|
||||
ib_uint32_t* val = user_arg;
|
||||
ulint tmp;
|
||||
|
||||
dfield_t* dfield = que_node_get_val(node->select_list);
|
||||
dtype_t* type = dfield_get_type(dfield);
|
||||
ulint len = dfield_get_len(dfield);
|
||||
|
||||
ut_a(dtype_get_mtype(type) == DATA_INT);
|
||||
ut_a(dtype_get_prtype(type) & DATA_UNSIGNED);
|
||||
ut_a(len == 4);
|
||||
|
||||
tmp = mach_read_from_4(dfield_get_data(dfield));
|
||||
*val = tmp;
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Prints a row in a select result. */
|
||||
|
||||
@@ -2397,18 +2487,16 @@ row_sel_field_store_in_mysql_format(
|
||||
} else if (templ->type == DATA_MYSQL) {
|
||||
memcpy(dest, data, len);
|
||||
|
||||
#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG)
|
||||
ut_a(templ->mysql_col_len >= len);
|
||||
ut_a(templ->mbmaxlen >= templ->mbminlen);
|
||||
ut_ad(templ->mysql_col_len >= len);
|
||||
ut_ad(templ->mbmaxlen >= templ->mbminlen);
|
||||
|
||||
ut_a(templ->mbmaxlen > templ->mbminlen
|
||||
ut_ad(templ->mbmaxlen > templ->mbminlen
|
||||
|| templ->mysql_col_len == len);
|
||||
ut_a(len * templ->mbmaxlen >= templ->mysql_col_len);
|
||||
#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */
|
||||
/* The following assertion would fail for old tables
|
||||
containing UTF-8 ENUM columns due to Bug #9526. */
|
||||
ut_ad(!templ->mbmaxlen
|
||||
|| !(templ->mysql_col_len % templ->mbmaxlen));
|
||||
ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len);
|
||||
|
||||
if (templ->mbminlen != templ->mbmaxlen) {
|
||||
/* Pad with spaces. This undoes the stripping
|
||||
@@ -2418,15 +2506,13 @@ row_sel_field_store_in_mysql_format(
|
||||
memset(dest + len, 0x20, templ->mysql_col_len - len);
|
||||
}
|
||||
} else {
|
||||
#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG)
|
||||
ut_a(templ->type == DATA_CHAR
|
||||
ut_ad(templ->type == DATA_CHAR
|
||||
|| templ->type == DATA_FIXBINARY
|
||||
/*|| templ->type == DATA_SYS_CHILD
|
||||
|| templ->type == DATA_SYS*/
|
||||
|| templ->type == DATA_FLOAT
|
||||
|| templ->type == DATA_DOUBLE
|
||||
|| templ->type == DATA_DECIMAL);
|
||||
#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */
|
||||
ut_ad(templ->mysql_col_len == len);
|
||||
|
||||
memcpy(dest, data, len);
|
||||
@@ -3210,10 +3296,12 @@ stderr);
|
||||
}
|
||||
|
||||
/* Reset the new record lock info if srv_locks_unsafe_for_binlog
|
||||
is set. Then we are able to remove the record locks set here on an
|
||||
individual row. */
|
||||
is set or session is using a READ COMMITED isolation level. Then
|
||||
we are able to remove the record locks set here on an individual
|
||||
row. */
|
||||
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
if ((srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& prebuilt->select_lock_type != LOCK_NONE) {
|
||||
|
||||
trx_reset_new_rec_lock_info(trx);
|
||||
@@ -3582,13 +3670,15 @@ rec_loop:
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
|
||||
if (set_also_gap_locks
|
||||
&& !srv_locks_unsafe_for_binlog
|
||||
&& !(srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& prebuilt->select_lock_type != LOCK_NONE) {
|
||||
|
||||
/* Try to place a lock on the index record */
|
||||
|
||||
/* If innodb_locks_unsafe_for_binlog option is used,
|
||||
we do not lock gaps. Supremum record is really
|
||||
/* If innodb_locks_unsafe_for_binlog option is used
|
||||
or this session is using a READ COMMITTED isolation
|
||||
level we do not lock gaps. Supremum record is really
|
||||
a gap and therefore we do not set locks there. */
|
||||
|
||||
offsets = rec_get_offsets(rec, index, offsets,
|
||||
@@ -3708,12 +3798,14 @@ wrong_offs:
|
||||
if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
|
||||
|
||||
if (set_also_gap_locks
|
||||
&& !srv_locks_unsafe_for_binlog
|
||||
&& !(srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& prebuilt->select_lock_type != LOCK_NONE) {
|
||||
|
||||
/* Try to place a gap lock on the index
|
||||
record only if innodb_locks_unsafe_for_binlog
|
||||
option is not set */
|
||||
option is not set or this session is not
|
||||
using a READ COMMITTED isolation level. */
|
||||
|
||||
err = sel_set_rec_lock(rec, index, offsets,
|
||||
prebuilt->select_lock_type,
|
||||
@@ -3739,12 +3831,14 @@ wrong_offs:
|
||||
if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
|
||||
|
||||
if (set_also_gap_locks
|
||||
&& !srv_locks_unsafe_for_binlog
|
||||
&& !(srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& prebuilt->select_lock_type != LOCK_NONE) {
|
||||
|
||||
/* Try to place a gap lock on the index
|
||||
record only if innodb_locks_unsafe_for_binlog
|
||||
option is not set */
|
||||
option is not set or this session is not
|
||||
using a READ COMMITTED isolation level. */
|
||||
|
||||
err = sel_set_rec_lock(rec, index, offsets,
|
||||
prebuilt->select_lock_type,
|
||||
@@ -3775,16 +3869,18 @@ wrong_offs:
|
||||
is a non-delete marked record, then it is enough to lock its
|
||||
existence with LOCK_REC_NOT_GAP. */
|
||||
|
||||
/* If innodb_locks_unsafe_for_binlog option is used,
|
||||
we lock only the record, i.e., next-key locking is
|
||||
/* If innodb_locks_unsafe_for_binlog option is used
|
||||
or this session is using a READ COMMITED isolation
|
||||
level we lock only the record, i.e., next-key locking is
|
||||
not used. */
|
||||
|
||||
ulint lock_type;
|
||||
|
||||
if (!set_also_gap_locks
|
||||
|| srv_locks_unsafe_for_binlog
|
||||
|| (unique_search && !UNIV_UNLIKELY(
|
||||
rec_get_deleted_flag(rec, comp)))) {
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED
|
||||
|| (unique_search
|
||||
&& !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) {
|
||||
|
||||
goto no_gap_lock;
|
||||
} else {
|
||||
@@ -3943,7 +4039,8 @@ no_gap_lock:
|
||||
|
||||
/* The record is delete-marked: we can skip it */
|
||||
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
if ((srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& prebuilt->select_lock_type != LOCK_NONE
|
||||
&& !did_semi_consistent_read) {
|
||||
|
||||
@@ -3996,7 +4093,8 @@ requires_clust_rec:
|
||||
|
||||
/* The record is delete marked: we can skip it */
|
||||
|
||||
if (srv_locks_unsafe_for_binlog
|
||||
if ((srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& prebuilt->select_lock_type != LOCK_NONE) {
|
||||
|
||||
/* No need to keep a lock on a delete-marked
|
||||
@@ -4117,7 +4215,8 @@ next_rec:
|
||||
}
|
||||
did_semi_consistent_read = FALSE;
|
||||
|
||||
if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog)
|
||||
if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& prebuilt->select_lock_type != LOCK_NONE) {
|
||||
|
||||
trx_reset_new_rec_lock_info(trx);
|
||||
@@ -4206,7 +4305,11 @@ lock_wait_or_error:
|
||||
sel_restore_position_for_mysql(&same_user_rec,
|
||||
BTR_SEARCH_LEAF, pcur,
|
||||
moves_up, &mtr);
|
||||
if (srv_locks_unsafe_for_binlog && !same_user_rec) {
|
||||
|
||||
if ((srv_locks_unsafe_for_binlog
|
||||
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
|
||||
&& !same_user_rec) {
|
||||
|
||||
/* Since we were not able to restore the cursor
|
||||
on the same user record, we cannot use
|
||||
row_unlock_for_mysql() to unlock any records, and
|
||||
|
@@ -28,6 +28,7 @@ Created 12/27/1996 Heikki Tuuri
|
||||
#include "log0log.h"
|
||||
#include "pars0sym.h"
|
||||
#include "eval0eval.h"
|
||||
#include "buf0lru.h"
|
||||
|
||||
|
||||
/* What kind of latch and lock can we assume when the control comes to
|
||||
@@ -869,6 +870,10 @@ row_upd_index_replace_new_col_vals_index_pos(
|
||||
upd_t* update, /* in: an update vector built for the index so
|
||||
that the field number in an upd_field is the
|
||||
index position */
|
||||
ibool order_only,
|
||||
/* in: if TRUE, limit the replacement to
|
||||
ordering fields of index; note that this
|
||||
does not work for non-clustered indexes. */
|
||||
mem_heap_t* heap) /* in: memory heap to which we allocate and
|
||||
copy the new values, set this as NULL if you
|
||||
do not want allocation */
|
||||
@@ -879,13 +884,20 @@ row_upd_index_replace_new_col_vals_index_pos(
|
||||
dfield_t* new_val;
|
||||
ulint j;
|
||||
ulint i;
|
||||
ulint n_fields;
|
||||
dtype_t* cur_type;
|
||||
|
||||
ut_ad(index);
|
||||
|
||||
dtuple_set_info_bits(entry, update->info_bits);
|
||||
|
||||
for (j = 0; j < dict_index_get_n_fields(index); j++) {
|
||||
if (order_only) {
|
||||
n_fields = dict_index_get_n_unique(index);
|
||||
} else {
|
||||
n_fields = dict_index_get_n_fields(index);
|
||||
}
|
||||
|
||||
for (j = 0; j < n_fields; j++) {
|
||||
|
||||
field = dict_index_get_nth_field(index, j);
|
||||
|
||||
@@ -1530,6 +1542,10 @@ row_upd_clust_rec(
|
||||
return(err);
|
||||
}
|
||||
|
||||
if (buf_LRU_buf_pool_running_out()) {
|
||||
|
||||
return(DB_LOCK_TABLE_FULL);
|
||||
}
|
||||
/* We may have to modify the tree structure: do a pessimistic descent
|
||||
down the index tree */
|
||||
|
||||
|
@@ -1713,6 +1713,8 @@ srv_printf_innodb_monitor(
|
||||
"; in additional pool allocated " ULINTPF "\n",
|
||||
ut_total_allocated_memory,
|
||||
mem_pool_get_reserved(mem_comm_pool));
|
||||
fprintf(file, "Dictionary memory allocated " ULINTPF "\n",
|
||||
dict_sys->size);
|
||||
|
||||
if (srv_use_awe) {
|
||||
fprintf(file,
|
||||
|
@@ -524,7 +524,7 @@ sync_array_cell_print(
|
||||
"Last time reserved in file %s line %lu, "
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
"waiters flag %lu\n",
|
||||
mutex, mutex->cfile_name, (ulong) mutex->cline,
|
||||
(void*) mutex, mutex->cfile_name, (ulong) mutex->cline,
|
||||
(ulong) mutex->lock_word,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
mutex->file_name, (ulong) mutex->line,
|
||||
@@ -539,7 +539,7 @@ sync_array_cell_print(
|
||||
|
||||
fprintf(file,
|
||||
" RW-latch at %p created in file %s line %lu\n",
|
||||
rwlock, rwlock->cfile_name,
|
||||
(void*) rwlock, rwlock->cfile_name,
|
||||
(ulong) rwlock->cline);
|
||||
if (rwlock->writer != RW_LOCK_NOT_LOCKED) {
|
||||
fprintf(file,
|
||||
@@ -670,7 +670,6 @@ sync_array_detect_deadlock(
|
||||
rw_lock_debug_t*debug;
|
||||
|
||||
ut_a(arr && start && cell);
|
||||
ut_ad(cell->state == SC_RESERVED);
|
||||
ut_ad(cell->wait_object);
|
||||
ut_ad(os_thread_get_curr_id() == start->thread);
|
||||
ut_ad(depth < 100);
|
||||
@@ -703,7 +702,7 @@ sync_array_detect_deadlock(
|
||||
if (ret) {
|
||||
fprintf(stderr,
|
||||
"Mutex %p owned by thread %lu file %s line %lu\n",
|
||||
mutex,
|
||||
(void*) mutex,
|
||||
(ulong) os_thread_pf(mutex->thread_id),
|
||||
mutex->file_name, (ulong) mutex->line);
|
||||
sync_array_cell_print(stderr, cell);
|
||||
@@ -740,7 +739,8 @@ sync_array_detect_deadlock(
|
||||
thread, debug->pass, depth);
|
||||
if (ret) {
|
||||
print:
|
||||
fprintf(stderr, "rw-lock %p ", lock);
|
||||
fprintf(stderr, "rw-lock %p ",
|
||||
(void*) lock);
|
||||
sync_array_cell_print(stderr, cell);
|
||||
rw_lock_debug_print(debug);
|
||||
return(TRUE);
|
||||
|
@@ -246,7 +246,7 @@ lock_loop:
|
||||
if (srv_print_latch_waits) {
|
||||
fprintf(stderr,
|
||||
"Thread %lu spin wait rw-s-lock at %p cfile %s cline %lu rnds %lu\n",
|
||||
(ulong) os_thread_pf(os_thread_get_curr_id()), lock,
|
||||
(ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock,
|
||||
lock->cfile_name, (ulong) lock->cline, (ulong) i);
|
||||
}
|
||||
|
||||
@@ -277,7 +277,8 @@ lock_loop:
|
||||
fprintf(stderr,
|
||||
"Thread %lu OS wait rw-s-lock at %p cfile %s cline %lu\n",
|
||||
os_thread_pf(os_thread_get_curr_id()),
|
||||
lock, lock->cfile_name, (ulong) lock->cline);
|
||||
(void*) lock, lock->cfile_name,
|
||||
(ulong) lock->cline);
|
||||
}
|
||||
|
||||
rw_s_system_call_count++;
|
||||
@@ -495,7 +496,7 @@ lock_loop:
|
||||
if (srv_print_latch_waits) {
|
||||
fprintf(stderr,
|
||||
"Thread %lu spin wait rw-x-lock at %p cfile %s cline %lu rnds %lu\n",
|
||||
os_thread_pf(os_thread_get_curr_id()), lock,
|
||||
os_thread_pf(os_thread_get_curr_id()), (void*) lock,
|
||||
lock->cfile_name, (ulong) lock->cline, (ulong) i);
|
||||
}
|
||||
|
||||
@@ -528,7 +529,7 @@ lock_loop:
|
||||
if (srv_print_latch_waits) {
|
||||
fprintf(stderr,
|
||||
"Thread %lu OS wait for rw-x-lock at %p cfile %s cline %lu\n",
|
||||
os_thread_pf(os_thread_get_curr_id()), lock,
|
||||
os_thread_pf(os_thread_get_curr_id()), (void*) lock,
|
||||
lock->cfile_name, (ulong) lock->cline);
|
||||
}
|
||||
|
||||
@@ -787,7 +788,7 @@ rw_lock_list_print_info(void)
|
||||
|| (rw_lock_get_reader_count(lock) != 0)
|
||||
|| (rw_lock_get_waiters(lock) != 0)) {
|
||||
|
||||
fprintf(stderr, "RW-LOCK: %p ", lock);
|
||||
fprintf(stderr, "RW-LOCK: %p ", (void*) lock);
|
||||
|
||||
if (rw_lock_get_waiters(lock)) {
|
||||
fputs(" Waiters for the lock exist\n", stderr);
|
||||
@@ -823,7 +824,7 @@ rw_lock_print(
|
||||
fprintf(stderr,
|
||||
"-------------\n"
|
||||
"RW-LATCH INFO\n"
|
||||
"RW-LATCH: %p ", lock);
|
||||
"RW-LATCH: %p ", (void*) lock);
|
||||
|
||||
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
|
||||
|| (rw_lock_get_reader_count(lock) != 0)
|
||||
|
@@ -423,7 +423,7 @@ spin_loop:
|
||||
#ifdef UNIV_SRV_PRINT_LATCH_WAITS
|
||||
fprintf(stderr,
|
||||
"Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n",
|
||||
(ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
|
||||
(ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex,
|
||||
mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
|
||||
#endif
|
||||
|
||||
@@ -485,7 +485,7 @@ spin_loop:
|
||||
fprintf(stderr, "Thread %lu spin wait succeeds at 2:"
|
||||
" mutex at %p\n",
|
||||
(ulong) os_thread_pf(os_thread_get_curr_id()),
|
||||
mutex);
|
||||
(void*) mutex);
|
||||
#endif
|
||||
|
||||
goto finish_timing;
|
||||
@@ -503,7 +503,7 @@ spin_loop:
|
||||
#ifdef UNIV_SRV_PRINT_LATCH_WAITS
|
||||
fprintf(stderr,
|
||||
"Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
|
||||
(ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
|
||||
(ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex,
|
||||
mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
|
||||
#endif
|
||||
|
||||
@@ -666,7 +666,7 @@ mutex_list_print_info(void)
|
||||
&thread_id);
|
||||
fprintf(stderr,
|
||||
"Locked mutex: addr %p thread %ld file %s line %ld\n",
|
||||
mutex, os_thread_pf(thread_id),
|
||||
(void*) mutex, os_thread_pf(thread_id),
|
||||
file_name, line);
|
||||
}
|
||||
|
||||
@@ -852,10 +852,10 @@ sync_thread_levels_g(
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Locked mutex: addr %p thread %ld file %s line %ld\n",
|
||||
mutex, os_thread_pf(thread_id), file_name, (ulong) line);
|
||||
(void*) mutex, os_thread_pf(thread_id), file_name, (ulong) line);
|
||||
#else /* UNIV_SYNC_DEBUG */
|
||||
fprintf(stderr,
|
||||
"InnoDB: Locked mutex: addr %p\n", mutex);
|
||||
"InnoDB: Locked mutex: addr %p\n", (void*) mutex);
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
} else {
|
||||
fputs("Not locked\n", stderr);
|
||||
|
@@ -366,8 +366,6 @@ trx_free_for_mysql(
|
||||
/*===============*/
|
||||
trx_t* trx) /* in, own: trx object */
|
||||
{
|
||||
thr_local_free(trx->mysql_thread_id);
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
|
||||
UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx);
|
||||
@@ -1770,6 +1768,9 @@ trx_print(
|
||||
fprintf(f, "%lu lock struct(s), heap size %lu",
|
||||
(ulong) UT_LIST_GET_LEN(trx->trx_locks),
|
||||
(ulong) mem_heap_get_size(trx->lock_heap));
|
||||
|
||||
fprintf(f, "%lu row lock(s)",
|
||||
(ulong) lock_number_of_rows_locked(trx));
|
||||
}
|
||||
|
||||
if (trx->has_search_latch) {
|
||||
|
@@ -19,6 +19,6 @@ include ../include/Makefile.i
|
||||
|
||||
noinst_LIBRARIES = libut.a
|
||||
|
||||
libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c
|
||||
libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c ut0vec.c
|
||||
|
||||
EXTRA_PROGRAMS =
|
||||
|
@@ -437,3 +437,96 @@ ut_memcpyq(
|
||||
|
||||
return(dest);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Return the number of times s2 occurs in s1. Overlapping instances of s2
|
||||
are only counted once. */
|
||||
|
||||
ulint
|
||||
ut_strcount(
|
||||
/*========*/
|
||||
/* out: the number of times s2 occurs in s1 */
|
||||
const char* s1, /* in: string to search in */
|
||||
const char* s2) /* in: string to search for */
|
||||
{
|
||||
ulint count = 0;
|
||||
ulint len = strlen(s2);
|
||||
|
||||
if (len == 0) {
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
s1 = strstr(s1, s2);
|
||||
|
||||
if (!s1) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
s1 += len;
|
||||
}
|
||||
|
||||
return(count);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
|
||||
are only replaced once. */
|
||||
|
||||
char *
|
||||
ut_strreplace(
|
||||
/*==========*/
|
||||
/* out, own: modified string, must be
|
||||
freed with mem_free() */
|
||||
const char* str, /* in: string to operate on */
|
||||
const char* s1, /* in: string to replace */
|
||||
const char* s2) /* in: string to replace s1 with */
|
||||
{
|
||||
char* new_str;
|
||||
char* ptr;
|
||||
const char* str_end;
|
||||
ulint str_len = strlen(str);
|
||||
ulint s1_len = strlen(s1);
|
||||
ulint s2_len = strlen(s2);
|
||||
ulint count = 0;
|
||||
int len_delta = (int)s2_len - (int)s1_len;
|
||||
|
||||
str_end = str + str_len;
|
||||
|
||||
if (len_delta <= 0) {
|
||||
len_delta = 0;
|
||||
} else {
|
||||
count = ut_strcount(str, s1);
|
||||
}
|
||||
|
||||
new_str = mem_alloc(str_len + count * len_delta + 1);
|
||||
ptr = new_str;
|
||||
|
||||
while (str) {
|
||||
const char* next = strstr(str, s1);
|
||||
|
||||
if (!next) {
|
||||
next = str_end;
|
||||
}
|
||||
|
||||
memcpy(ptr, str, next - str);
|
||||
ptr += next - str;
|
||||
|
||||
if (next == str_end) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(ptr, s2, s2_len);
|
||||
ptr += s2_len;
|
||||
|
||||
str = next + s1_len;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
return(new_str);
|
||||
}
|
||||
|
54
storage/innobase/ut/ut0vec.c
Normal file
54
storage/innobase/ut/ut0vec.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "ut0vec.h"
|
||||
#ifdef UNIV_NONINL
|
||||
#include "ut0vec.ic"
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
/********************************************************************
|
||||
Create a new vector with the given initial size. */
|
||||
|
||||
ib_vector_t*
|
||||
ib_vector_create(
|
||||
/*=============*/
|
||||
/* out: vector */
|
||||
mem_heap_t* heap, /* in: heap */
|
||||
ulint size) /* in: initial size */
|
||||
{
|
||||
ib_vector_t* vec;
|
||||
|
||||
ut_a(size > 0);
|
||||
|
||||
vec = mem_heap_alloc(heap, sizeof(*vec));
|
||||
|
||||
vec->heap = heap;
|
||||
vec->data = mem_heap_alloc(heap, sizeof(void*) * size);
|
||||
vec->used = 0;
|
||||
vec->total = size;
|
||||
|
||||
return(vec);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Push a new element to the vector, increasing its size if necessary. */
|
||||
|
||||
void
|
||||
ib_vector_push(
|
||||
/*===========*/
|
||||
ib_vector_t* vec, /* in: vector */
|
||||
void* elem) /* in: data element */
|
||||
{
|
||||
if (vec->used >= vec->total) {
|
||||
void** new_data;
|
||||
ulint new_total = vec->total * 2;
|
||||
|
||||
new_data = mem_heap_alloc(vec->heap,
|
||||
sizeof(void*) * new_total);
|
||||
memcpy(new_data, vec->data, sizeof(void*) * vec->total);
|
||||
|
||||
vec->data = new_data;
|
||||
vec->total = new_total;
|
||||
}
|
||||
|
||||
vec->data[vec->used] = elem;
|
||||
vec->used++;
|
||||
}
|
Reference in New Issue
Block a user