diff options
author | unknown <bell@sanja.is.com.ua> | 2003-10-16 15:54:47 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2003-10-16 15:54:47 +0300 |
commit | 724a6c3c6d09891f07352bbc4b041ec960fc8986 (patch) | |
tree | dff4a909ef6eed167999fe596d481efd2e38e613 /sql | |
parent | 1d17fd7d51f7100038eaa5fb4cb372c785a44010 (diff) | |
download | mariadb-git-724a6c3c6d09891f07352bbc4b041ec960fc8986.tar.gz |
subqueries made printable
new EXPLAIN parameter to show real query as it was interpreted
(SCRUM) (WL#1274)
mysql-test/r/subselect.result:
new explains
mysql-test/r/union.result:
new explains
mysql-test/t/subselect.test:
new explains
mysql-test/t/union.test:
new explains
sql/item.cc:
fixed printability of Items in SELECT list
sql/item.h:
fixed printability of Items in SELECT list
sql/item_cmpfunc.cc:
fixed print()
sql/item_cmpfunc.h:
fixed print()
sql/item_subselect.cc:
subqueries made printable
sql/item_subselect.h:
subqueries made printable
sql/mysql_priv.h:
union option made looks like options
sql/sql_derived.cc:
now this link is used
sql/sql_lex.cc:
subqueries made printable
sql/sql_lex.h:
subqueries made printable
new EXPLAIN parameter support
sql/sql_parse.cc:
new EXPLAIN parameter
sql/sql_select.cc:
debug output
new EXPLAIN parameter support
sql/sql_select.h:
new EXPLAIN parameter support
sql/sql_yacc.yy:
new EXPLAIN parameter support
SELECT printability support
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 102 | ||||
-rw-r--r-- | sql/item.h | 46 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 8 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 6 | ||||
-rw-r--r-- | sql/item_subselect.cc | 161 | ||||
-rw-r--r-- | sql/item_subselect.h | 27 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_derived.cc | 4 | ||||
-rw-r--r-- | sql/sql_lex.cc | 66 | ||||
-rw-r--r-- | sql/sql_lex.h | 14 | ||||
-rw-r--r-- | sql/sql_parse.cc | 10 | ||||
-rw-r--r-- | sql/sql_select.cc | 184 | ||||
-rw-r--r-- | sql/sql_select.h | 7 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 26 |
14 files changed, 571 insertions, 93 deletions
diff --git a/sql/item.cc b/sql/item.cc index ccca858c4c0..19ea85f123a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -86,6 +86,19 @@ Item::Item(THD *thd, Item &item): thd->free_list= this; } + +void Item::print_item_w_name(String *str) +{ + print(str); + if (name) + { + str->append(" AS `"); + str->append(name); + str->append('`'); + } +} + + // Constructor used by Item_field & Item_ref (see Item comment) Item_ident::Item_ident(THD *thd, Item_ident &item): Item(thd, item), @@ -441,12 +454,8 @@ String *Item_int::val_str(String *str) void Item_int::print(String *str) { - if (!name) - { - str_value.set(value, default_charset()); - name=str_value.c_ptr(); - } - str->append(name); + str_value.set(value, default_charset()); + str->append(str_value); } String *Item_uint::val_str(String *str) @@ -457,12 +466,8 @@ String *Item_uint::val_str(String *str) void Item_uint::print(String *str) { - if (!name) - { - str_value.set((ulonglong) value, default_charset()); - name=str_value.c_ptr(); - } - str->append(name); + str_value.set((ulonglong) value, default_charset()); + str->append(str_value); } @@ -476,17 +481,9 @@ void Item_string::print(String *str) { str->append('_'); str->append(collation.collation->csname); - if (varbin) - { - str->append(' '); - str->append(full_name()); - } - else - { - str->append('\''); - str->append(full_name()); - str->append('\''); - } + str->append('\''); + str->append(str_value); + str->append('\''); } bool Item_null::eq(const Item *item, bool binary_cmp) const @@ -785,7 +782,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, // store pointer on SELECT_LEX from wich item is dependent item->depended_from= last; current->mark_as_dependent(last); - if (thd->lex.describe) + if (thd->lex.describe & DESCRIBE_EXTENDED) { char warn_buff[MYSQL_ERRMSG_SIZE]; sprintf(warn_buff, ER(ER_WARN_FIELD_RESOLVED), @@ -1494,6 +1491,34 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) } +void Item_ref::print(String *str) +{ + if (ref && *ref) + (*ref)->print(str); + else + Item_ident::print(str); +} + + +void Item_ref_null_helper::print(String *str) +{ + str->append("<ref_null_helper>("); + if (ref && *ref) + (*ref)->print(str); + else + str->append('?'); + str->append(')'); +} + + +void Item_null_helper::print(String *str) +{ + str->append("<null_helper>("); + store->print(str); + str->append(')'); +} + + bool Item_default_value::eq(const Item *item, bool binary_cmp) const { return item->type() == DEFAULT_VALUE_ITEM && @@ -1715,6 +1740,34 @@ Item_cache* Item_cache::get_cache(Item_result type) } } + +void Item_cache::print(String *str) +{ + str->append("<cache>("); + if (example) + example->print(str); + else + Item::print(str); + str->append(')'); +} + + +void Item_cache_int::store(Item *item) +{ + value= item->val_int_result(); + null_value= item->null_value; + collation.set(item->collation); +} + + +void Item_cache_real::store(Item *item) +{ + value= item->val_result(); + null_value= item->null_value; + collation.set(item->collation); +} + + void Item_cache_str::store(Item *item) { value_buff.set(buffer, sizeof(buffer), item->collation.collation); @@ -1765,6 +1818,7 @@ bool Item_cache_row::allocate(uint num) bool Item_cache_row::setup(Item * item) { + example= item; if (!values && allocate(item->cols())) return 1; for (uint i= 0; i < item_count; i++) diff --git a/sql/item.h b/sql/item.h index 5e6df464fb3..78ca5a8f3fe 100644 --- a/sql/item.h +++ b/sql/item.h @@ -174,6 +174,7 @@ public: { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} virtual bool const_item() const { return used_tables() == 0; } virtual void print(String *str_arg) { str_arg->append(full_name()); } + void print_item_w_name(String *); virtual void update_used_tables() {} virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {} virtual bool get_date(TIME *ltime,bool fuzzydate); @@ -307,6 +308,7 @@ public: bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } + void print(String *str) { str->append("NULL"); } }; class Item_param :public Item @@ -357,6 +359,7 @@ public: String *query_val_str(String *str); enum_field_types field_type() const { return MYSQL_TYPE_STRING; } Item *new_item() { return new Item_param(pos_in_query); } + void print(String *str) { str->append('?'); } }; class Item_int :public Item @@ -449,11 +452,9 @@ public: class Item_string :public Item { - bool varbin; public: Item_string(const char *str,uint length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) - :varbin(0) { collation.set(cs, dv); str_value.set(str,length,cs); @@ -463,7 +464,6 @@ public: } Item_string(const char *name_par, const char *str, uint length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) - :varbin(0) { collation.set(cs, dv); str_value.set(str,length,cs); @@ -497,7 +497,6 @@ public: } String *const_string() { return &str_value; } inline void append(char *str, uint length) { str_value.append(str, length); } - inline void set_varbin_name(char *nm) { name= nm; varbin= 1; } void print(String *str); }; @@ -633,6 +632,7 @@ public: (*ref)->save_in_field(result_field, no_conversions); } Item *real_item() { return *ref; } + void print(String *str); }; class Item_in_subselect; @@ -648,15 +648,7 @@ public: longlong val_int(); String* val_str(String* s); bool get_date(TIME *ltime, bool fuzzydate); - void print(String *str) - { - str->append("<ref_null_helper>("); - if (ref && *ref) - (*ref)->print(str); - else - str->append('?'); - str->append(')'); - } + void print(String *str); }; class Item_null_helper :public Item_ref_null_helper @@ -668,12 +660,7 @@ public: :Item_ref_null_helper(master, &store, table_name_par, field_name_par), store(item) {} - void print(String *str) - { - str->append("<null_helper>("); - store->print(str); - str->append(')'); - } + void print(String *str); }; /* @@ -855,14 +842,16 @@ public: class Item_cache: public Item { +protected: + Item *example; table_map used_table_map; public: - Item_cache(): used_table_map(0) {fixed= 1; null_value= 1;} + Item_cache(): example(0), used_table_map(0) {fixed= 1; null_value= 1;} void set_used_tables(table_map map) { used_table_map= map; } virtual bool allocate(uint i) { return 0; }; - virtual bool setup(Item *) { return 0; }; + virtual bool setup(Item *item) { example= item; return 0; }; virtual void store(Item *)= 0; void set_len_n_dec(uint32 max_len, uint8 dec) { @@ -872,6 +861,7 @@ public: enum Type type() const { return CACHE_ITEM; } static Item_cache* get_cache(Item_result type); table_map used_tables() const { return used_table_map; } + void print(String *str); }; class Item_cache_int: public Item_cache @@ -880,12 +870,7 @@ class Item_cache_int: public Item_cache public: Item_cache_int(): Item_cache() {} - void store(Item *item) - { - value= item->val_int_result(); - null_value= item->null_value; - collation.set(item->collation); - } + void store(Item *item); double val() { return (double) value; } longlong val_int() { return value; } String* val_str(String *str) { str->set(value, default_charset()); return str; } @@ -898,12 +883,7 @@ class Item_cache_real: public Item_cache public: Item_cache_real(): Item_cache() {} - void store(Item *item) - { - value= item->val_result(); - null_value= item->null_value; - collation.set(item->collation); - } + void store(Item *item); double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } String* val_str(String *str) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 23b322ebd01..d183c81b230 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -112,6 +112,14 @@ longlong Item_func_not_all::val_int() return (!null_value && value == 0) ? 1 : 0; } +void Item_func_not_all::print(String *str) +{ + if (show) + Item_func::print(str); + else + args[0]->print(str); +} + /* Convert a constant expression or string to an integer. This is done when comparing DATE's of different formats and diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index ab03782b168..eb473a1a73d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -160,10 +160,14 @@ class Item_func_not_all :public Item_func_not { bool abort_on_null; public: - Item_func_not_all(Item *a) :Item_func_not(a), abort_on_null(0) {} + bool show; + + Item_func_not_all(Item *a) :Item_func_not(a), abort_on_null(0), show(0) {} virtual void top_level_item() { abort_on_null= 1; } bool top_level() { return abort_on_null; } longlong val_int(); + const char *func_name() const { return "<not>"; } + void print(String *str); }; class Item_func_eq :public Item_bool_rowready_func2 diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 5e0221ad6c7..0703179d92a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -141,17 +141,28 @@ Item::Type Item_subselect::type() const return SUBSELECT_ITEM; } + void Item_subselect::fix_length_and_dec() { engine->fix_length_and_dec(0); } + inline table_map Item_subselect::used_tables() const { return (table_map) (engine->dependent() ? 1L : (engine->uncacheable() ? RAND_TABLE_BIT : 0L)); } + +void Item_subselect::print(String *str) +{ + str->append('('); + engine->print(str); + str->append(')'); +} + + Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) :Item_subselect(), value(0) { @@ -164,17 +175,24 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) } Item_maxmin_subselect::Item_maxmin_subselect(st_select_lex *select_lex, - bool max) + bool max_arg) :Item_singlerow_subselect() { DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect"); - init(select_lex, new select_max_min_finder_subselect(this, max)); + max= max_arg; + init(select_lex, new select_max_min_finder_subselect(this, max_arg)); max_columns= 1; maybe_null= 1; max_columns= 1; DBUG_VOID_RETURN; } +void Item_maxmin_subselect::print(String *str) +{ + str->append(max?"<max>":"<min>"); + Item_singlerow_subselect::print(str); +} + void Item_singlerow_subselect::reset() { null_value= 1; @@ -217,7 +235,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) */ substitution->walk(&Item::remove_dependence_processor, (byte *) select_lex->outer_select()); - if (select_lex->where || select_lex->having) + if (join->conds || join->having) { Item *cond; if (!join->having) @@ -337,6 +355,7 @@ String *Item_singlerow_subselect::val_str (String *str) } } + Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): Item_subselect() { @@ -351,6 +370,14 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): DBUG_VOID_RETURN; } + +void Item_exists_subselect::print(String *str) +{ + str->append("exists"); + Item_subselect::print(str); +} + + bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) { if (unit->fake_select_lex && @@ -368,7 +395,7 @@ bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) Item_in_subselect::Item_in_subselect(Item * left_exp, st_select_lex *select_lex): - Item_exists_subselect(), upper_not(0) + Item_exists_subselect(), transformed(0), upper_not(0) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; @@ -384,8 +411,9 @@ Item_in_subselect::Item_in_subselect(Item * left_exp, Item_allany_subselect::Item_allany_subselect(Item * left_exp, compare_func_creator fn, - st_select_lex *select_lex) - :Item_in_subselect() + st_select_lex *select_lex, + bool all_arg) + :Item_in_subselect(), all(all_arg) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; @@ -758,6 +786,7 @@ Item_in_subselect::row_value_transformer(JOIN *join, Item_subselect::trans_res Item_in_subselect::select_transformer(JOIN *join) { + transformed= 1; if (left_expr->cols() == 1) return single_value_transformer(join, left_expr, &Item_bool_func2::eq_creator); @@ -765,12 +794,82 @@ Item_in_subselect::select_transformer(JOIN *join) } +void Item_in_subselect::print(String *str) +{ + if (transformed) + str->append("<exists>"); + else + { + left_expr->print(str); + str->append(" in "); + } + Item_subselect::print(str); +} + + Item_subselect::trans_res Item_allany_subselect::select_transformer(JOIN *join) { + transformed= 1; + if (upper_not) + upper_not->show= 1; return single_value_transformer(join, left_expr, func); } + +void Item_allany_subselect::print(String *str) +{ + if (transformed) + str->append("<exists>"); + else + { + left_expr->print(str); + str->append(' '); + if (all) + { + if (func == &Item_bool_func2::lt_creator) + str->append(">="); + else if (func == &Item_bool_func2::gt_creator) + str->append("<="); + else if (func == &Item_bool_func2::le_creator) + str->append('>'); + else if (func == &Item_bool_func2::ge_creator) + str->append('<'); + else if (func == &Item_bool_func2::eq_creator) + str->append("<>"); + else if (func == &Item_bool_func2::ne_creator) + str->append('='); + else + { + DBUG_ASSERT(0); // Impossible + } + str->append(" all "); + } + else + { + if (func == &Item_bool_func2::lt_creator) + str->append('<'); + else if (func == &Item_bool_func2::gt_creator) + str->append('>'); + else if (func == &Item_bool_func2::le_creator) + str->append("<="); + else if (func == &Item_bool_func2::ge_creator) + str->append(">="); + else if (func == &Item_bool_func2::eq_creator) + str->append('='); + else if (func == &Item_bool_func2::ne_creator) + str->append("<>"); + else + { + DBUG_ASSERT(0); // Impossible + } + str->append(" any "); + } + } + Item_subselect::print(str); +} + + subselect_single_select_engine:: subselect_single_select_engine(st_select_lex *select, select_subselect *result, @@ -1098,11 +1197,13 @@ uint subselect_single_select_engine::cols() return select_lex->item_list.elements; } + uint subselect_union_engine::cols() { return unit->first_select()->item_list.elements; } + bool subselect_single_select_engine::dependent() { return select_lex->dependent; @@ -1113,16 +1214,19 @@ bool subselect_union_engine::dependent() return unit->dependent; } + bool subselect_single_select_engine::uncacheable() { return select_lex->uncacheable; } + bool subselect_union_engine::uncacheable() { return unit->uncacheable; } + void subselect_single_select_engine::exclude() { select_lex->master_unit()->exclude_level(); @@ -1133,8 +1237,53 @@ void subselect_union_engine::exclude() unit->exclude_level(); } + void subselect_uniquesubquery_engine::exclude() { //this never should be called DBUG_ASSERT(0); } + + +void subselect_single_select_engine::print(String *str) +{ + select_lex->print(thd, str); +} + + +void subselect_union_engine::print(String *str) +{ + unit->print(str); +} + + +void subselect_uniquesubquery_engine::print(String *str) +{ + str->append("<primary_index_lookup>("); + tab->ref.items[0]->print(str); + str->append(" in "); + str->append(tab->table->real_name); + if (cond) + { + str->append(" where "); + cond->print(str); + } + str->append(')'); +} + + +void subselect_indexsubquery_engine::print(String *str) +{ + str->append("<index_lookup>("); + tab->ref.items[0]->print(str); + str->append(" in "); + str->append(tab->table->real_name); + if (check_null) + str->append(" chicking NULL"); + if (cond) + { + str->append(" where "); + cond->print(str); + } + str->append(')'); +} diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 312b453a5a2..fd4bca33c62 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -85,13 +85,7 @@ public: bool exec(); virtual void fix_length_and_dec(); table_map used_tables() const; - void print(String *str) - { - if (name) - str->append(name); - else - str->append("-subselect-"); - } + void print(String *str); bool change_engine(subselect_engine *eng) { engine= eng; @@ -138,8 +132,10 @@ public: /* used in static ALL/ANY optimisation */ class Item_maxmin_subselect: public Item_singlerow_subselect { + bool max; public: Item_maxmin_subselect(st_select_lex *select_lex, bool max); + void print(String *str); }; /* exists subselect */ @@ -164,6 +160,7 @@ public: double val(); String *val_str(String*); void fix_length_and_dec(); + void print(String *str); friend class select_exists_subselect; friend class subselect_uniquesubquery_engine; @@ -184,12 +181,15 @@ protected: Item_in_optimizer *optimizer; bool was_null; bool abort_on_null; + bool transformed; public: Item_func_not_all *upper_not; // point on NOT before ALL subquery Item_in_subselect(Item * left_expr, st_select_lex *select_lex); Item_in_subselect() - :Item_exists_subselect(), abort_on_null(0), upper_not(0) {} + :Item_exists_subselect(), abort_on_null(0), transformed(0), upper_not(0) + + {} subs_type substype() { return IN_SUBS; } void reset() @@ -209,6 +209,7 @@ public: String *val_str(String*); void top_level_item() { abort_on_null=1; } bool test_limit(st_select_lex_unit *unit); + void print(String *str); friend class Item_ref_null_helper; friend class Item_is_not_null_test; @@ -223,12 +224,15 @@ protected: compare_func_creator func; public: + bool all; + Item_allany_subselect(Item * left_expr, compare_func_creator f, - st_select_lex *select_lex); + st_select_lex *select_lex, bool all); // only ALL subquery has upper not subs_type substype() { return upper_not?ALL_SUBS:ANY_SUBS; } trans_res select_transformer(JOIN *join); + void print(String *str); }; @@ -264,6 +268,7 @@ public: enum Item_result type() { return res_type; } virtual void exclude()= 0; bool may_be_null() { return maybe_null; }; + virtual void print(String *str)= 0; }; @@ -285,6 +290,7 @@ public: bool dependent(); bool uncacheable(); void exclude(); + void print (String *str); }; @@ -302,6 +308,7 @@ public: bool dependent(); bool uncacheable(); void exclude(); + void print (String *str); }; @@ -328,6 +335,7 @@ public: bool dependent() { return 1; } bool uncacheable() { return 1; } void exclude(); + void print (String *str); }; @@ -344,4 +352,5 @@ public: check_null(chk_null) {} int exec(); + void print (String *str); }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index afbda2b4ad1..6ee6b8c5cb7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -186,6 +186,9 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_QUOTE_SHOW_CREATE OPTION_QUICK*2 #define OPTION_INTERNAL_SUBTRANSACTIONS OPTION_QUOTE_SHOW_CREATE*2 +/* options for UNION set by the yacc parser (stored in unit->union_option) */ +#define UNION_ALL 1 + /* Set if we are updating a non-transaction safe table */ #define OPTION_STATUS_NO_TRANS_UPDATE OPTION_INTERNAL_SUBTRANSACTIONS*2 diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 13d3cc27376..aac2e17086b 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -222,10 +222,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, else unit->exclude_level(); org_table_list->db= (char *)""; -#ifndef DBUG_OFF - /* Try to catch errors if this is accessed */ - org_table_list->derived=(SELECT_LEX_UNIT *) 1; -#endif // Force read of table stats in the optimizer table->file->info(HA_STATUS_VARIABLE); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 80d698dfc26..024d35150d8 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1421,7 +1421,73 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) order_group_num)* 5)) == 0; } +void st_select_lex_unit::print(String *str) +{ + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl != first_select()) + { + str->append(" union "); + if (union_option & UNION_ALL) + str->append("all "); + } + if (sl->braces) + str->append('('); + sl->print(thd, str); + if (sl->braces) + str->append(')'); + } + if (fake_select_lex == global_parameters) + { + if (fake_select_lex->order_list.elements) + { + str->append(" order by "); + fake_select_lex->print_order(str, + (ORDER *) fake_select_lex-> + order_list.first); + } + fake_select_lex->print_limit(thd, str); + } +} + + +void st_select_lex::print_order(String *str, ORDER *order) +{ + for (; order; order= order->next) + { + (*order->item)->print(str); + if (!order->asc) + str->append(" desc"); + if (order->next) + str->append(','); + } +} + +void st_select_lex::print_limit(THD *thd, String *str) +{ + if (!thd) + thd= current_thd; + + if (select_limit != thd->variables.select_limit || + select_limit != HA_POS_ERROR || + offset_limit != 0L) + { + str->append(" limit "); + char buff[21]; + snprintf(buff, 21, "%ld", select_limit); + str->append(buff); + if (offset_limit) + { + str->append(','); + snprintf(buff, 21, "%ld", offset_limit); + str->append(buff); + } + } +} + /* There are st_select_lex::add_table_to_list & st_select_lex::set_lock_for_tables in sql_parse.cc + + st_select_lex::print is in sql_select.h */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 8ce028020c2..2e62d65fd20 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -79,6 +79,10 @@ enum enum_sql_command { SQLCOM_END }; +// describe/explain types +#define DESCRIBE_NORMAL 1 +#define DESCRIBE_EXTENDED 2 + typedef List<Item> List_item; typedef struct st_lex_master_info @@ -321,7 +325,9 @@ public: int prepare(THD *thd, select_result *result, bool tables_and_fields_initied); int exec(); int cleanup(); - + + void print(String *str); + friend void mysql_init_query(THD *thd); friend int subselect_union_engine::exec(); private: @@ -462,6 +468,9 @@ public: init_select(); } bool setup_ref_array(THD *thd, uint order_group_num); + void print(THD *thd, String *str); + static void print_order(String *str, ORDER *order); + void print_limit(THD *thd, String *str); }; typedef class st_select_lex SELECT_LEX; @@ -535,9 +544,10 @@ typedef struct st_lex uint fk_delete_opt, fk_update_opt, fk_match_option; uint param_count; uint slave_thd_opt; + uint8 describe; bool drop_primary, drop_if_exists, drop_temporary, local_file; bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog; - bool derived_tables, describe; + bool derived_tables; bool safe_to_cache_query; st_lex() {} inline void uncacheable() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e30fd0acfae..fbd74c68ffb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1781,6 +1781,16 @@ mysql_execute_command(THD *thd) res= mysql_explain_union(thd, &thd->lex.unit, result); MYSQL_LOCK *save_lock= thd->lock; thd->lock= (MYSQL_LOCK *)0; + if (lex->describe & DESCRIBE_EXTENDED) + { + char buff[1024]; + String str(buff,(uint32) sizeof(buff), system_charset_info); + str.length(0); + thd->lex.unit.print(&str); + str.append('\0'); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_YES, str.ptr()); + } result->send_eof(); thd->lock= save_lock; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4bab97d4a46..f86435e1bb0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -328,6 +328,20 @@ JOIN::prepare(Item ***rref_pointer_array, having->split_sum_func(ref_pointer_array, all_fields); } +#ifndef DEBUG_OFF + { + char buff[256]; + String str(buff,(uint32) sizeof(buff), system_charset_info); + str.length(0); + if (select_lex->master_unit()->item) + select_lex->master_unit()->item->print(&str); + else + unit->print(&str); + str.append('\0'); + DBUG_PRINT("info", ("(SUB)SELECT: %s", str.ptr())); + } +#endif + // Is it subselect { Item_subselect *subselect; @@ -880,12 +894,12 @@ JOIN::optimize() need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + tmp_having= having; if (select_options & SELECT_DESCRIBE) { error= 0; DBUG_RETURN(0); } - tmp_having= having; having= 0; /* Perform FULLTEXT search before all regular searches */ @@ -1547,11 +1561,23 @@ mysql_select(THD *thd, Item ***rref_pointer_array, goto err; // 1 } + if (thd->lex.describe & DESCRIBE_EXTENDED) + { + join->conds_history= join->conds; + join->having_history= (join->having?join->having:join->tmp_having); + } + if (thd->net.report_error) goto err; join->exec(); + if (thd->lex.describe & DESCRIBE_EXTENDED) + { + select_lex->where= join->conds_history; + select_lex->having= join->having_history; + } + err: if (free_join) { @@ -8909,3 +8935,159 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, result, unit, select_lex, 0); DBUG_RETURN(res); } + + +void st_select_lex::print(THD *thd, String *str) +{ + if (!thd) + thd= current_thd; + + str->append("select "); + + //options + if (options & SELECT_STRAIGHT_JOIN) + str->append("straight_join "); + if ((thd->lex.lock_option & TL_READ_HIGH_PRIORITY) && + (this == &thd->lex.select_lex)) + str->append("high_priority "); + if (options & SELECT_DISTINCT) + str->append("distinct "); + if (options & SELECT_SMALL_RESULT) + str->append("small_result "); + if (options & SELECT_BIG_RESULT) + str->append("big_result "); + if (options & OPTION_BUFFER_RESULT) + str->append("buffer_result "); + if (options & OPTION_FOUND_ROWS) + str->append("calc_found_rows "); + if (!thd->lex.safe_to_cache_query) + str->append("no_cache "); + if (options & OPTION_TO_QUERY_CACHE) + str->append("cache "); + + //Item List + bool first= 1; + List_iterator_fast<Item> it(item_list); + Item *item; + while ((item= it++)) + { + if (first) + first= 0; + else + str->append(','); + item->print_item_w_name(str); + } + + /* + from clause + TODO: support USING/FORCE/IGNORE index + */ + if (table_list.elements) + { + str->append(" from "); + Item *next_on= 0; + for (TABLE_LIST *table= (TABLE_LIST *) table_list.first; + table; + table= table->next) + { + if (table->derived) + { + str->append('('); + table->derived->print(str); + str->append(") "); + str->append(table->alias); + } + else + { + str->append(table->db); + str->append('.'); + str->append(table->real_name); + if (strcmp(table->real_name, table->alias)) + { + str->append(' '); + str->append(table->alias); + } + } + + if (table->on_expr && ((table->outer_join & JOIN_TYPE_LEFT) || + !(table->outer_join & JOIN_TYPE_RIGHT))) + next_on= table->on_expr; + + if (next_on) + { + str->append(" on("); + next_on->print(str); + str->append(')'); + next_on= 0; + } + + TABLE_LIST *next; + if ((next= table->next)) + { + if (table->outer_join & JOIN_TYPE_RIGHT) + { + str->append(" right join "); + if (!(table->outer_join & JOIN_TYPE_LEFT) && + table->on_expr) + next_on= table->on_expr; + } + else if (next->straight) + str->append(" straight_join "); + else if (next->outer_join & JOIN_TYPE_LEFT) + str->append(" left join "); + else + str->append(" join "); + } + } + } + + //where + Item *where= this->where; + if (join) + where= join->conds; + if (where) + { + str->append(" where "); + where->print(str); + } + + //group by & olap + if (group_list.elements) + { + str->append(" group by "); + print_order(str, (ORDER *) group_list.first); + switch (olap) + { + case CUBE_TYPE: + str->append(" with cube"); + break; + case ROLLUP_TYPE: + str->append(" with rollup"); + break; + default: + ; //satisfy compiler + } + } + + //having + Item *having= this->having; + if (join) + having= join->having; + + if (having) + { + str->append(" having "); + having->print(str); + } + + if (order_list.elements) + { + str->append(" order by "); + print_order(str, (ORDER *) order_list.first); + } + + // limit + print_limit(thd, str); + + // PROCEDURE unsupported here +} diff --git a/sql/sql_select.h b/sql/sql_select.h index 6c17a646ee6..6c1410102fd 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -151,7 +151,8 @@ class JOIN :public Sql_alloc Item_sum **sum_funcs2, ***sum_funcs_end2; Procedure *procedure; Item *having; - Item *tmp_having; // To store Having when processed temporary table + Item *tmp_having; // To store having when processed temporary table + Item *having_history; // Store having for explain uint select_options; select_result *result; TMP_TABLE_PARAM tmp_table_param; @@ -181,6 +182,7 @@ class JOIN :public Sql_alloc ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select COND *conds; // ---"--- + Item *conds_history; // store WHERE for explain TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec SQL_SELECT *select; //created in optimisation phase Item **ref_pointer_array; //used pointer reference for this select @@ -217,8 +219,7 @@ class JOIN :public Sql_alloc thd= thd_arg; sum_funcs= sum_funcs2= 0; procedure= 0; - having= 0; - tmp_having= 0; + having= tmp_having= having_history= 0; select_options= select_options_arg; result= result_arg; lock= thd_arg->lock; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ebe05ec565f..38d251c3aef 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -704,6 +704,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); union_clause union_list union_option precision subselect_start opt_and charset subselect_end select_var_list select_var_list_init help opt_len + opt_extended_describe END_OF_INPUT %type <NONE> @@ -2263,7 +2264,7 @@ expr_expr: | expr comp_op all_or_any in_subselect %prec EQ { Item_allany_subselect *it= - new Item_allany_subselect($1, (*$2)($3), $4); + new Item_allany_subselect($1, (*$2)($3), $4, $3); if ($3) $$ = it->upper_not= new Item_func_not_all(it); /* ALL */ else @@ -2309,7 +2310,7 @@ no_in_expr: | no_in_expr comp_op all_or_any in_subselect %prec EQ { Item_allany_subselect *it= - new Item_allany_subselect($1, (*$2)($3), $4); + new Item_allany_subselect($1, (*$2)($3), $4, $3); if ($3) $$ = it->upper_not= new Item_func_not_all(it); /* ALL */ else @@ -2364,7 +2365,7 @@ no_and_expr: | no_and_expr comp_op all_or_any in_subselect %prec EQ { Item_allany_subselect *it= - new Item_allany_subselect($1, (*$2)($3), $4); + new Item_allany_subselect($1, (*$2)($3), $4, $3); if ($3) $$ = it->upper_not= new Item_func_not_all(it); /* ALL */ else @@ -4025,7 +4026,9 @@ describe: YYABORT; } opt_describe_column {} - | describe_command { Lex->describe=1; } select + | describe_command opt_extended_describe + { Lex->describe|= DESCRIBE_NORMAL; } + select { LEX *lex=Lex; lex->select_lex.options|= SELECT_DESCRIBE; @@ -4036,6 +4039,11 @@ describe_command: DESC | DESCRIBE; +opt_extended_describe: + /* empty */ {} + | EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } + ; + opt_describe_column: /* empty */ {} | text_string { Lex->wild= $1; } @@ -4291,11 +4299,9 @@ literal: { Item *tmp= new Item_varbinary($2.str,$2.length); String *str= tmp ? tmp->val_str((String*) 0) : (String*) 0; - Item_string *item = new Item_string(str ? str->ptr() : "", - str ? str->length() : - 0, Lex->charset); - item->set_varbin_name(tmp->name); - $$= item; + $$= new Item_string(str ? str->ptr() : "", + str ? str->length() : 0, + Lex->charset); } | DATE_SYM text_literal { $$ = $2; } | TIME_SYM text_literal { $$ = $2; } @@ -5349,7 +5355,7 @@ order_or_limit: union_option: /* empty */ {} - | ALL {Select->master_unit()->union_option= 1;}; + | ALL {Select->master_unit()->union_option|= UNION_ALL;}; singlerow_subselect: subselect_start singlerow_subselect_init |