Merge bk-internal.mysql.com:/home/bk/mysql-5.1

into  mockturtle.local:/home/dlenev/src/mysql-5.1-rt-merge


mysql-test/r/ps.result:
  Auto merged
mysql-test/t/ps.test:
  Auto merged
sql/item.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/opt_range.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
This commit is contained in:
unknown 2006-10-02 21:41:35 +04:00
commit 21070e43ef
76 changed files with 1578 additions and 602 deletions

View file

@ -225,6 +225,7 @@ extern int heap_indexes_are_disabled(HP_INFO *info);
extern void heap_update_auto_increment(HP_INFO *info, const byte *record);
ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
key_range *max_key);
int hp_panic(enum ha_panic_function flag);
int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
uint key_len, enum ha_rkey_function find_flag);
extern gptr heap_find(HP_INFO *info,int inx,const byte *key);

View file

@ -301,7 +301,6 @@ struct st_mysql_ftparser
struct st_mysql_storage_engine
{
int interface_version;
struct handlerton *handlerton;
};
#endif

View file

@ -755,6 +755,27 @@ select export_set(5, name, upper(name), ",", 5) from bug20536;
export_set(5, name, upper(name), ",", 5)
test1,TEST1,test1,TEST1,TEST1
'test\_2','TEST\_2','test\_2','TEST\_2','TEST\_2'
CREATE TABLE t1 (
status enum('active','passive') collate latin1_general_ci
NOT NULL default 'passive'
);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`status` enum('active','passive') CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL DEFAULT 'passive'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 ADD a int NOT NULL AFTER status;
CREATE TABLE t2 (
status enum('active','passive') collate ucs2_turkish_ci
NOT NULL default 'passive'
);
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`status` enum('active','passive') CHARACTER SET ucs2 COLLATE ucs2_turkish_ci NOT NULL DEFAULT 'passive'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t2 ADD a int NOT NULL AFTER status;
DROP TABLE t1,t2;
select password(name) from bug20536;
password(name)
????????????????????

View file

@ -660,3 +660,12 @@ CHAR_LENGTH( GROUP_CONCAT(b) )
240001
SET GROUP_CONCAT_MAX_LEN = 1024;
DROP TABLE t1;
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (2,1), (1,2), (2,2), (1,3);
SELECT GROUP_CONCAT(a), x
FROM (SELECT a, GROUP_CONCAT(b) x FROM t1 GROUP BY a) AS s
GROUP BY x;
GROUP_CONCAT(a) x
2 1,2
1 2,3
DROP TABLE t1;

View file

@ -851,8 +851,8 @@ CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,1),(1,2),(2,3);
SELECT (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a;
(SELECT COUNT(DISTINCT t1.b))
0
2
1
SELECT (SELECT COUNT(DISTINCT 12)) FROM t1 GROUP BY t1.a;
(SELECT COUNT(DISTINCT 12))
1
@ -1004,7 +1004,7 @@ SELECT SQL_NO_CACHE
WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid
FROM t1 t, t2 c WHERE t.a = c.b;
minid
NULL
1
DROP TABLE t1,t2;
create table t1 select variance(0);
show create table t1;

View file

@ -343,3 +343,71 @@ some_id
1
2
drop table t1;
create table t1(f1 char(1));
insert into t1 values ('a'),('b'),('1');
select f1 from t1 where f1 in ('a',1);
f1
a
1
select f1, case f1 when 'a' then '+' when 1 then '-' end from t1;
f1 case f1 when 'a' then '+' when 1 then '-' end
a +
b NULL
1 -
create index t1f1_idx on t1(f1);
select f1 from t1 where f1 in ('a',1);
f1
1
a
explain select f1 from t1 where f1 in ('a',1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL t1f1_idx 2 NULL 3 Using where; Using index
select f1 from t1 where f1 in ('a','b');
f1
a
b
explain select f1 from t1 where f1 in ('a','b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index
select f1 from t1 where f1 in (2,1);
f1
1
explain select f1 from t1 where f1 in (2,1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index
create table t2(f2 int, index t2f2(f2));
insert into t2 values(0),(1),(2);
select f2 from t2 where f2 in ('a',2);
f2
0
2
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'a'
explain select f2 from t2 where f2 in ('a',2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index
select f2 from t2 where f2 in ('a','b');
f2
0
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'b'
explain select f2 from t2 where f2 in ('a','b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'b'
select f2 from t2 where f2 in (1,'b');
f2
0
1
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'b'
Warning 1292 Truncated incorrect DOUBLE value: 'b'
explain select f2 from t2 where f2 in (1,'b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index
drop table t1, t2;

View file

@ -233,7 +233,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
@ -245,7 +245,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
@ -257,7 +257,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
@ -269,7 +269,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
set optimizer_search_depth=1;
select @@optimizer_search_depth;
@@optimizer_search_depth
@ -385,7 +385,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
@ -397,7 +397,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
@ -409,7 +409,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
@ -421,7 +421,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 274.418727
Last_query_cost 289.418727
set optimizer_prune_level=1;
select @@optimizer_prune_level;
@@optimizer_prune_level

View file

@ -776,3 +776,31 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL a,b NULL NULL NULL 1000 Using where
1 SIMPLE t3 ref b b 5 test.t2.b 1 Using where
drop table t1, t2, t3;
create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, primary key(a));
insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B;
explain select * from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
show status like '%cost%';
Variable_name Value
Last_query_cost 4.016090
select 'The cost of accessing t1 (dont care if it changes' '^';
The cost of accessing t1 (dont care if it changes
The cost of accessing t1 (dont care if it changes^
select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z;
Z
vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv
explain select * from t1, t2 A, t2 B where A.a = t1.a and B.a=A.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE A eq_ref PRIMARY PRIMARY 4 test.t1.a 1
1 SIMPLE B eq_ref PRIMARY PRIMARY 4 test.A.b 1
show status like '%cost%';
Variable_name Value
Last_query_cost 24.016090
select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z;
Z
^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error
drop table t1, t2;

View file

@ -495,17 +495,17 @@ gid sid uid
103853 5 250
EXPLAIN select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t1.gid, t3.uid;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index
1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 test.t1.gid 1
1 SIMPLE t2 ALL PRIMARY,uid NULL NULL NULL 6 Using temporary; Using filesort
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.gid 1 Using index
EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t1.gid,t3.skr;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 ALL PRIMARY NULL NULL NULL 6 Using temporary; Using filesort
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t3.uid 1 Using where; Using index
EXPLAIN SELECT t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index; Using temporary; Using filesort
1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 test.t1.gid 1
1 SIMPLE t2 ALL PRIMARY,uid NULL NULL NULL 6 Using temporary; Using filesort
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.gid 1 Using index
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index
EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t3.skr,t1.gid;
id select_type table type possible_keys key key_len ref rows Extra

View file

@ -68,7 +68,7 @@ create table t1 (a int)
engine = csv
partition by list (a)
(partition p0 values in (null));
ERROR HY000: CSV handler cannot be used in partitioned tables
ERROR HY000: Engine cannot be used in partitioned tables
create table t1 (a bigint)
partition by range (a)
(partition p0 values less than (0xFFFFFFFFFFFFFFFF),
@ -102,7 +102,7 @@ create table t1 (a int)
engine = csv
partition by list (a)
(partition p0 values in (null));
ERROR HY000: CSV handler cannot be used in partitioned tables
ERROR HY000: Engine cannot be used in partitioned tables
create table t1 (a int)
partition by key(a)
(partition p0 engine = MEMORY);
@ -1054,7 +1054,7 @@ drop table t1;
create table t1 (a int)
partition by key (a)
(partition p0 engine = MERGE);
ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables
ERROR HY000: Engine cannot be used in partitioned tables
create table t1 (a varchar(1))
partition by key (a)
as select 'a';

View file

@ -941,3 +941,17 @@ item started price
A1 2005-11-01 08:00:00 1000.000
A1 2005-11-15 00:00:00 2000.000
DROP TABLE t1;
create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, filler char(100));
insert into t2 select A.a + 10 * (B.a + 10 * C.a), 10, 'filler' from t1 A,
t1 B, t1 C where A.a < 5;
insert into t2 select 1000, b, 'filler' from t2;
alter table t2 add index (a,b);
select 'In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)' Z;
Z
In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)
explain select * from t2 where a=1000 and b<11;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref a a 5 const 502 Using where
drop table t1, t2;

View file

@ -1160,7 +1160,7 @@ Code2 char(2) NOT NULL default '',
PRIMARY KEY (Code)
) ENGINE=MyISAM;
INSERT INTO t2 VALUES ('AUS','Australia','Oceania','Australia and New Zealand',7741220.00,1901,18886000,79.8,351182.00,392911.00,'Australia','Constitutional Monarchy, Federation','Elisabeth II',135,'AU');
INSERT INTO t2 VALUES ('AZE','Azerbaijan','Asia','Middle East',86600.00,1991,7734000,62.9,4127.00,4100.00,'Azärbaycan','Federal Republic','Heydär Äliyev',144,'AZ');
INSERT INTO t2 VALUES ('AZE','Azerbaijan','Asia','Middle East',86600.00,1991,7734000,62.9,4127.00,4100.00,'Azärbaycan','Federal Republic','Heydär Äliyev',144,'AZ');
select t2.Continent, t1.Name, t1.Population from t2 LEFT JOIN t1 ON t2.Code = t1.t2 where t1.Population IN (select max(t1.Population) AS Population from t1, t2 where t1.t2 = t2.Code group by Continent);
Continent Name Population
Oceania Sydney 3276207
@ -2512,7 +2512,7 @@ Code2 char(2) NOT NULL default ''
) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('XXX','Xxxxx','Oceania','Xxxxxx',26.00,0,0,0,0,0,'Xxxxx','Xxxxx','Xxxxx',NULL,'XX');
INSERT INTO t1 VALUES ('ASM','American Samoa','Oceania','Polynesia',199.00,0,68000,75.1,334.00,NULL,'Amerika Samoa','US Territory','George W. Bush',54,'AS');
INSERT INTO t1 VALUES ('ATF','French Southern territories','Antarctica','Antarctica',7780.00,0,0,NULL,0.00,NULL,'Terres australes françaises','Nonmetropolitan Territory of France','Jacques Chirac',NULL,'TF');
INSERT INTO t1 VALUES ('ATF','French Southern territories','Antarctica','Antarctica',7780.00,0,0,NULL,0.00,NULL,'Terres australes françaises','Nonmetropolitan Territory of France','Jacques Chirac',NULL,'TF');
INSERT INTO t1 VALUES ('UMI','United States Minor Outlying Islands','Oceania','Micronesia/Caribbean',16.00,0,0,NULL,0.00,NULL,'United States Minor Outlying Islands','Dependent Territory of the US','George W. Bush',NULL,'UM');
/*!40000 ALTER TABLE t1 ENABLE KEYS */;
SELECT DISTINCT Continent AS c FROM t1 WHERE Code <> SOME ( SELECT Code FROM t1 WHERE Continent = c AND Population < 200);
@ -2966,6 +2966,42 @@ ORDER BY t2.c, t2.b LIMIT 1) WHERE t1.a = 10;
a a b
10 1 359
drop table t1,t2;
CREATE TABLE t1 (
field1 int NOT NULL,
field2 int NOT NULL,
field3 int NOT NULL,
PRIMARY KEY (field1,field2,field3)
);
CREATE TABLE t2 (
fieldA int NOT NULL,
fieldB int NOT NULL,
PRIMARY KEY (fieldA,fieldB)
);
INSERT INTO t1 VALUES
(1,1,1), (1,1,2), (1,2,1), (1,2,2), (1,2,3), (1,3,1);
INSERT INTO t2 VALUES (1,1), (1,2), (1,3);
SELECT field1, field2, COUNT(*)
FROM t1 GROUP BY field1, field2;
field1 field2 COUNT(*)
1 1 2
1 2 3
1 3 1
SELECT field1, field2
FROM t1
GROUP BY field1, field2
HAVING COUNT(*) >= ALL (SELECT fieldB
FROM t2 WHERE fieldA = field1);
field1 field2
1 2
SELECT field1, field2
FROM t1
GROUP BY field1, field2
HAVING COUNT(*) < ANY (SELECT fieldB
FROM t2 WHERE fieldA = field1);
field1 field2
1 1
1 3
DROP TABLE t1, t2;
create table t1 (df decimal(5,1));
insert into t1 values(1.1);
insert into t1 values(2.2);
@ -3422,3 +3458,64 @@ id select_type table type possible_keys key key_len ref rows Extra
4 UNION t12 system NULL NULL NULL NULL 0 const row not found
NULL UNION RESULT <union2,4> ALL NULL NULL NULL NULL NULL
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT);
CREATE TABLE t2 (a INT);
INSERT INTO t2 values (1);
INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(3,4);
SELECT (SELECT COUNT(DISTINCT t1.b) from t2) FROM t1 GROUP BY t1.a;
(SELECT COUNT(DISTINCT t1.b) from t2)
2
1
1
SELECT (SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3)
FROM t1 GROUP BY t1.a;
(SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3)
2
1
1
SELECT COUNT(DISTINCT t1.b), (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a;
COUNT(DISTINCT t1.b) (SELECT COUNT(DISTINCT t1.b))
2 2
1 1
1 1
SELECT COUNT(DISTINCT t1.b),
(SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3)
FROM t1 GROUP BY t1.a;
COUNT(DISTINCT t1.b) (SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3)
2 2
1 1
1 1
SELECT (
SELECT (
SELECT COUNT(DISTINCT t1.b)
)
)
FROM t1 GROUP BY t1.a;
(
SELECT (
SELECT COUNT(DISTINCT t1.b)
)
)
2
1
1
SELECT (
SELECT (
SELECT (
SELECT COUNT(DISTINCT t1.b)
)
)
FROM t1 GROUP BY t1.a LIMIT 1)
FROM t1 t2
GROUP BY t2.a;
(
SELECT (
SELECT (
SELECT COUNT(DISTINCT t1.b)
)
)
FROM t1 GROUP BY t1.a LIMIT 1)
2
2
2
DROP TABLE t1,t2;

View file

@ -472,11 +472,11 @@ create view v3 (x,y,z) as select b, a, b from t1;
create view v4 (x,y,z) as select c+1, b, a from t1;
create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
insert into v3 values (-60,4,30);
ERROR HY000: The target table v3 of the INSERT is not updatable
ERROR HY000: The target table v3 of the INSERT is not insertable-into
insert into v4 values (-60,4,30);
ERROR HY000: The target table v4 of the INSERT is not updatable
ERROR HY000: The target table v4 of the INSERT is not insertable-into
insert into v5 values (-60,4,30);
ERROR HY000: The target table v5 of the INSERT is not updatable
ERROR HY000: The target table v5 of the INSERT is not insertable-into
insert into v1 values (-60,4,30);
insert into v1 (z,y,x) values (50,6,-100);
insert into v2 values (5,40);
@ -499,11 +499,11 @@ create view v3 (x,y,z) as select b, a, b from t1;
create view v4 (x,y,z) as select c+1, b, a from t1;
create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
insert into v3 select c, b, a from t2;
ERROR HY000: The target table v3 of the INSERT is not updatable
ERROR HY000: The target table v3 of the INSERT is not insertable-into
insert into v4 select c, b, a from t2;
ERROR HY000: The target table v4 of the INSERT is not updatable
ERROR HY000: The target table v4 of the INSERT is not insertable-into
insert into v5 select c, b, a from t2;
ERROR HY000: The target table v5 of the INSERT is not updatable
ERROR HY000: The target table v5 of the INSERT is not insertable-into
insert into v1 select c, b, a from t2;
insert into v1 (z,y,x) select a+20,b+2,-100 from t2;
insert into v2 select b+1, a+10 from t2;
@ -1352,14 +1352,14 @@ drop table t1;
create table t1 (s1 smallint);
create view v1 as select * from t1 where 20 < (select (s1) from t1);
insert into v1 values (30);
ERROR HY000: The target table v1 of the INSERT is not updatable
ERROR HY000: The target table v1 of the INSERT is not insertable-into
create view v2 as select * from t1;
create view v3 as select * from t1 where 20 < (select (s1) from v2);
insert into v3 values (30);
ERROR HY000: The target table v3 of the INSERT is not updatable
ERROR HY000: The target table v3 of the INSERT is not insertable-into
create view v4 as select * from v2 where 20 < (select (s1) from t1);
insert into v4 values (30);
ERROR HY000: The target table v4 of the INSERT is not updatable
ERROR HY000: The target table v4 of the INSERT is not insertable-into
drop view v4, v3, v2, v1;
drop table t1;
create table t1 (a int);
@ -2911,7 +2911,7 @@ INSERT INTO v2 VALUES (0);
RETURN 0;
END |
SELECT f2();
ERROR HY000: The target table v2 of the INSERT is not updatable
ERROR HY000: The target table v2 of the INSERT is not insertable-into
DROP FUNCTION f1;
DROP FUNCTION f2;
DROP VIEW v1, v2;
@ -2935,4 +2935,25 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 3
DROP VIEW v1;
DROP TABLE t1;
create table t1 (s1 int);
create view v1 as select s1 as a, s1 as b from t1;
insert into v1 values (1,1);
ERROR HY000: The target table v1 of the INSERT is not insertable-into
update v1 set a = 5;
drop view v1;
drop table t1;
CREATE TABLE t1(pk int PRIMARY KEY);
CREATE TABLE t2(pk int PRIMARY KEY, fk int, ver int, org int);
CREATE ALGORITHM=MERGE VIEW v1 AS
SELECT t1.*
FROM t1 JOIN t2
ON t2.fk = t1.pk AND
t2.ver = (SELECT MAX(t.ver) FROM t2 t WHERE t.org = t2.org);
SHOW WARNINGS;
Level Code Message
SHOW CREATE VIEW v1;
View Create View
v1 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`pk` AS `pk` from (`t1` join `t2` on(((`t2`.`fk` = `t1`.`pk`) and (`t2`.`ver` = (select max(`t`.`ver`) AS `MAX(t.ver)` from `t2` `t` where (`t`.`org` = `t2`.`org`))))))
DROP VIEW v1;
DROP TABLE t1, t2;
End of 5.0 tests.

View file

@ -484,6 +484,27 @@ select make_set(3, name, upper(name)) from bug20536;
select export_set(5, name, upper(name)) from bug20536;
select export_set(5, name, upper(name), ",", 5) from bug20536;
#
# Bug #20108: corrupted default enum value for a ucs2 field
#
CREATE TABLE t1 (
status enum('active','passive') collate latin1_general_ci
NOT NULL default 'passive'
);
SHOW CREATE TABLE t1;
ALTER TABLE t1 ADD a int NOT NULL AFTER status;
CREATE TABLE t2 (
status enum('active','passive') collate ucs2_turkish_ci
NOT NULL default 'passive'
);
SHOW CREATE TABLE t2;
ALTER TABLE t2 ADD a int NOT NULL AFTER status;
DROP TABLE t1,t2;
# Some broken functions: add these tests just to document current behavior.
# PASSWORD and OLD_PASSWORD don't work with UCS2 strings, but to fix it would

View file

@ -447,3 +447,18 @@ SELECT a, CHAR_LENGTH(b) FROM t1;
SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1;
SET GROUP_CONCAT_MAX_LEN = 1024;
DROP TABLE t1;
#
# Bug #22015: crash with GROUP_CONCAT over a derived table that
# returns the results of aggregation by GROUP_CONCAT
#
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (2,1), (1,2), (2,2), (1,3);
SELECT GROUP_CONCAT(a), x
FROM (SELECT a, GROUP_CONCAT(b) x FROM t1 GROUP BY a) AS s
GROUP BY x;
DROP TABLE t1;

View file

@ -232,3 +232,27 @@ select some_id from t1 where some_id not in(2,-1);
select some_id from t1 where some_id not in(-4,-1,-4);
select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
drop table t1;
#
# Bug#18360: Type aggregation for IN and CASE may lead to a wrong result
#
create table t1(f1 char(1));
insert into t1 values ('a'),('b'),('1');
select f1 from t1 where f1 in ('a',1);
select f1, case f1 when 'a' then '+' when 1 then '-' end from t1;
create index t1f1_idx on t1(f1);
select f1 from t1 where f1 in ('a',1);
explain select f1 from t1 where f1 in ('a',1);
select f1 from t1 where f1 in ('a','b');
explain select f1 from t1 where f1 in ('a','b');
select f1 from t1 where f1 in (2,1);
explain select f1 from t1 where f1 in (2,1);
create table t2(f2 int, index t2f2(f2));
insert into t2 values(0),(1),(2);
select f2 from t2 where f2 in ('a',2);
explain select f2 from t2 where f2 in ('a',2);
select f2 from t2 where f2 in ('a','b');
explain select f2 from t2 where f2 in ('a','b');
select f2 from t2 where f2 in (1,'b');
explain select f2 from t2 where f2 in (1,'b');
drop table t1, t2;

View file

@ -609,3 +609,24 @@ explain select * from t2,t3 where t2.a < 200 and t2.b=t3.b;
drop table t1, t2, t3;
# BUG#14940 {Wrong query plan is chosen because of odd results of
# prev_record_reads() function }
create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, primary key(a));
insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B;
explain select * from t1;
show status like '%cost%';
select 'The cost of accessing t1 (dont care if it changes' '^';
select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z;
explain select * from t1, t2 A, t2 B where A.a = t1.a and B.a=A.b;
show status like '%cost%';
select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z;
drop table t1, t2;

View file

@ -988,6 +988,58 @@ execute stmt;
drop temporary table t1;
deallocate prepare stmt;
#
# BUG#22085: Crash on the execution of a prepared statement that
# uses an IN subquery with aggregate functions in HAVING
#
CREATE TABLE t1(
ID int(10) unsigned NOT NULL auto_increment,
Member_ID varchar(15) NOT NULL default '',
Action varchar(12) NOT NULL,
Action_Date datetime NOT NULL,
Track varchar(15) default NULL,
User varchar(12) default NULL,
Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update
CURRENT_TIMESTAMP,
PRIMARY KEY (ID),
KEY Action (Action),
KEY Action_Date (Action_Date)
);
INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES
('111111', 'Disenrolled', '2006-03-01', 'CAD' ),
('111111', 'Enrolled', '2006-03-01', 'CAD' ),
('111111', 'Disenrolled', '2006-07-03', 'CAD' ),
('222222', 'Enrolled', '2006-03-07', 'CAD' ),
('222222', 'Enrolled', '2006-03-07', 'CHF' ),
('222222', 'Disenrolled', '2006-08-02', 'CHF' ),
('333333', 'Enrolled', '2006-03-01', 'CAD' ),
('333333', 'Disenrolled', '2006-03-01', 'CAD' ),
('444444', 'Enrolled', '2006-03-01', 'CAD' ),
('555555', 'Disenrolled', '2006-03-01', 'CAD' ),
('555555', 'Enrolled', '2006-07-21', 'CAD' ),
('555555', 'Disenrolled', '2006-03-01', 'CHF' ),
('666666', 'Enrolled', '2006-02-09', 'CAD' ),
('666666', 'Enrolled', '2006-05-12', 'CHF' ),
('666666', 'Disenrolled', '2006-06-01', 'CAD' );
PREPARE STMT FROM
"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1
WHERE Member_ID=? AND Action='Enrolled' AND
(Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1
WHERE Member_ID=?
GROUP BY Track
HAVING Track>='CAD' AND
MAX(Action_Date)>'2006-03-01')";
SET @id='111111';
EXECUTE STMT USING @id,@id;
SET @id='222222';
EXECUTE STMT USING @id,@id;
DEALLOCATE PREPARE STMT;
DROP TABLE t1;
--echo End of 4.1 tests
############################# 5.0 tests start ################################
#

View file

@ -740,3 +740,30 @@ SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-02 00:00:00';
DROP TABLE t1;
# End of 5.0 tests
# BUG#22393 fix: Adjust 'ref' estimate if we have 'range' estimate for
# a smaller scan interval
create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, filler char(100));
insert into t2 select A.a + 10 * (B.a + 10 * C.a), 10, 'filler' from t1 A,
t1 B, t1 C where A.a < 5;
insert into t2 select 1000, b, 'filler' from t2;
alter table t2 add index (a,b);
# t2 values
# ( 1 , 10, 'filler')
# ( 2 , 10, 'filler')
# ( 3 , 10, 'filler')
# (... , 10, 'filler')
# ...
# (1000, 10, 'filler') - 500 times
# 500 rows, 1 row
select 'In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)' Z;
explain select * from t2 where a=1000 and b<11;
drop table t1, t2;

View file

@ -665,7 +665,7 @@ CREATE TABLE t2 (
) ENGINE=MyISAM;
INSERT INTO t2 VALUES ('AUS','Australia','Oceania','Australia and New Zealand',7741220.00,1901,18886000,79.8,351182.00,392911.00,'Australia','Constitutional Monarchy, Federation','Elisabeth II',135,'AU');
INSERT INTO t2 VALUES ('AZE','Azerbaijan','Asia','Middle East',86600.00,1991,7734000,62.9,4127.00,4100.00,'Azärbaycan','Federal Republic','Heydär Äliyev',144,'AZ');
INSERT INTO t2 VALUES ('AZE','Azerbaijan','Asia','Middle East',86600.00,1991,7734000,62.9,4127.00,4100.00,'Azärbaycan','Federal Republic','Heydär Äliyev',144,'AZ');
select t2.Continent, t1.Name, t1.Population from t2 LEFT JOIN t1 ON t2.Code = t1.t2 where t1.Population IN (select max(t1.Population) AS Population from t1, t2 where t1.t2 = t2.Code group by Continent);
@ -1526,7 +1526,7 @@ CREATE TABLE t1 (
) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('XXX','Xxxxx','Oceania','Xxxxxx',26.00,0,0,0,0,0,'Xxxxx','Xxxxx','Xxxxx',NULL,'XX');
INSERT INTO t1 VALUES ('ASM','American Samoa','Oceania','Polynesia',199.00,0,68000,75.1,334.00,NULL,'Amerika Samoa','US Territory','George W. Bush',54,'AS');
INSERT INTO t1 VALUES ('ATF','French Southern territories','Antarctica','Antarctica',7780.00,0,0,NULL,0.00,NULL,'Terres australes françaises','Nonmetropolitan Territory of France','Jacques Chirac',NULL,'TF');
INSERT INTO t1 VALUES ('ATF','French Southern territories','Antarctica','Antarctica',7780.00,0,0,NULL,0.00,NULL,'Terres australes françaises','Nonmetropolitan Territory of France','Jacques Chirac',NULL,'TF');
INSERT INTO t1 VALUES ('UMI','United States Minor Outlying Islands','Oceania','Micronesia/Caribbean',16.00,0,0,NULL,0.00,NULL,'United States Minor Outlying Islands','Dependent Territory of the US','George W. Bush',NULL,'UM');
/*!40000 ALTER TABLE t1 ENABLE KEYS */;
SELECT DISTINCT Continent AS c FROM t1 WHERE Code <> SOME ( SELECT Code FROM t1 WHERE Continent = c AND Population < 200);
@ -1918,6 +1918,43 @@ SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r
drop table t1,t2;
#
# Bug #21853: assert failure for a grouping query with
# an ALL/ANY quantified subquery in HAVING
#
CREATE TABLE t1 (
field1 int NOT NULL,
field2 int NOT NULL,
field3 int NOT NULL,
PRIMARY KEY (field1,field2,field3)
);
CREATE TABLE t2 (
fieldA int NOT NULL,
fieldB int NOT NULL,
PRIMARY KEY (fieldA,fieldB)
);
INSERT INTO t1 VALUES
(1,1,1), (1,1,2), (1,2,1), (1,2,2), (1,2,3), (1,3,1);
INSERT INTO t2 VALUES (1,1), (1,2), (1,3);
SELECT field1, field2, COUNT(*)
FROM t1 GROUP BY field1, field2;
SELECT field1, field2
FROM t1
GROUP BY field1, field2
HAVING COUNT(*) >= ALL (SELECT fieldB
FROM t2 WHERE fieldA = field1);
SELECT field1, field2
FROM t1
GROUP BY field1, field2
HAVING COUNT(*) < ANY (SELECT fieldB
FROM t2 WHERE fieldA = field1);
DROP TABLE t1, t2;
# End of 4.1 tests
#
@ -2332,3 +2369,34 @@ explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12));
DROP TABLE t1;
#
# Bug #21540: Subqueries with no from and aggregate functions return
# wrong results
CREATE TABLE t1 (a INT, b INT);
CREATE TABLE t2 (a INT);
INSERT INTO t2 values (1);
INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(3,4);
SELECT (SELECT COUNT(DISTINCT t1.b) from t2) FROM t1 GROUP BY t1.a;
SELECT (SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3)
FROM t1 GROUP BY t1.a;
SELECT COUNT(DISTINCT t1.b), (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a;
SELECT COUNT(DISTINCT t1.b),
(SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3)
FROM t1 GROUP BY t1.a;
SELECT (
SELECT (
SELECT COUNT(DISTINCT t1.b)
)
)
FROM t1 GROUP BY t1.a;
SELECT (
SELECT (
SELECT (
SELECT COUNT(DISTINCT t1.b)
)
)
FROM t1 GROUP BY t1.a LIMIT 1)
FROM t1 t2
GROUP BY t2.a;
DROP TABLE t1,t2;

View file

@ -347,13 +347,13 @@ create view v3 (x,y,z) as select b, a, b from t1;
create view v4 (x,y,z) as select c+1, b, a from t1;
create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
# try insert to VIEW with fields duplicate
-- error 1288
-- error 1573
insert into v3 values (-60,4,30);
# try insert to VIEW with expression in SELECT list
-- error 1288
-- error 1573
insert into v4 values (-60,4,30);
# try insert to VIEW using temporary table algorithm
-- error 1288
-- error 1573
insert into v5 values (-60,4,30);
insert into v1 values (-60,4,30);
insert into v1 (z,y,x) values (50,6,-100);
@ -375,13 +375,13 @@ create view v3 (x,y,z) as select b, a, b from t1;
create view v4 (x,y,z) as select c+1, b, a from t1;
create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
# try insert to VIEW with fields duplicate
-- error 1288
-- error 1573
insert into v3 select c, b, a from t2;
# try insert to VIEW with expression in SELECT list
-- error 1288
-- error 1573
insert into v4 select c, b, a from t2;
# try insert to VIEW using temporary table algorithm
-- error 1288
-- error 1573
insert into v5 select c, b, a from t2;
insert into v1 select c, b, a from t2;
insert into v1 (z,y,x) select a+20,b+2,-100 from t2;
@ -1249,14 +1249,14 @@ drop table t1;
#
create table t1 (s1 smallint);
create view v1 as select * from t1 where 20 < (select (s1) from t1);
-- error 1288
-- error 1573
insert into v1 values (30);
create view v2 as select * from t1;
create view v3 as select * from t1 where 20 < (select (s1) from v2);
-- error 1288
-- error 1573
insert into v3 values (30);
create view v4 as select * from v2 where 20 < (select (s1) from t1);
-- error 1288
-- error 1573
insert into v4 values (30);
drop view v4, v3, v2, v1;
drop table t1;
@ -2443,7 +2443,7 @@ DROP TABLE t1, t2;
#
# Bug #16069: VIEW does return the same results as underlying SELECT
# with WHERE condition containing BETWEEN over dates
# Dates as strings should be casted to date type
CREATE TABLE t1 (id int NOT NULL PRIMARY KEY,
td date DEFAULT NULL, KEY idx(td));
@ -2830,7 +2830,7 @@ BEGIN
END |
delimiter ;|
--error ER_NON_UPDATABLE_TABLE
--error ER_NON_INSERTABLE_TABLE
SELECT f2();
DROP FUNCTION f1;
@ -2855,4 +2855,33 @@ EXPLAIN SELECT * FROM v1 t WHERE t.s1+1 < (SELECT MAX(t1.s1) FROM t1);
DROP VIEW v1;
DROP TABLE t1;
#
# Bug #5505: Wrong error message on INSERT into a view
#
create table t1 (s1 int);
create view v1 as select s1 as a, s1 as b from t1;
--error 1573
insert into v1 values (1,1);
update v1 set a = 5;
drop view v1;
drop table t1;
#
# Bug #21646: view qith a subquery in ON expression
#
CREATE TABLE t1(pk int PRIMARY KEY);
CREATE TABLE t2(pk int PRIMARY KEY, fk int, ver int, org int);
CREATE ALGORITHM=MERGE VIEW v1 AS
SELECT t1.*
FROM t1 JOIN t2
ON t2.fk = t1.pk AND
t2.ver = (SELECT MAX(t.ver) FROM t2 t WHERE t.org = t2.org);
SHOW WARNINGS;
SHOW CREATE VIEW v1;
DROP VIEW v1;
DROP TABLE t1, t2;
--echo End of 5.0 tests.

View file

@ -46,7 +46,9 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
DBUG_PRINT("my",("fd: %d length: %lu MyFlags: %d",fd,(ulong) newlength,
MyFlags));
oldsize = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
if ((oldsize = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE))) == newlength)
DBUG_RETURN(0);
DBUG_PRINT("info",("old_size: %ld", (ulong) oldsize));
if (oldsize > newlength)

View file

@ -1522,6 +1522,8 @@ public:
uint decimals, flags, pack_length, key_length;
Field::utype unireg_check;
TYPELIB *interval; // Which interval to use
TYPELIB *save_interval; // Temporary copy for the above
// Used only for UCS2 intervals
List<String> interval_list;
CHARSET_INFO *charset;
Field::geometry_type geom_type;

View file

@ -1345,6 +1345,7 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
switch ((sortorder->result_type=sortorder->item->result_type())) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
set_if_smaller(sortorder->length, thd->variables.max_sort_length);
if (use_strnxfrm((cs=sortorder->item->collation.collation)))
{
sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);

View file

@ -75,17 +75,25 @@ static const int max_transactions= 3; // should really be 2 but there is a trans
static uint ndbcluster_partition_flags();
static uint ndbcluster_alter_table_flags(uint flags);
static int ndbcluster_init(void *);
static int ndbcluster_end(ha_panic_function flag);
static bool ndbcluster_show_status(THD*,stat_print_fn *,enum ha_stat_type);
static int ndbcluster_alter_tablespace(THD* thd, st_alter_tablespace *info);
static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond);
static int ndbcluster_end(handlerton *hton, ha_panic_function flag);
static bool ndbcluster_show_status(handlerton *hton, THD*,
stat_print_fn *,
enum ha_stat_type);
static int ndbcluster_alter_tablespace(handlerton *hton,
THD* thd,
st_alter_tablespace *info);
static int ndbcluster_fill_files_table(handlerton *hton,
THD *thd,
TABLE_LIST *tables,
COND *cond);
handlerton *ndbcluster_hton;
static handler *ndbcluster_create_handler(TABLE_SHARE *table,
static handler *ndbcluster_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_ndbcluster(table);
return new (mem_root) ha_ndbcluster(hton, table);
}
static uint ndbcluster_partition_flags()
@ -4201,7 +4209,7 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
Commit a transaction started in NDB
*/
static int ndbcluster_commit(THD *thd, bool all)
static int ndbcluster_commit(handlerton *hton, THD *thd, bool all)
{
int res= 0;
Thd_ndb *thd_ndb= get_thd_ndb(thd);
@ -4252,7 +4260,7 @@ static int ndbcluster_commit(THD *thd, bool all)
Rollback a transaction started in NDB
*/
static int ndbcluster_rollback(THD *thd, bool all)
static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all)
{
int res= 0;
Thd_ndb *thd_ndb= get_thd_ndb(thd);
@ -5552,8 +5560,8 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
HA_HAS_OWN_BINLOGGING | \
HA_HAS_RECORDS
ha_ndbcluster::ha_ndbcluster(TABLE_SHARE *table_arg):
handler(ndbcluster_hton, table_arg),
ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
handler(hton, table_arg),
m_active_trans(NULL),
m_active_cursor(NULL),
m_table(NULL),
@ -5816,7 +5824,7 @@ int ha_ndbcluster::check_ndb_connection(THD* thd)
}
static int ndbcluster_close_connection(THD *thd)
static int ndbcluster_close_connection(handlerton *hton, THD *thd)
{
Thd_ndb *thd_ndb= get_thd_ndb(thd);
DBUG_ENTER("ndbcluster_close_connection");
@ -5833,8 +5841,10 @@ static int ndbcluster_close_connection(THD *thd)
Try to discover one table from NDB
*/
int ndbcluster_discover(THD* thd, const char *db, const char *name,
const void** frmblob, uint* frmlen)
int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
const char *name,
const void** frmblob,
uint* frmlen)
{
int error= 0;
NdbError ndb_error;
@ -5914,7 +5924,8 @@ err:
*/
int ndbcluster_table_exists_in_engine(THD* thd, const char *db,
int ndbcluster_table_exists_in_engine(handlerton *hton, THD* thd,
const char *db,
const char *name)
{
Ndb* ndb;
@ -6014,7 +6025,7 @@ int ndbcluster_drop_database_impl(const char *path)
DBUG_RETURN(ret);
}
static void ndbcluster_drop_database(char *path)
static void ndbcluster_drop_database(handlerton *hton, char *path)
{
THD *thd= current_thd;
DBUG_ENTER("ndbcluster_drop_database");
@ -6175,7 +6186,9 @@ int ndbcluster_find_all_files(THD *thd)
DBUG_RETURN(-(skipped + unhandled));
}
int ndbcluster_find_files(THD *thd,const char *db,const char *path,
int ndbcluster_find_files(handlerton *hton, THD *thd,
const char *db,
const char *path,
const char *wild, bool dir, List<char> *files)
{
DBUG_ENTER("ndbcluster_find_files");
@ -6285,7 +6298,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
DBUG_PRINT("info", ("%s existed on disk", name));
// The .ndb file exists on disk, but it's not in list of tables in ndb
// Verify that handler agrees table is gone.
if (ndbcluster_table_exists_in_engine(thd, db, file_name) == 0)
if (ndbcluster_table_exists_in_engine(hton, thd, db, file_name) == 0)
{
DBUG_PRINT("info", ("NDB says %s does not exists", file_name));
it.remove();
@ -6539,7 +6552,7 @@ ndbcluster_init_error:
DBUG_RETURN(TRUE);
}
static int ndbcluster_end(ha_panic_function type)
static int ndbcluster_end(handlerton *hton, ha_panic_function type)
{
DBUG_ENTER("ndbcluster_end");
@ -6623,7 +6636,7 @@ void ndbcluster_print_error(int error, const NdbOperation *error_op)
share.db.length= 0;
share.table_name.str= (char *) tab_name;
share.table_name.length= strlen(tab_name);
ha_ndbcluster error_handler(&share);
ha_ndbcluster error_handler(ndbcluster_hton, &share);
error_handler.print_error(error, MYF(0));
DBUG_VOID_RETURN;
}
@ -9703,7 +9716,7 @@ err:
Implements the SHOW NDB STATUS command.
*/
bool
ndbcluster_show_status(THD* thd, stat_print_fn *stat_print,
ndbcluster_show_status(handlerton *hton, THD* thd, stat_print_fn *stat_print,
enum ha_stat_type stat_type)
{
char buf[IO_SIZE];
@ -10167,7 +10180,7 @@ bool set_up_undofile(st_alter_tablespace *info,
return false;
}
int ndbcluster_alter_tablespace(THD* thd, st_alter_tablespace *info)
int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace *info)
{
DBUG_ENTER("ha_ndbcluster::alter_tablespace");
@ -10428,7 +10441,9 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
DBUG_RETURN(TRUE);
}
static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables,
static int ndbcluster_fill_files_table(handlerton *hton,
THD *thd,
TABLE_LIST *tables,
COND *cond)
{
TABLE* table= tables->table;
@ -10749,7 +10764,7 @@ SHOW_VAR ndb_status_variables_export[]= {
};
struct st_mysql_storage_engine ndbcluster_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, ndbcluster_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(ndbcluster)
{

View file

@ -627,7 +627,7 @@ class Thd_ndb
class ha_ndbcluster: public handler
{
public:
ha_ndbcluster(TABLE_SHARE *table);
ha_ndbcluster(handlerton *hton, TABLE_SHARE *table);
~ha_ndbcluster();
int ha_initialise();

View file

@ -506,7 +506,7 @@ ndbcluster_binlog_index_purge_file(THD *thd, const char *file)
}
static void
ndbcluster_binlog_log_query(THD *thd, enum_binlog_command binlog_command,
ndbcluster_binlog_log_query(handlerton *hton, THD *thd, enum_binlog_command binlog_command,
const char *query, uint query_length,
const char *db, const char *table_name)
{
@ -637,7 +637,9 @@ static void ndbcluster_reset_slave(THD *thd)
/*
Initialize the binlog part of the ndb handlerton
*/
static int ndbcluster_binlog_func(THD *thd, enum_binlog_func fn, void *arg)
static int ndbcluster_binlog_func(handlerton *hton, THD *thd,
enum_binlog_func fn,
void *arg)
{
switch(fn)
{

View file

@ -31,6 +31,8 @@ extern ulong ndb_extra_logging;
#define NDB_INVALID_SCHEMA_OBJECT 241
extern handlerton *ndbcluster_hton;
/*
The numbers below must not change as they
are passed between mysql servers, and if changed
@ -103,7 +105,6 @@ extern pthread_mutex_t injector_mutex;
extern pthread_cond_t injector_cond;
extern unsigned char g_node_id_map[max_ndb_nodes];
extern handlerton *ndbcluster_hton;
extern pthread_t ndb_util_thread;
extern pthread_mutex_t LOCK_ndb_util_thread;
extern pthread_cond_t COND_ndb_util_thread;

View file

@ -69,16 +69,17 @@ static PARTITION_SHARE *get_share(const char *table_name, TABLE * table);
MODULE create/delete handler object
****************************************************************************/
static handler *partition_create_handler(TABLE_SHARE *share,
static handler *partition_create_handler(handlerton *hton,
TABLE_SHARE *share,
MEM_ROOT *mem_root);
static uint partition_flags();
static uint alter_table_flags(uint flags);
handlerton *partition_hton;
static int partition_initialize(void *p)
{
handlerton *partition_hton;
partition_hton= (handlerton *)p;
partition_hton->state= SHOW_OPTION_YES;
@ -102,10 +103,11 @@ static int partition_initialize(void *p)
New partition object
*/
static handler *partition_create_handler(TABLE_SHARE *share,
static handler *partition_create_handler(handlerton *hton,
TABLE_SHARE *share,
MEM_ROOT *mem_root)
{
ha_partition *file= new (mem_root) ha_partition(share);
ha_partition *file= new (mem_root) ha_partition(hton, share);
if (file && file->initialise_partition(mem_root))
{
delete file;
@ -155,8 +157,8 @@ static uint alter_table_flags(uint flags __attribute__((unused)))
NONE
*/
ha_partition::ha_partition(TABLE_SHARE *share)
:handler(partition_hton, share), m_part_info(NULL), m_create_handler(FALSE),
ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
:handler(hton, share), m_part_info(NULL), m_create_handler(FALSE),
m_is_sub_partitioned(0)
{
DBUG_ENTER("ha_partition::ha_partition(table)");
@ -176,8 +178,8 @@ ha_partition::ha_partition(TABLE_SHARE *share)
NONE
*/
ha_partition::ha_partition(partition_info *part_info)
:handler(partition_hton, NULL), m_part_info(part_info),
ha_partition::ha_partition(handlerton *hton, partition_info *part_info)
:handler(hton, NULL), m_part_info(part_info),
m_create_handler(TRUE),
m_is_sub_partitioned(m_part_info->is_sub_partitioned())
@ -5632,7 +5634,7 @@ static int free_share(PARTITION_SHARE *share)
#endif /* NOT_USED */
struct st_mysql_storage_engine partition_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, partition_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(partition)
{

View file

@ -149,8 +149,8 @@ public:
partition handler.
-------------------------------------------------------------------------
*/
ha_partition(TABLE_SHARE * table);
ha_partition(partition_info * part_info);
ha_partition(handlerton *hton, TABLE_SHARE * table);
ha_partition(handlerton *hton, partition_info * part_info);
~ha_partition();
/*
A partition handler has no characteristics in itself. It only inherits

View file

@ -170,7 +170,7 @@ const char *ha_get_storage_engine(enum legacy_db_type db_type)
static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
handlerton *hton= ha_default_handlerton(current_thd);
return (hton && hton->create) ? hton->create(table, mem_root) : NULL;
return (hton && hton->create) ? hton->create(hton, table, mem_root) : NULL;
}
@ -232,7 +232,7 @@ handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
{
if ((file= db_type->create(share, alloc)))
if ((file= db_type->create(db_type, share, alloc)))
file->init();
DBUG_RETURN(file);
}
@ -251,7 +251,7 @@ handler *get_ha_partition(partition_info *part_info)
{
ha_partition *partition;
DBUG_ENTER("get_ha_partition");
if ((partition= new ha_partition(part_info)))
if ((partition= new ha_partition(partition_hton, part_info)))
{
if (partition->initialise_partition(current_thd->mem_root))
{
@ -376,7 +376,7 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
case SHOW_OPTION_YES:
if (installed_htons[hton->db_type] == hton)
installed_htons[hton->db_type]= NULL;
if (hton->panic && hton->panic(HA_PANIC_CLOSE))
if (hton->panic && hton->panic(hton, HA_PANIC_CLOSE))
DBUG_RETURN(1);
break;
};
@ -465,6 +465,26 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
hton->state= SHOW_OPTION_DISABLED;
break;
}
/*
This is entirely for legacy. We will create a new "disk based" hton and a
"memory" hton which will be configurable longterm. We should be able to
remove partition and myisammrg.
*/
switch (hton->db_type) {
case DB_TYPE_HEAP:
heap_hton= hton;
break;
case DB_TYPE_MYISAM:
myisam_hton= hton;
break;
case DB_TYPE_PARTITION_DB:
partition_hton= hton;
break;
default:
break;
};
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@ -498,7 +518,7 @@ static my_bool panic_handlerton(THD *unused1, st_plugin_int *plugin, void *arg)
{
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->panic)
((int*)arg)[0]|= hton->panic((enum ha_panic_function)((int*)arg)[1]);
((int*)arg)[0]|= hton->panic(hton, (enum ha_panic_function)((int*)arg)[1]);
return FALSE;
}
@ -520,7 +540,7 @@ static my_bool dropdb_handlerton(THD *unused1, st_plugin_int *plugin,
{
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->drop_database)
hton->drop_database((char *)path);
hton->drop_database(hton, (char *)path);
return FALSE;
}
@ -541,7 +561,7 @@ static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin,
*/
if (hton->state == SHOW_OPTION_YES && hton->close_connection &&
thd->ha_data[hton->slot])
hton->close_connection(thd);
hton->close_connection(hton, thd);
return FALSE;
}
@ -617,7 +637,7 @@ int ha_prepare(THD *thd)
statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status);
if ((*ht)->prepare)
{
if ((err= (*(*ht)->prepare)(thd, all)))
if ((err= (*(*ht)->prepare)(*ht, thd, all)))
{
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
ha_rollback_trans(thd, all);
@ -691,7 +711,7 @@ int ha_commit_trans(THD *thd, bool all)
for (; *ht && !error; ht++)
{
int err;
if ((err= (*(*ht)->prepare)(thd, all)))
if ((err= (*(*ht)->prepare)(*ht, thd, all)))
{
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error= 1;
@ -738,7 +758,7 @@ int ha_commit_one_phase(THD *thd, bool all)
for (ht=trans->ht; *ht; ht++)
{
int err;
if ((err= (*(*ht)->commit)(thd, all)))
if ((err= (*(*ht)->commit)(*ht, thd, all)))
{
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error=1;
@ -794,7 +814,7 @@ int ha_rollback_trans(THD *thd, bool all)
for (handlerton **ht=trans->ht; *ht; ht++)
{
int err;
if ((err= (*(*ht)->rollback)(thd, all)))
if ((err= (*(*ht)->rollback)(*ht, thd, all)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
@ -871,7 +891,7 @@ static my_bool xacommit_handlerton(THD *unused1, st_plugin_int *plugin,
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
hton->commit_by_xid(((struct xahton_st *)arg)->xid);
hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid);
((struct xahton_st *)arg)->result= 0;
}
return FALSE;
@ -883,7 +903,7 @@ static my_bool xarollback_handlerton(THD *unused1, st_plugin_int *plugin,
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
hton->rollback_by_xid(((struct xahton_st *)arg)->xid);
hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid);
((struct xahton_st *)arg)->result= 0;
}
return FALSE;
@ -993,7 +1013,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin,
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
while ((got= hton->recover(info->list, info->len)) > 0 )
while ((got= hton->recover(hton, info->list, info->len)) > 0 )
{
sql_print_information("Found %d prepared transaction(s) in %s",
got, hton2plugin[hton->slot]->name.str);
@ -1024,7 +1044,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin,
char buf[XIDDATASIZE*4+6]; // see xid_to_str
sql_print_information("commit xid %s", xid_to_str(buf, info->list+i));
#endif
hton->commit_by_xid(info->list+i);
hton->commit_by_xid(hton, info->list+i);
}
else
{
@ -1033,7 +1053,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin,
sql_print_information("rollback xid %s",
xid_to_str(buf, info->list+i));
#endif
hton->rollback_by_xid(info->list+i);
hton->rollback_by_xid(hton, info->list+i);
}
}
if (got < info->len)
@ -1179,7 +1199,7 @@ static my_bool release_temporary_latches(THD *thd, st_plugin_int *plugin,
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches)
hton->release_temporary_latches(thd);
hton->release_temporary_latches(hton, thd);
return FALSE;
}
@ -1212,7 +1232,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
{
int err;
DBUG_ASSERT((*ht)->savepoint_set != 0);
if ((err= (*(*ht)->savepoint_rollback)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
if ((err= (*(*ht)->savepoint_rollback)(*ht, thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
@ -1228,7 +1248,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
for (; *ht ; ht++)
{
int err;
if ((err= (*(*ht)->rollback)(thd, !thd->in_sub_stmt)))
if ((err= (*(*ht)->rollback)(*ht, thd, !thd->in_sub_stmt)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
@ -1262,7 +1282,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
error=1;
break;
}
if ((err= (*(*ht)->savepoint_set)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
if ((err= (*(*ht)->savepoint_set)(*ht, thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
error=1;
@ -1288,7 +1308,9 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
int err;
if (!(*ht)->savepoint_release)
continue;
if ((err= (*(*ht)->savepoint_release)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
if ((err= (*(*ht)->savepoint_release)(*ht, thd,
(byte *)(sv+1)+
(*ht)->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
error=1;
@ -1305,7 +1327,7 @@ static my_bool snapshot_handlerton(THD *thd, st_plugin_int *plugin,
if (hton->state == SHOW_OPTION_YES &&
hton->start_consistent_snapshot)
{
hton->start_consistent_snapshot(thd);
hton->start_consistent_snapshot(hton, thd);
*((bool *)arg)= false;
}
return FALSE;
@ -1333,7 +1355,8 @@ static my_bool flush_handlerton(THD *thd, st_plugin_int *plugin,
void *arg)
{
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->flush_logs && hton->flush_logs())
if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
hton->flush_logs(hton))
return TRUE;
return FALSE;
}
@ -1350,7 +1373,7 @@ bool ha_flush_logs(handlerton *db_type)
else
{
if (db_type->state != SHOW_OPTION_YES ||
(db_type->flush_logs && db_type->flush_logs()))
(db_type->flush_logs && db_type->flush_logs(db_type)))
return TRUE;
}
return FALSE;
@ -2765,7 +2788,9 @@ static my_bool discover_handlerton(THD *thd, st_plugin_int *plugin,
st_discover_args *vargs= (st_discover_args *)arg;
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->discover &&
(!(hton->discover(thd, vargs->db, vargs->name, vargs->frmblob, vargs->frmlen))))
(!(hton->discover(hton, thd, vargs->db, vargs->name,
vargs->frmblob,
vargs->frmlen))))
return TRUE;
return FALSE;
@ -2814,7 +2839,7 @@ static my_bool find_files_handlerton(THD *thd, st_plugin_int *plugin,
if (hton->state == SHOW_OPTION_YES && hton->find_files)
if (hton->find_files(thd, vargs->db, vargs->path, vargs->wild,
if (hton->find_files(hton, thd, vargs->db, vargs->path, vargs->wild,
vargs->dir, vargs->files))
return TRUE;
@ -2861,7 +2886,7 @@ static my_bool table_exists_in_engine_handlerton(THD *thd, st_plugin_int *plugin
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine)
if ((hton->table_exists_in_engine(thd, vargs->db, vargs->name)) == 1)
if ((hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name)) == 1)
return TRUE;
return FALSE;
@ -2930,7 +2955,7 @@ static my_bool binlog_func_foreach(THD *thd, binlog_func_st *bfn)
uint i= 0, sz= hton_list.sz;
while(i < sz)
hton_list.hton[i++]->binlog_func(thd, bfn->fn, bfn->arg);
hton_list.hton[i++]->binlog_func(hton, thd, bfn->fn, bfn->arg);
return FALSE;
}
@ -2977,12 +3002,12 @@ struct binlog_log_query_st
};
static my_bool binlog_log_query_handlerton2(THD *thd,
const handlerton *hton,
handlerton *hton,
void *args)
{
struct binlog_log_query_st *b= (struct binlog_log_query_st*)args;
if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query)
hton->binlog_log_query(thd,
hton->binlog_log_query(hton, thd,
b->binlog_command,
b->query,
b->query_length,
@ -2995,10 +3020,10 @@ static my_bool binlog_log_query_handlerton(THD *thd,
st_plugin_int *plugin,
void *args)
{
return binlog_log_query_handlerton2(thd, (const handlerton *)plugin->data, args);
return binlog_log_query_handlerton2(thd, (handlerton *)plugin->data, args);
}
void ha_binlog_log_query(THD *thd, const handlerton *hton,
void ha_binlog_log_query(THD *thd, handlerton *hton,
enum_binlog_command binlog_command,
const char *query, uint query_length,
const char *db, const char *table_name)
@ -3296,7 +3321,7 @@ static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin,
handlerton *hton= (handlerton *)plugin->data;
handler *file;
if (hton->state == SHOW_OPTION_YES && hton->create &&
(file= hton->create((TABLE_SHARE*) 0, current_thd->mem_root)))
(file= hton->create(hton, (TABLE_SHARE*) 0, current_thd->mem_root)))
{
List_iterator_fast<char> it(*found_exts);
const char **ext, *old_ext;
@ -3371,7 +3396,7 @@ static my_bool showstat_handlerton(THD *thd, st_plugin_int *plugin,
enum ha_stat_type stat= *(enum ha_stat_type *) arg;
handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->show_status &&
hton->show_status(thd, stat_print, stat))
hton->show_status(hton, thd, stat_print, stat))
return TRUE;
return FALSE;
}
@ -3405,7 +3430,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
}
else
result= db_type->show_status &&
db_type->show_status(thd, stat_print, stat) ? 1 : 0;
db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
}
if (!result)
@ -3726,7 +3751,7 @@ int example_of_iterator_using_for_logs_cleanup(handlerton *hton)
if (!hton->create_iterator)
return 1; /* iterator creator is not supported */
if ((*hton->create_iterator)(HA_TRANSACTLOG_ITERATOR, &iterator) !=
if ((*hton->create_iterator)(hton, HA_TRANSACTLOG_ITERATOR, &iterator) !=
HA_ITERATOR_OK)
{
/* error during creation of log iterator or iterator is not supported */

View file

@ -449,7 +449,7 @@ class st_alter_tablespace : public Sql_alloc
ulonglong autoextend_size;
ulonglong max_size;
uint nodegroup_id;
const handlerton *storage_engine;
handlerton *storage_engine;
bool wait_until_completed;
const char *ts_comment;
enum tablespace_access_mode ts_access_mode;
@ -605,18 +605,18 @@ struct handlerton
this storage area - set it to something, so that MySQL would know
this storage engine was accessed in this connection
*/
int (*close_connection)(THD *thd);
int (*close_connection)(handlerton *hton, THD *thd);
/*
sv points to an uninitialized storage area of requested size
(see savepoint_offset description)
*/
int (*savepoint_set)(THD *thd, void *sv);
int (*savepoint_set)(handlerton *hton, THD *thd, void *sv);
/*
sv points to a storage area, that was earlier passed
to the savepoint_set call
*/
int (*savepoint_rollback)(THD *thd, void *sv);
int (*savepoint_release)(THD *thd, void *sv);
int (*savepoint_rollback)(handlerton *hton, THD *thd, void *sv);
int (*savepoint_release)(handlerton *hton, THD *thd, void *sv);
/*
'all' is true if it's a real commit, that makes persistent changes
'all' is false if it's not in fact a commit but an end of the
@ -624,25 +624,25 @@ struct handlerton
NOTE 'all' is also false in auto-commit mode where 'end of statement'
and 'real commit' mean the same event.
*/
int (*commit)(THD *thd, bool all);
int (*rollback)(THD *thd, bool all);
int (*prepare)(THD *thd, bool all);
int (*recover)(XID *xid_list, uint len);
int (*commit_by_xid)(XID *xid);
int (*rollback_by_xid)(XID *xid);
void *(*create_cursor_read_view)();
void (*set_cursor_read_view)(void *);
void (*close_cursor_read_view)(void *);
handler *(*create)(TABLE_SHARE *table, MEM_ROOT *mem_root);
void (*drop_database)(char* path);
int (*panic)(enum ha_panic_function flag);
int (*start_consistent_snapshot)(THD *thd);
bool (*flush_logs)();
bool (*show_status)(THD *thd, stat_print_fn *print, enum ha_stat_type stat);
int (*commit)(handlerton *hton, THD *thd, bool all);
int (*rollback)(handlerton *hton, THD *thd, bool all);
int (*prepare)(handlerton *hton, THD *thd, bool all);
int (*recover)(handlerton *hton, XID *xid_list, uint len);
int (*commit_by_xid)(handlerton *hton, XID *xid);
int (*rollback_by_xid)(handlerton *hton, XID *xid);
void *(*create_cursor_read_view)(handlerton *hton, THD *thd);
void (*set_cursor_read_view)(handlerton *hton, THD *thd, void *read_view);
void (*close_cursor_read_view)(handlerton *hton, THD *thd, void *read_view);
handler *(*create)(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root);
void (*drop_database)(handlerton *hton, char* path);
int (*panic)(handlerton *hton, enum ha_panic_function flag);
int (*start_consistent_snapshot)(handlerton *hton, THD *thd);
bool (*flush_logs)(handlerton *hton);
bool (*show_status)(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat);
uint (*partition_flags)();
uint (*alter_table_flags)(uint flags);
int (*alter_tablespace)(THD *thd, st_alter_tablespace *ts_info);
int (*fill_files_table)(THD *thd,
int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info);
int (*fill_files_table)(handlerton *hton, THD *thd,
struct st_table_list *tables,
class Item *cond);
uint32 flags; /* global handler flags */
@ -650,11 +650,12 @@ struct handlerton
Those handlerton functions below are properly initialized at handler
init.
*/
int (*binlog_func)(THD *thd, enum_binlog_func fn, void *arg);
void (*binlog_log_query)(THD *thd, enum_binlog_command binlog_command,
int (*binlog_func)(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg);
void (*binlog_log_query)(handlerton *hton, THD *thd,
enum_binlog_command binlog_command,
const char *query, uint query_length,
const char *db, const char *table_name);
int (*release_temporary_latches)(THD *thd);
int (*release_temporary_latches)(handlerton *hton, THD *thd);
/*
Get log status.
@ -663,20 +664,24 @@ struct handlerton
(see example of implementation in handler.cc, TRANS_LOG_MGM_EXAMPLE_CODE)
*/
enum log_status (*get_log_status)(char *log);
enum log_status (*get_log_status)(handlerton *hton, char *log);
/*
Iterators creator.
Presence of the pointer should be checked before using
*/
enum handler_create_iterator_result
(*create_iterator)(enum handler_iterator_type type,
(*create_iterator)(handlerton *hton, enum handler_iterator_type type,
struct handler_iterator *fill_this_in);
int (*discover)(THD* thd, const char *db, const char *name,
const void** frmblob, uint* frmlen);
int (*find_files)(THD *thd,const char *db,const char *path,
int (*discover)(handlerton *hton, THD* thd, const char *db,
const char *name,
const void** frmblob,
uint* frmlen);
int (*find_files)(handlerton *hton, THD *thd,
const char *db,
const char *path,
const char *wild, bool dir, List<char> *files);
int (*table_exists_in_engine)(THD* thd, const char *db,
int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db,
const char *name);
};
@ -691,6 +696,7 @@ struct handlerton
#define HTON_NOT_USER_SELECTABLE (1 << 5)
#define HTON_TEMPORARY_NOT_SUPPORTED (1 << 6) //Having temporary tables not supported
#define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables
#define HTON_NO_PARTITION (1 << 8) //You can not partition these tables
typedef struct st_thd_trans
{
@ -893,7 +899,7 @@ class handler :public Sql_alloc
virtual void start_bulk_insert(ha_rows rows) {}
virtual int end_bulk_insert() {return 0; }
public:
const handlerton *ht; /* storage engine of this handler */
handlerton *ht; /* storage engine of this handler */
byte *ref; /* Pointer to current row */
byte *dup_ref; /* Pointer to duplicate row */
@ -943,7 +949,7 @@ public:
*/
Discrete_interval auto_inc_interval_for_cur_row;
handler(const handlerton *ht_arg, TABLE_SHARE *share_arg)
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
:table_share(share_arg), estimation_rows_to_insert(0), ht(ht_arg),
ref(0), key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
ref_length(sizeof(my_off_t)),
@ -1716,7 +1722,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht);
int ha_reset_logs(THD *thd);
int ha_binlog_index_purge_file(THD *thd, const char *file);
void ha_reset_slave(THD *thd);
void ha_binlog_log_query(THD *thd, const handlerton *db_type,
void ha_binlog_log_query(THD *thd, handlerton *db_type,
enum_binlog_command binlog_command,
const char *query, uint query_length,
const char *db, const char *table_name);

View file

@ -1210,6 +1210,7 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
split_sum_func(thd, ref_pointer_array, fields);
}
else if ((type() == SUM_FUNC_ITEM || (used_tables() & ~PARAM_TABLE_BIT)) &&
type() != SUBSELECT_ITEM &&
(type() != REF_ITEM ||
((Item_ref*)this)->ref_type() == Item_ref::VIEW_REF))
{
@ -5711,11 +5712,6 @@ void Item_trigger_field::cleanup()
}
/*
If item is a const function, calculate it and return a const item
The original item is freed if not returned
*/
Item_result item_cmp_type(Item_result a,Item_result b)
{
if (a == STRING_RESULT && b == STRING_RESULT)

View file

@ -66,12 +66,10 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
/*
Aggregates result types from the array of items.
SYNOPSIS:
SYNOPSIS
agg_cmp_type()
thd thread handle
type [out] the aggregated type
items array of items to aggregate the type from
nitems number of items in the array
items array of items to aggregate the type from
nitems number of items in the array
DESCRIPTION
This function aggregates result types from the array of items. Found type
@ -79,12 +77,43 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
Aggregation itself is performed by the item_cmp_type() function.
*/
static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
static Item_result agg_cmp_type(Item **items, uint nitems)
{
uint i;
type[0]= items[0]->result_type();
Item_result type= items[0]->result_type();
for (i= 1 ; i < nitems ; i++)
type[0]= item_cmp_type(type[0], items[i]->result_type());
type= item_cmp_type(type, items[i]->result_type());
return type;
}
/*
Collects different types for comparison of first item with each other items
SYNOPSIS
collect_cmp_types()
items Array of items to collect types from
nitems Number of items in the array
DESCRIPTION
This function collects different result types for comparison of the first
item in the list with each of the remaining items in the 'items' array.
RETURN
Bitmap of collected types
*/
static uint collect_cmp_types(Item **items, uint nitems)
{
uint i;
uint found_types;
Item_result left_result= items[0]->result_type();
DBUG_ASSERT(nitems > 1);
found_types= 0;
for (i= 1; i < nitems ; i++)
found_types|= 1<< (uint)item_cmp_type(left_result,
items[i]->result_type());
return found_types;
}
@ -1117,7 +1146,7 @@ void Item_func_between::fix_length_and_dec()
*/
if (!args[0] || !args[1] || !args[2])
return;
agg_cmp_type(thd, &cmp_type, args, 3);
cmp_type= agg_cmp_type(args, 3);
if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
return;
@ -1597,94 +1626,65 @@ Item_func_nullif::is_null()
return (null_value= (!cmp.compare() ? 1 : args[0]->null_value));
}
/*
CASE expression
Return the matching ITEM or NULL if all compares (including else) failed
SYNOPSIS
find_item()
str Buffer string
DESCRIPTION
Find and return matching items for CASE or ELSE item if all compares
are failed or NULL if ELSE item isn't defined.
IMPLEMENTATION
In order to do correct comparisons of the CASE expression (the expression
between CASE and the first WHEN) with each WHEN expression several
comparators are used. One for each result type. CASE expression can be
evaluated up to # of different result types are used. To check whether
the CASE expression already was evaluated for a particular result type
a bit mapped variable value_added_map is used. Result types are mapped
to it according to their int values i.e. STRING_RESULT is mapped to bit
0, REAL_RESULT to bit 1, so on.
RETURN
NULL - Nothing found and there is no ELSE expression defined
item - Found item or ELSE item if defined and all comparisons are
failed
*/
Item *Item_func_case::find_item(String *str)
{
String *first_expr_str, *tmp;
my_decimal *first_expr_dec, first_expr_dec_val;
longlong first_expr_int;
double first_expr_real;
char buff[MAX_FIELD_WIDTH];
String buff_str(buff,sizeof(buff),default_charset());
uint value_added_map= 0;
/* These will be initialized later */
LINT_INIT(first_expr_str);
LINT_INIT(first_expr_int);
LINT_INIT(first_expr_real);
LINT_INIT(first_expr_dec);
if (first_expr_num != -1)
if (first_expr_num == -1)
{
switch (cmp_type)
{
case STRING_RESULT:
// We can't use 'str' here as this may be overwritten
if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str)))
return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible
break;
case INT_RESULT:
first_expr_int= args[first_expr_num]->val_int();
if (args[first_expr_num]->null_value)
return else_expr_num != -1 ? args[else_expr_num] : 0;
break;
case REAL_RESULT:
first_expr_real= args[first_expr_num]->val_real();
if (args[first_expr_num]->null_value)
return else_expr_num != -1 ? args[else_expr_num] : 0;
break;
case DECIMAL_RESULT:
first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val);
if (args[first_expr_num]->null_value)
return else_expr_num != -1 ? args[else_expr_num] : 0;
break;
case ROW_RESULT:
default:
// This case should never be chosen
DBUG_ASSERT(0);
break;
}
}
// Compare every WHEN argument with it and return the first match
for (uint i=0 ; i < ncases ; i+=2)
{
if (first_expr_num == -1)
for (uint i=0 ; i < ncases ; i+=2)
{
// No expression between CASE and the first WHEN
if (args[i]->val_bool())
return args[i+1];
continue;
}
switch (cmp_type) {
case STRING_RESULT:
if ((tmp=args[i]->val_str(str))) // If not null
if (sortcmp(tmp,first_expr_str,cmp_collation.collation)==0)
return args[i+1];
break;
case INT_RESULT:
if (args[i]->val_int()==first_expr_int && !args[i]->null_value)
return args[i+1];
break;
case REAL_RESULT:
if (args[i]->val_real() == first_expr_real && !args[i]->null_value)
return args[i+1];
break;
case DECIMAL_RESULT:
}
else
{
/* Compare every WHEN argument with it and return the first match */
for (uint i=0 ; i < ncases ; i+=2)
{
my_decimal value;
if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0)
return args[i+1];
break;
}
case ROW_RESULT:
default:
// This case should never be chosen
DBUG_ASSERT(0);
break;
cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
DBUG_ASSERT(cmp_type != ROW_RESULT);
DBUG_ASSERT(cmp_items[(uint)cmp_type]);
if (!(value_added_map & (1<<(uint)cmp_type)))
{
cmp_items[(uint)cmp_type]->store_value(args[first_expr_num]);
if ((null_value=args[first_expr_num]->null_value))
return else_expr_num != -1 ? args[else_expr_num] : 0;
value_added_map|= 1<<(uint)cmp_type;
}
if (!cmp_items[(uint)cmp_type]->cmp(args[i]) && !args[i]->null_value)
return args[i + 1];
}
}
// No, WHEN clauses all missed, return ELSE expression
@ -1791,7 +1791,7 @@ void Item_func_case::fix_length_and_dec()
Item **agg;
uint nagg;
THD *thd= current_thd;
uint found_types= 0;
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return;
@ -1818,16 +1818,31 @@ void Item_func_case::fix_length_and_dec()
*/
if (first_expr_num != -1)
{
uint i;
agg[0]= args[first_expr_num];
left_result_type= agg[0]->result_type();
for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2];
nagg++;
agg_cmp_type(thd, &cmp_type, agg, nagg);
if ((cmp_type == STRING_RESULT) &&
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
return;
found_types= collect_cmp_types(agg, nagg);
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
if ((Item_result)i == STRING_RESULT &&
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
return;
if (!(cmp_items[i]=
cmp_item::get_comparator((Item_result)i,
cmp_collation.collation)))
return;
}
}
}
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
maybe_null=1;
@ -2412,16 +2427,14 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
void Item_func_in::fix_length_and_dec()
{
Item **arg, **arg_end;
uint const_itm= 1;
bool const_itm= 1;
THD *thd= current_thd;
uint found_types= 0;
uint type_cnt= 0, i;
left_result_type= args[0]->result_type();
found_types= collect_cmp_types(args, arg_count);
agg_cmp_type(thd, &cmp_type, args, arg_count);
if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
return;
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++)
{
if (!arg[0]->const_item())
{
@ -2429,26 +2442,39 @@ void Item_func_in::fix_length_and_dec()
break;
}
}
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
if (found_types & 1 << i)
(type_cnt)++;
}
/*
Row item with NULLs inside can return NULL or FALSE =>
Row item with NULLs inside can return NULL or FALSE =>
they can't be processed as static
*/
if (const_itm && !nulls_in_row())
if (type_cnt == 1 && const_itm && !nulls_in_row())
{
uint tmp_type;
Item_result cmp_type;
/* Only one cmp type was found. Extract it here */
for (tmp_type= 0; found_types - 1; found_types>>= 1)
tmp_type++;
cmp_type= (Item_result)tmp_type;
switch (cmp_type) {
case STRING_RESULT:
array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
return;
array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in,
cmp_collation.collation);
break;
case INT_RESULT:
array= new in_longlong(arg_count-1);
array= new in_longlong(arg_count - 1);
break;
case REAL_RESULT:
array= new in_double(arg_count-1);
array= new in_double(arg_count - 1);
break;
case ROW_RESULT:
array= new in_row(arg_count-1, args[0]);
array= new in_row(arg_count - 1, args[0]);
break;
case DECIMAL_RESULT:
array= new in_decimal(arg_count - 1);
@ -2468,15 +2494,25 @@ void Item_func_in::fix_length_and_dec()
else
have_null= 1;
}
if ((array->used_count=j))
if ((array->used_count= j))
array->sort();
}
}
else
{
in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation);
if (cmp_type == STRING_RESULT)
in_item->cmp_charset= cmp_collation.collation;
for (i= 0; i <= (uint) DECIMAL_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
if ((Item_result)i == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
return;
if (!(cmp_items[i]=
cmp_item::get_comparator((Item_result)i,
cmp_collation.collation)))
return;
}
}
}
maybe_null= args[0]->maybe_null;
max_length= 1;
@ -2495,25 +2531,61 @@ void Item_func_in::print(String *str)
}
/*
Evaluate the function and return its value.
SYNOPSIS
val_int()
DESCRIPTION
Evaluate the function and return its value.
IMPLEMENTATION
If the array object is defined then the value of the function is
calculated by means of this array.
Otherwise several cmp_item objects are used in order to do correct
comparison of left expression and an expression from the values list.
One cmp_item object correspond to one used comparison type. Left
expression can be evaluated up to number of different used comparison
types. A bit mapped variable value_added_map is used to check whether
the left expression already was evaluated for a particular result type.
Result types are mapped to it according to their integer values i.e.
STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on.
RETURN
Value of the function
*/
longlong Item_func_in::val_int()
{
cmp_item *in_item;
DBUG_ASSERT(fixed == 1);
uint value_added_map= 0;
if (array)
{
int tmp=array->find(args[0]);
null_value=args[0]->null_value || (!tmp && have_null);
return (longlong) (!null_value && tmp != negated);
}
in_item->store_value(args[0]);
if ((null_value=args[0]->null_value))
return 0;
have_null= 0;
for (uint i=1 ; i < arg_count ; i++)
for (uint i= 1 ; i < arg_count ; i++)
{
Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
in_item= cmp_items[(uint)cmp_type];
DBUG_ASSERT(in_item);
if (!(value_added_map & (1 << (uint)cmp_type)))
{
in_item->store_value(args[0]);
if ((null_value=args[0]->null_value))
return 0;
have_null= 0;
value_added_map|= 1 << (uint)cmp_type;
}
if (!in_item->cmp(args[i]) && !args[i]->null_value)
return (longlong) (!negated);
have_null|= args[i]->null_value;
}
null_value= have_null;
return (longlong) (!null_value && negated);
}

View file

@ -589,49 +589,6 @@ public:
};
class Item_func_case :public Item_func
{
int first_expr_num, else_expr_num;
enum Item_result cached_result_type;
String tmp_value;
uint ncases;
Item_result cmp_type;
DTCollation cmp_collation;
public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
:Item_func(), first_expr_num(-1), else_expr_num(-1),
cached_result_type(INT_RESULT)
{
ncases= list.elements;
if (first_expr_arg)
{
first_expr_num= list.elements;
list.push_back(first_expr_arg);
}
if (else_expr_arg)
{
else_expr_num= list.elements;
list.push_back(else_expr_arg);
}
set_arguments(list);
}
double val_real();
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
uint decimal_precision() const;
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; }
void print(String *str);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
/* Functions to handle the optimized IN */
@ -686,6 +643,7 @@ public:
{
return test(compare(collation, base + pos1*size, base + pos2*size));
}
virtual Item_result result_type()= 0;
};
class in_string :public in_vector
@ -707,6 +665,7 @@ public:
Item_string *to= (Item_string*)item;
to->str_value= *str;
}
Item_result result_type() { return STRING_RESULT; }
};
class in_longlong :public in_vector
@ -729,6 +688,7 @@ public:
{
((Item_int*)item)->value= ((longlong*)base)[pos];
}
Item_result result_type() { return INT_RESULT; }
};
class in_double :public in_vector
@ -746,6 +706,7 @@ public:
{
((Item_float*)item)->value= ((double*) base)[pos];
}
Item_result result_type() { return REAL_RESULT; }
};
@ -766,6 +727,8 @@ public:
Item_decimal *item_dec= (Item_decimal*)item;
item_dec->set_decimal_value(dec);
}
Item_result result_type() { return DECIMAL_RESULT; }
};
@ -796,7 +759,9 @@ class cmp_item_string :public cmp_item
protected:
String *value_res;
public:
cmp_item_string () {}
cmp_item_string (CHARSET_INFO *cs) { cmp_charset= cs; }
void set_charset(CHARSET_INFO *cs) { cmp_charset= cs; }
friend class cmp_item_sort_string;
friend class cmp_item_sort_string_in_static;
};
@ -807,6 +772,8 @@ protected:
char value_buff[STRING_BUFFER_USUAL_SIZE];
String value;
public:
cmp_item_sort_string():
cmp_item_string() {}
cmp_item_sort_string(CHARSET_INFO *cs):
cmp_item_string(cs),
value(value_buff, sizeof(value_buff), cs) {}
@ -828,6 +795,11 @@ public:
return sortcmp(value_res, cmp->value_res, cmp_charset);
}
cmp_item *make_same();
void set_charset(CHARSET_INFO *cs)
{
cmp_charset= cs;
value.set_quick(value_buff, sizeof(value_buff), cs);
}
};
class cmp_item_int :public cmp_item
@ -908,6 +880,7 @@ public:
~in_row();
void set(uint pos,Item *item);
byte *get_value(Item *item);
Item_result result_type() { return ROW_RESULT; }
};
/*
@ -943,18 +916,109 @@ public:
}
};
/*
The class Item_func_case is the CASE ... WHEN ... THEN ... END function
implementation.
When there is no expression between CASE and the first WHEN
(the CASE expression) then this function simple checks all WHEN expressions
one after another. When some WHEN expression evaluated to TRUE then the
value of the corresponding THEN expression is returned.
When the CASE expression is specified then it is compared to each WHEN
expression individually. When an equal WHEN expression is found
corresponding THEN expression is returned.
In order to do correct comparisons several comparators are used. One for
each result type. Different result types that are used in particular
CASE ... END expression are collected in the fix_length_and_dec() member
function and only comparators for there result types are used.
*/
class Item_func_case :public Item_func
{
int first_expr_num, else_expr_num;
enum Item_result cached_result_type, left_result_type;
String tmp_value;
uint ncases;
Item_result cmp_type;
DTCollation cmp_collation;
cmp_item *cmp_items[5]; /* For all result types */
cmp_item *case_item;
public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
:Item_func(), first_expr_num(-1), else_expr_num(-1),
cached_result_type(INT_RESULT), left_result_type(INT_RESULT), case_item(0)
{
ncases= list.elements;
if (first_expr_arg)
{
first_expr_num= list.elements;
list.push_back(first_expr_arg);
}
if (else_expr_arg)
{
else_expr_num= list.elements;
list.push_back(else_expr_arg);
}
set_arguments(list);
bzero(&cmp_items, sizeof(cmp_items));
}
double val_real();
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
uint decimal_precision() const;
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; }
void print(String *str);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
bool check_partition_func_processor(byte *bool_arg) { return 0;}
void cleanup()
{
uint i;
DBUG_ENTER("Item_func_case::cleanup");
Item_func::cleanup();
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
}
DBUG_VOID_RETURN;
}
};
/*
The Item_func_in class implements the in_expr IN(values_list) function.
The current implementation distinguishes 2 cases:
1) all items in the value_list are constants and have the same
result type. This case is handled by in_vector class.
2) items in the value_list have different result types or there is some
non-constant items.
In this case Item_func_in employs several cmp_item objects to performs
comparisons of in_expr and an item from the values_list. One cmp_item
object for each result type. Different result types are collected in the
fix_length_and_dec() member function by means of collect_cmp_types()
function.
*/
class Item_func_in :public Item_func_opt_neg
{
public:
Item_result cmp_type;
in_vector *array;
cmp_item *in_item;
bool have_null;
Item_result left_result_type;
cmp_item *cmp_items[5]; /* One cmp_item for each result type */
DTCollation cmp_collation;
Item_func_in(List<Item> &list)
:Item_func_opt_neg(list), array(0), in_item(0), have_null(0)
:Item_func_opt_neg(list), array(0), have_null(0)
{
bzero(&cmp_items, sizeof(cmp_items));
allowed_arg_cols= 0; // Fetch this value from first argument
}
longlong val_int();
@ -963,12 +1027,16 @@ public:
uint decimal_precision() const { return 1; }
void cleanup()
{
uint i;
DBUG_ENTER("Item_func_in::cleanup");
Item_int_func::cleanup();
delete array;
delete in_item;
array= 0;
in_item= 0;
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
}
DBUG_VOID_RETURN;
}
optimize_type select_optimize() const

View file

@ -246,7 +246,27 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
aggr_sl->inner_sum_func_list->next= this;
}
aggr_sl->inner_sum_func_list= this;
aggr_sl->with_sum_func= 1;
/*
Mark Item_subselect(s) as containing aggregate function all the way up
to aggregate function's calculation context.
Note that we must not mark the Item of calculation context itself
because with_sum_func on the calculation context st_select_lex is
already set above.
with_sum_func being set for an Item means that this Item refers
(somewhere in it, e.g. one of its arguments if it's a function) directly
or through intermediate items to an aggregate function that is calculated
in a context "outside" of the Item (e.g. in the current or outer select).
with_sum_func being set for an st_select_lex means that this st_select_lex
has aggregate functions directly referenced (i.e. not through a sub-select).
*/
for (sl= thd->lex->current_select;
sl && sl != aggr_sl && sl->master_unit()->item;
sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1;
}
return FALSE;
}

View file

@ -46,13 +46,13 @@ static Muted_query_log_event invisible_commit;
static bool test_if_number(const char *str,
long *res, bool allow_wildcards);
static int binlog_init();
static int binlog_close_connection(THD *thd);
static int binlog_savepoint_set(THD *thd, void *sv);
static int binlog_savepoint_rollback(THD *thd, void *sv);
static int binlog_commit(THD *thd, bool all);
static int binlog_rollback(THD *thd, bool all);
static int binlog_prepare(THD *thd, bool all);
static int binlog_init(void *p);
static int binlog_close_connection(handlerton *hton, THD *thd);
static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
static int binlog_commit(handlerton *hton, THD *thd, bool all);
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
sql_print_message_func sql_print_message_handlers[3] =
{
@ -1171,7 +1171,7 @@ int binlog_init(void *p)
return 0;
}
static int binlog_close_connection(THD *thd)
static int binlog_close_connection(handlerton *hton, THD *thd)
{
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
@ -1184,7 +1184,8 @@ static int binlog_close_connection(THD *thd)
}
static int
binlog_end_trans(THD *thd, binlog_trx_data *trx_data, Log_event *end_ev)
binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
Log_event *end_ev)
{
DBUG_ENTER("binlog_end_trans");
int error=0;
@ -1238,7 +1239,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, Log_event *end_ev)
DBUG_RETURN(error);
}
static int binlog_prepare(THD *thd, bool all)
static int binlog_prepare(handlerton *hton, THD *thd, bool all)
{
/*
do nothing.
@ -1249,7 +1250,7 @@ static int binlog_prepare(THD *thd, bool all)
return 0;
}
static int binlog_commit(THD *thd, bool all)
static int binlog_commit(handlerton *hton, THD *thd, bool all)
{
DBUG_ENTER("binlog_commit");
binlog_trx_data *const trx_data=
@ -1273,7 +1274,7 @@ static int binlog_commit(THD *thd, bool all)
DBUG_RETURN(binlog_end_trans(thd, trx_data, &invisible_commit));
}
static int binlog_rollback(THD *thd, bool all)
static int binlog_rollback(handlerton *hton, THD *thd, bool all)
{
DBUG_ENTER("binlog_rollback");
int error=0;
@ -1326,7 +1327,7 @@ static int binlog_rollback(THD *thd, bool all)
that case there is no need to have it in the binlog).
*/
static int binlog_savepoint_set(THD *thd, void *sv)
static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
{
DBUG_ENTER("binlog_savepoint_set");
binlog_trx_data *const trx_data=
@ -1342,7 +1343,7 @@ static int binlog_savepoint_set(THD *thd, void *sv)
DBUG_RETURN(error);
}
static int binlog_savepoint_rollback(THD *thd, void *sv)
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
{
DBUG_ENTER("binlog_savepoint_rollback");
binlog_trx_data *const trx_data=
@ -4678,7 +4679,7 @@ err1:
}
struct st_mysql_storage_engine binlog_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, binlog_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(binlog)
{

View file

@ -458,7 +458,8 @@ enum enum_parsing_place
NO_MATTER,
IN_HAVING,
SELECT_LIST,
IN_WHERE
IN_WHERE,
IN_ON
};
struct st_table;
@ -1637,19 +1638,7 @@ extern SHOW_COMP_OPTION have_ndbcluster;
extern SHOW_COMP_OPTION have_partition_db;
extern SHOW_COMP_OPTION have_merge_db;
#ifdef WITH_CSV_STORAGE_ENGINE
extern handlerton *tina_hton;
#endif
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
extern handlerton *ndbcluster_hton;
#endif
#ifdef WITH_PARTITION_STORAGE_ENGINE
extern handlerton *partition_hton;
#endif
#ifdef WITH_MYISAMMRG_STORAGE_ENGINE
extern handlerton *myisammrg_hton;
#endif
extern handlerton *myisam_hton;
extern handlerton *heap_hton;

View file

@ -354,6 +354,14 @@ my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0;
my_bool opt_innodb;
/*
Legacy global handlerton. These will be removed (please do not add more).
*/
handlerton *heap_hton;
handlerton *myisam_hton;
handlerton *partition_hton;
#ifdef WITH_INNOBASE_STORAGE_ENGINE
extern ulong innobase_fast_shutdown;
extern ulong innobase_large_page_size;

View file

@ -4913,9 +4913,17 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
{
Item_func_in *func=(Item_func_in*) cond_func;
/*
Array for IN() is constructed when all values have the same result
type. Tree won't be built for values with different result types,
so we check it here to avoid unnecessary work.
*/
if (!func->array)
break;
if (inv)
{
if (func->array && func->cmp_type != ROW_RESULT)
if (func->array->result_type() != ROW_RESULT)
{
/*
We get here for conditions in form "t.key NOT IN (c1, c2, ...)",

View file

@ -443,11 +443,9 @@ bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts)
DBUG_RETURN(TRUE);
}
} while (++i < no_parts);
if (engine_array[0] == myisammrg_hton ||
engine_array[0] == tina_hton)
if (engine_array[0]->flags & HTON_NO_PARTITION)
{
my_error(ER_PARTITION_MERGE_ERROR, MYF(0),
engine_array[0] == myisammrg_hton ? "MyISAM Merge" : "CSV");
my_error(ER_PARTITION_MERGE_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);

View file

@ -5960,9 +5960,9 @@ ER_EVENT_SET_VAR_ERROR
eng "Error during starting/stopping of the scheduler. Error code %u"
ger "Fehler während des Startens oder Anhalten des Schedulers. Fehlercode %u"
ER_PARTITION_MERGE_ERROR
eng "%s handler cannot be used in partitioned tables"
ger "%s-Handler kann in partitionierten Tabellen nicht verwendet werden"
swe "%s kan inte användas i en partitionerad tabell"
eng "Engine cannot be used in partitioned tables"
ger "Engine kann in partitionierten Tabellen nicht verwendet werden"
swe "Engine inte användas i en partitionerad tabell"
ER_CANT_ACTIVATE_LOG
eng "Cannot activate '%-.64s' log"
ger "Kann Logdatei '%-.64s' nicht aktivieren"
@ -5990,4 +5990,6 @@ ER_UNSUPORTED_LOG_ENGINE
eng "This storage engine cannot be used for log tables""
ER_BAD_LOG_STATEMENT
eng "You cannot '%s' a log table if logging is enabled"
ER_NON_INSERTABLE_TABLE
eng "The target table %-.100s of the %s is not insertable-into"

View file

@ -1461,8 +1461,11 @@ void update_non_unique_table_error(TABLE_LIST *update,
*/
if (update->view)
{
/* Issue the ER_NON_INSERTABLE_TABLE error for an INSERT */
if (update->view == duplicate->view)
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), update->alias, operation);
my_error(!strncmp(operation, "INSERT", 6) ?
ER_NON_INSERTABLE_TABLE : ER_NON_UPDATABLE_TABLE, MYF(0),
update->alias, operation);
else
my_error(ER_VIEW_PREVENT_UPDATE, MYF(0),
(duplicate->view ? duplicate->alias : update->alias),

View file

@ -2389,7 +2389,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
tables_used->engine_data))
DBUG_RETURN(0);
if (tables_used->table->s->db_type == myisammrg_hton)
if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM)
{
ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
MYRG_INFO *file = handler->myrg_info();
@ -3013,7 +3013,7 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
"other non-cacheable table(s)"));
DBUG_RETURN(0);
}
if (tables_used->table->s->db_type == myisammrg_hton)
if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM)
{
ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
MYRG_INFO *file = handler->myrg_info();

View file

@ -45,7 +45,7 @@ class Sensitive_cursor: public Server_side_cursor
query_id_t query_id;
struct Engine_info
{
const handlerton *ht;
handlerton *ht;
void *read_view;
};
Engine_info ht_info[MAX_HA];
@ -318,12 +318,12 @@ Sensitive_cursor::post_open(THD *thd)
info= &ht_info[0];
for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
{
const handlerton *ht= *pht;
handlerton *ht= *pht;
close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
if (ht->create_cursor_read_view)
{
info->ht= ht;
info->read_view= (ht->create_cursor_read_view)();
info->read_view= (ht->create_cursor_read_view)(ht, thd);
++info;
}
}
@ -433,7 +433,7 @@ Sensitive_cursor::fetch(ulong num_rows)
thd->set_n_backup_active_arena(this, &backup_arena);
for (info= ht_info; info->read_view ; info++)
(info->ht->set_cursor_read_view)(info->read_view);
(info->ht->set_cursor_read_view)(info->ht, thd, info->read_view);
join->fetch_limit+= num_rows;
@ -454,7 +454,7 @@ Sensitive_cursor::fetch(ulong num_rows)
reset_thd(thd);
for (info= ht_info; info->read_view; info++)
(info->ht->set_cursor_read_view)(0);
(info->ht->set_cursor_read_view)(info->ht, thd, 0);
if (error == NESTED_LOOP_CURSOR_LIMIT)
{
@ -487,7 +487,7 @@ Sensitive_cursor::close()
for (Engine_info *info= ht_info; info->read_view; info++)
{
(info->ht->close_cursor_read_view)(info->read_view);
(info->ht->close_cursor_read_view)(info->ht, thd, info->read_view);
info->read_view= 0;
info->ht= 0;
}

View file

@ -112,7 +112,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (!table_list->updatable)
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
}
@ -228,7 +228,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
(table_list->view &&
check_view_insertability(thd, table_list)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
}

View file

@ -1722,7 +1722,8 @@ bool st_lex::can_be_merged()
unit= unit->next_unit())
{
if (unit->first_select()->parent_lex == this &&
(unit->item == 0 || unit->item->place() != IN_WHERE))
(unit->item == 0 ||
(unit->item->place() != IN_WHERE && unit->item->place() != IN_ON)))
{
selects_allow_merge= 0;
break;

View file

@ -70,7 +70,7 @@ static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
static void find_best(JOIN *join,table_map rest_tables,uint index,
double record_count,double read_time);
static uint cache_record_length(JOIN *join,uint index);
static double prev_record_reads(JOIN *join,table_map found_ref);
static double prev_record_reads(JOIN *join, uint idx, table_map found_ref);
static bool get_best_combination(JOIN *join);
static store_key *get_store_key(THD *thd,
KEYUSE *keyuse, table_map used_tables,
@ -3437,6 +3437,7 @@ set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
join->positions[idx].table= table;
join->positions[idx].key=key;
join->positions[idx].records_read=1.0; /* This is a const table */
join->positions[idx].ref_depend_map= 0;
/* Move the const table as down as possible in best_ref */
JOIN_TAB **pos=join->best_ref+idx+1;
@ -3494,6 +3495,7 @@ best_access_path(JOIN *join,
double best= DBL_MAX;
double best_time= DBL_MAX;
double records= DBL_MAX;
table_map best_ref_depends_map;
double tmp;
ha_rows rec;
@ -3522,13 +3524,20 @@ best_access_path(JOIN *join,
/* Calculate how many key segments of the current key we can use */
start_key= keyuse;
do
{ /* for each keypart */
do /* For each keypart */
{
uint keypart= keyuse->keypart;
table_map best_part_found_ref= 0;
double best_prev_record_reads= DBL_MAX;
do
do /* For each way to access the keypart */
{
/*
if 1. expression doesn't refer to forward tables
2. we won't get two ref-or-null's
*/
if (!(remaining_tables & keyuse->used_tables) &&
!(ref_or_null_part && (keyuse->optimize &
KEY_OPTIMIZE_REF_OR_NULL)))
@ -3536,8 +3545,9 @@ best_access_path(JOIN *join,
found_part|= keyuse->keypart_map;
if (!(keyuse->used_tables & ~join->const_table_map))
const_part|= keyuse->keypart_map;
double tmp= prev_record_reads(join, (found_ref |
keyuse->used_tables));
double tmp= prev_record_reads(join, idx, (found_ref |
keyuse->used_tables));
if (tmp < best_prev_record_reads)
{
best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
@ -3576,7 +3586,7 @@ best_access_path(JOIN *join,
Really, there should be records=0.0 (yes!)
but 1.0 would be probably safer
*/
tmp= prev_record_reads(join, found_ref);
tmp= prev_record_reads(join, idx, found_ref);
records= 1.0;
}
else
@ -3591,7 +3601,7 @@ best_access_path(JOIN *join,
max_key_part= (uint) ~0;
if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
{
tmp = prev_record_reads(join, found_ref);
tmp = prev_record_reads(join, idx, found_ref);
records=1.0;
}
else
@ -3728,7 +3738,30 @@ best_access_path(JOIN *join,
{
/* Check if we have statistic about the distribution */
if ((records= keyinfo->rec_per_key[max_key_part-1]))
{
/*
Fix for the case where the index statistics is too
optimistic: If
(1) We're considering ref(const) and there is quick select
on the same index,
(2) and that quick select uses more keyparts (i.e. it will
scan equal/smaller interval then this ref(const))
(3) and E(#rows) for quick select is higher then our
estimate,
Then
We'll use E(#rows) from quick select.
Q: Why do we choose to use 'ref'? Won't quick select be
cheaper in some cases ?
TODO: figure this out and adjust the plan choice if needed.
*/
if (!found_ref && table->quick_keys.is_set(key) && // (1)
table->quick_key_parts[key] > max_key_part && // (2)
records < (double)table->quick_rows[key]) // (3)
records= (double)table->quick_rows[key];
tmp= records;
}
else
{
/*
@ -3821,6 +3854,7 @@ best_access_path(JOIN *join,
best_records= records;
best_key= start_key;
best_max_key_part= max_key_part;
best_ref_depends_map= found_ref;
}
}
records= best_records;
@ -3949,6 +3983,8 @@ best_access_path(JOIN *join,
best= tmp;
records= rows2double(rnd_records);
best_key= 0;
/* range/index_merge/ALL/index access method are "independent", so: */
best_ref_depends_map= 0;
}
}
@ -3957,6 +3993,7 @@ best_access_path(JOIN *join,
join->positions[idx].read_time= best;
join->positions[idx].key= best_key;
join->positions[idx].table= s;
join->positions[idx].ref_depend_map= best_ref_depends_map;
if (!best_key &&
idx == join->const_tables &&
@ -4724,17 +4761,85 @@ cache_record_length(JOIN *join,uint idx)
}
/*
Get the number of different row combinations for subset of partial join
SYNOPSIS
prev_record_reads()
join The join structure
idx Number of tables in the partial join order (i.e. the
partial join order is in join->positions[0..idx-1])
found_ref Bitmap of tables for which we need to find # of distinct
row combinations.
DESCRIPTION
Given a partial join order (in join->positions[0..idx-1]) and a subset of
tables within that join order (specified in found_ref), find out how many
distinct row combinations of subset tables will be in the result of the
partial join order.
This is used as follows: Suppose we have a table accessed with a ref-based
method. The ref access depends on current rows of tables in found_ref.
We want to count # of different ref accesses. We assume two ref accesses
will be different if at least one of access parameters is different.
Example: consider a query
SELECT * FROM t1, t2, t3 WHERE t1.key=c1 AND t2.key=c2 AND t3.key=t1.field
and a join order:
t1, ref access on t1.key=c1
t2, ref access on t2.key=c2
t3, ref access on t3.key=t1.field
For t1: n_ref_scans = 1, n_distinct_ref_scans = 1
For t2: n_ref_scans = records_read(t1), n_distinct_ref_scans=1
For t3: n_ref_scans = records_read(t1)*records_read(t2)
n_distinct_ref_scans = #records_read(t1)
The reason for having this function (at least the latest version of it)
is that we need to account for buffering in join execution.
An edge-case example: if we have a non-first table in join accessed via
ref(const) or ref(param) where there is a small number of different
values of param, then the access will likely hit the disk cache and will
not require any disk seeks.
The proper solution would be to assume an LRU disk cache of some size,
calculate probability of cache hits, etc. For now we just count
identical ref accesses as one.
RETURN
Expected number of row combinations
*/
static double
prev_record_reads(JOIN *join,table_map found_ref)
prev_record_reads(JOIN *join, uint idx, table_map found_ref)
{
double found=1.0;
found_ref&= ~OUTER_REF_TABLE_BIT;
for (POSITION *pos=join->positions ; found_ref ; pos++)
POSITION *pos_end= join->positions - 1;
for (POSITION *pos= join->positions + idx - 1; pos != pos_end; pos--)
{
if (pos->table->table->map & found_ref)
{
found_ref&= ~pos->table->table->map;
found*=pos->records_read;
found_ref|= pos->ref_depend_map;
/*
For the case of "t1 LEFT JOIN t2 ON ..." where t2 is a const table
with no matching row we will get position[t2].records_read==0.
Actually the size of output is one null-complemented row, therefore
we will use value of 1 whenever we get records_read==0.
Note
- the above case can't occur if inner part of outer join has more
than one table: table with no matches will not be marked as const.
- Ideally we should add 1 to records_read for every possible null-
complemented row. We're not doing it because: 1. it will require
non-trivial code and add overhead. 2. The value of records_read
is an inprecise estimate and adding 1 (or, in the worst case,
#max_nested_outer_joins=64-1) will not make it any more precise.
*/
if (pos->records_read)
found*= pos->records_read;
}
}
return found;
@ -10478,6 +10583,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="const row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
pos->ref_depend_map= 0;
if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}
@ -10503,6 +10609,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="unique row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
pos->ref_depend_map= 0;
if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}

View file

@ -176,7 +176,13 @@ enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool
*/
typedef struct st_position
{
/*
The "fanout": number of output rows that will be produced (after
pushed down selection condition is applied) per each row combination of
previous tables.
*/
double records_read;
/*
Cost accessing the table in course of the entire complete join execution,
i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times
@ -184,7 +190,15 @@ typedef struct st_position
*/
double read_time;
JOIN_TAB *table;
/*
NULL - 'index' or 'range' or 'index_merge' or 'ALL' access is used.
Other - [eq_]ref[_or_null] access is used. Pointer to {t.keypart1 = expr}
*/
KEYUSE *key;
/* If ref-based access is used: bitmap of tables this table depends on */
table_map ref_depend_map;
} POSITION;

View file

@ -4999,7 +4999,7 @@ static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin,
(run_hton_fill_schema_files_args *) arg;
handlerton *hton= (handlerton *)plugin->data;
if(hton->fill_files_table && hton->state == SHOW_OPTION_YES)
hton->fill_files_table(thd, args->tables, args->cond);
hton->fill_files_table(hton, thd, args->tables, args->cond);
return false;
}

View file

@ -21,7 +21,7 @@
int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
{
int error= HA_ADMIN_NOT_IMPLEMENTED;
const handlerton *hton= ts_info->storage_engine;
handlerton *hton= ts_info->storage_engine;
DBUG_ENTER("mysql_alter_tablespace");
/*
@ -42,7 +42,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
if (hton->alter_tablespace)
{
if ((error= hton->alter_tablespace(thd, ts_info)))
if ((error= hton->alter_tablespace(hton, thd, ts_info)))
{
if (error == HA_ADMIN_NOT_IMPLEMENTED)
{

View file

@ -1603,7 +1603,7 @@ bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view)
list->push_back(fld);
else
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT");
my_error(ER_NON_INSERTABLE_TABLE, MYF(0), view->alias, "INSERT");
DBUG_RETURN(TRUE);
}
}

View file

@ -6847,11 +6847,13 @@ join_table:
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $3))
YYABORT;
Select->parsing_place= IN_ON;
}
expr
{
add_join_on($3,$6);
Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
| table_ref STRAIGHT_JOIN table_factor
ON
@ -6860,12 +6862,14 @@ join_table:
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $3))
YYABORT;
Select->parsing_place= IN_ON;
}
expr
{
$3->straight=1;
add_join_on($3,$6);
Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
| table_ref normal_join table_ref
USING
@ -6889,6 +6893,7 @@ join_table:
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $5))
YYABORT;
Select->parsing_place= IN_ON;
}
expr
{
@ -6896,6 +6901,7 @@ join_table:
Lex->pop_context();
$5->outer_join|=JOIN_TYPE_LEFT;
$$=$5;
Select->parsing_place= NO_MATTER;
}
| table_ref LEFT opt_outer JOIN_SYM table_factor
{
@ -6920,6 +6926,7 @@ join_table:
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $5))
YYABORT;
Select->parsing_place= IN_ON;
}
expr
{
@ -6928,6 +6935,7 @@ join_table:
YYABORT;
add_join_on($$, $8);
Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
| table_ref RIGHT opt_outer JOIN_SYM table_factor
{

View file

@ -292,13 +292,19 @@ bool mysql_create_frm(THD *thd, const char *file_name,
goto err3;
{
/* Unescape all UCS2 intervals: were escaped in pack_headers */
/*
Restore all UCS2 intervals.
HEX representation of them is not needed anymore.
*/
List_iterator<create_field> it(create_fields);
create_field *field;
while ((field=it++))
{
if (field->interval && field->charset->mbminlen > 1)
unhex_type2(field->interval);
if (field->save_interval)
{
field->interval= field->save_interval;
field->save_interval= 0;
}
}
}
DBUG_RETURN(0);
@ -589,18 +595,36 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
reclength=(uint) (field->offset+ data_offset + length);
n_length+= (ulong) strlen(field->field_name)+1;
field->interval_id=0;
field->save_interval= 0;
if (field->interval)
{
uint old_int_count=int_count;
if (field->charset->mbminlen > 1)
{
/* Escape UCS2 intervals using HEX notation */
/*
Escape UCS2 intervals using HEX notation to avoid
problems with delimiters between enum elements.
As the original representation is still needed in
the function make_empty_rec to create a record of
filled with default values it is saved in save_interval
The HEX representation is created from this copy.
*/
field->save_interval= field->interval;
field->interval= (TYPELIB*) sql_alloc(sizeof(TYPELIB));
*field->interval= *field->save_interval;
field->interval->type_names=
(const char **) sql_alloc(sizeof(char*) *
(field->interval->count+1));
field->interval->type_names[field->interval->count]= 0;
field->interval->type_lengths=
(uint *) sql_alloc(sizeof(uint) * field->interval->count);
for (uint pos= 0; pos < field->interval->count; pos++)
{
char *dst;
uint length= field->interval->type_lengths[pos], hex_length;
const char *src= field->interval->type_names[pos];
uint length= field->save_interval->type_lengths[pos], hex_length;
const char *src= field->save_interval->type_names[pos];
hex_length= length * 2;
field->interval->type_lengths[pos]= hex_length;
field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1);
@ -842,18 +866,19 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
/*
regfield don't have to be deleted as it's allocated with sql_alloc()
*/
Field *regfield= make_field(&share,
(char*) buff+field->offset + data_offset,
field->length,
null_pos + null_count / 8,
null_count & 7,
field->pack_flag,
field->sql_type,
field->charset,
field->geom_type,
field->unireg_check,
field->interval,
field->field_name);
Field *regfield=make_field(&share,
(char*) buff+field->offset + data_offset,
field->length,
null_pos + null_count / 8,
null_count & 7,
field->pack_flag,
field->sql_type,
field->charset,
field->geom_type,
field->unireg_check,
field->save_interval ? field->save_interval :
field->interval,
field->field_name);
if (!regfield)
goto err; // End of memory

View file

@ -139,17 +139,21 @@ static HASH archive_open_tables;
#define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption
/* Static declarations for handerton */
static handler *archive_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
static handler *archive_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
int archive_db_end(handlerton *hton, ha_panic_function type);
/*
Number of rows that will force a bulk insert.
*/
#define ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT 2
handlerton *archive_hton;
static handler *archive_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
static handler *archive_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_archive(table);
return new (mem_root) ha_archive(hton, table);
}
/*
@ -178,6 +182,7 @@ static byte* archive_get_key(ARCHIVE_SHARE *share,uint *length,
int archive_db_init(void *p)
{
DBUG_ENTER("archive_db_init");
handlerton *archive_hton;
if (archive_inited)
DBUG_RETURN(FALSE);
archive_hton= (handlerton *)p;
@ -226,13 +231,13 @@ int archive_db_done(void *p)
}
int archive_db_end(ha_panic_function type)
int archive_db_end(handlerton *hton, ha_panic_function type)
{
return archive_db_done(NULL);
}
ha_archive::ha_archive(TABLE_SHARE *table_arg)
:handler(archive_hton, table_arg), delayed_insert(0), bulk_insert(0)
ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg), delayed_insert(0), bulk_insert(0)
{
/* Set our original buffer from pre-allocated memory */
buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
@ -1571,7 +1576,7 @@ bool ha_archive::check_and_repair(THD *thd)
}
struct st_mysql_storage_engine archive_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, archive_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(archive)
{

View file

@ -67,7 +67,7 @@ class ha_archive: public handler
uint current_k_offset;
public:
ha_archive(TABLE_SHARE *table_arg);
ha_archive(handlerton *hton, TABLE_SHARE *table_arg);
~ha_archive()
{
}
@ -139,5 +139,3 @@ public:
bool check_and_repair(THD *thd);
};
int archive_db_end(ha_panic_function type);

View file

@ -24,11 +24,11 @@
/* Static declarations for handlerton */
handlerton *blackhole_hton;
static handler *blackhole_create_handler(TABLE_SHARE *table,
static handler *blackhole_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_blackhole(table);
return new (mem_root) ha_blackhole(hton, table);
}
@ -36,8 +36,9 @@ static handler *blackhole_create_handler(TABLE_SHARE *table,
** BLACKHOLE tables
*****************************************************************************/
ha_blackhole::ha_blackhole(TABLE_SHARE *table_arg)
:handler(blackhole_hton, table_arg)
ha_blackhole::ha_blackhole(handlerton *hton,
TABLE_SHARE *table_arg)
:handler(hton, table_arg)
{}
@ -203,6 +204,7 @@ int ha_blackhole::index_last(byte * buf)
static int blackhole_init(void *p)
{
handlerton *blackhole_hton;
blackhole_hton= (handlerton *)p;
blackhole_hton->state= SHOW_OPTION_YES;
blackhole_hton->db_type= DB_TYPE_BLACKHOLE_DB;
@ -212,7 +214,7 @@ static int blackhole_init(void *p)
}
struct st_mysql_storage_engine blackhole_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, blackhole_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(blackhole)
{

View file

@ -28,7 +28,7 @@ class ha_blackhole: public handler
THR_LOCK thr_lock;
public:
ha_blackhole(TABLE_SHARE *table_arg);
ha_blackhole(handlerton *hton, TABLE_SHARE *table_arg);
~ha_blackhole()
{
}

View file

@ -74,7 +74,11 @@ static int write_meta_file(File meta_file, ha_rows rows, bool dirty);
pthread_mutex_t tina_mutex;
static HASH tina_open_tables;
static int tina_init= 0;
static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
static handler *tina_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
int tina_end(handlerton *hton, ha_panic_function type);
off_t Transparent_file::read_next()
{
@ -123,7 +127,6 @@ char Transparent_file::get_value(off_t offset)
return buff[0];
}
}
handlerton *tina_hton;
/*****************************************************************************
** TINA tables
@ -150,6 +153,8 @@ static byte* tina_get_key(TINA_SHARE *share,uint *length,
static int tina_init_func(void *p)
{
handlerton *tina_hton;
if (!tina_init)
{
tina_hton= (handlerton *)p;
@ -161,7 +166,8 @@ static int tina_init_func(void *p)
tina_hton->db_type= DB_TYPE_CSV_DB;
tina_hton->create= tina_create_handler;
tina_hton->panic= tina_end;
tina_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
tina_hton->flags= (HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES |
HTON_NO_PARTITION);
}
return 0;
}
@ -449,7 +455,7 @@ static int free_share(TINA_SHARE *share)
DBUG_RETURN(result_code);
}
int tina_end(ha_panic_function type)
int tina_end(handlerton *hton, ha_panic_function type)
{
return tina_done_func(NULL);
}
@ -493,14 +499,16 @@ off_t find_eoln_buff(Transparent_file *data_buff, off_t begin,
}
static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
static handler *tina_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_tina(table);
return new (mem_root) ha_tina(hton, table);
}
ha_tina::ha_tina(TABLE_SHARE *table_arg)
:handler(tina_hton, table_arg),
ha_tina::ha_tina(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg),
/*
These definitions are found in handler.h
They are not probably completely right.
@ -1516,7 +1524,7 @@ bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info,
}
struct st_mysql_storage_engine csv_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, tina_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(csv)
{

View file

@ -129,7 +129,7 @@ private:
int init_tina_writer();
public:
ha_tina(TABLE_SHARE *table_arg);
ha_tina(handlerton *hton, TABLE_SHARE *table_arg);
~ha_tina()
{
if (chain_alloced)
@ -212,5 +212,3 @@ public:
int chain_append();
};
int tina_end(ha_panic_function type);

View file

@ -73,7 +73,9 @@
#include <mysql/plugin.h>
static handler *example_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
static handler *example_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
static int example_init_func();
static bool example_init_func_for_handlerton();
static int example_panic(enum ha_panic_function flag);
@ -201,14 +203,16 @@ static int free_share(EXAMPLE_SHARE *share)
}
static handler* example_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
static handler* example_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_example(table);
return new (mem_root) ha_example(hton, table);
}
ha_example::ha_example(TABLE_SHARE *table_arg)
:handler(example_hton, table_arg)
ha_example::ha_example(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg)
{}
/*
@ -703,7 +707,7 @@ int ha_example::create(const char *name, TABLE *table_arg,
}
struct st_mysql_storage_engine example_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, example_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(example)

View file

@ -45,7 +45,7 @@ class ha_example: public handler
EXAMPLE_SHARE *share; /* Shared lock info */
public:
ha_example(TABLE_SHARE *table_arg);
ha_example(handlerton *hton, TABLE_SHARE *table_arg);
~ha_example()
{
}

View file

@ -359,19 +359,22 @@ static const uint sizeof_trailing_and= sizeof(" AND ") - 1;
static const uint sizeof_trailing_where= sizeof(" WHERE ") - 1;
/* Static declaration for handerton */
static handler *federated_create_handler(TABLE_SHARE *table,
static handler *federated_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
static int federated_commit(THD *thd, bool all);
static int federated_rollback(THD *thd, bool all);
static int federated_commit(handlerton *hton, THD *thd, bool all);
static int federated_rollback(handlerton *hton, THD *thd, bool all);
static int federated_db_init(void);
static int federated_db_end(handlerton *hton, ha_panic_function type);
/* Federated storage engine handlerton */
handlerton *federated_hton;
static handler *federated_create_handler(TABLE_SHARE *table,
static handler *federated_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_federated(table);
return new (mem_root) ha_federated(hton, table);
}
@ -399,7 +402,7 @@ static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
int federated_db_init(void *p)
{
DBUG_ENTER("federated_db_init");
federated_hton= (handlerton *)p;
handlerton *federated_hton= (handlerton *)p;
federated_hton->state= SHOW_OPTION_YES;
federated_hton->db_type= DB_TYPE_FEDERATED_DB;
federated_hton->commit= federated_commit;
@ -434,7 +437,7 @@ error:
FALSE OK
*/
int federated_db_end(ha_panic_function type)
int federated_db_end(handlerton *hton, ha_panic_function type)
{
if (federated_init)
{
@ -723,8 +726,9 @@ error:
** FEDERATED tables
*****************************************************************************/
ha_federated::ha_federated(TABLE_SHARE *table_arg)
:handler(federated_hton, table_arg),
ha_federated::ha_federated(handlerton *hton,
TABLE_SHARE *table_arg)
:handler(hton, table_arg),
mysql(0), stored_result(0)
{
trx_next= 0;
@ -2736,7 +2740,7 @@ bool ha_federated::get_error_message(int error, String* buf)
int ha_federated::external_lock(THD *thd, int lock_type)
{
int error= 0;
ha_federated *trx= (ha_federated *)thd->ha_data[federated_hton->slot];
ha_federated *trx= (ha_federated *)thd->ha_data[ht->slot];
DBUG_ENTER("ha_federated::external_lock");
if (lock_type != F_UNLCK)
@ -2754,7 +2758,7 @@ int ha_federated::external_lock(THD *thd, int lock_type)
DBUG_PRINT("info", ("error setting autocommit TRUE: %d", error));
DBUG_RETURN(error);
}
trans_register_ha(thd, FALSE, federated_hton);
trans_register_ha(thd, FALSE, ht);
}
else
{
@ -2770,8 +2774,8 @@ int ha_federated::external_lock(THD *thd, int lock_type)
DBUG_PRINT("info", ("error setting autocommit FALSE: %d", error));
DBUG_RETURN(error);
}
thd->ha_data[federated_hton->slot]= this;
trans_register_ha(thd, TRUE, federated_hton);
thd->ha_data[ht->slot]= this;
trans_register_ha(thd, TRUE, ht);
/*
Send a lock table to the remote end.
We do not support this at the moment
@ -2796,10 +2800,10 @@ int ha_federated::external_lock(THD *thd, int lock_type)
}
static int federated_commit(THD *thd, bool all)
static int federated_commit(handlerton *hton, THD *thd, bool all)
{
int return_val= 0;
ha_federated *trx= (ha_federated *)thd->ha_data[federated_hton->slot];
ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot];
DBUG_ENTER("federated_commit");
if (all)
@ -2814,7 +2818,7 @@ static int federated_commit(THD *thd, bool all)
if (error && !return_val);
return_val= error;
}
thd->ha_data[federated_hton->slot]= NULL;
thd->ha_data[hton->slot]= NULL;
}
DBUG_PRINT("info", ("error val: %d", return_val));
@ -2822,10 +2826,10 @@ static int federated_commit(THD *thd, bool all)
}
static int federated_rollback(THD *thd, bool all)
static int federated_rollback(handlerton *hton, THD *thd, bool all)
{
int return_val= 0;
ha_federated *trx= (ha_federated *)thd->ha_data[federated_hton->slot];
ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot];
DBUG_ENTER("federated_rollback");
if (all)
@ -2840,7 +2844,7 @@ static int federated_rollback(THD *thd, bool all)
if (error && !return_val)
return_val= error;
}
thd->ha_data[federated_hton->slot]= NULL;
thd->ha_data[hton->slot]= NULL;
}
DBUG_PRINT("info", ("error val: %d", return_val));
@ -2882,7 +2886,7 @@ int ha_federated::execute_simple_query(const char *query, int len)
}
struct st_mysql_storage_engine federated_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, federated_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(federated)
{

View file

@ -94,7 +94,7 @@ private:
int stash_remote_error();
public:
ha_federated(TABLE_SHARE *table_arg);
ha_federated(handlerton *hton, TABLE_SHARE *table_arg);
~ha_federated() {}
/* The name that will be used for display purposes */
const char *table_type() const { return "FEDERATED"; }
@ -236,6 +236,3 @@ public:
MYSQL_RES **result);
};
int federated_db_init(void);
int federated_db_end(ha_panic_function type);

View file

@ -25,12 +25,20 @@
#include "ha_heap.h"
static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
static handler *heap_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
int heap_panic(handlerton *hton, ha_panic_function flag)
{
return hp_panic(flag);
}
handlerton *heap_hton;
int heap_init(void *p)
{
handlerton *heap_hton;
heap_hton= (handlerton *)p;
heap_hton->state= SHOW_OPTION_YES;
heap_hton->db_type= DB_TYPE_HEAP;
@ -41,9 +49,11 @@ int heap_init(void *p)
return 0;
}
static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
static handler *heap_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_heap(table);
return new (mem_root) ha_heap(hton, table);
}
@ -51,8 +61,8 @@ static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
** HEAP tables
*****************************************************************************/
ha_heap::ha_heap(TABLE_SHARE *table_arg)
:handler(heap_hton, table_arg), file(0), records_changed(0),
ha_heap::ha_heap(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg), file(0), records_changed(0),
key_stat_version(0)
{}
@ -701,7 +711,7 @@ bool ha_heap::check_if_incompatible_data(HA_CREATE_INFO *info,
}
struct st_mysql_storage_engine heap_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, heap_hton};
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(heap)
{

View file

@ -31,7 +31,7 @@ class ha_heap: public handler
uint records_changed;
uint key_stat_version;
public:
ha_heap(TABLE_SHARE *table);
ha_heap(handlerton *hton, TABLE_SHARE *table);
~ha_heap() {}
const char *table_type() const
{

View file

@ -19,10 +19,10 @@
/* if flag == HA_PANIC_CLOSE then all files are removed for more
memory */
int heap_panic(enum ha_panic_function flag)
int hp_panic(enum ha_panic_function flag)
{
LIST *element,*next_open;
DBUG_ENTER("heap_panic");
DBUG_ENTER("hp_panic");
pthread_mutex_lock(&THR_LOCK_heap);
for (element=heap_open_list ; element ; element=next_open)
@ -54,4 +54,4 @@ int heap_panic(enum ha_panic_function flag)
}
pthread_mutex_unlock(&THR_LOCK_heap);
DBUG_RETURN(0);
} /* heap_panic */
} /* hp_panic */

View file

@ -155,7 +155,7 @@ int main(int argc, char **argv)
}
#endif
if (heap_close(file) || heap_panic(HA_PANIC_CLOSE))
if (heap_close(file) || hp_panic(HA_PANIC_CLOSE))
goto err;
my_end(MY_GIVE_INFO);
return(0);

View file

@ -603,7 +603,7 @@ end:
if (heap_close(file) || (file2 && heap_close(file2)))
goto err;
heap_delete_table(filename2);
heap_panic(HA_PANIC_CLOSE);
hp_panic(HA_PANIC_CLOSE);
my_end(MY_GIVE_INFO);
return(0);
err:
@ -669,7 +669,7 @@ static sig_handler endprog(int sig_number __attribute__((unused)))
else
#endif
{
heap_panic(HA_PANIC_CLOSE);
hp_panic(HA_PANIC_CLOSE);
my_end(1);
exit(1);
}

View file

@ -54,6 +54,12 @@ pthread_cond_t commit_cond;
pthread_mutex_t commit_cond_m;
bool innodb_inited= 0;
/*
This needs to exist until the query cache callback is removed
or learns to pass hton.
*/
static handlerton *legacy_innodb_hton;
/*-----------------------------------------------------------------*/
/* These variables are used to implement (semi-)synchronous MySQL binlog
replication for InnoDB tables. */
@ -197,22 +203,25 @@ static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
my_bool not_used __attribute__((unused)));
static INNOBASE_SHARE *get_share(const char *table_name);
static void free_share(INNOBASE_SHARE *share);
static int innobase_close_connection(THD* thd);
static int innobase_commit(THD* thd, bool all);
static int innobase_rollback(THD* thd, bool all);
static int innobase_rollback_to_savepoint(THD* thd, void *savepoint);
static int innobase_savepoint(THD* thd, void *savepoint);
static int innobase_release_savepoint(THD* thd, void *savepoint);
static handler *innobase_create_handler(TABLE_SHARE *table,
static int innobase_close_connection(handlerton *hton, THD* thd);
static int innobase_commit(handlerton *hton, THD* thd, bool all);
static int innobase_rollback(handlerton *hton, THD* thd, bool all);
static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd,
void *savepoint);
static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint);
static int innobase_release_savepoint(handlerton *hton, THD* thd,
void *savepoint);
static handler *innobase_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
static const char innobase_hton_name[]= "InnoDB";
handlerton *innobase_hton;
static handler *innobase_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
static handler *innobase_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_innobase(table);
return new (mem_root) ha_innobase(hton, table);
}
@ -380,7 +389,8 @@ documentation, see handler.cc. */
int
innobase_release_temporary_latches(
/*===============================*/
THD *thd)
handlerton *hton,
THD *thd)
{
trx_t* trx;
@ -389,7 +399,7 @@ innobase_release_temporary_latches(
return 0;
}
trx = (trx_t*) thd->ha_data[innobase_hton->slot];
trx = (trx_t*) thd->ha_data[hton->slot];
if (trx) {
innobase_release_stat_resources(trx);
@ -841,13 +851,14 @@ trx_t*
check_trx_exists(
/*=============*/
/* out: InnoDB transaction handle */
handlerton* hton, /* in: handlerton for innodb */
THD* thd) /* in: user thread handle */
{
trx_t* trx;
ut_ad(thd == current_thd);
trx = (trx_t*) thd->ha_data[innobase_hton->slot];
trx = (trx_t*) thd->ha_data[hton->slot];
if (trx == NULL) {
DBUG_ASSERT(thd != NULL);
@ -861,7 +872,7 @@ check_trx_exists(
CPU time */
trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
thd->ha_data[innobase_hton->slot] = trx;
thd->ha_data[hton->slot] = trx;
} else {
if (trx->magic_n != TRX_MAGIC_N) {
mem_analyze_corruption(trx);
@ -889,8 +900,8 @@ check_trx_exists(
/*************************************************************************
Construct ha_innobase handler. */
ha_innobase::ha_innobase(TABLE_SHARE *table_arg)
:handler(innobase_hton, table_arg),
ha_innobase::ha_innobase(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg),
int_table_flags(HA_REC_NOT_IN_SEQ |
HA_NULL_IN_KEY |
HA_CAN_INDEX_BLOBS |
@ -917,7 +928,7 @@ ha_innobase::update_thd(
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
trx_t* trx;
trx = check_trx_exists(thd);
trx = check_trx_exists(ht, thd);
if (prebuilt->trx != trx) {
@ -938,10 +949,11 @@ inline
void
innobase_register_stmt(
/*===================*/
handlerton* hton, /* in: Innobase hton */
THD* thd) /* in: MySQL thd (connection) object */
{
/* Register the statement */
trans_register_ha(thd, FALSE, innobase_hton);
trans_register_ha(thd, FALSE, hton);
}
/*************************************************************************
@ -955,17 +967,18 @@ inline
void
innobase_register_trx_and_stmt(
/*===========================*/
handlerton *hton, /* in: Innobase handlerton */
THD* thd) /* in: MySQL thd (connection) object */
{
/* NOTE that actually innobase_register_stmt() registers also
the transaction in the AUTOCOMMIT=1 mode. */
innobase_register_stmt(thd);
innobase_register_stmt(hton, thd);
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
/* No autocommit mode, register for a transaction */
trans_register_ha(thd, TRUE, innobase_hton);
trans_register_ha(thd, TRUE, hton);
}
}
@ -1061,7 +1074,7 @@ innobase_query_caching_of_table_permitted(
return((my_bool)FALSE);
}
trx = check_trx_exists(thd);
trx = check_trx_exists(legacy_innodb_hton, thd);
if (trx->has_search_latch) {
ut_print_timestamp(stderr);
sql_print_error("The calling thread is holding the adaptive "
@ -1120,7 +1133,7 @@ innobase_query_caching_of_table_permitted(
if (trx->active_trans == 0) {
innobase_register_trx_and_stmt(thd);
innobase_register_trx_and_stmt(legacy_innodb_hton, thd);
trx->active_trans = 1;
}
@ -1295,7 +1308,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
if (prebuilt->trx->active_trans == 0) {
innobase_register_trx_and_stmt(current_thd);
innobase_register_trx_and_stmt(ht, current_thd);
prebuilt->trx->active_trans = 1;
}
@ -1338,7 +1351,8 @@ innobase_init(void *p)
char *default_path;
DBUG_ENTER("innobase_init");
innobase_hton= (handlerton *)p;
handlerton *innobase_hton= (handlerton *)p;
legacy_innodb_hton= innobase_hton;
innobase_hton->state=have_innodb;
innobase_hton->db_type= DB_TYPE_INNODB;
@ -1613,7 +1627,7 @@ error:
Closes an InnoDB database. */
int
innobase_end(ha_panic_function type)
innobase_end(handlerton *hton, ha_panic_function type)
/*==============*/
/* out: TRUE if error */
{
@ -1651,7 +1665,7 @@ Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
the logs, and the name of this function should be innobase_checkpoint. */
bool
innobase_flush_logs(void)
innobase_flush_logs(handlerton *hton)
/*=====================*/
/* out: TRUE if error */
{
@ -1690,6 +1704,7 @@ int
innobase_start_trx_and_assign_read_view(
/*====================================*/
/* out: 0 */
handlerton *hton, /* in: Innodb handlerton */
THD* thd) /* in: MySQL thread handle of the user for whom
the transaction should be committed */
{
@ -1699,7 +1714,7 @@ innobase_start_trx_and_assign_read_view(
/* Create a new trx struct for thd, if it does not yet have one */
trx = check_trx_exists(thd);
trx = check_trx_exists(hton, thd);
/* This is just to play safe: release a possible FIFO ticket and
search latch. Since we will reserve the kernel mutex, we have to
@ -1718,9 +1733,7 @@ innobase_start_trx_and_assign_read_view(
/* Set the MySQL flag to mark that there is an active transaction */
if (trx->active_trans == 0) {
innobase_register_trx_and_stmt(current_thd);
innobase_register_trx_and_stmt(hton, current_thd);
trx->active_trans = 1;
}
@ -1735,7 +1748,8 @@ int
innobase_commit(
/*============*/
/* out: 0 */
THD* thd, /* in: MySQL thread handle of the user for whom
handlerton *hton, /* in: Innodb handlerton */
THD* thd, /* in: MySQL thread handle of the user for whom
the transaction should be committed */
bool all) /* in: TRUE - commit transaction
FALSE - the current SQL statement ended */
@ -1745,7 +1759,7 @@ innobase_commit(
DBUG_ENTER("innobase_commit");
DBUG_PRINT("trans", ("ending transaction"));
trx = check_trx_exists(thd);
trx = check_trx_exists(hton, thd);
/* Update the info whether we should skip XA steps that eat CPU time */
trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
@ -1871,6 +1885,7 @@ int
innobase_report_binlog_offset_and_commit(
/*=====================================*/
/* out: 0 */
handlerton *hton, /* in: Innodb handlerton */
THD* thd, /* in: user thread */
void* trx_handle, /* in: InnoDB trx handle */
char* log_file_name, /* in: latest binlog file name */
@ -1888,7 +1903,7 @@ innobase_report_binlog_offset_and_commit(
trx->flush_log_later = TRUE;
innobase_commit(thd, TRUE);
innobase_commit(hton, thd, TRUE);
trx->flush_log_later = FALSE;
@ -1936,11 +1951,12 @@ int
innobase_commit_complete(
/*=====================*/
/* out: 0 */
handlerton *hton, /* in: Innodb handlerton */
THD* thd) /* in: user thread */
{
trx_t* trx;
trx = (trx_t*) thd->ha_data[innobase_hton->slot];
trx = (trx_t*) thd->ha_data[hton->slot];
if (trx && trx->active_trans) {
@ -1964,6 +1980,7 @@ static int
innobase_rollback(
/*==============*/
/* out: 0 or error number */
handlerton *hton, /* in: Innodb handlerton */
THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
bool all) /* in: TRUE - commit transaction
@ -1975,7 +1992,7 @@ innobase_rollback(
DBUG_ENTER("innobase_rollback");
DBUG_PRINT("trans", ("aborting transaction"));
trx = check_trx_exists(thd);
trx = check_trx_exists(hton, thd);
/* Update the info whether we should skip XA steps that eat CPU time */
trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
@ -2047,6 +2064,7 @@ innobase_rollback_to_savepoint(
/*===========================*/
/* out: 0 if success, HA_ERR_NO_SAVEPOINT if
no savepoint with the given name */
handlerton *hton, /* in: Innodb handlerton */
THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
void* savepoint) /* in: savepoint data */
@ -2058,7 +2076,7 @@ innobase_rollback_to_savepoint(
DBUG_ENTER("innobase_rollback_to_savepoint");
trx = check_trx_exists(thd);
trx = check_trx_exists(hton, thd);
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
@ -2083,6 +2101,7 @@ innobase_release_savepoint(
/*=======================*/
/* out: 0 if success, HA_ERR_NO_SAVEPOINT if
no savepoint with the given name */
handlerton* hton, /* in: handlerton for Innodb */
THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
void* savepoint) /* in: savepoint data */
@ -2093,7 +2112,7 @@ innobase_release_savepoint(
DBUG_ENTER("innobase_release_savepoint");
trx = check_trx_exists(thd);
trx = check_trx_exists(hton, thd);
/* TODO: use provided savepoint data area to store savepoint data */
@ -2111,6 +2130,7 @@ int
innobase_savepoint(
/*===============*/
/* out: always 0, that is, always succeeds */
handlerton* hton, /* in: handle to the Innodb handlerton */
THD* thd, /* in: handle to the MySQL thread */
void* savepoint) /* in: savepoint data */
{
@ -2127,7 +2147,7 @@ innobase_savepoint(
DBUG_ASSERT(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
thd->in_sub_stmt);
trx = check_trx_exists(thd);
trx = check_trx_exists(hton, thd);
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
@ -2154,12 +2174,13 @@ int
innobase_close_connection(
/*======================*/
/* out: 0 or error number */
handlerton* hton, /* in: innobase handlerton */
THD* thd) /* in: handle to the MySQL thread of the user
whose resources should be free'd */
{
trx_t* trx;
trx = (trx_t*)thd->ha_data[innobase_hton->slot];
trx = (trx_t*)thd->ha_data[hton->slot];
ut_a(trx);
@ -3252,11 +3273,11 @@ ha_innobase::write_row(
DBUG_ENTER("ha_innobase::write_row");
if (prebuilt->trx !=
(trx_t*) current_thd->ha_data[innobase_hton->slot]) {
(trx_t*) current_thd->ha_data[ht->slot]) {
sql_print_error("The transaction object for the table handle is at "
"%p, but for the current thread it is at %p",
prebuilt->trx,
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
@ -3264,7 +3285,7 @@ ha_innobase::write_row(
"InnoDB: Dump of 200 bytes around transaction.all: ",
stderr);
ut_print_buf(stderr,
((byte*)(&(current_thd->ha_data[innobase_hton->slot]))) - 100,
((byte*)(&(current_thd->ha_data[ht->slot]))) - 100,
200);
putc('\n', stderr);
ut_error;
@ -3318,7 +3339,7 @@ no_commit:
no need to re-acquire locks on it. */
/* Altering to InnoDB format */
innobase_commit(user_thd, 1);
innobase_commit(ht, user_thd, 1);
/* Note that this transaction is still active. */
prebuilt->trx->active_trans = 1;
/* We will need an IX lock on the destination table. */
@ -3334,7 +3355,7 @@ no_commit:
/* Commit the transaction. This will release the table
locks, so they have to be acquired again. */
innobase_commit(user_thd, 1);
innobase_commit(ht, user_thd, 1);
/* Note that this transaction is still active. */
prebuilt->trx->active_trans = 1;
/* Re-acquire the table lock on the source table. */
@ -3637,7 +3658,7 @@ ha_innobase::update_row(
DBUG_ENTER("ha_innobase::update_row");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
@ -3698,7 +3719,7 @@ ha_innobase::delete_row(
DBUG_ENTER("ha_innobase::delete_row");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@ -3796,7 +3817,7 @@ ha_innobase::try_semi_consistent_read(bool yes)
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
/* Row read type is set to semi consistent read if this was
requested by the MySQL and either innodb_locks_unsafe_for_binlog
@ -3963,7 +3984,7 @@ ha_innobase::index_read(
DBUG_ENTER("index_read");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
statistic_increment(current_thd->status_var.ha_read_key_count,
&LOCK_status);
@ -4078,7 +4099,7 @@ ha_innobase::change_active_index(
ut_ad(user_thd == current_thd);
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
active_index = keynr;
@ -4168,7 +4189,7 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
innodb_srv_conc_enter_innodb(prebuilt->trx);
@ -4404,7 +4425,7 @@ ha_innobase::rnd_pos(
&LOCK_status);
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we
@ -4454,7 +4475,7 @@ ha_innobase::position(
uint len;
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we
@ -4782,7 +4803,7 @@ ha_innobase::create(
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(thd);
parent_trx = check_trx_exists(ht, thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@ -4955,7 +4976,7 @@ ha_innobase::discard_or_import_tablespace(
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
dict_table = prebuilt->table;
trx = prebuilt->trx;
@ -5035,7 +5056,7 @@ ha_innobase::delete_table(
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(thd);
parent_trx = check_trx_exists(ht, thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@ -5102,6 +5123,7 @@ void
innobase_drop_database(
/*===================*/
/* out: error number */
handlerton *hton, /* in: handlerton of Innodb */
char* path) /* in: database path; inside InnoDB the name
of the last directory in the path is used as
the database name: for example, in 'mysql/data/test'
@ -5117,7 +5139,7 @@ innobase_drop_database(
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
parent_trx = check_trx_exists(hton, current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@ -5196,7 +5218,7 @@ ha_innobase::rename_table(
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
parent_trx = check_trx_exists(ht, current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@ -5283,7 +5305,7 @@ ha_innobase::records_in_range(
DBUG_ENTER("records_in_range");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
prebuilt->trx->op_info = (char*)"estimating records in index range";
@ -5725,7 +5747,7 @@ ha_innobase::check(
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
if (prebuilt->mysql_template == NULL) {
/* Build the template; we will use a dummy template
@ -6009,7 +6031,7 @@ ha_innobase::can_switch_engines(void)
DBUG_ENTER("ha_innobase::can_switch_engines");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[innobase_hton->slot]);
(trx_t*) current_thd->ha_data[ht->slot]);
prebuilt->trx->op_info =
"determining if there are foreign key constraints";
@ -6202,10 +6224,10 @@ ha_innobase::start_stmt(
/* Set the MySQL flag to mark that there is an active transaction */
if (trx->active_trans == 0) {
innobase_register_trx_and_stmt(thd);
innobase_register_trx_and_stmt(ht, thd);
trx->active_trans = 1;
} else {
innobase_register_stmt(thd);
innobase_register_stmt(ht, thd);
}
return(0);
@ -6278,10 +6300,10 @@ ha_innobase::external_lock(
transaction */
if (trx->active_trans == 0) {
innobase_register_trx_and_stmt(thd);
innobase_register_trx_and_stmt(ht, thd);
trx->active_trans = 1;
} else if (trx->n_mysql_tables_in_use == 0) {
innobase_register_stmt(thd);
innobase_register_stmt(ht, thd);
}
trx->n_mysql_tables_in_use++;
@ -6359,7 +6381,7 @@ ha_innobase::external_lock(
if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
if (trx->active_trans != 0) {
innobase_commit(thd, TRUE);
innobase_commit(ht, thd, TRUE);
}
} else {
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
@ -6440,7 +6462,7 @@ ha_innobase::transactional_table_lock(
/* Set the MySQL flag to mark that there is an active transaction */
if (trx->active_trans == 0) {
innobase_register_trx_and_stmt(thd);
innobase_register_trx_and_stmt(ht, thd);
trx->active_trans = 1;
}
@ -6488,6 +6510,7 @@ Monitor to the client. */
bool
innodb_show_status(
/*===============*/
handlerton* hton, /* in: the innodb handlerton */
THD* thd, /* in: the MySQL query thread of the caller */
stat_print_fn *stat_print)
{
@ -6503,7 +6526,7 @@ innodb_show_status(
DBUG_RETURN(FALSE);
}
trx = check_trx_exists(thd);
trx = check_trx_exists(hton, thd);
innobase_release_stat_resources(trx);
@ -6578,6 +6601,7 @@ Implements the SHOW MUTEX STATUS command. . */
bool
innodb_mutex_show_status(
/*=====================*/
handlerton* hton, /* in: the innodb handlerton */
THD* thd, /* in: the MySQL query thread of the
caller */
stat_print_fn* stat_print)
@ -6659,14 +6683,15 @@ innodb_mutex_show_status(
DBUG_RETURN(FALSE);
}
bool innobase_show_status(THD* thd, stat_print_fn* stat_print,
enum ha_stat_type stat_type)
bool innobase_show_status(handlerton *hton, THD* thd,
stat_print_fn* stat_print,
enum ha_stat_type stat_type)
{
switch (stat_type) {
case HA_ENGINE_STATUS:
return innodb_show_status(thd, stat_print);
return innodb_show_status(hton, thd, stat_print);
case HA_ENGINE_MUTEX:
return innodb_mutex_show_status(thd, stat_print);
return innodb_mutex_show_status(hton, thd, stat_print);
default:
return FALSE;
}
@ -6766,7 +6791,7 @@ ha_innobase::store_lock(
because we call update_thd() later, in ::external_lock()! Failure to
understand this caused a serious memory corruption bug in 5.1.11. */
trx = check_trx_exists(thd);
trx = check_trx_exists(ht, thd);
/* 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
@ -7152,7 +7177,7 @@ ha_innobase::reset_auto_increment(ulonglong value)
bool
ha_innobase::get_error_message(int error, String *buf)
{
trx_t* trx = check_trx_exists(current_thd);
trx_t* trx = check_trx_exists(ht, current_thd);
buf->copy(trx->detailed_error, strlen(trx->detailed_error),
system_charset_info);
@ -7371,13 +7396,14 @@ int
innobase_xa_prepare(
/*================*/
/* out: 0 or error number */
handlerton *hton,
THD* thd, /* in: handle to the MySQL thread of the user
whose XA transaction should be prepared */
bool all) /* in: TRUE - commit transaction
FALSE - the current SQL statement ended */
{
int error = 0;
trx_t* trx = check_trx_exists(thd);
trx_t* trx = check_trx_exists(hton, thd);
if (thd->lex->sql_command != SQLCOM_XA_PREPARE &&
(all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))))
@ -7467,6 +7493,7 @@ innobase_xa_recover(
/*================*/
/* out: number of prepared transactions
stored in xid_list */
handlerton *hton,
XID* xid_list, /* in/out: prepared transactions */
uint len) /* in: number of slots in xid_list */
{
@ -7486,6 +7513,7 @@ int
innobase_commit_by_xid(
/*===================*/
/* out: 0 or error number */
handlerton *hton,
XID* xid) /* in: X/Open XA transaction identification */
{
trx_t* trx;
@ -7509,6 +7537,7 @@ int
innobase_rollback_by_xid(
/*=====================*/
/* out: 0 or error number */
handlerton *hton,
XID *xid) /* in: X/Open XA transaction identification */
{
trx_t* trx;
@ -7529,12 +7558,13 @@ This consistent view is then used inside of MySQL when accessing records
using a cursor. */
void*
innobase_create_cursor_view(void)
/*=============================*/
/* out: Pointer to cursor view or NULL */
innobase_create_cursor_view(
/* out: pointer to cursor view or NULL */
handlerton *hton, /* in: innobase hton */
THD* thd) /* in: user thread handle */
{
return(read_cursor_view_create_for_mysql(
check_trx_exists(current_thd)));
check_trx_exists(hton, thd)));
}
/***********************************************************************
@ -7544,10 +7574,11 @@ corresponding MySQL thread still lacks one. */
void
innobase_close_cursor_view(
/*=======================*/
handlerton *hton,
THD* thd, /* in: user thread handle */
void* curview)/* in: Consistent read view to be closed */
{
read_cursor_view_close_for_mysql(check_trx_exists(current_thd),
read_cursor_view_close_for_mysql(check_trx_exists(hton, current_thd),
(cursor_view_t*) curview);
}
@ -7560,9 +7591,11 @@ restored to a transaction read view. */
void
innobase_set_cursor_view(
/*=====================*/
handlerton *hton,
THD* thd, /* in: user thread handle */
void* curview)/* in: Consistent cursor view to be set */
{
read_cursor_set_for_mysql(check_trx_exists(current_thd),
read_cursor_set_for_mysql(check_trx_exists(hton, current_thd),
(cursor_view_t*) curview);
}
@ -7607,7 +7640,7 @@ SHOW_VAR innodb_status_variables_export[]= {
};
struct st_mysql_storage_engine innobase_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, innobase_hton};
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(innobase)
{

View file

@ -80,7 +80,7 @@ class ha_innobase: public handler
/* Init values for the class: */
public:
ha_innobase(TABLE_SHARE *table_arg);
ha_innobase(handlerton *hton, TABLE_SHARE *table_arg);
~ha_innobase() {}
/*
Get the row type from the storage engine. If this method returns
@ -240,8 +240,8 @@ extern ulong srv_flush_log_at_trx_commit;
}
int innobase_init(void);
int innobase_end(ha_panic_function type);
bool innobase_flush_logs(void);
int innobase_end(handlerton *hton, ha_panic_function type);
bool innobase_flush_logs(handlerton *hton);
uint innobase_get_free_space(void);
/*
@ -258,14 +258,14 @@ int innobase_commit_complete(void* trx_handle);
void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset);
#endif
void innobase_drop_database(char *path);
bool innobase_show_status(THD* thd, stat_print_fn*, enum ha_stat_type);
void innobase_drop_database(handlerton *hton, char *path);
bool innobase_show_status(handlerton *hton, THD* thd, stat_print_fn*, enum ha_stat_type);
int innobase_release_temporary_latches(THD *thd);
int innobase_release_temporary_latches(handlerton *hton, THD *thd);
void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset);
void innobase_store_binlog_offset_and_flush_log(handlerton *hton, char *binlog_name,longlong offset);
int innobase_start_trx_and_assign_read_view(THD* thd);
int innobase_start_trx_and_assign_read_view(handlerton *hton, THD* thd);
/***********************************************************************
This function is used to prepare X/Open XA distributed transaction */
@ -273,6 +273,7 @@ This function is used to prepare X/Open XA distributed transaction */
int innobase_xa_prepare(
/*====================*/
/* out: 0 or error number */
handlerton *hton, /* in: innobase hton */
THD* thd, /* in: handle to the MySQL thread of the user
whose XA transaction should be prepared */
bool all); /* in: TRUE - commit transaction
@ -285,6 +286,7 @@ int innobase_xa_recover(
/*====================*/
/* out: number of prepared transactions
stored in xid_list */
handlerton *hton, /* in: innobase hton */
XID* xid_list, /* in/out: prepared transactions */
uint len); /* in: number of slots in xid_list */
@ -295,6 +297,7 @@ which is in the prepared state */
int innobase_commit_by_xid(
/*=======================*/
/* out: 0 or error number */
handlerton *hton, /* in: innobase hton */
XID* xid); /* in : X/Open XA Transaction Identification */
/***********************************************************************
@ -303,6 +306,7 @@ which is in the prepared state */
int innobase_rollback_by_xid(
/* out: 0 or error number */
handlerton *hton, /* in: innobase hton */
XID *xid); /* in : X/Open XA Transaction Identification */
@ -313,9 +317,10 @@ This consistent view is then used inside of MySQL when accessing records
using a cursor. */
void*
innobase_create_cursor_view(void);
/*=============================*/
/* out: Pointer to cursor view or NULL */
innobase_create_cursor_view(
/* out: Pointer to cursor view or NULL */
handlerton *hton, /* in: innobase hton */
THD* thd); /* in: user thread handle */
/***********************************************************************
Close the given consistent cursor view of a transaction and restore
@ -325,8 +330,11 @@ corresponding MySQL thread still lacks one. */
void
innobase_close_cursor_view(
/*=======================*/
handlerton *hton, /* in: innobase hton */
THD* thd, /* in: user thread handle */
void* curview); /* in: Consistent read view to be closed */
/***********************************************************************
Set the given consistent cursor view to a transaction which is created
if the corresponding MySQL thread still lacks one. If the given
@ -336,4 +344,6 @@ restored to a transaction read view. */
void
innobase_set_cursor_view(
/*=====================*/
handlerton *hton, /* in: innobase hton */
THD* thd, /* in: user thread handle */
void* curview); /* in: Consistent read view to be set */

View file

@ -48,9 +48,11 @@ TYPELIB myisam_stats_method_typelib= {
** MyISAM tables
*****************************************************************************/
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
static handler *myisam_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
return new (mem_root) ha_myisam(hton, table);
}
// collect errors printed by mi_check routines
@ -133,8 +135,8 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
}
ha_myisam::ha_myisam(TABLE_SHARE *table_arg)
:handler(myisam_hton, table_arg), file(0),
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg), file(0),
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
@ -1787,21 +1789,27 @@ bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_YES;
}
handlerton *myisam_hton;
extern int mi_panic(enum ha_panic_function flag);
int myisam_panic(handlerton *hton, ha_panic_function flag)
{
return mi_panic(flag);
}
static int myisam_init(void *p)
{
handlerton *myisam_hton;
myisam_hton= (handlerton *)p;
myisam_hton->state=SHOW_OPTION_YES;
myisam_hton->db_type=DB_TYPE_MYISAM;
myisam_hton->create=myisam_create_handler;
myisam_hton->panic=mi_panic;
myisam_hton->state= SHOW_OPTION_YES;
myisam_hton->db_type= DB_TYPE_MYISAM;
myisam_hton->create= myisam_create_handler;
myisam_hton->panic= myisam_panic;
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
return 0;
}
struct st_mysql_storage_engine myisam_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, myisam_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(myisam)
{

View file

@ -43,7 +43,7 @@ class ha_myisam: public handler
int repair(THD *thd, MI_CHECK &param, bool optimize);
public:
ha_myisam(TABLE_SHARE *table_arg);
ha_myisam(handlerton *hton, TABLE_SHARE *table_arg);
~ha_myisam() {}
handler *clone(MEM_ROOT *mem_root);
const char *table_type() const { return "MyISAM"; }

View file

@ -1370,7 +1370,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
param->temp_filename);
goto err;
}
if (filecopy(param,new_file,info->dfile,0L,new_header_length,
if (new_header_length &&
filecopy(param,new_file,info->dfile,0L,new_header_length,
"datafile-header"))
goto err;
info->s->state.dellink= HA_OFFSET_ERROR;
@ -2072,7 +2073,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
param->temp_filename);
goto err;
}
if (filecopy(param, new_file,info->dfile,0L,new_header_length,
if (new_header_length &&
filecopy(param, new_file,info->dfile,0L,new_header_length,
"datafile-header"))
goto err;
if (param->testflag & T_UNPACK)
@ -2466,7 +2468,8 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
param->temp_filename);
goto err;
}
if (filecopy(param, new_file,info->dfile,0L,new_header_length,
if (new_header_length &&
filecopy(param, new_file,info->dfile,0L,new_header_length,
"datafile-header"))
goto err;
if (param->testflag & T_UNPACK)

View file

@ -34,19 +34,16 @@
static handler *myisammrg_create_handler(TABLE_SHARE *table,
MEM_ROOT *mem_root);
/* MyISAM MERGE handlerton */
handlerton *myisammrg_hton;
static handler *myisammrg_create_handler(TABLE_SHARE *table,
static handler *myisammrg_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisammrg(table);
return new (mem_root) ha_myisammrg(hton, table);
}
ha_myisammrg::ha_myisammrg(TABLE_SHARE *table_arg)
:handler(myisammrg_hton, table_arg), file(0)
ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg), file(0)
{}
static const char *ha_myisammrg_exts[] = {
@ -554,21 +551,29 @@ bool ha_myisammrg::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_NO;
}
extern int myrg_panic(enum ha_panic_function flag);
int myisammrg_panic(handlerton *hton, ha_panic_function flag)
{
return myrg_panic(flag);
}
static int myisammrg_init(void *p)
{
handlerton *myisammrg_hton;
myisammrg_hton= (handlerton *)p;
myisammrg_hton->state=have_merge_db;
myisammrg_hton->db_type=DB_TYPE_MRG_MYISAM;
myisammrg_hton->create=myisammrg_create_handler;
myisammrg_hton->panic=myrg_panic;
myisammrg_hton->flags= HTON_CAN_RECREATE;
myisammrg_hton->state= have_merge_db;
myisammrg_hton->db_type= DB_TYPE_MRG_MYISAM;
myisammrg_hton->create= myisammrg_create_handler;
myisammrg_hton->panic= myisammrg_panic;
myisammrg_hton->flags= HTON_CAN_RECREATE|HTON_NO_PARTITION;
return 0;
}
struct st_mysql_storage_engine myisammrg_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION, myisammrg_hton };
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
mysql_declare_plugin(myisammrg)
{

View file

@ -28,7 +28,7 @@ class ha_myisammrg: public handler
MYRG_INFO *file;
public:
ha_myisammrg(TABLE_SHARE *table_arg);
ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg);
~ha_myisammrg() {}
const char *table_type() const { return "MRG_MyISAM"; }
const char **bas_ext() const;