mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
EXPLAIN FORMAT=JSON: further development
Writing JSON: - Fix a bug in Single_line_formatting_helper - Add Json_writer_nesting_guard - safety class EXPLAIN JSON support - Add basic subquery support - Add tests for UNION/UNION ALL.
This commit is contained in:
@ -175,4 +175,138 @@ EXPLAIN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop table t1,t2;
|
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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "t1",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 10,
|
||||||
|
"filtered": 100,
|
||||||
|
"attached_condition": "(t1.b = t0.a)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop table t1;
|
||||||
drop table t0;
|
drop table t0;
|
||||||
|
@ -39,4 +39,24 @@ explain format=json select * from t2 where a1=1 or (b1=2 and b2=3);
|
|||||||
explain format=json select * from t0,t2 where t2.b1=t0.a and t2.b2=4;
|
explain format=json select * from t0,t2 where t2.b1=t0.a and t2.b2=4;
|
||||||
|
|
||||||
drop table t1,t2;
|
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;
|
||||||
drop table t0;
|
drop table t0;
|
||||||
|
|
||||||
|
@ -7536,6 +7536,13 @@ void Item_cache_wrapper::init_on_demand()
|
|||||||
|
|
||||||
void Item_cache_wrapper::print(String *str, enum_query_type query_type)
|
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());
|
str->append(func_name());
|
||||||
if (expr_cache)
|
if (expr_cache)
|
||||||
{
|
{
|
||||||
|
@ -894,6 +894,21 @@ void Item_subselect::update_used_tables()
|
|||||||
|
|
||||||
void Item_subselect::print(String *str, enum_query_type query_type)
|
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)
|
if (engine)
|
||||||
{
|
{
|
||||||
str->append('(');
|
str->append('(');
|
||||||
@ -3716,6 +3731,10 @@ int subselect_union_engine::exec()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int subselect_union_engine::get_identifier()
|
||||||
|
{
|
||||||
|
return unit->first_select()->select_number;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Search for at least one row satisfying select condition
|
Search for at least one row satisfying select condition
|
||||||
|
@ -871,6 +871,7 @@ public:
|
|||||||
bool is_executed() const;
|
bool is_executed() const;
|
||||||
bool no_rows();
|
bool no_rows();
|
||||||
virtual enum_engine_type engine_type() { return UNION_ENGINE; }
|
virtual enum_engine_type engine_type() { return UNION_ENGINE; }
|
||||||
|
int get_identifier();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,7 +79,12 @@ Json_writer& Json_writer::add_member(const char *name)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used by formatting helper to print something that is formatted by the helper. */
|
|
||||||
|
/*
|
||||||
|
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()
|
void Json_writer::start_sub_element()
|
||||||
{
|
{
|
||||||
//element_started= true;
|
//element_started= true;
|
||||||
@ -184,6 +189,7 @@ bool Single_line_formatting_helper::on_add_member(const char *name)
|
|||||||
return false; // not handled
|
return false; // not handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Single_line_formatting_helper::on_start_array()
|
bool Single_line_formatting_helper::on_start_array()
|
||||||
{
|
{
|
||||||
if (state == ADD_MEMBER)
|
if (state == ADD_MEMBER)
|
||||||
@ -200,6 +206,7 @@ bool Single_line_formatting_helper::on_start_array()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Single_line_formatting_helper::on_end_array()
|
bool Single_line_formatting_helper::on_end_array()
|
||||||
{
|
{
|
||||||
if (state == IN_ARRAY)
|
if (state == IN_ARRAY)
|
||||||
@ -211,12 +218,14 @@ bool Single_line_formatting_helper::on_end_array()
|
|||||||
return false; // not handled
|
return false; // not handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Single_line_formatting_helper::on_start_object()
|
void Single_line_formatting_helper::on_start_object()
|
||||||
{
|
{
|
||||||
// Nested objects will not be printed on one line
|
// Nested objects will not be printed on one line
|
||||||
disable_and_flush();
|
disable_and_flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Single_line_formatting_helper::on_add_str(const char *str)
|
bool Single_line_formatting_helper::on_add_str(const char *str)
|
||||||
{
|
{
|
||||||
if (state == IN_ARRAY)
|
if (state == IN_ARRAY)
|
||||||
@ -244,9 +253,13 @@ bool Single_line_formatting_helper::on_add_str(const char *str)
|
|||||||
return false; // not handled
|
return false; // not handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Append everything accumulated to the output on one line
|
||||||
|
*/
|
||||||
|
|
||||||
void Single_line_formatting_helper::flush_on_one_line()
|
void Single_line_formatting_helper::flush_on_one_line()
|
||||||
{
|
{
|
||||||
// append everything to output on one line
|
|
||||||
owner->start_sub_element();
|
owner->start_sub_element();
|
||||||
char *ptr= buffer;
|
char *ptr= buffer;
|
||||||
int nr= 0;
|
int nr= 0;
|
||||||
@ -281,6 +294,7 @@ void Single_line_formatting_helper::flush_on_one_line()
|
|||||||
|
|
||||||
void Single_line_formatting_helper::disable_and_flush()
|
void Single_line_formatting_helper::disable_and_flush()
|
||||||
{
|
{
|
||||||
|
bool start_array= (state == IN_ARRAY);
|
||||||
state= DISABLED;
|
state= DISABLED;
|
||||||
// deactivate ourselves and flush all accumulated calls.
|
// deactivate ourselves and flush all accumulated calls.
|
||||||
char *ptr= buffer;
|
char *ptr= buffer;
|
||||||
@ -291,11 +305,13 @@ void Single_line_formatting_helper::disable_and_flush()
|
|||||||
if (nr == 0)
|
if (nr == 0)
|
||||||
{
|
{
|
||||||
owner->add_member(str);
|
owner->add_member(str);
|
||||||
|
if (start_array)
|
||||||
|
owner->start_array();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (nr == 1)
|
//if (nr == 1)
|
||||||
owner->start_array();
|
// owner->start_array();
|
||||||
owner->add_str(str);
|
owner->add_str(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,30 @@ class Single_line_formatting_helper
|
|||||||
DISABLED
|
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 enum_state state;
|
||||||
enum { MAX_LINE_LEN= 80 };
|
enum { MAX_LINE_LEN= 80 };
|
||||||
char buffer[80];
|
char buffer[80];
|
||||||
|
|
||||||
|
/* The data in the buffer is located between buffer[0] and buf_ptr */
|
||||||
char *buf_ptr;
|
char *buf_ptr;
|
||||||
uint line_len;
|
uint line_len;
|
||||||
|
|
||||||
@ -99,8 +120,9 @@ private:
|
|||||||
// TODO: a stack of (name, bool is_object_or_array) elements.
|
// TODO: a stack of (name, bool is_object_or_array) elements.
|
||||||
int indent_level;
|
int indent_level;
|
||||||
enum { INDENT_SIZE = 2 };
|
enum { INDENT_SIZE = 2 };
|
||||||
|
|
||||||
friend class Single_line_formatting_helper;
|
friend class Single_line_formatting_helper;
|
||||||
|
friend class Json_writer_nesting_guard;
|
||||||
bool document_start;
|
bool document_start;
|
||||||
bool element_started;
|
bool element_started;
|
||||||
bool first_child;
|
bool first_child;
|
||||||
@ -116,3 +138,40 @@ public:
|
|||||||
String output;
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ int Explain_union::print_explain(Explain_query *query,
|
|||||||
uint8 explain_flags,
|
uint8 explain_flags,
|
||||||
bool is_analyze)
|
bool is_analyze)
|
||||||
{
|
{
|
||||||
const CHARSET_INFO *cs= system_charset_info;
|
//const CHARSET_INFO *cs= system_charset_info;
|
||||||
char table_name_buffer[SAFE_NAME_LEN];
|
char table_name_buffer[SAFE_NAME_LEN];
|
||||||
|
|
||||||
/* print all UNION children, in order */
|
/* print all UNION children, in order */
|
||||||
@ -391,6 +391,7 @@ int Explain_union::print_explain(Explain_query *query,
|
|||||||
void Explain_union::print_explain_json(Explain_query *query,
|
void Explain_union::print_explain_json(Explain_query *query,
|
||||||
Json_writer *writer, bool is_analyze)
|
Json_writer *writer, bool is_analyze)
|
||||||
{
|
{
|
||||||
|
Json_writer_nesting_guard guard(writer);
|
||||||
char table_name_buffer[SAFE_NAME_LEN];
|
char table_name_buffer[SAFE_NAME_LEN];
|
||||||
|
|
||||||
writer->add_member("query_block").start_object();
|
writer->add_member("query_block").start_object();
|
||||||
@ -404,17 +405,18 @@ void Explain_union::print_explain_json(Explain_query *query,
|
|||||||
for (int i= 0; i < (int) union_members.elements(); i++)
|
for (int i= 0; i < (int) union_members.elements(); i++)
|
||||||
{
|
{
|
||||||
writer->start_object();
|
writer->start_object();
|
||||||
writer->add_member("dependent").add_str("TODO");
|
//writer->add_member("dependent").add_str("TODO");
|
||||||
writer->add_member("cacheable").add_str("TODO");
|
//writer->add_member("cacheable").add_str("TODO");
|
||||||
Explain_select *sel= query->get_select(union_members.at(i));
|
Explain_select *sel= query->get_select(union_members.at(i));
|
||||||
sel->print_explain_json(query, writer, is_analyze);
|
sel->print_explain_json(query, writer, is_analyze);
|
||||||
writer->end_object();
|
writer->end_object();
|
||||||
}
|
}
|
||||||
writer->end_array();
|
writer->end_array();
|
||||||
|
|
||||||
//TODO: print_explain_for_children
|
print_explain_json_for_children(query, writer, is_analyze);
|
||||||
|
|
||||||
writer->end_object();
|
writer->end_object(); // union_result
|
||||||
|
writer->end_object(); // query_block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -423,9 +425,9 @@ void Explain_union::print_explain_json(Explain_query *query,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int Explain_node::print_explain_for_children(Explain_query *query,
|
int Explain_node::print_explain_for_children(Explain_query *query,
|
||||||
select_result_sink *output,
|
select_result_sink *output,
|
||||||
uint8 explain_flags,
|
uint8 explain_flags,
|
||||||
bool is_analyze)
|
bool is_analyze)
|
||||||
{
|
{
|
||||||
for (int i= 0; i < (int) children.elements(); i++)
|
for (int i= 0; i < (int) children.elements(); i++)
|
||||||
{
|
{
|
||||||
@ -437,6 +439,25 @@ int Explain_node::print_explain_for_children(Explain_query *query,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Explain_node::print_explain_json_for_children(Explain_query *query,
|
||||||
|
Json_writer *writer,
|
||||||
|
bool is_analyze)
|
||||||
|
{
|
||||||
|
if (!children.elements())
|
||||||
|
return;
|
||||||
|
|
||||||
|
writer->add_member("subqueries").start_array();
|
||||||
|
for (int i= 0; i < (int) children.elements(); i++)
|
||||||
|
{
|
||||||
|
writer->start_object();
|
||||||
|
Explain_node *node= query->get_node(children.at(i));
|
||||||
|
node->print_explain_json(query, writer, is_analyze);
|
||||||
|
writer->end_object();
|
||||||
|
}
|
||||||
|
writer->end_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Explain_select::replace_table(uint idx, Explain_table_access *new_tab)
|
void Explain_select::replace_table(uint idx, Explain_table_access *new_tab)
|
||||||
{
|
{
|
||||||
delete join_tabs[idx];
|
delete join_tabs[idx];
|
||||||
@ -514,6 +535,8 @@ int Explain_select::print_explain(Explain_query *query,
|
|||||||
void Explain_select::print_explain_json(Explain_query *query,
|
void Explain_select::print_explain_json(Explain_query *query,
|
||||||
Json_writer *writer, bool is_analyze)
|
Json_writer *writer, bool is_analyze)
|
||||||
{
|
{
|
||||||
|
Json_writer_nesting_guard guard(writer);
|
||||||
|
|
||||||
writer->add_member("query_block").start_object();
|
writer->add_member("query_block").start_object();
|
||||||
writer->add_member("select_id").add_ll(1);
|
writer->add_member("select_id").add_ll(1);
|
||||||
if (message)
|
if (message)
|
||||||
@ -530,6 +553,8 @@ void Explain_select::print_explain_json(Explain_query *query,
|
|||||||
join_tabs[i]->print_explain_json(writer, is_analyze);
|
join_tabs[i]->print_explain_json(writer, is_analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_explain_json_for_children(query, writer, is_analyze);
|
||||||
writer->end_object();
|
writer->end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,7 +683,7 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
|
|||||||
uint select_id, const char *select_type,
|
uint select_id, const char *select_type,
|
||||||
bool using_temporary, bool using_filesort)
|
bool using_temporary, bool using_filesort)
|
||||||
{
|
{
|
||||||
const CHARSET_INFO *cs= system_charset_info;
|
//const CHARSET_INFO *cs= system_charset_info;
|
||||||
|
|
||||||
List<Item> item_list;
|
List<Item> item_list;
|
||||||
Item *item_null= new Item_null();
|
Item *item_null= new Item_null();
|
||||||
@ -899,6 +924,7 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t
|
|||||||
void Explain_table_access::print_explain_json(Json_writer *writer,
|
void Explain_table_access::print_explain_json(Json_writer *writer,
|
||||||
bool is_analyze)
|
bool is_analyze)
|
||||||
{
|
{
|
||||||
|
Json_writer_nesting_guard guard(writer);
|
||||||
writer->add_member("table").start_object();
|
writer->add_member("table").start_object();
|
||||||
|
|
||||||
writer->add_member("table_name").add_str(table_name);
|
writer->add_member("table_name").add_str(table_name);
|
||||||
|
@ -112,6 +112,8 @@ public:
|
|||||||
|
|
||||||
int print_explain_for_children(Explain_query *query, select_result_sink *output,
|
int print_explain_for_children(Explain_query *query, select_result_sink *output,
|
||||||
uint8 explain_flags, bool is_analyze);
|
uint8 explain_flags, bool is_analyze);
|
||||||
|
void print_explain_json_for_children(Explain_query *query,
|
||||||
|
Json_writer *writer, bool is_analyze);
|
||||||
virtual ~Explain_node(){}
|
virtual ~Explain_node(){}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user