Skip to content

Commit da3ec3d

Browse files
committed
MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
Printing non-trivial HAVING added.
1 parent 79140b0 commit da3ec3d

File tree

7 files changed

+271
-3
lines changed

7 files changed

+271
-3
lines changed

mysql-test/r/analyze_format_json.result

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,116 @@ ANALYZE
467467
}
468468
}
469469
drop table t0, t1;
470+
#
471+
# MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
472+
#
473+
create table t0(a int);
474+
insert into t0 values (0),(1),(2),(3);
475+
create table t1(a int);
476+
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
477+
create table t2 (
478+
a int,
479+
b int,
480+
key (a)
481+
);
482+
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
483+
# normal HAVING
484+
analyze format=json select a, max(b) as TOP from t2 group by a having TOP > a;
485+
ANALYZE
486+
{
487+
"query_block": {
488+
"select_id": 1,
489+
"r_loops": 1,
490+
"r_total_time_ms": "REPLACED",
491+
"having_condition": "(TOP > a)",
492+
"filesort": {
493+
"r_loops": 1,
494+
"r_total_time_ms": "REPLACED",
495+
"r_used_priority_queue": false,
496+
"r_output_rows": 0,
497+
"r_buffer_size": "5Kb",
498+
"temporary_table": {
499+
"table": {
500+
"table_name": "t2",
501+
"access_type": "ALL",
502+
"r_loops": 1,
503+
"rows": 256,
504+
"r_rows": 256,
505+
"r_total_time_ms": "REPLACED",
506+
"filtered": 100,
507+
"r_filtered": 100
508+
}
509+
}
510+
}
511+
}
512+
}
513+
# HAVING is always TRUE (not printed)
514+
analyze format=json select a, max(b) as TOP from t2 group by a having 1<>2;
515+
ANALYZE
516+
{
517+
"query_block": {
518+
"select_id": 1,
519+
"r_loops": 1,
520+
"r_total_time_ms": "REPLACED",
521+
"filesort": {
522+
"r_loops": 1,
523+
"r_total_time_ms": "REPLACED",
524+
"r_used_priority_queue": false,
525+
"r_output_rows": 256,
526+
"r_buffer_size": "5Kb",
527+
"temporary_table": {
528+
"table": {
529+
"table_name": "t2",
530+
"access_type": "ALL",
531+
"r_loops": 1,
532+
"rows": 256,
533+
"r_rows": 256,
534+
"r_total_time_ms": "REPLACED",
535+
"filtered": 100,
536+
"r_filtered": 100
537+
}
538+
}
539+
}
540+
}
541+
}
542+
# HAVING is always FALSE (intercepted by message)
543+
analyze format=json select a, max(b) as TOP from t2 group by a having 1=2;
544+
ANALYZE
545+
{
546+
"query_block": {
547+
"select_id": 1,
548+
"table": {
549+
"message": "Impossible HAVING"
550+
}
551+
}
552+
}
553+
# HAVING is absent
554+
analyze format=json select a, max(b) as TOP from t2 group by a;
555+
ANALYZE
556+
{
557+
"query_block": {
558+
"select_id": 1,
559+
"r_loops": 1,
560+
"r_total_time_ms": "REPLACED",
561+
"filesort": {
562+
"r_loops": 1,
563+
"r_total_time_ms": "REPLACED",
564+
"r_used_priority_queue": false,
565+
"r_output_rows": 256,
566+
"r_buffer_size": "5Kb",
567+
"temporary_table": {
568+
"table": {
569+
"table_name": "t2",
570+
"access_type": "ALL",
571+
"r_loops": 1,
572+
"rows": 256,
573+
"r_rows": 256,
574+
"r_total_time_ms": "REPLACED",
575+
"filtered": 100,
576+
"r_filtered": 100
577+
}
578+
}
579+
}
580+
}
581+
}
582+
drop table t0, t1, t2;

mysql-test/r/explain_json.result

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ EXPLAIN
799799
{
800800
"query_block": {
801801
"select_id": 2,
802+
"having_condition": "trigcond(<is_not_null_test>(t1.a))",
802803
"full-scan-on-null_key": {
803804
"table": {
804805
"table_name": "t1",
@@ -1110,3 +1111,86 @@ EXPLAIN
11101111
}
11111112
}
11121113
DROP TABLE t1;
1114+
#
1115+
# MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
1116+
#
1117+
create table t0(a int);
1118+
insert into t0 values (0),(1),(2),(3);
1119+
create table t1(a int);
1120+
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
1121+
create table t2 (
1122+
a int,
1123+
b int,
1124+
key (a)
1125+
);
1126+
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
1127+
# normal HAVING
1128+
explain format=json select a, max(b) as TOP from t2 group by a having TOP > a;
1129+
EXPLAIN
1130+
{
1131+
"query_block": {
1132+
"select_id": 1,
1133+
"having_condition": "(TOP > t2.a)",
1134+
"filesort": {
1135+
"temporary_table": {
1136+
"function": "buffer",
1137+
"table": {
1138+
"table_name": "t2",
1139+
"access_type": "ALL",
1140+
"rows": 256,
1141+
"filtered": 100
1142+
}
1143+
}
1144+
}
1145+
}
1146+
}
1147+
# HAVING is always TRUE (not printed)
1148+
explain format=json select a, max(b) as TOP from t2 group by a having 1<>2;
1149+
EXPLAIN
1150+
{
1151+
"query_block": {
1152+
"select_id": 1,
1153+
"filesort": {
1154+
"temporary_table": {
1155+
"function": "buffer",
1156+
"table": {
1157+
"table_name": "t2",
1158+
"access_type": "ALL",
1159+
"rows": 256,
1160+
"filtered": 100
1161+
}
1162+
}
1163+
}
1164+
}
1165+
}
1166+
# HAVING is always FALSE (intercepted by message)
1167+
explain format=json select a, max(b) as TOP from t2 group by a having 1=2;
1168+
EXPLAIN
1169+
{
1170+
"query_block": {
1171+
"select_id": 1,
1172+
"table": {
1173+
"message": "Impossible HAVING"
1174+
}
1175+
}
1176+
}
1177+
# HAVING is absent
1178+
explain format=json select a, max(b) as TOP from t2 group by a;
1179+
EXPLAIN
1180+
{
1181+
"query_block": {
1182+
"select_id": 1,
1183+
"filesort": {
1184+
"temporary_table": {
1185+
"function": "buffer",
1186+
"table": {
1187+
"table_name": "t2",
1188+
"access_type": "ALL",
1189+
"rows": 256,
1190+
"filtered": 100
1191+
}
1192+
}
1193+
}
1194+
}
1195+
}
1196+
drop table t0, t1, t2;

mysql-test/t/analyze_format_json.test

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,29 @@ analyze format=json (select * from t1 tbl1 where a<5) union (select * from t1 tb
150150
drop table t0, t1;
151151

152152

153+
--echo #
154+
--echo # MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
155+
--echo #
156+
create table t0(a int);
157+
insert into t0 values (0),(1),(2),(3);
158+
create table t1(a int);
159+
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
160+
create table t2 (
161+
a int,
162+
b int,
163+
key (a)
164+
);
165+
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
166+
--echo # normal HAVING
167+
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
168+
analyze format=json select a, max(b) as TOP from t2 group by a having TOP > a;
169+
--echo # HAVING is always TRUE (not printed)
170+
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
171+
analyze format=json select a, max(b) as TOP from t2 group by a having 1<>2;
172+
--echo # HAVING is always FALSE (intercepted by message)
173+
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
174+
analyze format=json select a, max(b) as TOP from t2 group by a having 1=2;
175+
--echo # HAVING is absent
176+
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
177+
analyze format=json select a, max(b) as TOP from t2 group by a;
178+
drop table t0, t1, t2;

mysql-test/t/explain_json.test

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,6 @@ explain format=json select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') a
278278

279279
drop table t1;
280280

281-
282281
--echo #
283282
--echo # MDEV-8786 Wrong result for SELECT FORMAT=JSON * FROM t1 WHERE a=_latin1 0xDF
284283
--echo #
@@ -294,3 +293,26 @@ CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1);
294293
INSERT INTO t1 VALUES ('a'),('A');
295294
EXPLAIN FORMAT=JSON SELECT * FROM t1 WHERE NULLIF(a,_utf8'a' COLLATE utf8_bin);
296295
DROP TABLE t1;
296+
297+
--echo #
298+
--echo # MDEV-7970: EXPLAIN FORMAT=JSON does not print HAVING
299+
--echo #
300+
create table t0(a int);
301+
insert into t0 values (0),(1),(2),(3);
302+
create table t1(a int);
303+
insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C;
304+
create table t2 (
305+
a int,
306+
b int,
307+
key (a)
308+
);
309+
insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B;
310+
--echo # normal HAVING
311+
explain format=json select a, max(b) as TOP from t2 group by a having TOP > a;
312+
--echo # HAVING is always TRUE (not printed)
313+
explain format=json select a, max(b) as TOP from t2 group by a having 1<>2;
314+
--echo # HAVING is always FALSE (intercepted by message)
315+
explain format=json select a, max(b) as TOP from t2 group by a having 1=2;
316+
--echo # HAVING is absent
317+
explain format=json select a, max(b) as TOP from t2 group by a;
318+
drop table t0, t1, t2;

sql/sql_explain.cc

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,20 @@ void Explain_select::print_explain_json(Explain_query *query,
862862
writer->add_member("const_condition");
863863
write_item(writer, exec_const_cond);
864864
}
865-
865+
/* we do not print HAVING which always evaluates to TRUE */
866+
if (having || (having_value == Item::COND_FALSE))
867+
{
868+
writer->add_member("having_condition");
869+
if (likely(having))
870+
write_item(writer, having);
871+
else
872+
{
873+
/* Normally we should not go this branch, left just for safety */
874+
DBUG_ASSERT(having_value == Item::COND_FALSE);
875+
writer->add_str("0");
876+
}
877+
}
878+
866879
Filesort_tracker *first_table_sort= NULL;
867880
bool first_table_sort_used= false;
868881
int started_objects= 0;

sql/sql_explain.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class Explain_select : public Explain_basic_join
209209
Explain_select(MEM_ROOT *root, bool is_analyze) :
210210
Explain_basic_join(root),
211211
message(NULL),
212+
having(NULL), having_value(Item::COND_UNDEF),
212213
using_temporary(false), using_filesort(false),
213214
time_tracker(is_analyze),
214215
ops_tracker(is_analyze)
@@ -231,7 +232,11 @@ class Explain_select : public Explain_basic_join
231232

232233
/* Expensive constant condition */
233234
Item *exec_const_cond;
234-
235+
236+
/* HAVING condition */
237+
COND *having;
238+
Item::cond_result having_value;
239+
235240
/* Global join attributes. In tabular form, they are printed on the first row */
236241
bool using_temporary;
237242
bool using_filesort;

sql/sql_select.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24197,6 +24197,11 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
2419724197
xpl_sel->using_filesort= true;
2419824198

2419924199
xpl_sel->exec_const_cond= exec_const_cond;
24200+
if (tmp_having)
24201+
xpl_sel->having= tmp_having;
24202+
else
24203+
xpl_sel->having= having;
24204+
xpl_sel->having_value= having_value;
2420024205

2420124206
JOIN_TAB* const first_top_tab= join->first_breadth_first_optimization_tab();
2420224207
JOIN_TAB* prev_bush_root_tab= NULL;

0 commit comments

Comments
 (0)