mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
Printing non-trivial HAVING added.
This commit is contained in:
@ -467,3 +467,116 @@ ANALYZE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop table t0, t1;
|
drop table t0, t1;
|
||||||
|
#
|
||||||
|
# MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
|
||||||
|
#
|
||||||
|
create table t0(a int);
|
||||||
|
insert into t0 values (0),(1),(2),(3);
|
||||||
|
create table t1(a int);
|
||||||
|
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
|
||||||
|
create table t2 (
|
||||||
|
a int,
|
||||||
|
b int,
|
||||||
|
key (a)
|
||||||
|
);
|
||||||
|
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
|
||||||
|
# normal HAVING
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a having TOP > a;
|
||||||
|
ANALYZE
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"having_condition": "(TOP > a)",
|
||||||
|
"filesort": {
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"r_used_priority_queue": false,
|
||||||
|
"r_output_rows": 0,
|
||||||
|
"r_buffer_size": "5Kb",
|
||||||
|
"temporary_table": {
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 256,
|
||||||
|
"r_rows": 256,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# HAVING is always TRUE (not printed)
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a having 1<>2;
|
||||||
|
ANALYZE
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"filesort": {
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"r_used_priority_queue": false,
|
||||||
|
"r_output_rows": 256,
|
||||||
|
"r_buffer_size": "5Kb",
|
||||||
|
"temporary_table": {
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 256,
|
||||||
|
"r_rows": 256,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# HAVING is always FALSE (intercepted by message)
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a having 1=2;
|
||||||
|
ANALYZE
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"message": "Impossible HAVING"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# HAVING is absent
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a;
|
||||||
|
ANALYZE
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"filesort": {
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"r_used_priority_queue": false,
|
||||||
|
"r_output_rows": 256,
|
||||||
|
"r_buffer_size": "5Kb",
|
||||||
|
"temporary_table": {
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 256,
|
||||||
|
"r_rows": 256,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop table t0, t1, t2;
|
||||||
|
@ -799,6 +799,7 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 2,
|
"select_id": 2,
|
||||||
|
"having_condition": "trigcond(<is_not_null_test>(t1.a))",
|
||||||
"full-scan-on-null_key": {
|
"full-scan-on-null_key": {
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "t1",
|
"table_name": "t1",
|
||||||
@ -1110,3 +1111,86 @@ EXPLAIN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
|
||||||
|
#
|
||||||
|
create table t0(a int);
|
||||||
|
insert into t0 values (0),(1),(2),(3);
|
||||||
|
create table t1(a int);
|
||||||
|
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
|
||||||
|
create table t2 (
|
||||||
|
a int,
|
||||||
|
b int,
|
||||||
|
key (a)
|
||||||
|
);
|
||||||
|
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
|
||||||
|
# normal HAVING
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a having TOP > a;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"having_condition": "(TOP > t2.a)",
|
||||||
|
"filesort": {
|
||||||
|
"temporary_table": {
|
||||||
|
"function": "buffer",
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 256,
|
||||||
|
"filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# HAVING is always TRUE (not printed)
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a having 1<>2;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"filesort": {
|
||||||
|
"temporary_table": {
|
||||||
|
"function": "buffer",
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 256,
|
||||||
|
"filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# HAVING is always FALSE (intercepted by message)
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a having 1=2;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"message": "Impossible HAVING"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# HAVING is absent
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"filesort": {
|
||||||
|
"temporary_table": {
|
||||||
|
"function": "buffer",
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 256,
|
||||||
|
"filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop table t0, t1, t2;
|
||||||
|
@ -150,3 +150,29 @@ analyze format=json (select * from t1 tbl1 where a<5) union (select * from t1 tb
|
|||||||
drop table t0, t1;
|
drop table t0, t1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
|
||||||
|
--echo #
|
||||||
|
create table t0(a int);
|
||||||
|
insert into t0 values (0),(1),(2),(3);
|
||||||
|
create table t1(a int);
|
||||||
|
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
|
||||||
|
create table t2 (
|
||||||
|
a int,
|
||||||
|
b int,
|
||||||
|
key (a)
|
||||||
|
);
|
||||||
|
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
|
||||||
|
--echo # normal HAVING
|
||||||
|
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a having TOP > a;
|
||||||
|
--echo # HAVING is always TRUE (not printed)
|
||||||
|
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a having 1<>2;
|
||||||
|
--echo # HAVING is always FALSE (intercepted by message)
|
||||||
|
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a having 1=2;
|
||||||
|
--echo # HAVING is absent
|
||||||
|
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
|
||||||
|
analyze format=json select a, max(b) as TOP from t2 group by a;
|
||||||
|
drop table t0, t1, t2;
|
||||||
|
@ -278,7 +278,6 @@ explain format=json select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') a
|
|||||||
|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-8786 Wrong result for SELECT FORMAT=JSON * FROM t1 WHERE a=_latin1 0xDF
|
--echo # MDEV-8786 Wrong result for SELECT FORMAT=JSON * FROM t1 WHERE a=_latin1 0xDF
|
||||||
--echo #
|
--echo #
|
||||||
@ -294,3 +293,26 @@ CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1);
|
|||||||
INSERT INTO t1 VALUES ('a'),('A');
|
INSERT INTO t1 VALUES ('a'),('A');
|
||||||
EXPLAIN FORMAT=JSON SELECT * FROM t1 WHERE NULLIF(a,_utf8'a' COLLATE utf8_bin);
|
EXPLAIN FORMAT=JSON SELECT * FROM t1 WHERE NULLIF(a,_utf8'a' COLLATE utf8_bin);
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
|
||||||
|
--echo #
|
||||||
|
create table t0(a int);
|
||||||
|
insert into t0 values (0),(1),(2),(3);
|
||||||
|
create table t1(a int);
|
||||||
|
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
|
||||||
|
create table t2 (
|
||||||
|
a int,
|
||||||
|
b int,
|
||||||
|
key (a)
|
||||||
|
);
|
||||||
|
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
|
||||||
|
--echo # normal HAVING
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a having TOP > a;
|
||||||
|
--echo # HAVING is always TRUE (not printed)
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a having 1<>2;
|
||||||
|
--echo # HAVING is always FALSE (intercepted by message)
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a having 1=2;
|
||||||
|
--echo # HAVING is absent
|
||||||
|
explain format=json select a, max(b) as TOP from t2 group by a;
|
||||||
|
drop table t0, t1, t2;
|
||||||
|
@ -862,7 +862,20 @@ void Explain_select::print_explain_json(Explain_query *query,
|
|||||||
writer->add_member("const_condition");
|
writer->add_member("const_condition");
|
||||||
write_item(writer, exec_const_cond);
|
write_item(writer, exec_const_cond);
|
||||||
}
|
}
|
||||||
|
/* we do not print HAVING which always evaluates to TRUE */
|
||||||
|
if (having || (having_value == Item::COND_FALSE))
|
||||||
|
{
|
||||||
|
writer->add_member("having_condition");
|
||||||
|
if (likely(having))
|
||||||
|
write_item(writer, having);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Normally we should not go this branch, left just for safety */
|
||||||
|
DBUG_ASSERT(having_value == Item::COND_FALSE);
|
||||||
|
writer->add_str("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Filesort_tracker *first_table_sort= NULL;
|
Filesort_tracker *first_table_sort= NULL;
|
||||||
bool first_table_sort_used= false;
|
bool first_table_sort_used= false;
|
||||||
int started_objects= 0;
|
int started_objects= 0;
|
||||||
|
@ -209,6 +209,7 @@ public:
|
|||||||
Explain_select(MEM_ROOT *root, bool is_analyze) :
|
Explain_select(MEM_ROOT *root, bool is_analyze) :
|
||||||
Explain_basic_join(root),
|
Explain_basic_join(root),
|
||||||
message(NULL),
|
message(NULL),
|
||||||
|
having(NULL), having_value(Item::COND_UNDEF),
|
||||||
using_temporary(false), using_filesort(false),
|
using_temporary(false), using_filesort(false),
|
||||||
time_tracker(is_analyze),
|
time_tracker(is_analyze),
|
||||||
ops_tracker(is_analyze)
|
ops_tracker(is_analyze)
|
||||||
@ -231,7 +232,11 @@ public:
|
|||||||
|
|
||||||
/* Expensive constant condition */
|
/* Expensive constant condition */
|
||||||
Item *exec_const_cond;
|
Item *exec_const_cond;
|
||||||
|
|
||||||
|
/* HAVING condition */
|
||||||
|
COND *having;
|
||||||
|
Item::cond_result having_value;
|
||||||
|
|
||||||
/* Global join attributes. In tabular form, they are printed on the first row */
|
/* Global join attributes. In tabular form, they are printed on the first row */
|
||||||
bool using_temporary;
|
bool using_temporary;
|
||||||
bool using_filesort;
|
bool using_filesort;
|
||||||
|
@ -24197,6 +24197,11 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
|
|||||||
xpl_sel->using_filesort= true;
|
xpl_sel->using_filesort= true;
|
||||||
|
|
||||||
xpl_sel->exec_const_cond= exec_const_cond;
|
xpl_sel->exec_const_cond= exec_const_cond;
|
||||||
|
if (tmp_having)
|
||||||
|
xpl_sel->having= tmp_having;
|
||||||
|
else
|
||||||
|
xpl_sel->having= having;
|
||||||
|
xpl_sel->having_value= having_value;
|
||||||
|
|
||||||
JOIN_TAB* const first_top_tab= join->first_breadth_first_optimization_tab();
|
JOIN_TAB* const first_top_tab= join->first_breadth_first_optimization_tab();
|
||||||
JOIN_TAB* prev_bush_root_tab= NULL;
|
JOIN_TAB* prev_bush_root_tab= NULL;
|
||||||
|
Reference in New Issue
Block a user