Merge branch '10.1' into bb-10.1-merge

This commit is contained in:
Sergei Golubchik 2014-12-03 11:37:26 +01:00
commit ec4137c62b
47 changed files with 3414 additions and 694 deletions

View File

@ -216,6 +216,8 @@
#cmakedefine HAVE_POLL 1
#cmakedefine HAVE_PORT_CREATE 1
#cmakedefine HAVE_POSIX_FALLOCATE 1
#cmakedefine HAVE_LINUX_FALLOC_H 1
#cmakedefine HAVE_FALLOCATE 1
#cmakedefine HAVE_PREAD 1
#cmakedefine HAVE_PAUSE_INSTRUCTION 1
#cmakedefine HAVE_FAKE_PAUSE_INSTRUCTION 1

View File

@ -199,6 +199,7 @@ CHECK_INCLUDE_FILES (ieeefp.h HAVE_IEEEFP_H)
CHECK_INCLUDE_FILES (inttypes.h HAVE_INTTYPES_H)
CHECK_INCLUDE_FILES (langinfo.h HAVE_LANGINFO_H)
CHECK_INCLUDE_FILES (linux/unistd.h HAVE_LINUX_UNISTD_H)
CHECK_INCLUDE_FILES (linux/falloc.h HAVE_LINUX_FALLOC_H)
CHECK_INCLUDE_FILES (limits.h HAVE_LIMITS_H)
CHECK_INCLUDE_FILES (locale.h HAVE_LOCALE_H)
CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
@ -399,6 +400,7 @@ CHECK_FUNCTION_EXISTS (perror HAVE_PERROR)
CHECK_FUNCTION_EXISTS (poll HAVE_POLL)
CHECK_FUNCTION_EXISTS (port_create HAVE_PORT_CREATE)
CHECK_FUNCTION_EXISTS (posix_fallocate HAVE_POSIX_FALLOCATE)
CHECK_FUNCTION_EXISTS (fallocate HAVE_FALLOCATE)
CHECK_FUNCTION_EXISTS (pread HAVE_PREAD)
CHECK_FUNCTION_EXISTS (pthread_attr_create HAVE_PTHREAD_ATTR_CREATE)
CHECK_FUNCTION_EXISTS (pthread_attr_getstacksize HAVE_PTHREAD_ATTR_GETSTACKSIZE)

View File

@ -100,6 +100,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/rpl_reporting.cc
../sql/sql_expression_cache.cc
../sql/my_apc.cc ../sql/my_apc.h
../sql/my_json_writer.cc ../sql/my_json_writer.h
../sql/rpl_gtid.cc
../sql/sql_explain.cc ../sql/sql_explain.h
../sql/compat56.cc

View File

@ -0,0 +1,172 @@
drop table if exists t0,t1,t2,t3;
create table t0 (a int);
INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
# r_filtered=30%, because 3 rows match: 0,1,2
analyze format=json select * from t0 where a<3;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"filtered": 100,
"r_filtered": 30,
"attached_condition": "(t0.a < 3)"
}
}
}
create table t1 (a int, b int, c int, key(a));
insert into t1 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B;
analyze
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 0.00 Using where
1 SIMPLE t1 ref a a 5 test.t0.a 1 NULL 100.00 NULL
analyze format=json
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"filtered": 100,
"r_filtered": 0,
"attached_condition": "((t0.a > 9) and (t0.a is not null))"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["a"],
"key": "a",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t0.a"],
"r_loops": 0,
"rows": 1,
"r_rows": null,
"filtered": 100,
"r_filtered": null
}
}
}
analyze
select * from t0, t1 where t1.a=t0.a and t1.b<4;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 100.00 Using where
1 SIMPLE t1 ref a a 5 test.t0.a 1 1 100.00 40.00 Using where
analyze format=json
select * from t0, t1 where t1.a=t0.a and t1.b<4;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"filtered": 100,
"r_filtered": 100,
"attached_condition": "(t0.a is not null)"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["a"],
"key": "a",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t0.a"],
"r_loops": 10,
"rows": 1,
"r_rows": 1,
"filtered": 100,
"r_filtered": 40,
"attached_condition": "(t1.b < 4)"
}
}
}
analyze
select * from t1 tbl1, t1 tbl2 where tbl1.b<2 and tbl2.b>5;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE tbl1 ALL NULL NULL NULL NULL 100 100 100.00 2.00 Using where
1 SIMPLE tbl2 ALL NULL NULL NULL NULL 100 100 100.00 94.00 Using where; Using join buffer (flat, BNL join)
analyze format=json
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "tbl1",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"filtered": 100,
"r_filtered": 20,
"attached_condition": "(tbl1.b < 20)"
},
"block-nl-join": {
"table": {
"table_name": "tbl2",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"filtered": 100,
"r_filtered": 60,
"attached_condition": "(tbl2.b < 60)"
},
"buffer_type": "flat",
"join_type": "BNL",
"r_filtered": 100
}
}
}
analyze format=json
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60 and tbl1.c > tbl2.c;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "tbl1",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"filtered": 100,
"r_filtered": 20,
"attached_condition": "(tbl1.b < 20)"
},
"block-nl-join": {
"table": {
"table_name": "tbl2",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"filtered": 100,
"r_filtered": 60,
"attached_condition": "(tbl2.b < 60)"
},
"buffer_type": "flat",
"join_type": "BNL",
"attached_condition": "(tbl1.c > tbl2.c)",
"r_filtered": 15.833
}
}
}
drop table t1;
drop table t0;

View File

@ -0,0 +1,668 @@
drop table if exists t0,t1;
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
explain format=json select * from t0;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
explain format=json select * from t0 where 1>2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"message": "Impossible WHERE"
}
}
}
explain format=json select * from t0 where a<3;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(t0.a < 3)"
}
}
}
# Try a basic join
create table t1 (a int, b int, filler char(32), key(a));
insert into t1
select
a.a + b.a* 10 + c.a * 100,
a.a + b.a* 10 + c.a * 100,
'filler'
from t0 a, t0 b, t0 c;
explain format=json select * from t0,t1 where t1.a=t0.a;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(t0.a is not null)"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["a"],
"key": "a",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t0.a"],
"rows": 1,
"filtered": 100
}
}
}
# Try range and index_merge
create table t2 (a1 int, a2 int, b1 int, b2 int, key(a1,a2), key(b1,b2));
insert into t2 select a,a,a,a from t1;
explain format=json select * from t2 where a1<5;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["a1"],
"key": "a1",
"key_length": "5",
"used_key_parts": ["a1"],
"rows": 5,
"filtered": 100,
"index_condition": "(t2.a1 < 5)"
}
}
}
explain format=json select * from t2 where a1=1 or b1=2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "index_merge",
"possible_keys": ["a1", "b1"],
"key_length": "5,5",
"index_merge": {
"sort_union": {
"range": {
"key": "a1",
"used_key_parts": ["a1"]
},
"range": {
"key": "b1",
"used_key_parts": ["b1"]
}
}
},
"rows": 2,
"filtered": 100,
"attached_condition": "((t2.a1 = 1) or (t2.b1 = 2))"
}
}
}
explain format=json select * from t2 where a1=1 or (b1=2 and b2=3);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "index_merge",
"possible_keys": ["a1", "b1"],
"key_length": "5,10",
"index_merge": {
"sort_union": {
"range": {
"key": "a1",
"used_key_parts": ["a1"]
},
"range": {
"key": "b1",
"used_key_parts": ["b1", "b2"]
}
}
},
"rows": 2,
"filtered": 100,
"attached_condition": "((t2.a1 = 1) or ((t2.b1 = 2) and (t2.b2 = 3)))"
}
}
}
# Try ref access on two key components
explain format=json select * from t0,t2 where t2.b1=t0.a and t2.b2=4;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(t0.a is not null)"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["b1"],
"key": "b1",
"key_length": "10",
"used_key_parts": ["b1", "b2"],
"ref": ["test.t0.a", "const"],
"rows": 1,
"filtered": 100
}
}
}
drop table t1,t2;
#
# Try a UNION
#
explain format=json select * from t0 A union select * from t0 B;
EXPLAIN
{
"query_block": {
"union_result": {
"table_name": "<union1,2>",
"access_type": "ALL",
"query_specifications": [
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "A",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
},
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "B",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
]
}
}
}
explain format=json select * from t0 A union all select * from t0 B;
EXPLAIN
{
"query_block": {
"union_result": {
"table_name": "<union1,2>",
"access_type": "ALL",
"query_specifications": [
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "A",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
},
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "B",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
]
}
}
}
#
# Subqueries
#
create table t1 (a int, b int);
insert into t1 select a,a from t0;
explain format=json select a, a > (select max(b) from t1 where t1.b=t0.a) from t0;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(t1.b = t0.a)"
}
}
}
]
}
}
explain format=json
select * from t0 where
a > (select max(b) from t1 where t1.b=t0.a) or a < 3 ;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "((t0.a > (subquery#2)) or (t0.a < 3))"
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(t1.b = t0.a)"
}
}
}
]
}
}
drop table t1;
#
# Join buffering
#
create table t1 (a int, b int);
insert into t1 select tbl1.a+10*tbl2.a, tbl1.a+10*tbl2.a from t0 tbl1, t0 tbl2;
explain format=json
select * from t1 tbl1, t1 tbl2 where tbl1.a=tbl2.a and tbl1.b < 3 and tbl2.b < 5;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "tbl1",
"access_type": "ALL",
"rows": 100,
"filtered": 100,
"attached_condition": "(tbl1.b < 3)"
},
"block-nl-join": {
"table": {
"table_name": "tbl2",
"access_type": "ALL",
"rows": 100,
"filtered": 100,
"attached_condition": "(tbl2.b < 5)"
},
"buffer_type": "flat",
"join_type": "BNL",
"attached_condition": "(tbl2.a = tbl1.a)"
}
}
}
drop table t1;
#
# Single-table UPDATE/DELETE, INSERT
#
explain format=json delete from t0;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"message": "Deleting all rows"
}
}
}
explain format=json delete from t0 where 1 > 2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"message": "Impossible WHERE"
}
}
}
explain format=json delete from t0 where a < 3;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"delete": 1,
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"attached_condition": "(t0.a < 3)"
}
}
}
explain format=json update t0 set a=3 where a in (2,3,4);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"update": 1,
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"attached_condition": "(t0.a in (2,3,4))"
}
}
}
explain format=json insert into t0 values (1);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t0"
}
}
}
create table t1 like t0;
explain format=json insert into t1 values ((select max(a) from t0));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1"
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
]
}
}
drop table t1;
#
# A derived table
#
create table t1 (a int, b int);
insert into t1 select a,a from t0;
explain format=json
select * from (select a, count(*) as cnt from t1 group by a) as tbl
where cnt>0;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "<derived2>",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(tbl.cnt > 0)",
"materialized": {
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
}
}
explain format=json
select * from (select a, count(*) as cnt from t1 group by a) as tbl1, t1 as
tbl2 where cnt=tbl2.a;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "tbl2",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(tbl2.a is not null)"
},
"table": {
"table_name": "<derived2>",
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
"key_length": "8",
"used_key_parts": ["cnt"],
"ref": ["test.tbl2.a"],
"rows": 2,
"filtered": 100,
"attached_condition": "(tbl1.cnt = tbl2.a)",
"materialized": {
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
}
}
#
# Non-merged semi-join (aka JTBM)
#
explain format=json
select * from t1 where a in (select max(a) from t1 group by b);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(t1.a is not null)"
},
"table": {
"table_name": "<subquery2>",
"access_type": "eq_ref",
"possible_keys": ["distinct_key"],
"key": "distinct_key",
"key_length": "4",
"used_key_parts": ["max(a)"],
"ref": ["test.t1.a"],
"rows": 1,
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
}
}
#
# Semi-join Materialization
#
create table t2 like t1;
insert into t2 select * from t1;
explain format=json
select * from t1,t2 where t1.a in ( select a from t0);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"table": {
"table_name": "<subquery2>",
"access_type": "eq_ref",
"possible_keys": ["distinct_key"],
"key": "distinct_key",
"key_length": "4",
"used_key_parts": ["a"],
"ref": ["func"],
"rows": 1,
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
},
"block-nl-join": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"buffer_type": "flat",
"join_type": "BNL"
}
}
}
#
# First-Match
#
explain
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 10
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; FirstMatch(t2); Using join buffer (flat, BNL join)
explain format=json
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"block-nl-join": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"first_match": "t2"
},
"buffer_type": "flat",
"join_type": "BNL",
"attached_condition": "((t1.b = t2.b) and (t1.a = t2.a))"
}
}
}
#
# Duplicate Weedout
#
set @tmp= @@optimizer_switch;
set optimizer_switch='firstmatch=off';
explain
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 10
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join)
explain format=json
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"duplicates_removal": {
"block-nl-join": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"buffer_type": "flat",
"join_type": "BNL",
"attached_condition": "((t1.b = t2.b) and (t1.a = t2.a))"
}
}
}
}
set optimizer_switch=@tmp;
drop table t1,t2;
drop table t0;

View File

@ -872,7 +872,7 @@ explain extended select period_add("9602",-12),period_diff(199505,"9404"),from_d
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select period_add('9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,'9404') AS `period_diff(199505,"9404")`,from_days(to_days('960101')) AS `from_days(to_days("960101"))`,dayofmonth('1997-01-02') AS `dayofmonth("1997-01-02")`,month('1997-01-02') AS `month("1997-01-02")`,monthname('1972-03-04') AS `monthname("1972-03-04")`,dayofyear('0000-00-00') AS `dayofyear("0000-00-00")`,hour('1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute('23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week('1998-03-03',0) AS `WEEK("1998-03-03")`,yearweek('2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year('98-02-03') AS `year("98-02-03")`,(weekday(curdate()) - weekday(now())) AS `weekday(curdate())-weekday(now())`,dayname('1962-03-03') AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec('0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format('1997-01-02 03:04:05','%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp('1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,('1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,('1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,('1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from '1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,('1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)`
Note 1003 select period_add('9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,'9404') AS `period_diff(199505,"9404")`,from_days(to_days('960101')) AS `from_days(to_days("960101"))`,dayofmonth('1997-01-02') AS `dayofmonth("1997-01-02")`,month('1997-01-02') AS `month("1997-01-02")`,monthname('1972-03-04') AS `monthname("1972-03-04")`,dayofyear('0000-00-00') AS `dayofyear("0000-00-00")`,hour('1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute('23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week('1998-03-03',@@default_week_format) AS `WEEK("1998-03-03")`,yearweek('2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year('98-02-03') AS `year("98-02-03")`,(weekday(curdate()) - weekday(now())) AS `weekday(curdate())-weekday(now())`,dayname('1962-03-03') AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec('0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format('1997-01-02 03:04:05','%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp('1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,('1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,('1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,('1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from '1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,('1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)`
SET @TMP='2007-08-01 12:22:49';
CREATE TABLE t1 (d DATETIME);
INSERT INTO t1 VALUES ('2007-08-01 12:22:59');

View File

@ -130,7 +130,8 @@ ERROR HY000: Constant, random or timezone-dependent expressions in (sub)partitio
create table t1 (col1 datetime)
partition by range(week(col1))
(partition p0 values less than (10), partition p1 values less than (30));
ERROR HY000: This partition function is not allowed
ERROR 42000: Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed near ')
(partition p0 values less than (10), partition p1 values less than (30))' at line 2
create table t1 (col1 varchar(25))
partition by range(cast(col1 as signed))
(partition p0 values less than (10), partition p1 values less than (30));

View File

@ -1070,11 +1070,71 @@ set statement character_set_filesystem=default for select 1;
ERROR 42000: The system variable character_set_filesystem cannot be set in SET STATEMENT.
set statement collation_connection=default for select 1;
ERROR 42000: The system variable collation_connection cannot be set in SET STATEMENT.
set statement old_passwords=default for select 1;
ERROR 42000: The system variable old_passwords cannot be set in SET STATEMENT.
set statement query_cache_type=default for select 1;
ERROR 42000: The system variable query_cache_type cannot be set in SET STATEMENT.
set statement wait_timeout=default for select 1;
ERROR 42000: The system variable wait_timeout cannot be set in SET STATEMENT.
set statement interactive_timeout=default for select 1;
ERROR 42000: The system variable interactive_timeout cannot be set in SET STATEMENT.
set @save_week_format=@@default_week_format;
set @@default_week_format=0;
SET STATEMENT default_week_format = 2 FOR SELECT WEEK('2000-01-01');
WEEK('2000-01-01')
52
create table t1 (a date);
insert t1 values ('2000-01-01');
explain extended select week(a) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 100.00
Warnings:
Note 1003 select week('2000-01-01',@@default_week_format) AS `week(a)` from dual
prepare stmt1 from "select week(a) from t1";
execute stmt1;
week(a)
0
set default_week_format = 2;
execute stmt1;
week(a)
52
alter table t1 engine=myisam;
execute stmt1;
week(a)
52
deallocate prepare stmt1;
drop table t1;
set @@default_week_format=@save_week_format;
set @save_old_passwords=@@old_passwords;
set @@old_passwords=0;
set statement OLD_PASSWORDS = 0 for select password('test');
password('test')
*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
set statement OLD_PASSWORDS = 1 for select password('test');
password('test')
378b243e220ca493
set statement OLD_PASSWORDS = 0 for explain extended select password('test');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select password('test') AS `password('test')`
set statement OLD_PASSWORDS = 1 for explain extended select password('test');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select password('test') AS `password('test')`
create table t1 (a char(10));
insert t1 values ('qwertyuiop');
prepare stmt1 from "select password(a) from t1";
execute stmt1;
password(a)
*6063C78456BB048BAF36BE1104D12D547834DFEA
set old_passwords=1;
execute stmt1;
password(a)
2013610f6aac2950
alter table t1 engine=myisam;
execute stmt1;
password(a)
2013610f6aac2950
deallocate prepare stmt1;
drop table t1;
set @@old_passwords=@save_old_passwords;

View File

@ -1617,7 +1617,7 @@ NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL NULL Using filesort
3 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1276 Field or reference 'a' of SELECT #3 was resolved in SELECT #-1
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` union select `test`.`t1`.`a` AS `a` from `test`.`t1` order by <expr_cache><>((select `a` from `test`.`t2` where (`test`.`t2`.`b` = 12)))
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` union select `test`.`t1`.`a` AS `a` from `test`.`t1` order by <expr_cache><`a`>((select `a` from `test`.`t2` where (`test`.`t2`.`b` = 12)))
# Should not crash
SELECT * FROM t1 UNION SELECT * FROM t1
ORDER BY (SELECT a FROM t2 WHERE b = 12);

View File

@ -181,7 +181,7 @@ NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL NULL Using filesort
3 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1276 Field or reference 'a' of SELECT #3 was resolved in SELECT #-1
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` union select `test`.`t1`.`a` AS `a` from `test`.`t1` order by <expr_cache><>((select `a` from `test`.`t2` where (`test`.`t2`.`b` = 12)))
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` union select `test`.`t1`.`a` AS `a` from `test`.`t1` order by <expr_cache><`a`>((select `a` from `test`.`t2` where (`test`.`t2`.`b` = 12)))
# Should not crash
SELECT * FROM t1 UNION SELECT * FROM t1
ORDER BY (SELECT a FROM t2 WHERE b = 12);

View File

@ -0,0 +1,38 @@
#
# Tests for "ANALYZE FORMAT=JSON $statement" syntax
#
--disable_warnings
drop table if exists t0,t1,t2,t3;
--enable_warnings
create table t0 (a int);
INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
--echo # r_filtered=30%, because 3 rows match: 0,1,2
analyze format=json select * from t0 where a<3;
create table t1 (a int, b int, c int, key(a));
insert into t1 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B;
analyze
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
analyze format=json
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
analyze
select * from t0, t1 where t1.a=t0.a and t1.b<4;
analyze format=json
select * from t0, t1 where t1.a=t0.a and t1.b<4;
analyze
select * from t1 tbl1, t1 tbl2 where tbl1.b<2 and tbl2.b>5;
analyze format=json
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60;
analyze format=json
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60 and tbl1.c > tbl2.c;
drop table t1;
drop table t0;

View File

@ -0,0 +1,138 @@
#
# EXPLAIN FORMAT=JSON tests. These are tests developed for MariaDB.
#
--disable_warnings
drop table if exists t0,t1;
--enable_warnings
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
explain format=json select * from t0;
explain format=json select * from t0 where 1>2;
explain format=json select * from t0 where a<3;
--echo # Try a basic join
create table t1 (a int, b int, filler char(32), key(a));
insert into t1
select
a.a + b.a* 10 + c.a * 100,
a.a + b.a* 10 + c.a * 100,
'filler'
from t0 a, t0 b, t0 c;
explain format=json select * from t0,t1 where t1.a=t0.a;
--echo # Try range and index_merge
create table t2 (a1 int, a2 int, b1 int, b2 int, key(a1,a2), key(b1,b2));
insert into t2 select a,a,a,a from t1;
explain format=json select * from t2 where a1<5;
explain format=json select * from t2 where a1=1 or b1=2;
explain format=json select * from t2 where a1=1 or (b1=2 and b2=3);
--echo # Try ref access on two key components
explain format=json select * from t0,t2 where t2.b1=t0.a and t2.b2=4;
drop table t1,t2;
--echo #
--echo # Try a UNION
--echo #
explain format=json select * from t0 A union select * from t0 B;
explain format=json select * from t0 A union all select * from t0 B;
--echo #
--echo # Subqueries
--echo #
create table t1 (a int, b int);
insert into t1 select a,a from t0;
explain format=json select a, a > (select max(b) from t1 where t1.b=t0.a) from t0;
explain format=json
select * from t0 where
a > (select max(b) from t1 where t1.b=t0.a) or a < 3 ;
drop table t1;
--echo #
--echo # Join buffering
--echo #
create table t1 (a int, b int);
insert into t1 select tbl1.a+10*tbl2.a, tbl1.a+10*tbl2.a from t0 tbl1, t0 tbl2;
explain format=json
select * from t1 tbl1, t1 tbl2 where tbl1.a=tbl2.a and tbl1.b < 3 and tbl2.b < 5;
drop table t1;
--echo #
--echo # Single-table UPDATE/DELETE, INSERT
--echo #
explain format=json delete from t0;
explain format=json delete from t0 where 1 > 2;
explain format=json delete from t0 where a < 3;
explain format=json update t0 set a=3 where a in (2,3,4);
explain format=json insert into t0 values (1);
create table t1 like t0;
explain format=json insert into t1 values ((select max(a) from t0));
drop table t1;
--echo #
--echo # A derived table
--echo #
create table t1 (a int, b int);
insert into t1 select a,a from t0;
explain format=json
select * from (select a, count(*) as cnt from t1 group by a) as tbl
where cnt>0;
explain format=json
select * from (select a, count(*) as cnt from t1 group by a) as tbl1, t1 as
tbl2 where cnt=tbl2.a;
--echo #
--echo # Non-merged semi-join (aka JTBM)
--echo #
explain format=json
select * from t1 where a in (select max(a) from t1 group by b);
--echo #
--echo # Semi-join Materialization
--echo #
create table t2 like t1;
insert into t2 select * from t1;
explain format=json
select * from t1,t2 where t1.a in ( select a from t0);
--echo #
--echo # First-Match
--echo #
explain
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
explain format=json
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
--echo #
--echo # Duplicate Weedout
--echo #
set @tmp= @@optimizer_switch;
set optimizer_switch='firstmatch=off';
explain
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
explain format=json
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
set optimizer_switch=@tmp;
drop table t1,t2;
drop table t0;

View File

@ -163,7 +163,7 @@ create table t1 (col1 date)
partition by range(unix_timestamp(col1))
(partition p0 values less than (10), partition p1 values less than (30));
-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
-- error ER_PARSE_ERROR
create table t1 (col1 datetime)
partition by range(week(col1))
(partition p0 values less than (10), partition p1 values less than (30));

View File

@ -1025,11 +1025,44 @@ set statement character_set_filesystem=default for select 1;
--error ER_SET_STATEMENT_NOT_SUPPORTED
set statement collation_connection=default for select 1;
--error ER_SET_STATEMENT_NOT_SUPPORTED
set statement old_passwords=default for select 1;
--error ER_SET_STATEMENT_NOT_SUPPORTED
set statement query_cache_type=default for select 1;
--error ER_SET_STATEMENT_NOT_SUPPORTED
set statement wait_timeout=default for select 1;
--error ER_SET_STATEMENT_NOT_SUPPORTED
set statement interactive_timeout=default for select 1;
# MDEV-6996: SET STATEMENT default_week_format = .. has no effect
set @save_week_format=@@default_week_format;
set @@default_week_format=0;
SET STATEMENT default_week_format = 2 FOR SELECT WEEK('2000-01-01');
create table t1 (a date);
insert t1 values ('2000-01-01');
explain extended select week(a) from t1;
prepare stmt1 from "select week(a) from t1";
execute stmt1;
set default_week_format = 2;
execute stmt1;
alter table t1 engine=myisam;
execute stmt1;
deallocate prepare stmt1;
drop table t1;
set @@default_week_format=@save_week_format;
# MDEV-7015: SET STATEMENT old_passwords has no effect
set @save_old_passwords=@@old_passwords;
set @@old_passwords=0;
set statement OLD_PASSWORDS = 0 for select password('test');
set statement OLD_PASSWORDS = 1 for select password('test');
set statement OLD_PASSWORDS = 0 for explain extended select password('test');
set statement OLD_PASSWORDS = 1 for explain extended select password('test');
create table t1 (a char(10));
insert t1 values ('qwertyuiop');
prepare stmt1 from "select password(a) from t1";
execute stmt1;
set old_passwords=1;
execute stmt1;
alter table t1 engine=myisam;
execute stmt1;
deallocate prepare stmt1;
drop table t1;
set @@old_passwords=@save_old_passwords;

View File

@ -112,6 +112,7 @@ SET (SQL_SOURCE
threadpool_common.cc
../sql-common/mysql_async.c
my_apc.cc my_apc.h
my_json_writer.cc my_json_writer.h
rpl_gtid.cc rpl_parallel.cc
${WSREP_SOURCES}
table_cache.cc

View File

@ -2504,7 +2504,13 @@ void Item_ident::print(String *str, enum_query_type query_type)
}
if (db_name && db_name[0] && !alias_name_used)
{
if (!(cached_table && cached_table->belong_to_view &&
/*
When printing EXPLAIN, don't print database name when it's the same as
current database.
*/
bool skip_db= (query_type & QT_EXPLAIN) && !strcmp(thd->db, db_name);
if (!skip_db &&
!(cached_table && cached_table->belong_to_view &&
cached_table->belong_to_view->compact_view_format))
{
append_identifier(thd, str, d_name, (uint)strlen(d_name));
@ -7542,6 +7548,13 @@ void Item_cache_wrapper::init_on_demand()
void Item_cache_wrapper::print(String *str, enum_query_type query_type)
{
if (query_type == QT_EXPLAIN)
{
/* Don't print the cache in EXPLAIN EXTENDED */
orig_item->print(str, query_type);
return;
}
str->append(func_name());
if (expr_cache)
{

View File

@ -2171,56 +2171,67 @@ void Item_func_trim::print(String *str, enum_query_type query_type)
/* Item_func_password */
bool Item_func_password::fix_fields(THD *thd, Item **ref)
{
if (deflt)
alg= (thd->variables.old_passwords ? OLD : NEW);
return Item_str_ascii_func::fix_fields(thd, ref);
}
String *Item_func_password::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res= args[0]->val_str(str);
check_password_policy(res);
if (args[0]->null_value || res->length() == 0)
return make_empty_result();
my_make_scrambled_password(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
switch (alg){
case NEW:
check_password_policy(res);
if (args[0]->null_value || res->length() == 0)
return make_empty_result();
my_make_scrambled_password(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
break;
case OLD:
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return make_empty_result();
my_make_scrambled_password_323(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1);
break;
default:
DBUG_ASSERT(0);
}
return str;
}
char *Item_func_password::alloc(THD *thd, const char *password, size_t pass_len)
char *Item_func_password::alloc(THD *thd, const char *password,
size_t pass_len, enum PW_Alg al)
{
char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff)
{
String *password_str= new (thd->mem_root)String(password, thd->variables.
character_set_client);
check_password_policy(password_str);
my_make_scrambled_password(buff, password, pass_len);
char *buff= (char *) thd->alloc((al==NEW)?
SCRAMBLED_PASSWORD_CHAR_LENGTH + 1:
SCRAMBLED_PASSWORD_CHAR_LENGTH_323 + 1);
if (!buff)
return NULL;
switch (al) {
case NEW:
{
String *password_str= new (thd->mem_root)String(password, thd->variables.
character_set_client);
check_password_policy(password_str);
my_make_scrambled_password(buff, password, pass_len);
break;
}
case OLD:
my_make_scrambled_password_323(buff, password, pass_len);
break;
default:
DBUG_ASSERT(0);
}
return buff;
}
/* Item_func_old_password */
String *Item_func_old_password::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return make_empty_result();
my_make_scrambled_password_323(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1);
return str;
}
char *Item_func_old_password::alloc(THD *thd, const char *password,
size_t pass_len)
{
char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
if (buff)
my_make_scrambled_password_323(buff, password, pass_len);
return buff;
}
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')

View File

@ -407,40 +407,32 @@ public:
class Item_func_password :public Item_str_ascii_func
{
public:
enum PW_Alg {OLD, NEW};
private:
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
enum PW_Alg alg;
bool deflt;
public:
Item_func_password(Item *a) :Item_str_ascii_func(a) {}
Item_func_password(Item *a) :Item_str_ascii_func(a), alg(NEW), deflt(1) {}
Item_func_password(Item *a, PW_Alg al) :Item_str_ascii_func(a),
alg(al), deflt(0) {}
String *val_str_ascii(String *str);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec()
{
fix_length_and_charset(SCRAMBLED_PASSWORD_CHAR_LENGTH, default_charset());
fix_length_and_charset((alg == 1 ?
SCRAMBLED_PASSWORD_CHAR_LENGTH :
SCRAMBLED_PASSWORD_CHAR_LENGTH_323),
default_charset());
}
const char *func_name() const { return "password"; }
static char *alloc(THD *thd, const char *password, size_t pass_len);
const char *func_name() const { return ((deflt || alg == 1) ?
"password" : "old_password"); }
static char *alloc(THD *thd, const char *password, size_t pass_len,
enum PW_Alg al);
};
/*
Item_func_old_password -- PASSWORD() implementation used in MySQL 3.21 - 4.0
compatibility mode. This item is created in sql_yacc.yy when
'old_passwords' session variable is set, and to handle OLD_PASSWORD()
function.
*/
class Item_func_old_password :public Item_str_ascii_func
{
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1];
public:
Item_func_old_password(Item *a) :Item_str_ascii_func(a) {}
String *val_str_ascii(String *str);
void fix_length_and_dec()
{
fix_length_and_charset(SCRAMBLED_PASSWORD_CHAR_LENGTH_323, default_charset());
}
const char *func_name() const { return "old_password"; }
static char *alloc(THD *thd, const char *password, size_t pass_len);
};
class Item_func_des_encrypt :public Item_str_func
{

View File

@ -895,6 +895,21 @@ void Item_subselect::update_used_tables()
void Item_subselect::print(String *str, enum_query_type query_type)
{
if (query_type == QT_EXPLAIN)
{
str->append("(subquery#");
if (engine)
{
char buf[64];
ll2str(engine->get_identifier(), buf, 10, 0);
str->append(buf);
}
else
str->append("NULL"); // TODO: what exactly does this mean?
str->append(")");
return;
}
if (engine)
{
str->append('(');
@ -3717,6 +3732,10 @@ int subselect_union_engine::exec()
return res;
}
int subselect_union_engine::get_identifier()
{
return unit->first_select()->select_number;
}
/*
Search for at least one row satisfying select condition

View File

@ -871,6 +871,7 @@ public:
bool is_executed() const;
bool no_rows();
virtual enum_engine_type engine_type() { return UNION_ENGINE; }
int get_identifier();
};

View File

@ -242,6 +242,7 @@ static SYMBOL symbols[] = {
{ "FOR", SYM(FOR_SYM)},
{ "FORCE", SYM(FORCE_SYM)},
{ "FOREIGN", SYM(FOREIGN)},
{ "FORMAT", SYM(FORMAT_SYM)},
{ "FOUND", SYM(FOUND_SYM)},
{ "FROM", SYM(FROM)},
{ "FULL", SYM(FULL)},

345
sql/my_json_writer.cc Normal file
View File

@ -0,0 +1,345 @@
/* Copyright (C) 2014 SkySQL Ab, MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include "sql_priv.h"
#include "sql_string.h"
#include "my_json_writer.h"
void Json_writer::append_indent()
{
if (!document_start)
output.append('\n');
for (int i=0; i< indent_level; i++)
output.append(' ');
}
void Json_writer::start_object()
{
fmt_helper.on_start_object();
if (!element_started)
start_element();
output.append("{");
indent_level+=INDENT_SIZE;
first_child=true;
element_started= false;
document_start= false;
}
void Json_writer::start_array()
{
if (fmt_helper.on_start_array())
return;
if (!element_started)
start_element();
output.append("[");
indent_level+=INDENT_SIZE;
first_child=true;
element_started= false;
document_start= false;
}
void Json_writer::end_object()
{
indent_level-=INDENT_SIZE;
if (!first_child)
append_indent();
output.append("}");
}
void Json_writer::end_array()
{
if (fmt_helper.on_end_array())
return;
indent_level-=INDENT_SIZE;
if (!first_child)
append_indent();
output.append("]");
}
Json_writer& Json_writer::add_member(const char *name)
{
if (fmt_helper.on_add_member(name))
return *this; // handled
// assert that we are in an object
DBUG_ASSERT(!element_started);
start_element();
output.append('"');
output.append(name);
output.append("\": ");
return *this;
}
/*
Used by formatting helper to print something that is formatted by the helper.
We should only separate it from the previous element.
*/
void Json_writer::start_sub_element()
{
//element_started= true;
if (first_child)
first_child= false;
else
output.append(',');
append_indent();
}
void Json_writer::start_element()
{
element_started= true;
if (first_child)
first_child= false;
else
output.append(',');
append_indent();
}
void Json_writer::add_ll(longlong val)
{
char buf[64];
my_snprintf(buf, sizeof(buf), "%ld", val);
add_unquoted_str(buf);
}
void Json_writer::add_double(double val)
{
char buf[64];
my_snprintf(buf, sizeof(buf), "%lg", val);
add_unquoted_str(buf);
}
void Json_writer::add_bool(bool val)
{
add_unquoted_str(val? "true" : "false");
}
void Json_writer::add_null()
{
add_unquoted_str("null");
}
void Json_writer::add_unquoted_str(const char* str)
{
if (fmt_helper.on_add_str(str))
return;
if (!element_started)
start_element();
output.append(str);
element_started= false;
}
void Json_writer::add_str(const char *str)
{
if (fmt_helper.on_add_str(str))
return;
if (!element_started)
start_element();
output.append('"');
output.append(str);
output.append('"');
element_started= false;
}
void Json_writer::add_str(const String &str)
{
add_str(str.ptr());
}
bool Single_line_formatting_helper::on_add_member(const char *name)
{
DBUG_ASSERT(state== INACTIVE || state == DISABLED);
if (state != DISABLED)
{
// remove everything from the array
buf_ptr= buffer;
//append member name to the array
size_t len= strlen(name);
if (len < MAX_LINE_LEN)
{
memcpy(buf_ptr, name, len);
buf_ptr+=len;
*(buf_ptr++)= 0;
line_len= owner->indent_level + len + 1;
state= ADD_MEMBER;
return true; // handled
}
}
return false; // not handled
}
bool Single_line_formatting_helper::on_start_array()
{
if (state == ADD_MEMBER)
{
state= IN_ARRAY;
return true; // handled
}
else
{
state= INACTIVE;
// TODO: what if we have accumulated some stuff already? shouldn't we
// flush it?
return false; // not handled
}
}
bool Single_line_formatting_helper::on_end_array()
{
if (state == IN_ARRAY)
{
flush_on_one_line();
state= INACTIVE;
return true; // handled
}
return false; // not handled
}
void Single_line_formatting_helper::on_start_object()
{
// Nested objects will not be printed on one line
disable_and_flush();
}
bool Single_line_formatting_helper::on_add_str(const char *str)
{
if (state == IN_ARRAY)
{
size_t len= strlen(str);
// New length will be:
// "$string",
// quote + quote + comma + space = 4
if (line_len + len + 4 > MAX_LINE_LEN)
{
disable_and_flush();
return false; // didn't handle the last element
}
//append string to array
memcpy(buf_ptr, str, len);
buf_ptr+=len;
*(buf_ptr++)= 0;
line_len += len + 4;
return true; // handled
}
disable_and_flush();
return false; // not handled
}
/*
Append everything accumulated to the output on one line
*/
void Single_line_formatting_helper::flush_on_one_line()
{
owner->start_sub_element();
char *ptr= buffer;
int nr= 0;
while (ptr < buf_ptr)
{
char *str= ptr;
if (nr == 0)
{
owner->output.append('"');
owner->output.append(str);
owner->output.append("\": ");
owner->output.append('[');
}
else
{
if (nr != 1)
owner->output.append(", ");
owner->output.append('"');
owner->output.append(str);
owner->output.append('"');
}
nr++;
while (*ptr!=0)
ptr++;
ptr++;
}
owner->output.append(']');
}
void Single_line_formatting_helper::disable_and_flush()
{
bool start_array= (state == IN_ARRAY);
state= DISABLED;
// deactivate ourselves and flush all accumulated calls.
char *ptr= buffer;
int nr= 0;
while (ptr < buf_ptr)
{
char *str= ptr;
if (nr == 0)
{
owner->add_member(str);
if (start_array)
owner->start_array();
}
else
{
//if (nr == 1)
// owner->start_array();
owner->add_str(str);
}
nr++;
while (*ptr!=0)
ptr++;
ptr++;
}
buf_ptr= buffer;
state= INACTIVE;
}

189
sql/my_json_writer.h Normal file
View File

@ -0,0 +1,189 @@
/* Copyright (C) 2014 SkySQL Ab, MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class Json_writer;
/*
Single_line_formatting_helper is used by Json_writer to do better formatting
of JSON documents.
The idea is to catch arrays that can be printed on one line:
arrayName : [ "boo", 123, 456 ]
and actually print them on one line. Arrrays that occupy too much space on
the line, or have nested members cannot be printed on one line.
We hook into JSON printing functions and try to detect the pattern. While
detecting the pattern, we will accumulate "boo", 123, 456 as strings.
Then,
- either the pattern is broken, and we print the elements out,
- or the pattern lasts till the end of the array, and we print the
array on one line.
*/
class Single_line_formatting_helper
{
enum enum_state
{
INACTIVE,
ADD_MEMBER,
IN_ARRAY,
DISABLED
};
/*
This works like a finite automaton.
state=DISABLED means the helper is disabled - all on_XXX functions will
return false (which means "not handled") and do nothing.
+->-+
| v
INACTIVE ---> ADD_MEMBER ---> IN_ARRAY--->-+
^ |
+------------------<--------------------+
For other states:
INACTIVE - initial state, we have nothing.
ADD_MEMBER - add_member() was called, the buffer has "member_name\0".
IN_ARRAY - start_array() was called.
*/
enum enum_state state;
enum { MAX_LINE_LEN= 80 };
char buffer[80];
/* The data in the buffer is located between buffer[0] and buf_ptr */
char *buf_ptr;
uint line_len;
Json_writer *owner;
public:
Single_line_formatting_helper() : state(INACTIVE), buf_ptr(buffer) {}
void init(Json_writer *owner_arg) { owner= owner_arg; }
bool on_add_member(const char *name);
bool on_start_array();
bool on_end_array();
void on_start_object();
// on_end_object() is not needed.
bool on_add_str(const char *str);
void flush_on_one_line();
void disable_and_flush();
};
/*
A class to write well-formed JSON documents. The documents are also formatted
for human readability.
*/
class Json_writer
{
public:
/* Add a member. We must be in an object. */
Json_writer& add_member(const char *name);
/* Add atomic values */
void add_str(const char* val);
void add_str(const String &str);
void add_ll(longlong val);
void add_double(double val);
void add_bool(bool val);
void add_null();
private:
void add_unquoted_str(const char* val);
public:
/* Start a child object */
void start_object();
void start_array();
void end_object();
void end_array();
Json_writer() :
indent_level(0), document_start(true), element_started(false),
first_child(true)
{
fmt_helper.init(this);
}
private:
// TODO: a stack of (name, bool is_object_or_array) elements.
int indent_level;
enum { INDENT_SIZE = 2 };
friend class Single_line_formatting_helper;
friend class Json_writer_nesting_guard;
bool document_start;
bool element_started;
bool first_child;
Single_line_formatting_helper fmt_helper;
void append_indent();
void start_element();
void start_sub_element();
//const char *new_member_name;
public:
String output;
};
/*
RAII-based helper class to detect incorrect use of Json_writer.
The idea is that a function typically must leave Json_writer at the same
identation level as it was when it was invoked. Leaving it at a different
level typically means we forgot to close an object or an array
So, here is a way to guard
void foo(Json_writer *writer)
{
Json_writer_nesting_guard(writer);
.. do something with writer
// at the end of the function, ~Json_writer_nesting_guard() is called
// and it makes sure that the nesting is the same as when the function was
// entered.
}
*/
class Json_writer_nesting_guard
{
Json_writer* writer;
int indent_level;
public:
Json_writer_nesting_guard(Json_writer *writer_arg) :
writer(writer_arg),
indent_level(writer->indent_level)
{}
~Json_writer_nesting_guard()
{
DBUG_ASSERT(indent_level == writer->indent_level);
}
};

View File

@ -613,9 +613,13 @@ enum enum_query_type
/// Without character set introducers.
QT_WITHOUT_INTRODUCERS= (1 << 1),
/// view internal representation (like QT_ORDINARY except ORDER BY clause)
QT_VIEW_INTERNAL= (1 << 2)
QT_VIEW_INTERNAL= (1 << 2),
/// This value means focus on readability, not on ability to parse back, etc.
QT_EXPLAIN= (1 << 4)
};
/* query_id */
typedef int64 query_id_t;
extern query_id_t global_query_id;

View File

@ -12269,7 +12269,7 @@ Explain_quick_select* QUICK_RANGE_SELECT::get_explain(MEM_ROOT *alloc)
{
Explain_quick_select *res;
if ((res= new (alloc) Explain_quick_select(QS_TYPE_RANGE)))
res->range.set(alloc, head->key_info[index].name, max_used_key_length);
res->range.set(alloc, &head->key_info[index], max_used_key_length);
return res;
}
@ -12278,7 +12278,7 @@ Explain_quick_select* QUICK_GROUP_MIN_MAX_SELECT::get_explain(MEM_ROOT *alloc)
{
Explain_quick_select *res;
if ((res= new (alloc) Explain_quick_select(QS_TYPE_GROUP_MIN_MAX)))
res->range.set(alloc, head->key_info[index].name, max_used_key_length);
res->range.set(alloc, &head->key_info[index], max_used_key_length);
return res;
}

View File

@ -2370,7 +2370,11 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
int THD::send_explain_fields(select_result *result, uint8 explain_flags, bool is_analyze)
{
List<Item> field_list;
make_explain_field_list(field_list, explain_flags, is_analyze);
if (lex->explain_json)
make_explain_json_field_list(field_list);
else
make_explain_field_list(field_list, explain_flags, is_analyze);
result->prepare(field_list, NULL);
return (result->send_result_set_metadata(field_list,
Protocol::SEND_NUM_ROWS |
@ -2378,6 +2382,13 @@ int THD::send_explain_fields(select_result *result, uint8 explain_flags, bool is
}
void THD::make_explain_json_field_list(List<Item> &field_list)
{
Item *item= new Item_empty_string("EXPLAIN", 78, system_charset_info);
field_list.push_back(item);
}
/*
Populate the provided field_list with EXPLAIN output columns.
this->lex->describe has the EXPLAIN flags

View File

@ -3097,6 +3097,8 @@ public:
bool is_analyze);
void make_explain_field_list(List<Item> &field_list, uint8 explain_flags,
bool is_analyze);
void make_explain_json_field_list(List<Item> &field_list);
/**
Clear the current error, if any.
We do not clear is_fatal_error or is_fatal_sub_stmt_error since we

View File

@ -52,7 +52,7 @@
invoked on a running DELETE statement.
*/
void Delete_plan::save_explain_data(Explain_query *query)
void Delete_plan::save_explain_data(MEM_ROOT *mem_root, Explain_query *query)
{
Explain_delete* explain= new Explain_delete;
@ -65,22 +65,23 @@ void Delete_plan::save_explain_data(Explain_query *query)
else
{
explain->deleting_all_rows= false;
Update_plan::save_explain_data_intern(query, explain);
Update_plan::save_explain_data_intern(mem_root, query, explain);
}
query->add_upd_del_plan(explain);
}
void Update_plan::save_explain_data(Explain_query *query)
void Update_plan::save_explain_data(MEM_ROOT *mem_root, Explain_query *query)
{
Explain_update* explain= new Explain_update;
save_explain_data_intern(query, explain);
save_explain_data_intern(mem_root, query, explain);
query->add_upd_del_plan(explain);
}
void Update_plan::save_explain_data_intern(Explain_query *query,
void Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
Explain_query *query,
Explain_update *explain)
{
explain->select_type= "SIMPLE";
@ -142,10 +143,12 @@ void Update_plan::save_explain_data_intern(Explain_query *query,
}
explain->using_where= MY_TEST(select && select->cond);
explain->where_cond= select? select->cond: NULL;
explain->using_filesort= using_filesort;
explain->using_io_buffer= using_io_buffer;
make_possible_keys_line(table, possible_keys, &explain->possible_keys_line);
append_possible_keys(mem_root, explain->possible_keys, table,
possible_keys);
explain->quick_info= NULL;
@ -158,11 +161,8 @@ void Update_plan::save_explain_data_intern(Explain_query *query,
{
if (index != MAX_KEY)
{
explain->key_str.append(table->key_info[index].name);
char buf[64];
size_t length;
length= longlong10_to_str(table->key_info[index].key_length, buf, 10) - buf;
explain->key_len_str.append(buf, length);
explain->key.set(mem_root, &table->key_info[index],
table->key_info[index].key_length);
}
}
explain->rows= scanned_rows;
@ -461,7 +461,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (thd->lex->describe)
goto produce_explain_and_leave;
query_plan.save_explain_data(thd->lex->explain);
query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start",
dbug_serve_apcs(thd, 1););
@ -699,7 +699,7 @@ produce_explain_and_leave:
We come here for various "degenerate" query plans: impossible WHERE,
no-partitions-used, impossible-range, etc.
*/
query_plan.save_explain_data(thd->lex->explain);
query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
send_nothing_and_leave:
/*

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Data structures for ANALYZE */
class String_list: public List<char>
{
public:
bool append_str(MEM_ROOT *mem_root, const char *str);
};
/*
A class for collecting read statistics.
The idea is that we run several scans. Each scans gets rows, and then filters
some of them out. We count scans, rows, and rows left after filtering.
*/
class Table_access_tracker
{
public:
@ -29,6 +43,7 @@ public:
ha_rows r_rows_after_where; /* Rows after applying attached part of WHERE */
bool has_scans() { return (r_scans != 0); }
ha_rows get_loops() { return r_scans; }
ha_rows get_avg_rows()
{
return r_scans ? (ha_rows)rint((double) r_rows / r_scans): 0;
@ -67,24 +82,43 @@ const int FAKE_SELECT_LEX_ID= (int)UINT_MAX;
class Explain_query;
class Json_writer;
/*
A node can be either a SELECT, or a UNION.
*/
class Explain_node : public Sql_alloc
{
public:
/* A type specifying what kind of node this is */
enum explain_node_type
{
EXPLAIN_UNION,
EXPLAIN_SELECT,
EXPLAIN_SELECT,
EXPLAIN_BASIC_JOIN,
EXPLAIN_UPDATE,
EXPLAIN_DELETE,
EXPLAIN_INSERT
};
/* How this node is connected */
enum explain_connection_type {
EXPLAIN_NODE_OTHER,
EXPLAIN_NODE_DERIVED, /* Materialized derived table */
EXPLAIN_NODE_NON_MERGED_SJ /* aka JTBM semi-join */
};
Explain_node() : connection_type(EXPLAIN_NODE_OTHER) {}
virtual enum explain_node_type get_type()= 0;
virtual int get_select_id()= 0;
/*
How this node is connected to its parent.
(NOTE: EXPLAIN_NODE_NON_MERGED_SJ is set very late currently)
*/
enum explain_connection_type connection_type;
/*
A node may have children nodes. When a node's explain structure is
created, children nodes may not yet have QPFs. This is why we store ids.
@ -97,9 +131,13 @@ public:
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze)=0;
virtual void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze)= 0;
int print_explain_for_children(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json_for_children(Explain_query *query,
Json_writer *writer, bool is_analyze);
virtual ~Explain_node(){}
};
@ -107,6 +145,49 @@ public:
class Explain_table_access;
/*
A basic join. This is only used for SJ-Materialization nests.
Basic join doesn't have ORDER/GROUP/DISTINCT operations. It also cannot be
degenerate.
It has its own select_id.
*/
class Explain_basic_join : public Explain_node
{
public:
enum explain_node_type get_type() { return EXPLAIN_BASIC_JOIN; }
Explain_basic_join() : join_tabs(NULL) {}
~Explain_basic_join();
bool add_table(Explain_table_access *tab)
{
if (!join_tabs)
{
join_tabs= (Explain_table_access**) my_malloc(sizeof(Explain_table_access*) *
MAX_TABLES, MYF(0));
n_join_tabs= 0;
}
join_tabs[n_join_tabs++]= tab;
return false;
}
int get_select_id() { return select_id; }
int select_id;
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
/* A flat array of Explain structs for tables. */
Explain_table_access** join_tabs;
uint n_join_tabs;
};
/*
EXPLAIN structure for a SELECT.
@ -122,30 +203,16 @@ class Explain_table_access;
a way get node's children.
*/
class Explain_select : public Explain_node
class Explain_select : public Explain_basic_join
{
public:
enum explain_node_type get_type() { return EXPLAIN_SELECT; }
Explain_select() :
message(NULL), join_tabs(NULL),
message(NULL),
using_temporary(false), using_filesort(false)
{}
~Explain_select();
bool add_table(Explain_table_access *tab)
{
if (!join_tabs)
{
join_tabs= (Explain_table_access**) my_malloc(sizeof(Explain_table_access*) *
MAX_TABLES, MYF(0));
n_join_tabs= 0;
}
join_tabs[n_join_tabs++]= tab;
return false;
}
/*
This is used to save the results of "late" test_if_skip_sort_order() calls
that are made from JOIN::exec
@ -153,30 +220,22 @@ public:
void replace_table(uint idx, Explain_table_access *new_tab);
public:
int select_id;
const char *select_type;
int get_select_id() { return select_id; }
/*
If message != NULL, this is a degenerate join plan, and all subsequent
members have no info
*/
const char *message;
/*
A flat array of Explain structs for tables. The order is "just like EXPLAIN
would print them".
*/
Explain_table_access** join_tabs;
uint n_join_tabs;
/* Global join attributes. In tabular form, they are printed on the first row */
bool using_temporary;
bool using_filesort;
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
Table_access_tracker *get_using_temporary_read_tracker()
{
@ -222,6 +281,8 @@ public:
}
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
const char *fake_select_type;
bool using_filesort;
@ -236,6 +297,8 @@ public:
return &tmptable_read_tracker;
}
private:
uint make_union_table_name(char *buf);
Table_access_tracker fake_select_lex_tracker;
/* This one is for reading after ORDER BY */
Table_access_tracker tmptable_read_tracker;
@ -311,6 +374,8 @@ public:
/* Return tabular EXPLAIN output as a text string */
bool print_explain_str(THD *thd, String *out_str, bool is_analyze);
void print_explain_json(select_result_sink *output, bool is_analyze);
/* If true, at least part of EXPLAIN can be printed */
bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1) != NULL; }
@ -407,24 +472,24 @@ class Explain_index_use : public Sql_alloc
{
char *key_name;
uint key_len;
/* will add #keyparts here if we implement EXPLAIN FORMAT=JSON */
public:
void set(MEM_ROOT *root, const char *key_name_arg, uint key_len_arg)
String_list key_parts_list;
Explain_index_use()
{
if (key_name_arg)
{
size_t name_len= strlen(key_name_arg);
if ((key_name= (char*)alloc_root(root, name_len+1)))
memcpy(key_name, key_name_arg, name_len+1);
}
else
key_name= NULL;
key_len= key_len_arg;
clear();
}
inline const char *get_key_name() { return key_name; }
inline uint get_key_len() { return key_len; }
void clear()
{
key_name= NULL;
key_len= (uint)-1;
}
void set(MEM_ROOT *root, KEY *key_name, uint key_len_arg);
void set_pseudo_key(MEM_ROOT *root, const char *key_name);
inline const char *get_key_name() const { return key_name; }
inline uint get_key_len() const { return key_len; }
};
@ -438,6 +503,13 @@ public:
{}
const int quick_type;
bool is_basic()
{
return (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX);
}
/* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */
Explain_index_use range;
@ -448,8 +520,11 @@ public:
void print_extra(String *str);
void print_key(String *str);
void print_key_len(String *str);
private:
void print_json(Json_writer *writer);
void print_extra_recursive(String *str);
private:
const char *get_name_by_type();
};
@ -461,26 +536,40 @@ private:
class Explain_table_access : public Sql_alloc
{
public:
Explain_table_access() :
derived_select_number(0),
non_merged_sjm_number(0),
start_dups_weedout(false),
end_dups_weedout(false),
where_cond(NULL),
cache_cond(NULL),
pushed_index_cond(NULL),
sjm_nest(NULL)
{}
~Explain_table_access() { delete sjm_nest; }
void push_extra(enum explain_extra_tag extra_tag);
/* Internals */
public:
/*
0 means this tab is not inside SJM nest and should use Explain_select's id
other value means the tab is inside an SJM nest.
*/
int sjm_nest_select_id;
/* id and 'select_type' are cared-of by the parent Explain_select */
StringBuffer<32> table_name;
/*
Non-zero number means this is a derived table. The number can be used to
find the query plan for the derived table
*/
int derived_select_number;
/* TODO: join with the previous member. */
int non_merged_sjm_number;
enum join_type type;
StringBuffer<32> used_partitions;
bool used_partitions_set;
/* Empty string means "NULL" will be printed */
StringBuffer<32> possible_keys_str;
/* Empty means "NULL" will be printed */
String_list possible_keys;
/*
Index use: key name and length.
@ -498,8 +587,7 @@ public:
*/
Explain_index_use hash_next_key;
bool ref_set; /* not set means 'NULL' should be printed */
StringBuffer<32> ref;
String_list ref_list;
bool rows_set; /* not set means 'NULL' should be printed */
ha_rows rows;
@ -530,17 +618,40 @@ public:
StringBuffer<32> firstmatch_table_name;
bool start_dups_weedout;
bool end_dups_weedout;
/*
Note: lifespan of WHERE condition is less than lifespan of this object.
The below two are valid if tags include "ET_USING_WHERE".
(TODO: indexsubquery may put ET_USING_WHERE without setting where_cond?)
*/
Item *where_cond;
Item *cache_cond;
Item *pushed_index_cond;
Explain_basic_join *sjm_nest;
int print_explain(select_result_sink *output, uint8 explain_flags,
bool is_analyze,
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
/* ANALYZE members*/
/* ANALYZE members */
/* Tracker for reading the table */
Table_access_tracker tracker;
Table_access_tracker jbuf_tracker;
private:
void append_tag_name(String *str, enum explain_extra_tag tag);
void fill_key_str(String *key_str, bool is_json) const;
void fill_key_len_str(String *key_len_str) const;
double get_r_filtered();
void tag_to_json(Json_writer *writer, enum explain_extra_tag tag);
};
@ -567,14 +678,22 @@ public:
StringBuffer<64> table_name;
enum join_type jtype;
StringBuffer<128> possible_keys_line;
StringBuffer<128> key_str;
StringBuffer<128> key_len_str;
String_list possible_keys;
/* Used key when doing a full index scan (possibly with limit) */
Explain_index_use key;
/*
MRR that's used with quick select. This should probably belong to the
quick select
*/
StringBuffer<64> mrr_type;
Explain_quick_select *quick_info;
bool using_where;
Item *where_cond;
ha_rows rows;
bool using_filesort;
@ -585,6 +704,8 @@ public:
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
virtual void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
};
@ -605,6 +726,8 @@ public:
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
};
@ -626,6 +749,8 @@ public:
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
virtual void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
};

View File

@ -485,6 +485,7 @@ void lex_start(THD *thd)
lex->select_lex.group_list_ptrs->clear();
lex->describe= 0;
lex->analyze_stmt= 0;
lex->explain_json= false;
lex->subqueries= FALSE;
lex->context_analysis_only= 0;
lex->derived_tables= 0;
@ -4269,6 +4270,13 @@ int st_select_lex_unit::save_union_explain(Explain_query *output)
SELECT_LEX *first= first_select();
Explain_union *eu= new (output->mem_root) Explain_union;
if (derived)
eu->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
/*
Note: Non-merged semi-joins cannot be made out of UNIONs currently, so we
dont ever set EXPLAIN_NODE_NON_MERGED_SJ.
*/
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
eu->add_select(sl->select_number);

View File

@ -2312,8 +2312,9 @@ public:
void set_impossible_where() { impossible_where= true; }
void set_no_partitions() { no_partitions= true; }
void save_explain_data(Explain_query *query);
void save_explain_data_intern(Explain_query *query, Explain_update *eu);
void save_explain_data(MEM_ROOT *mem_root, Explain_query *query);
void save_explain_data_intern(MEM_ROOT *mem_root, Explain_query *query,
Explain_update *eu);
virtual ~Update_plan() {}
@ -2344,7 +2345,7 @@ public:
scanned_rows= rows_arg;
}
void save_explain_data(Explain_query *query);
void save_explain_data(MEM_ROOT *mem_root, Explain_query *query);
};
@ -2509,6 +2510,7 @@ struct LEX: public Query_tables_list
uint table_count;
uint8 describe;
bool analyze_stmt; /* TRUE<=> this is "ANALYZE $stmt" */
bool explain_json;
/*
A flag that indicates what kinds of derived tables are present in the
query (0 if no derived tables, otherwise a combination of flags

View File

@ -97,6 +97,8 @@
#include "log_slow.h"
#include "sql_bootstrap.h"
#include "my_json_writer.h"
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
#ifdef WITH_ARIA_STORAGE_ENGINE
@ -5722,19 +5724,27 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
top-level LIMIT
*/
result->reset_offset_limit();
lex->explain->print_explain(result, lex->describe, lex->analyze_stmt);
if (lex->describe & DESCRIBE_EXTENDED)
if (lex->explain_json)
{
char buff[1024];
String str(buff,(uint32) sizeof(buff), system_charset_info);
str.length(0);
/*
The warnings system requires input in utf8, @see
mysqld_show_warnings().
*/
lex->unit.print(&str, QT_TO_SYSTEM_CHARSET);
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_YES, str.c_ptr_safe());
lex->explain->print_explain_json(result, lex->analyze_stmt);
}
else
{
lex->explain->print_explain(result, thd->lex->describe,
thd->lex->analyze_stmt);
if (lex->describe & DESCRIBE_EXTENDED)
{
char buff[1024];
String str(buff,(uint32) sizeof(buff), system_charset_info);
str.length(0);
/*
The warnings system requires input in utf8, @see
mysqld_show_warnings().
*/
lex->unit.print(&str, QT_TO_SYSTEM_CHARSET);
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_YES, str.c_ptr_safe());
}
}
}
@ -7749,6 +7759,9 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
fake_select_lex->context.resolve_in_select_list= TRUE;
fake_select_lex->context.select_lex= fake_select_lex;
fake_select_lex->nest_level_base= first_select()->nest_level_base;
fake_select_lex->nest_level=first_select()->nest_level;
if (!is_union())
{
/*

View File

@ -8232,6 +8232,41 @@ JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind,
}
/*
Enumerate JOIN_TABs in "EXPLAIN order". This order
- const tabs are included
- we enumerate "optimization tabs".
-
*/
JOIN_TAB *first_explain_order_tab(JOIN* join)
{
JOIN_TAB* tab;
tab= join->table_access_tabs;
return (tab->bush_children) ? tab->bush_children->start : tab;
}
JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab)
{
/* If we're inside SJM nest and have reached its end, get out */
if (tab->last_leaf_in_bush)
return tab->bush_root_tab;
/* Move to next tab in the array we're traversing */
tab++;
if (tab == join->table_access_tabs + join->top_join_tab_count)
return NULL; /* Outside SJM nest and reached EOF */
if (tab->bush_children)
return tab->bush_children->start;
return tab;
}
JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables const_tbls)
{
JOIN_TAB *tab= join->join_tab;
@ -16426,6 +16461,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
((field_count-param->hidden_field_count)+
(share->uniques ? MY_TEST(null_pack_length) : 0));
keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
keyinfo->usable_key_parts= keyinfo->user_defined_key_parts;
table->distinct= 1;
share->keys= 1;
if (!(key_part_info= (KEY_PART_INFO*)
@ -20861,6 +20897,24 @@ static void free_blobs(Field **ptr)
}
/*
@brief
Remove duplicates from a temporary table.
@detail
Remove duplicate rows from a temporary table. This is used for e.g. queries
like
select distinct count(*) as CNT from tbl group by col
Here, we get a group table with count(*) values. It is not possible to
prevent duplicates from appearing in the table (as we don't know the values
before we've done the grouping). Because of that, we have this function to
scan the temptable (maybe, multiple times) and remove the duplicate rows
Rows that do not satisfy 'having' condition are also removed.
*/
static int
remove_duplicates(JOIN *join, TABLE *table, List<Item> &fields, Item *having)
{
@ -23121,7 +23175,6 @@ void JOIN::clear()
/*
Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
TODO: is_analyze
*/
int print_explain_message_line(select_result_sink *result,
@ -23180,208 +23233,6 @@ int print_explain_message_line(select_result_sink *result,
}
/*
Make a comma-separated list of possible_keys names and add it into the string
*/
void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line)
{
if (!possible_keys.is_clear_all())
{
uint j;
for (j=0 ; j < table->s->keys ; j++)
{
if (possible_keys.is_set(j))
{
if (line->length())
line->append(',');
line->append(table->key_info[j].name,
strlen(table->key_info[j].name),
system_charset_info);
}
}
}
}
/*
Print an EXPLAIN output row, based on information provided in the parameters
@note
Parameters that may have NULL value in EXPLAIN output, should be passed
(char*)NULL.
@return
0 - OK
1 - OOM Error
*/
int print_explain_row(select_result_sink *result,
uint8 options, bool is_analyze,
uint select_number,
const char *select_type,
const char *table_name,
const char *partitions,
enum join_type jtype,
const char *possible_keys,
const char *index,
const char *key_len,
const char *ref,
ha_rows *rows,
ha_rows *r_rows,
double r_filtered,
const char *extra)
{
Item *item_null= new Item_null();
List<Item> item_list;
Item *item;
item_list.push_back(new Item_int((int32) select_number));
item_list.push_back(new Item_string_sys(select_type));
item_list.push_back(new Item_string_sys(table_name));
if (options & DESCRIBE_PARTITIONS)
{
if (partitions)
{
item_list.push_back(new Item_string_sys(partitions));
}
else
item_list.push_back(item_null);
}
const char *jtype_str= join_type_str[jtype];
item_list.push_back(new Item_string_sys(jtype_str));
item= possible_keys? new Item_string_sys(possible_keys) : item_null;
item_list.push_back(item);
/* 'index */
item= index ? new Item_string_sys(index) : item_null;
item_list.push_back(item);
/* 'key_len */
item= key_len ? new Item_string_sys(key_len) : item_null;
item_list.push_back(item);
/* 'ref' */
item= ref ? new Item_string_sys(ref) : item_null;
item_list.push_back(item);
/* 'rows' */
if (rows)
{
item_list.push_back(new Item_int(*rows,
MY_INT64_NUM_DECIMAL_DIGITS));
}
else
item_list.push_back(item_null);
/* 'r_rows' */
if (is_analyze)
{
if (r_rows)
{
item_list.push_back(new Item_int(*r_rows,
MY_INT64_NUM_DECIMAL_DIGITS));
}
else
item_list.push_back(item_null);
}
/* 'filtered' */
const double filtered=100.0;
if (options & DESCRIBE_EXTENDED || is_analyze)
item_list.push_back(new Item_float(filtered, 2));
/* 'r_filtered' */
if (is_analyze)
item_list.push_back(new Item_float(r_filtered, 2));
/* 'Extra' */
if (extra)
item_list.push_back(new Item_string_sys(extra));
else
item_list.push_back(item_null);
if (result->send_data(item_list))
return 1;
return 0;
}
int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
SELECT_LEX *select_lex, uint8 explain_flags)
{
Item *item_null= new Item_null();
List<Item> item_list;
if (on_the_fly)
select_lex->set_explain_type(on_the_fly);
/*
here we assume that the query will return at least two rows, so we
show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong
and no filesort will be actually done, but executing all selects in
the UNION to provide precise EXPLAIN information will hardly be
appreciated :)
*/
char table_name_buffer[SAFE_NAME_LEN];
item_list.empty();
/* id */
item_list.push_back(new Item_null);
/* select_type */
item_list.push_back(new Item_string_sys(select_lex->type));
/* table */
{
SELECT_LEX *sl= select_lex->master_unit()->first_select();
uint len= 6, lastop= 0;
memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select())
{
len+= lastop;
lastop= my_snprintf(table_name_buffer + len, NAME_LEN - len,
"%u,", sl->select_number);
}
if (sl || len + lastop >= NAME_LEN)
{
memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
len+= 4;
}
else
{
len+= lastop;
table_name_buffer[len - 1]= '>'; // change ',' to '>'
}
item_list.push_back(new Item_string_sys(table_name_buffer, len));
}
/* partitions */
if (explain_flags & DESCRIBE_PARTITIONS)
item_list.push_back(item_null);
/* type */
item_list.push_back(new Item_string_sys(join_type_str[JT_ALL]));
/* possible_keys */
item_list.push_back(item_null);
/* key*/
item_list.push_back(item_null);
/* key_len */
item_list.push_back(item_null);
/* ref */
item_list.push_back(item_null);
/* in_rows */
if (explain_flags & DESCRIBE_EXTENDED)
item_list.push_back(item_null);
/* rows */
item_list.push_back(item_null);
/* extra */
if (select_lex->master_unit()->global_parameters()->order_list.first)
item_list.push_back(new Item_string_sys("Using filesort", 14));
else
item_list.push_back(new Item_string_sys("", 0));
if (result->send_data(item_list))
return 1;
return 0;
}
/*
Append MRR information from quick select to the given string
*/
@ -23403,21 +23254,16 @@ void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res)
///////////////////////////////////////////////////////////////////////////////
// TODO: join with make_possible_keys_line ?
void append_possible_keys(String *str, TABLE *table, key_map possible_keys)
int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table,
key_map possible_keys)
{
uint j;
for (j=0 ; j < table->s->keys ; j++)
{
if (possible_keys.is_set(j))
{
if (str->length())
str->append(',');
str->append(table->key_info[j].name,
strlen(table->key_info[j].name),
system_charset_info);
}
list.append_str(alloc, table->key_info[j].name);
}
return 0;
}
// TODO: this function is only applicable for the first non-const optimization
@ -23450,32 +23296,20 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
TABLE *table=tab->table;
TABLE_LIST *table_list= tab->table->pos_in_table_list;
char buff4[512];
my_bool key_read;
char table_name_buffer[SAFE_NAME_LEN];
String tmp4(buff4,sizeof(buff4),cs);
KEY *key_info= 0;
uint key_len= 0;
tmp4.length(0);
quick_type= -1;
QUICK_SELECT_I *quick= NULL;
eta->key.set(thd->mem_root, NULL, (uint)-1);
eta->key.clear();
eta->quick_info= NULL;
tab->tracker= &eta->tracker;
tab->jbuf_tracker= &eta->jbuf_tracker;
/* id */
if (tab->bush_root_tab)
{
JOIN_TAB *first_sibling= tab->bush_root_tab->bush_children->start;
eta->sjm_nest_select_id= first_sibling->emb_sj_nest->sj_subq_pred->get_identifier();
}
else
eta->sjm_nest_select_id= 0;
/* select_type is kept in Explain_select */
/* id and select_type are kept in Explain_select */
/* table */
if (table->derived_select_number)
@ -23558,7 +23392,11 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
eta->type= tab_type;
/* Build "possible_keys" value */
append_possible_keys(&eta->possible_keys_str, table, tab->keys);
// psergey-todo: why does this use thd MEM_ROOT??? Doesn't this
// break ANALYZE ? thd->mem_root will be freed, and after that we will
// attempt to print the query plan?
append_possible_keys(thd->mem_root, eta->possible_keys, table, tab->keys);
// psergey-todo: ^ check for error return code
/* Build "key", "key_len", and "ref" */
if (tab_type == JT_NEXT)
@ -23583,21 +23421,18 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
if (key_info) /* 'index' or 'ref' access */
{
eta->key.set(thd->mem_root, key_info->name, key_len);
eta->key.set(thd->mem_root, key_info, key_len);
if (tab->ref.key_parts && tab_type != JT_FT)
{
store_key **ref=tab->ref.key_copy;
for (uint kp= 0; kp < tab->ref.key_parts; kp++)
{
if (tmp4.length())
tmp4.append(',');
if ((key_part_map(1) << kp) & tab->ref.const_ref_part_map)
tmp4.append("const");
eta->ref_list.append_str(thd->mem_root, "const");
else
{
tmp4.append((*ref)->name(), strlen((*ref)->name()), cs);
eta->ref_list.append_str(thd->mem_root, (*ref)->name());
ref++;
}
}
@ -23607,21 +23442,13 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
if (tab_type == JT_HASH_NEXT) /* full index scan + hash join */
{
eta->hash_next_key.set(thd->mem_root,
table->key_info[tab->index].name,
& table->key_info[tab->index],
table->key_info[tab->index].key_length);
// psergey-todo: ^ is the above correct? are we necessarily joining on all
// columns?
}
if (key_info)
{
if (key_info && tab_type != JT_NEXT)
{
eta->ref.copy(tmp4);
eta->ref_set= true;
}
else
eta->ref_set= false;
}
else
if (!key_info)
{
if (table_list && /* SJM bushes don't have table_list */
table_list->schema_table &&
@ -23652,9 +23479,8 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
}
if (key_name_buf.length())
eta->key.set(thd->mem_root, key_name_buf.c_ptr_safe(), -1);
eta->key.set_pseudo_key(thd->mem_root, key_name_buf.c_ptr_safe());
}
eta->ref_set= false;
}
/* "rows" */
@ -23719,7 +23545,10 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
if (keyno != MAX_KEY && keyno == table->file->pushed_idx_cond_keyno &&
table->file->pushed_idx_cond)
{
eta->push_extra(ET_USING_INDEX_CONDITION);
eta->pushed_index_cond= table->file->pushed_idx_cond;
}
else if (tab->cache_idx_cond)
eta->push_extra(ET_USING_INDEX_CONDITION_BKA);
@ -23749,7 +23578,11 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
eta->push_extra(ET_USING_WHERE_WITH_PUSHED_CONDITION);
}
else
{
eta->where_cond= tab->select->cond;
eta->cache_cond= tab->cache_select? tab->cache_select->cond : NULL;
eta->push_extra(ET_USING_WHERE);
}
}
}
if (table_list /* SJM bushes don't have table_list */ &&
@ -23804,9 +23637,16 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
}
if (tab->first_weedout_table)
{
eta->start_dups_weedout= true;
eta->push_extra(ET_START_TEMPORARY);
}
if (tab->check_weed_out_table)
{
eta->push_extra(ET_END_TEMPORARY);
eta->end_dups_weedout= true;
}
else if (tab->do_firstmatch)
{
if (tab->do_firstmatch == /*join->join_tab*/ first_top_tab - 1)
@ -23844,8 +23684,18 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
tab->cache->save_explain_data(&eta->bka_type);
}
}
/*
In case this is a derived table, here we remember the number of
subselect that used to produce it.
*/
eta->derived_select_number= table->derived_select_number;
/* The same for non-merged semi-joins */
eta->non_merged_sjm_number = get_non_merged_semijoin_select();
}
/*
Save Query Plan Footprint
@ -23876,6 +23726,8 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
xpl_sel->select_id= join->select_lex->select_number;
xpl_sel->select_type= join->select_lex->type;
xpl_sel->message= message;
if (select_lex->master_unit()->derived)
xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
/* Setting xpl_sel->message means that all other members are invalid */
output->add_node(xpl_sel);
}
@ -23893,13 +23745,23 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
join->select_lex->set_explain_type(true);
xpl_sel->select_id= join->select_lex->select_number;
xpl_sel->select_type= join->select_lex->type;
if (select_lex->master_unit()->derived)
xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
if (need_tmp_table)
xpl_sel->using_temporary= true;
if (need_order)
xpl_sel->using_filesort= true;
JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS);
JOIN_TAB* prev_bush_root_tab= NULL;
for (JOIN_TAB *tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); tab;
tab= next_breadth_first_tab(join, WALK_OPTIMIZATION_TABS, tab))
Explain_basic_join *cur_parent= xpl_sel;
for (JOIN_TAB *tab= first_explain_order_tab(join); tab;
tab= next_explain_order_tab(join, tab))
{
JOIN_TAB *saved_join_tab= NULL;
TABLE *table=tab->table;
@ -23910,6 +23772,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
continue;
}
if (join->table_access_tabs == join->join_tab &&
tab == (first_top_tab + join->const_tables) && pre_sort_join_tab)
{
@ -23918,21 +23781,36 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
}
Explain_table_access *eta= new (output->mem_root) Explain_table_access;
xpl_sel->add_table(eta);
if (tab->bush_root_tab != prev_bush_root_tab)
{
if (tab->bush_root_tab)
{
/*
We've entered an SJ-Materialization nest. Create an object for it.
*/
cur_parent= new Explain_basic_join;
JOIN_TAB *first_child= tab->bush_root_tab->bush_children->start;
cur_parent->select_id=
first_child->emb_sj_nest->sj_subq_pred->get_identifier();
}
else
{
/*
We've just left an SJ-Materialization nest. We are at the join tab
that 'embeds the nest'
*/
DBUG_ASSERT(tab->bush_children);
eta->sjm_nest= cur_parent;
cur_parent= xpl_sel;
}
}
prev_bush_root_tab= tab->bush_root_tab;
cur_parent->add_table(eta);
tab->save_explain_data(eta, used_tables, distinct, first_top_tab);
if (need_tmp_table)
{
need_tmp_table=0;
xpl_sel->using_temporary= true;
}
if (need_order)
{
need_order=0;
xpl_sel->using_filesort= true;
}
if (saved_join_tab)
tab= saved_join_tab;

View File

@ -527,6 +527,21 @@ typedef struct st_join_table {
bool preread_init();
bool is_sjm_nest() { return MY_TEST(bush_children); }
/*
If this join_tab reads a non-merged semi-join (also called jtbm), return
the select's number. Otherwise, return 0.
*/
int get_non_merged_semijoin_select() const
{
Item_in_subselect *subq;
if (table->pos_in_table_list &&
(subq= table->pos_in_table_list->jtbm_subselect))
{
return subq->unit->first_select()->select_number;
}
return 0; /* Not a merged semi-join */
}
bool access_from_tables_is_allowed(table_map used_tables,
table_map sjm_lookup_tables)
@ -982,7 +997,13 @@ public:
*/
uint top_join_tab_count;
uint send_group_parts;
bool group; /**< If query contains GROUP BY clause */
/*
True if the query has GROUP BY.
(that is, if group_by != NULL. when DISTINCT is converted into GROUP BY, it
will set this, too. It is not clear why we need a separate var from
group_list)
*/
bool group;
bool need_distinct;
/**
@ -1826,8 +1847,10 @@ inline bool optimizer_flag(THD *thd, uint flag)
return (thd->variables.optimizer_switch & flag);
}
/*
int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
SELECT_LEX *select_lex, uint8 select_options);
*/
uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
ha_rows limit, ha_rows *scanned_limit,
@ -1855,22 +1878,8 @@ int print_explain_message_line(select_result_sink *result,
ha_rows *rows,
const char *message);
void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res);
int print_explain_row(select_result_sink *result,
uint8 options, bool is_analyze,
uint select_number,
const char *select_type,
const char *table_name,
const char *partitions,
enum join_type jtype,
const char *possible_keys,
const char *index,
const char *key_len,
const char *ref,
ha_rows *rows,
ha_rows *r_rows,
double r_filtered,
const char *extra);
void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line);
int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table,
key_map possible_keys);
/****************************************************************************
Temporary table support for SQL Runtime
@ -1914,4 +1923,5 @@ ulong check_selectivity(THD *thd,
TABLE *table,
List<COND_STATISTIC> *conds);
#endif /* SQL_SELECT_INCLUDED */

View File

@ -517,7 +517,7 @@ int mysql_update(THD *thd,
*/
if (thd->lex->describe)
goto produce_explain_and_leave;
query_plan.save_explain_data(thd->lex->explain);
query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
DBUG_EXECUTE_IF("show_explain_probe_update_exec_start",
dbug_serve_apcs(thd, 1););
@ -1042,7 +1042,7 @@ produce_explain_and_leave:
We come here for various "degenerate" query plans: impossible WHERE,
no-partitions-used, impossible-range, etc.
*/
query_plan.save_explain_data(thd->lex->explain);
query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
emit_explain_and_leave:
int err2= thd->lex->explain->send_explain(thd);

View File

@ -1152,6 +1152,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token FORCE_SYM
%token FOREIGN /* SQL-2003-R */
%token FOR_SYM /* SQL-2003-R */
%token FORMAT_SYM
%token FOUND_SYM /* SQL-2003-R */
%token FROM
%token FULL /* SQL-2003-R */
@ -1827,6 +1828,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
subselect_end select_var_list select_var_list_init help
field_length opt_field_length
opt_extended_describe shutdown
opt_format_json
prepare prepare_src execute deallocate
statement sp_suid
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
@ -9743,6 +9745,18 @@ function_call_conflict:
if ($$ == NULL)
MYSQL_YYABORT;
}
| FORMAT_SYM '(' expr ',' expr ')'
{
$$= new (thd->mem_root) Item_func_format($3, $5);
if ($$ == NULL)
MYSQL_YYABORT;
}
| FORMAT_SYM '(' expr ',' expr ',' expr ')'
{
$$= new (thd->mem_root) Item_func_format($3, $5, $7);
if ($$ == NULL)
MYSQL_YYABORT;
}
| LAST_VALUE '(' expr_list ')'
{
$$= new (thd->mem_root) Item_func_last_value(* $3);
@ -9763,17 +9777,15 @@ function_call_conflict:
}
| OLD_PASSWORD '(' expr ')'
{
$$= new (thd->mem_root) Item_func_old_password($3);
$$= new (thd->mem_root)
Item_func_password($3, Item_func_password::OLD);
if ($$ == NULL)
MYSQL_YYABORT;
}
| PASSWORD '(' expr ')'
{
Item* i1;
if (thd->variables.old_passwords)
i1= new (thd->mem_root) Item_func_old_password($3);
else
i1= new (thd->mem_root) Item_func_password($3);
i1= new (thd->mem_root) Item_func_password($3);
if (i1 == NULL)
MYSQL_YYABORT;
$$= i1;
@ -9818,11 +9830,14 @@ function_call_conflict:
}
| WEEK_SYM '(' expr ')'
{
Item *i1= new (thd->mem_root) Item_int((char*) "0",
thd->variables.default_week_format,
1);
if (i1 == NULL)
Item *i1;
LEX_STRING name= {STRING_WITH_LEN("default_week_format")};
if (!(i1= get_system_var(thd, OPT_SESSION,
name, null_lex_str)))
MYSQL_YYABORT;
i1->set_name((const char *)
STRING_WITH_LEN("@@default_week_format"),
system_charset_info);
$$= new (thd->mem_root) Item_func_week($3, i1);
if ($$ == NULL)
MYSQL_YYABORT;
@ -12771,16 +12786,34 @@ describe_command:
;
analyze_stmt_command:
ANALYZE_SYM explainable_command
ANALYZE_SYM opt_format_json explainable_command
{
Lex->analyze_stmt= true;
}
;
opt_extended_describe:
/* empty */ {}
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
| PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
| opt_format_json {}
;
opt_format_json:
/* empty */ {}
| FORMAT_SYM EQ ident_or_text
{
if (!my_strcasecmp(system_charset_info, $3.str, "JSON"))
Lex->explain_json= true;
else if (!my_strcasecmp(system_charset_info, $3.str, "TRADITIONAL"))
{
DBUG_ASSERT(Lex->explain_json==false);
}
else
{
my_error(ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), $3.str);
MYSQL_YYABORT;
}
}
;
opt_describe_column:
@ -14025,6 +14058,7 @@ keyword:
| EXAMINED_SYM {}
| EXECUTE_SYM {}
| FLUSH_SYM {}
| FORMAT_SYM {}
| GET_SYM {}
| HANDLER_SYM {}
| HELP_SYM {}
@ -14868,17 +14902,19 @@ text_or_password:
TEXT_STRING { $$=$1.str;}
| PASSWORD '(' TEXT_STRING ')'
{
$$= $3.length ? thd->variables.old_passwords ?
Item_func_old_password::alloc(thd, $3.str, $3.length) :
Item_func_password::alloc(thd, $3.str, $3.length) :
$$= $3.length ?
Item_func_password::alloc(thd, $3.str, $3.length,
thd->variables.old_passwords ?
Item_func_password::OLD :
Item_func_password::NEW) :
$3.str;
if ($$ == NULL)
MYSQL_YYABORT;
}
| OLD_PASSWORD '(' TEXT_STRING ')'
{
$$= $3.length ? Item_func_old_password::
alloc(thd, $3.str, $3.length) :
$$= $3.length ? Item_func_password::
alloc(thd, $3.str, $3.length, Item_func_password::OLD) :
$3.str;
if ($$ == NULL)
MYSQL_YYABORT;

View File

@ -2130,7 +2130,7 @@ static bool check_old_passwords(sys_var *self, THD *thd, set_var *var)
static Sys_var_mybool Sys_old_passwords(
"old_passwords",
"Use old password encryption method (needed for 4.0 and older clients)",
NO_SET_STMT SESSION_VAR(old_passwords), CMD_LINE(OPT_ARG),
SESSION_VAR(old_passwords), CMD_LINE(OPT_ARG),
DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_old_passwords));
export sys_var *Sys_old_passwords_ptr= &Sys_old_passwords; // for sql_acl.cc
@ -3742,7 +3742,7 @@ static Sys_var_session_special Sys_warning_count(
static Sys_var_ulong Sys_default_week_format(
"default_week_format",
"The default week format used by WEEK() functions",
NO_SET_STMT SESSION_VAR(default_week_format), CMD_LINE(REQUIRED_ARG),
SESSION_VAR(default_week_format), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, 7), DEFAULT(0), BLOCK_SIZE(1));
static Sys_var_ulonglong Sys_group_concat_max_len(

View File

@ -1072,6 +1072,12 @@ public:
TABLE_LIST *pos_in_table_list;/* Element referring to this table */
/* Position in thd->locked_table_list under LOCK TABLES */
TABLE_LIST *pos_in_locked_tables;
/*
Not-null for temporary tables only. Non-null values means this table is
used to compute GROUP BY, it has a unique of GROUP BY columns.
(set by create_tmp_table)
*/
ORDER *group;
String alias; /* alias or table name */
uchar *null_flags;

View File

@ -456,11 +456,14 @@ fil_compress_page(
/* Actual write needs to be alligned on block size */
if (write_size % block_size) {
#ifdef UNIV_DEBUG
size_t tmp = write_size;
#ifdef UNIV_DEBUG
ut_a(block_size > 0);
#endif
write_size = (size_t)ut_uint64_align_up((ib_uint64_t)write_size, block_size);
/* Initialize rest of the written data to avoid
uninitialized bytes */
memset(out_buf+tmp, 0, write_size-tmp);
#ifdef UNIV_DEBUG
ut_a(write_size > 0 && ((write_size % block_size) == 0));
ut_a(write_size >= tmp);
@ -477,19 +480,10 @@ fil_compress_page(
srv_stats.page_compression_saved.add((len - write_size));
srv_stats.pages_page_compressed.inc();
#if defined (__linux__) && (!defined(FALLOC_FL_PUNCH_HOLE) || !defined (FALLOC_FL_KEEP_SIZE))
if (srv_use_trim) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: [Warning] System does not support FALLOC_FL_PUNCH_HOLE || FALLOC_FL_KEEP_SIZE.\n"
" InnoDB: Disabling trim for now.\n");
srv_use_trim = FALSE;
}
#endif
if (!srv_use_trim) {
/* If persistent trims are not used we always write full
page */
page and end of the page needs to be initialized.*/
memset(out_buf+write_size, 0, len-write_size);
write_size = len;
}

View File

@ -135,4 +135,11 @@ fil_page_is_compressed(
/*===================*/
byte *buf); /*!< in: page */
/*******************************************************************//**
Find out wheather the page is page compressed with lzo method
@return true if page is page compressed with lzo method*/
ibool
fil_page_is_lzo_compressed(
/*=======================*/
byte *buf); /*!< in: page */
#endif

View File

@ -182,3 +182,16 @@ fil_space_get_atomic_writes(
return((atomic_writes_t)0);
}
/*******************************************************************//**
Find out wheather the page is page compressed with lzo method
@return true if page is page compressed with lzo method, false if not */
UNIV_INLINE
ibool
fil_page_is_lzo_compressed(
/*=======================*/
byte *buf) /*!< in: page */
{
return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED &&
mach_read_from_8(buf+FIL_PAGE_FILE_FLUSH_LSN) == PAGE_LZO_ALGORITHM);
}

View File

@ -48,6 +48,7 @@ Created 10/21/1995 Heikki Tuuri
#include "srv0mon.h"
#include "srv0srv.h"
#ifdef HAVE_POSIX_FALLOCATE
#include "unistd.h"
#include "fcntl.h"
#endif
#ifndef UNIV_HOTBACKUP
@ -77,6 +78,19 @@ Created 10/21/1995 Heikki Tuuri
#include <sys/statvfs.h>
#endif
#if defined(UNIV_LINUX) && defined(HAVE_LINUX_FALLOC_H)
#include <linux/falloc.h>
#endif
#if defined(HAVE_FALLOCATE)
#ifndef FALLOC_FL_KEEP_SIZE
#define FALLOC_FL_KEEP_SIZE 0x01
#endif
#ifndef FALLOC_FL_PUNCH_HOLE
#define FALLOC_FL_PUNCH_HOLE 0x02
#endif
#endif
#ifdef HAVE_LZO
#include "lzo/lzo1x.h"
#endif
@ -2920,7 +2934,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, len, NULL);
}
@ -2940,7 +2954,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, n, NULL);
}
@ -3065,7 +3079,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, n, NULL);
}
@ -3085,7 +3099,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, n, NULL);
}
@ -4638,12 +4652,10 @@ found:
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
if (slot->page_buf == NULL) {
os_slot_alloc_page_buf(slot);
}
os_slot_alloc_page_buf(slot);
#ifdef HAVE_LZO
if (innodb_compression_algorithm == 3 && slot->lzo_mem == NULL) {
if (innodb_compression_algorithm == 3) {
os_slot_alloc_lzo_mem(slot);
}
#endif
@ -5309,6 +5321,7 @@ os_aio_windows_handle(
case OS_FILE_WRITE:
if (slot->message1 &&
slot->page_compression &&
slot->page_compress_success &&
slot->page_buf) {
ret = WriteFile(slot->file, slot->page_buf,
(DWORD) slot->len, &len,
@ -5349,26 +5362,24 @@ os_aio_windows_handle(
ret_val = ret && len == slot->len;
}
if (slot->message1 && slot->page_compression) {
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
if (slot->page_buf == NULL) {
if (slot->type == OS_FILE_READ) {
if(fil_page_is_compressed(slot->buf)) {
os_slot_alloc_page_buf(slot);
}
#ifdef HAVE_LZO
if (innodb_compression_algorithm == 3 && slot->lzo_mem == NULL) {
os_slot_alloc_lzo_mem(slot);
}
if (fil_page_is_lzo_compressed(slot->buf)) {
os_slot_alloc_lzo_mem(slot);
}
#endif
if (slot->type == OS_FILE_READ) {
fil_decompress_page(slot->page_buf, slot->buf, slot->len, slot->write_size);
} else {
if (slot->page_compress_success && fil_page_is_compressed(slot->page_buf)) {
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
} else {
/* OS_FILE_WRITE */
if (slot->page_compress_success && fil_page_is_compressed(slot->page_buf)) {
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
}
@ -5462,32 +5473,30 @@ retry:
/* We have not overstepped to next segment. */
ut_a(slot->pos < end_pos);
/* If the table is page compressed and this is read,
we decompress before we annouce the read is
complete. For writes, we free the compressed page. */
if (slot->message1 && slot->page_compression) {
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
if (slot->page_buf == NULL) {
if (slot->type == OS_FILE_READ) {
/* If the table is page compressed and this is read,
we decompress before we annouce the read is
complete. For writes, we free the compressed page. */
if (fil_page_is_compressed(slot->buf)) {
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
os_slot_alloc_page_buf(slot);
}
#ifdef HAVE_LZO
if (innodb_compression_algorithm == 3 && slot->lzo_mem == NULL) {
os_slot_alloc_lzo_mem(slot);
}
if (fil_page_is_lzo_compressed(slot->buf)) {
os_slot_alloc_lzo_mem(slot);
}
#endif
if (slot->type == OS_FILE_READ) {
fil_decompress_page(slot->page_buf, slot->buf, slot->len, slot->write_size);
} else {
if (slot->page_compress_success &&
fil_page_is_compressed(slot->page_buf)) {
ut_ad(slot->page_compression_page);
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
} else {
/* OS_FILE_WRITE */
if (slot->page_compress_success &&
fil_page_is_compressed(slot->page_buf)) {
ut_ad(slot->page_compression_page);
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
}
@ -6401,7 +6410,7 @@ os_file_trim(
}
#ifdef __linux__
#if defined(FALLOC_FL_PUNCH_HOLE) && defined (FALLOC_FL_KEEP_SIZE)
#if defined(HAVE_FALLOCATE)
int ret = fallocate(slot->file, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, off, trim_len);
if (ret) {
@ -6522,12 +6531,15 @@ os_slot_alloc_page_buf(
byte* cbuf;
ut_a(slot != NULL);
/* We allocate extra to avoid memory overwrite on compression */
cbuf2 = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
cbuf = static_cast<byte *>(ut_align(cbuf2, UNIV_PAGE_SIZE));
slot->page_compression_page = static_cast<byte *>(cbuf2);
slot->page_buf = static_cast<byte *>(cbuf);
ut_a(slot->page_buf != NULL);
if (slot->page_compression_page == NULL) {
/* We allocate extra to avoid memory overwrite on compression */
cbuf2 = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
cbuf = static_cast<byte *>(ut_align(cbuf2, UNIV_PAGE_SIZE));
slot->page_compression_page = static_cast<byte *>(cbuf2);
slot->page_buf = static_cast<byte *>(cbuf);
memset(slot->page_compression_page, 0, UNIV_PAGE_SIZE*2);
ut_a(slot->page_buf != NULL);
}
}
#ifdef HAVE_LZO
@ -6541,8 +6553,11 @@ os_slot_alloc_lzo_mem(
os_aio_slot_t* slot) /*!< in: slot structure */
{
ut_a(slot != NULL);
slot->lzo_mem = static_cast<byte *>(ut_malloc(LZO1X_1_15_MEM_COMPRESS));
ut_a(slot->lzo_mem != NULL);
if(slot->lzo_mem == NULL) {
slot->lzo_mem = static_cast<byte *>(ut_malloc(LZO1X_1_15_MEM_COMPRESS));
memset(slot->lzo_mem, 0, LZO1X_1_15_MEM_COMPRESS);
ut_a(slot->lzo_mem != NULL);
}
}
#endif

View File

@ -453,11 +453,14 @@ fil_compress_page(
/* Actual write needs to be alligned on block size */
if (write_size % block_size) {
#ifdef UNIV_DEBUG
size_t tmp = write_size;
#ifdef UNIV_DEBUG
ut_a(block_size > 0);
#endif
write_size = (size_t)ut_uint64_align_up((ib_uint64_t)write_size, block_size);
/* Initialize rest of the written data to avoid
uninitialized bytes */
memset(out_buf+tmp, 0, write_size-tmp);
#ifdef UNIV_DEBUG
ut_a(write_size > 0 && ((write_size % block_size) == 0));
ut_a(write_size >= tmp);
@ -474,19 +477,10 @@ fil_compress_page(
srv_stats.page_compression_saved.add((len - write_size));
srv_stats.pages_page_compressed.inc();
#if defined (__linux__) && (!defined(FALLOC_FL_PUNCH_HOLE) || !defined (FALLOC_FL_KEEP_SIZE))
if (srv_use_trim) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: [Warning] System does not support FALLOC_FL_PUNCH_HOLE || FALLOC_FL_KEEP_SIZE.\n"
" InnoDB: Disabling trim for now.\n");
srv_use_trim = FALSE;
}
#endif
if (!srv_use_trim) {
/* If persistent trims are not used we always write full
page */
page and end of the page needs to be initialized.*/
memset(out_buf+write_size, 0, len-write_size);
write_size = len;
}

View File

@ -135,4 +135,11 @@ fil_page_is_compressed(
/*===================*/
byte *buf); /*!< in: page */
/*******************************************************************//**
Find out wheather the page is page compressed with lzo method
@return true if page is page compressed with lzo method*/
ibool
fil_page_is_lzo_compressed(
/*=======================*/
byte *buf); /*!< in: page */
#endif

View File

@ -182,3 +182,16 @@ fil_space_get_atomic_writes(
return((atomic_writes_t)0);
}
/*******************************************************************//**
Find out wheather the page is page compressed with lzo method
@return true if page is page compressed with lzo method, false if not */
UNIV_INLINE
ibool
fil_page_is_lzo_compressed(
/*=======================*/
byte *buf) /*!< in: page */
{
return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED &&
mach_read_from_8(buf+FIL_PAGE_FILE_FLUSH_LSN) == PAGE_LZO_ALGORITHM);
}

View File

@ -50,6 +50,7 @@ Created 10/21/1995 Heikki Tuuri
#include "srv0mon.h"
#include "srv0srv.h"
#ifdef HAVE_POSIX_FALLOCATE
#include "unistd.h"
#include "fcntl.h"
#endif
#ifndef UNIV_HOTBACKUP
@ -83,6 +84,19 @@ Created 10/21/1995 Heikki Tuuri
#include <sys/statvfs.h>
#endif
#if defined(UNIV_LINUX) && defined(HAVE_LINUX_FALLOC_H)
#include <linux/falloc.h>
#endif
#if defined(HAVE_FALLOCATE)
#ifndef FALLOC_FL_KEEP_SIZE
#define FALLOC_FL_KEEP_SIZE 0x01
#endif
#ifndef FALLOC_FL_PUNCH_HOLE
#define FALLOC_FL_PUNCH_HOLE 0x02
#endif
#endif
#ifdef HAVE_LZO
#include "lzo/lzo1x.h"
#endif
@ -3116,7 +3130,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, len, NULL);
}
@ -3137,7 +3151,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, n, NULL);
}
@ -3235,7 +3249,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, n, NULL);
}
@ -3256,7 +3270,7 @@ try_again:
as file spaces and they do not have FIL_PAGE_TYPE
field, thus we must use here information is the actual
file space compressed. */
if (compressed && fil_page_is_compressed((byte *)buf)) {
if (fil_page_is_compressed((byte *)buf)) {
fil_decompress_page(NULL, (byte *)buf, n, NULL);
}
@ -4757,12 +4771,10 @@ found:
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
if (slot->page_buf == NULL) {
os_slot_alloc_page_buf(slot);
}
os_slot_alloc_page_buf(slot);
#ifdef HAVE_LZO
if (innodb_compression_algorithm == 3 && slot->lzo_mem == NULL) {
if (innodb_compression_algorithm == 3) {
os_slot_alloc_lzo_mem(slot);
}
#endif
@ -4790,7 +4802,6 @@ found:
/* Take array mutex back */
os_mutex_enter(array->mutex);
}
#ifdef WIN_ASYNC_IO
@ -5180,9 +5191,11 @@ try_again:
trx->io_reads++;
trx->io_read += n;
}
slot = os_aio_array_reserve_slot(type, array, message1, message2, file,
name, buf, offset, n, space_id,
page_compression, page_compression_level, write_size);
if (type == OS_FILE_READ) {
if (srv_use_native_aio) {
os_n_file_reads++;
@ -5368,7 +5381,7 @@ os_aio_windows_handle(
switch (slot->type) {
case OS_FILE_WRITE:
if (slot->message1 && slot->page_compression && slot->page_buf) {
if (slot->message1 && slot->page_compression && slot->page_compress_success && slot->page_buf) {
ret_val = os_file_write(slot->name, slot->file, slot->page_buf,
slot->offset, slot->len);
} else {
@ -5404,26 +5417,23 @@ os_aio_windows_handle(
ret_val = ret && len == slot->len;
}
if (slot->message1 && slot->page_compression) {
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
if (slot->page_buf == NULL) {
if (slot->type == OS_FILE_READ) {
if (fil_page_is_compressed(slot->buf)) {
os_slot_alloc_page_buf(slot);
}
#ifdef HAVE_LZO
if (innodb_compression_algorithm == 3 && slot->lzo_mem == NULL) {
os_slot_alloc_lzo_mem(slot);
}
if (fil_page_is_lzo_compressed(slot->buf)) {
os_slot_alloc_lzo_mem(slot);
}
#endif
if (slot->type == OS_FILE_READ) {
fil_decompress_page(slot->page_buf, slot->buf, slot->len, slot->write_size);
} else {
if (slot->page_compress_success && fil_page_is_compressed(slot->page_buf)) {
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
} else {
/* OS_FILE_WRITE */
if (slot->page_compress_success && fil_page_is_compressed(slot->page_buf)) {
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
}
@ -5517,31 +5527,29 @@ retry:
/* We have not overstepped to next segment. */
ut_a(slot->pos < end_pos);
/* If the table is page compressed and this is read,
we decompress before we annouce the read is
complete. For writes, we free the compressed page. */
if (slot->message1 && slot->page_compression) {
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
if (slot->page_buf == NULL) {
if (slot->type == OS_FILE_READ) {
/* If the table is page compressed and this is read,
we decompress before we annouce the read is
complete. For writes, we free the compressed page. */
if (fil_page_is_compressed(slot->buf)) {
// We allocate memory for page compressed buffer if and only
// if it is not yet allocated.
os_slot_alloc_page_buf(slot);
}
#ifdef HAVE_LZO
if (innodb_compression_algorithm == 3 && slot->lzo_mem == NULL) {
os_slot_alloc_lzo_mem(slot);
}
if (fil_page_is_lzo_compressed(slot->buf)) {
os_slot_alloc_lzo_mem(slot);
}
#endif
if (slot->type == OS_FILE_READ) {
fil_decompress_page(slot->page_buf, slot->buf, slot->len, slot->write_size);
} else {
if (slot->page_compress_success &&
fil_page_is_compressed(slot->page_buf)) {
ut_ad(slot->page_compression_page);
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
} else {
/* OS_FILE_WRITE */
if (slot->page_compress_success &&
fil_page_is_compressed(slot->page_buf)) {
ut_ad(slot->page_compression_page);
if (srv_use_trim && os_fallocate_failed == FALSE) {
// Deallocate unused blocks from file system
os_file_trim(slot);
}
}
}
@ -6494,7 +6502,7 @@ os_file_trim(
}
#ifdef __linux__
#if defined(FALLOC_FL_PUNCH_HOLE) && defined (FALLOC_FL_KEEP_SIZE)
#if defined(HAVE_FALLOCATE)
int ret = fallocate(slot->file, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, off, trim_len);
if (ret) {
@ -6614,12 +6622,15 @@ os_slot_alloc_page_buf(
byte* cbuf;
ut_a(slot != NULL);
/* We allocate extra to avoid memory overwrite on compression */
cbuf2 = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
cbuf = static_cast<byte *>(ut_align(cbuf2, UNIV_PAGE_SIZE));
slot->page_compression_page = static_cast<byte *>(cbuf2);
slot->page_buf = static_cast<byte *>(cbuf);
ut_a(slot->page_buf != NULL);
if (slot->page_compression_page == NULL) {
/* We allocate extra to avoid memory overwrite on compression */
cbuf2 = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
cbuf = static_cast<byte *>(ut_align(cbuf2, UNIV_PAGE_SIZE));
slot->page_compression_page = static_cast<byte *>(cbuf2);
slot->page_buf = static_cast<byte *>(cbuf);
memset(slot->page_compression_page, 0, UNIV_PAGE_SIZE*2);
ut_a(slot->page_buf != NULL);
}
}
#ifdef HAVE_LZO
@ -6633,8 +6644,11 @@ os_slot_alloc_lzo_mem(
os_aio_slot_t* slot) /*!< in: slot structure */
{
ut_a(slot != NULL);
slot->lzo_mem = static_cast<byte *>(ut_malloc(LZO1X_1_15_MEM_COMPRESS));
ut_a(slot->lzo_mem != NULL);
if(slot->lzo_mem == NULL) {
slot->lzo_mem = static_cast<byte *>(ut_malloc(LZO1X_1_15_MEM_COMPRESS));
memset(slot->lzo_mem, 0, LZO1X_1_15_MEM_COMPRESS);
ut_a(slot->lzo_mem != NULL);
}
}
#endif