diff options
author | bell@sanja.is.com.ua <> | 2003-10-31 22:14:49 +0200 |
---|---|---|
committer | bell@sanja.is.com.ua <> | 2003-10-31 22:14:49 +0200 |
commit | 0747324edef93a955b9f337a188a6d7e377c4fe0 (patch) | |
tree | 2c6fd809f0c5f377f0c9be63a16c38f0853a56cf /sql | |
parent | d1bfa5c598ee3af9288ca496c90ca01c15ebfe24 (diff) | |
parent | 101a9f0180b39f27fb76b59a162f8dec09917cc5 (diff) | |
download | mariadb-git-0747324edef93a955b9f337a188a6d7e377c4fe0.tar.gz |
merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 141 | ||||
-rw-r--r-- | sql/item.h | 36 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 64 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 18 | ||||
-rw-r--r-- | sql/item_create.cc | 2 | ||||
-rw-r--r-- | sql/item_func.cc | 84 | ||||
-rw-r--r-- | sql/item_func.h | 13 | ||||
-rw-r--r-- | sql/item_geofunc.h | 3 | ||||
-rw-r--r-- | sql/item_row.cc | 12 | ||||
-rw-r--r-- | sql/item_row.h | 1 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 54 | ||||
-rw-r--r-- | sql/item_strfunc.h | 20 | ||||
-rw-r--r-- | sql/item_subselect.cc | 170 | ||||
-rw-r--r-- | sql/item_subselect.h | 27 | ||||
-rw-r--r-- | sql/item_sum.cc | 34 | ||||
-rw-r--r-- | sql/item_sum.h | 2 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 85 | ||||
-rw-r--r-- | sql/item_timefunc.h | 26 | ||||
-rw-r--r-- | sql/item_uniq.h | 2 | ||||
-rw-r--r-- | sql/key.cc | 4 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_derived.cc | 4 | ||||
-rw-r--r-- | sql/sql_lex.cc | 68 | ||||
-rw-r--r-- | sql/sql_lex.h | 14 | ||||
-rw-r--r-- | sql/sql_parse.cc | 12 | ||||
-rw-r--r-- | sql/sql_repl.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 184 | ||||
-rw-r--r-- | sql/sql_select.h | 7 | ||||
-rw-r--r-- | sql/sql_show.cc | 14 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 41 |
30 files changed, 1016 insertions, 131 deletions
diff --git a/sql/item.cc b/sql/item.cc index 7c7cad7c290..0fbf3ae587b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -87,6 +87,19 @@ Item::Item(THD *c_thd, Item &item): thd->free_list= this; } + +void Item::print_item_w_name(String *str) +{ + print(str); + if (name) + { + str->append(" AS `", 5); + 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), @@ -422,6 +435,7 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const db_name)))))); } + table_map Item_field::used_tables() const { if (field->table->const_table) @@ -429,6 +443,7 @@ table_map Item_field::used_tables() const return (depended_from ? OUTER_REF_TABLE_BIT : field->table->map); } + Item *Item_field::get_tmp_table_item(THD *thd) { Item_field *new_item= new Item_field(thd, *this); @@ -437,6 +452,7 @@ Item *Item_field::get_tmp_table_item(THD *thd) return new_item; } + String *Item_int::val_str(String *str) { str->set(value, default_charset()); @@ -445,28 +461,24 @@ 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); + // latin1 is good enough for numbers + str_value.set(value, &my_charset_latin1); + str->append(str_value); } + String *Item_uint::val_str(String *str) { str->set((ulonglong) value, default_charset()); return str; } + void Item_uint::print(String *str) { - if (!name) - { - str_value.set((ulonglong) value, default_charset()); - name=str_value.c_ptr(); - } - str->append(name); + // latin1 is good enough for numbers + str_value.set((ulonglong) value, default_charset()); + str->append(str_value); } @@ -476,10 +488,46 @@ String *Item_real::val_str(String *str) return str; } + void Item_string::print(String *str) { + str->append('_'); + str->append(collation.collation->csname); str->append('\''); - str->append(full_name()); + char *st= (char*)str_value.ptr(), *end= st+str_value.length(); + for(; st < end; st++) + { + uchar c= *st; + switch (c) + { + case '\\': + str->append("\\\\", 2); + break; + case '\0': + str->append("\\0", 2); + break; + case '\'': + str->append("\\'", 2); + break; + case '\n': + str->append("\\n", 2); + break; + case '\r': + str->append("\\r", 2); + break; + case '\t': + str->append("\\t", 2); + break; + case '\b': + str->append("\\b", 2); + break; + case 26: //Ctrl-Z + str->append("\\z", 2); + break; + default: + str->append(c); + } + } str->append('\''); } @@ -700,7 +748,7 @@ String *Item_param::query_val_str(String* str) make_datetime(str, <ime, is_time_only, 0, tmp_format->format, tmp_format->format_length, 0); } - str->append("'"); + str->append('\''); } return str; } @@ -777,7 +825,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), @@ -1533,6 +1581,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>(", 18); + if (ref && *ref) + (*ref)->print(str); + else + str->append('?'); + str->append(')'); +} + + +void Item_null_helper::print(String *str) +{ + str->append("<null_helper>(", 14); + store->print(str); + str->append(')'); +} + + bool Item_default_value::eq(const Item *item, bool binary_cmp) const { return item->type() == DEFAULT_VALUE_ITEM && @@ -1574,10 +1650,10 @@ void Item_default_value::print(String *str) { if (!arg) { - str->append("DEFAULT"); + str->append("default", 7); return; } - str->append("DEFAULT("); + str->append("default(", 8); arg->print(str); str->append(')'); } @@ -1630,7 +1706,7 @@ bool Item_insert_value::fix_fields(THD *thd, struct st_table_list *table_list, I void Item_insert_value::print(String *str) { - str->append("VALUE("); + str->append("values(", 7); arg->print(str); str->append(')'); } @@ -1754,6 +1830,34 @@ Item_cache* Item_cache::get_cache(Item_result type) } } + +void Item_cache::print(String *str) +{ + str->append("<cache>(", 8); + 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); @@ -1804,6 +1908,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 8bb28068618..dcefde05605 100644 --- a/sql/item.h +++ b/sql/item.h @@ -182,6 +182,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); @@ -318,6 +319,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", 4); } }; class Item_param :public Item @@ -368,6 +370,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 @@ -640,6 +643,7 @@ public: (*ref)->save_in_field(result_field, no_conversions); } Item *real_item() { return *ref; } + void print(String *str); }; class Item_in_subselect; @@ -655,15 +659,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 @@ -675,6 +671,7 @@ public: :Item_ref_null_helper(master, &store, table_name_par, field_name_par), store(item) {} + void print(String *str); }; /* @@ -856,14 +853,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) { @@ -873,6 +872,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 @@ -881,12 +881,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; } @@ -899,12 +894,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 d6c05f47964..3897022e8ce 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -113,6 +113,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 @@ -707,6 +715,18 @@ longlong Item_func_between::val_int() return 0; } + +void Item_func_between::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(" between ", 9); + args[1]->print(str); + str->append(" and ", 5); + args[2]->print(str); + str->append(')'); +} + void Item_func_ifnull::fix_length_and_dec() { @@ -863,7 +883,7 @@ Item_func_nullif::fix_length_and_dec() } /* - nullif () returns NULL if arguments are different, else it returns the + nullif () returns NULL if arguments are equal, else it returns the first argument. Note that we have to evaluate the first argument twice as the compare may have been done with a different type than return value @@ -1100,7 +1120,27 @@ void Item_func_case::fix_length_and_dec() void Item_func_case::print(String *str) { - str->append("case "); // Not yet complete + str->append("(case ", 6); + if (first_expr_num != -1) + { + args[first_expr_num]->print(str); + str->append(' '); + } + for (uint i=0 ; i < ncases ; i+=2) + { + str->append("when ", 5); + args[i]->print(str); + str->append(" then ", 6); + args[i+1]->print(str); + str->append(' '); + } + if (else_expr_num != -1) + { + str->append("else ", 5); + args[else_expr_num]->print(str); + str->append(' '); + } + str->append("end)", 4); } /* @@ -1507,8 +1547,15 @@ void Item_func_in::fix_length_and_dec() void Item_func_in::print(String *str) { str->append('('); - Item_func::print(str); - str->append(')'); + args[0]->print(str); + str->append(" in (", 5); + for (uint i=1 ; i < arg_count ; i++) + { + if (i > 1) + str->append(','); + args[i]->print(str); + } + str->append("))", 2); } @@ -1882,12 +1929,21 @@ void Item_is_not_null_test::update_used_tables() } } + longlong Item_func_isnotnull::val_int() { return args[0]->is_null() ? 0 : 1; } +void Item_func_isnotnull::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(" is not null)", 13); +} + + longlong Item_func_like::val_int() { String* res = args[0]->val_str(&tmp_value1); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 9a1b087a63c..3f73c7736da 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -105,7 +105,7 @@ public: Item_in_optimizer return NULL, else it evaluate Item_in_subselect. */ longlong val_int(); - const char *func_name() const { return "IN_OPTIMIZER"; } + const char *func_name() const { return "<in_optimizer>"; } Item_cache **get_cache() { return &cache; } }; @@ -162,12 +162,15 @@ 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(); enum Functype functype() const { return NOT_ALL_FUNC; } - const char *func_name() const { return "not_all"; } + const char *func_name() const { return "<not>"; } + void print(String *str); }; class Item_func_eq :public Item_bool_rowready_func2 @@ -272,6 +275,7 @@ public: enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } void fix_length_and_dec(); + void print(String *str); }; @@ -354,6 +358,7 @@ public: enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "nullif"; } + void print(String *str) { Item_func::print(str); } table_map not_null_tables() const { return 0; } }; @@ -714,7 +719,7 @@ public: {} enum Functype functype() const { return ISNOTNULLTEST_FUNC; } longlong val_int(); - const char *func_name() const { return "is_not_null_test"; } + const char *func_name() const { return "<is_not_null_test>"; } void update_used_tables(); }; @@ -733,6 +738,7 @@ public: optimize_type select_optimize() const { return OPTIMIZE_NULL; } table_map not_null_tables() const { return 0; } Item *neg_transformer(); + void print(String *str); }; @@ -785,7 +791,8 @@ public: ~Item_func_regex(); longlong val_int(); bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); - const char *func_name() const { return "regex"; } + const char *func_name() const { return "regexp"; } + void print(String *str) { print_op(str); } }; #else @@ -796,6 +803,7 @@ public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b) {} longlong val_int() { return 0;} const char *func_name() const { return "regex"; } + void print(String *str) { print_op(str); } }; #endif /* USE_REGEX */ diff --git a/sql/item_create.cc b/sql/item_create.cc index fce59d68c1f..a25ccfe984b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -292,7 +292,7 @@ Item *create_func_period_diff(Item* a, Item *b) Item *create_func_pi(void) { - return new Item_real(NullS,M_PI,6,8); + return new Item_real("pi()",M_PI,6,8); } Item *create_func_pow(Item* a, Item *b) diff --git a/sql/item_func.cc b/sql/item_func.cc index b47c833d404..7717eaee425 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -287,13 +287,19 @@ void Item_func::print(String *str) { str->append(func_name()); str->append('('); + print_args(str); + str->append(')'); +} + + +void Item_func::print_args(String *str) +{ for (uint i=0 ; i < arg_count ; i++) { if (i) str->append(','); args[i]->print(str); } - str->append(')'); } @@ -462,6 +468,24 @@ String *Item_num_op::val_str(String *str) } +void Item_func_signed::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as signed)", 11); + +} + + +void Item_func_unsigned::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as unsigned)", 13); + +} + + double Item_func_plus::val() { double value=args[0]->val()+args[1]->val(); @@ -1184,6 +1208,21 @@ longlong Item_func_locate::val_int() } +void Item_func_locate::print(String *str) +{ + str->append("locate(", 7); + args[1]->print(str); + str->append(','); + args[0]->print(str); + if (arg_count == 3) + { + str->append(','); + args[2]->print(str); + } + str->append(')'); +} + + longlong Item_func_field::val_int() { if (cmp_type == STRING_RESULT) @@ -1764,7 +1803,7 @@ void item_user_lock_release(ULL *ull) String tmp(buf,sizeof(buf), system_charset_info); tmp.copy(command, strlen(command), tmp.charset()); tmp.append(ull->key,ull->key_length); - tmp.append("\")"); + tmp.append("\")", 2); Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1); qev.error_code=0; // this query is always safe to run on slave mysql_bin_log.write(&qev); @@ -2049,6 +2088,19 @@ longlong Item_func_benchmark::val_int() } +void Item_func_benchmark::print(String *str) +{ + str->append("benchmark(", 10); + char buffer[20]; + // latin1 is good enough for numbers + String st(buffer, sizeof(buffer), &my_charset_latin1); + st.set((ulonglong)loop_count, &my_charset_latin1); + str->append(st); + str->append(','); + args[0]->print(str); + str->append(')'); +} + #define extra_size sizeof(double) static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, @@ -2387,9 +2439,9 @@ String *Item_func_set_user_var::val_str(String *str) void Item_func_set_user_var::print(String *str) { - str->append("(@@",3); - str->append(name.str,name.length); - str->append(":=",2); + str->append("(@", 2); + str->append(name.str, name.length); + str->append(":=", 2); args[0]->print(str); str->append(')'); } @@ -2535,7 +2587,7 @@ enum Item_result Item_func_get_user_var::result_type() const void Item_func_get_user_var::print(String *str) { - str->append('@'); + str->append("(@", 2); str->append(name.str,name.length); str->append(')'); } @@ -2815,6 +2867,26 @@ double Item_func_match::val() table->record[0], 0)); } +void Item_func_match::print(String *str) +{ + str->append("(match ", 7); + List_iterator_fast<Item> li(fields); + Item *item; + bool first= 1; + while ((item= li++)) + { + if (first) + first= 0; + else + str->append(','); + item->print(str); + } + str->append(" against (", 10); + args[0]->print(str); + if (mode == FT_BOOL) + str->append(" in boolean mode", 16); + str->append("))", 2); +} longlong Item_func_bit_xor::val_int() { diff --git a/sql/item_func.h b/sql/item_func.h index 29e40f603b4..cee1d73847a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -125,6 +125,7 @@ public: virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields); void print(String *str); void print_op(String *str); + void print_args(String *str); void fix_num_length_and_dec(); inline bool get_arg0_date(TIME *ltime,bool fuzzy_date) { @@ -215,6 +216,7 @@ public: longlong val_int() { return args[0]->val_int(); } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=0; } + void print(String *str); }; @@ -226,6 +228,7 @@ public: longlong val_int() { return args[0]->val_int(); } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=1; } + void print(String *str); }; @@ -607,6 +610,7 @@ public: const char *func_name() const { return "locate"; } longlong val_int(); void fix_length_and_dec(); + void print(String *str); }; @@ -663,6 +667,7 @@ public: longlong val_int(); const char *func_name() const { return "|"; } void fix_length_and_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_bit_and :public Item_int_func @@ -672,6 +677,7 @@ public: longlong val_int(); const char *func_name() const { return "&"; } void fix_length_and_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_bit_count :public Item_int_func @@ -690,6 +696,7 @@ public: longlong val_int(); const char *func_name() const { return "<<"; } void fix_length_and_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_shift_right :public Item_int_func @@ -698,6 +705,7 @@ public: Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {} longlong val_int(); const char *func_name() const { return ">>"; } + void print(String *str) { print_op(str); } }; class Item_func_bit_neg :public Item_int_func @@ -728,6 +736,7 @@ class Item_func_benchmark :public Item_int_func longlong val_int(); const char *func_name() const { return "benchmark"; } void fix_length_and_dec() { max_length=1; maybe_null=0; } + void print(String *str); }; @@ -1005,6 +1014,7 @@ public: bool eq(const Item *, bool binary_cmp) const; longlong val_int() { return val()!=0.0; } double val(); + void print(String *str); bool fix_index(); void init_search(bool no_order); @@ -1018,6 +1028,7 @@ public: longlong val_int(); const char *func_name() const { return "^"; } void fix_length_xor_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_is_free_lock :public Item_int_func @@ -1026,7 +1037,7 @@ class Item_func_is_free_lock :public Item_int_func public: Item_func_is_free_lock(Item *a) :Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "check_lock"; } + const char *func_name() const { return "is_free_lock"; } void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} }; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 79e45cca26f..72dc6620f3b 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -118,6 +118,7 @@ public: case SP_EXTERIORRING: return "exteriorring"; default: + DBUG_ASSERT(0); // Should never happened return "spatial_decomp_unknown"; } } @@ -142,6 +143,7 @@ public: case SP_INTERIORRINGN: return "interiorringn"; default: + DBUG_ASSERT(0); // Should never happened return "spatial_decomp_n_unknown"; } } @@ -210,6 +212,7 @@ public: case SP_OVERLAPS_FUNC: return "overlaps"; default: + DBUG_ASSERT(0); // Should never happened return "sp_unknown"; } } diff --git a/sql/item_row.cc b/sql/item_row.cc index fcc6e5192ec..89b38c8a753 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -118,6 +118,18 @@ bool Item_row::check_cols(uint c) return 0; } +void Item_row::print(String *str) +{ + str->append('('); + for (uint i= 0; i < arg_count; i++) + { + if (i) + str->append(','); + items[i]->print(str); + } + str->append(')'); +} + bool Item_row::walk(Item_processor processor, byte *arg) { for (uint i= 0; i < arg_count; i++) diff --git a/sql/item_row.h b/sql/item_row.h index 6dd955ed426..a09bd1a2c31 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -68,6 +68,7 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } void update_used_tables(); + void print(String *str); bool walk(Item_processor processor, byte *arg); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 99dd06c566c..70f98783624 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -654,6 +654,17 @@ void Item_func_concat_ws::update_used_tables() const_item_cache&=separator->const_item(); } +void Item_func_concat_ws::print(String *str) +{ + str->append("concat_ws(", 10); + separator->print(str); + if (arg_count) + { + str->append(','); + print_args(str); + } + str->append(')'); +} String *Item_func_reverse::val_str(String *str) { @@ -1613,6 +1624,19 @@ String *Item_func_format::val_str(String *str) } +void Item_func_format::print(String *str) +{ + str->append("format(", 7); + args[0]->print(str); + str->append(','); + // latin1 is good enough for numbers + char buffer[20]; + String st(buffer, sizeof(buffer), &my_charset_latin1); + st.set((ulonglong)decimals, &my_charset_latin1); + str->append(st); + str->append(')'); +} + void Item_func_elt::fix_length_and_dec() { max_length=0; @@ -1764,6 +1788,19 @@ String *Item_func_make_set::val_str(String *str) } +void Item_func_make_set::print(String *str) +{ + str->append("make_set(", 9); + item->print(str); + if (arg_count) + { + str->append(','); + print_args(str); + } + str->append(')'); +} + + String *Item_func_char::val_str(String *str) { str->length(0); @@ -2077,7 +2114,14 @@ void Item_func_conv_charset::fix_length_and_dec() max_length = args[0]->max_length*conv_charset->mbmaxlen; } - +void Item_func_conv_charset::print(String *str) +{ + str->append("convert(", 8); + args[0]->print(str); + str->append(" using ", 7); + str->append(conv_charset->csname); + str->append(')'); +} String *Item_func_conv_charset3::val_str(String *str) { @@ -2271,6 +2315,14 @@ String *Item_func_hex::val_str(String *str) } +void Item_func_binary::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as binary)", 11); +} + + #include <my_dir.h> // For my_stat String *Item_load_file::val_str(String *str) diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index b82dacb4fe0..00b1ebb0732 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -112,6 +112,7 @@ public: return separator->walk(processor, arg) || Item_str_func::walk(processor, arg); } + void print(String *str); }; class Item_func_reverse :public Item_str_func @@ -120,6 +121,7 @@ public: Item_func_reverse(Item *a) :Item_str_func(a) {} String *val_str(String *); void fix_length_and_dec(); + const char *func_name() const { return "reverse"; } }; @@ -324,10 +326,12 @@ public: Item_func_encrypt(Item *a, Item *b): Item_str_func(a,b) {} String *val_str(String *); void fix_length_and_dec() { maybe_null=1; max_length = 13; } + const char *func_name() const { return "ecrypt"; } }; #include "sql_crypt.h" + class Item_func_encode :public Item_str_func { protected: @@ -337,13 +341,16 @@ public: Item_str_func(a),sql_crypt(seed) {} String *val_str(String *); void fix_length_and_dec(); + const char *func_name() const { return "encode"; } }; + class Item_func_decode :public Item_func_encode { public: Item_func_decode(Item *a, char *seed): Item_func_encode(a,seed) {} String *val_str(String *); + const char *func_name() const { return "decode"; } }; @@ -420,6 +427,7 @@ public: return item->walk(processor, arg) || Item_str_func::walk(processor, arg); } + void print(String *str); }; @@ -435,6 +443,7 @@ public: max_length=args[0]->max_length+(args[0]->max_length-args[0]->decimals)/3; } const char *func_name() const { return "format"; } + void print(String *); }; @@ -520,7 +529,6 @@ class Item_func_binary :public Item_str_func { public: Item_func_binary(Item *a) :Item_str_func(a) {} - const char *func_name() const { return "binary"; } String *val_str(String *a) { String *tmp=args[0]->val_str(a); @@ -534,7 +542,7 @@ public: collation.set(&my_charset_bin); max_length=args[0]->max_length; } - void print(String *str) { print_op(str); } + void print(String *str); }; @@ -597,7 +605,8 @@ public: { conv_charset=cs; } String *val_str(String *); void fix_length_and_dec(); - const char *func_name() const { return "conv_charset"; } + const char *func_name() const { return "convert"; } + void print(String *str); }; class Item_func_set_collation :public Item_str_func @@ -607,7 +616,8 @@ public: String *val_str(String *); void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; - const char *func_name() const { return "set_collation"; } + const char *func_name() const { return "collate"; } + void print(String *str) { print_op(str); } }; class Item_func_conv_charset3 :public Item_str_func @@ -617,7 +627,7 @@ public: :Item_str_func(arg1,arg2,arg3) {} String *val_str(String *); void fix_length_and_dec(); - const char *func_name() const { return "conv_charset3"; } + const char *func_name() const { return "convert"; } }; class Item_func_charset :public Item_str_func diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 589a41052c5..ae44647b11c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -146,21 +146,25 @@ Item::Type Item_subselect::type() const return SUBSELECT_ITEM; } + void Item_subselect::fix_length_and_dec() { engine->fix_length_and_dec(0); } + table_map Item_subselect::used_tables() const { return (table_map) (engine->dependent() ? used_tables_cache : 0L); } + bool Item_subselect::const_item() const { return const_item_cache; } + void Item_subselect::update_used_tables() { if (!engine->uncacheable()) @@ -171,6 +175,15 @@ void Item_subselect::update_used_tables() } } + +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) { @@ -184,11 +197,12 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent, 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; @@ -203,6 +217,12 @@ Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent, DBUG_VOID_RETURN; } +void Item_maxmin_subselect::print(String *str) +{ + str->append(max?"<max>":"<min>", 5); + Item_singlerow_subselect::print(str); +} + void Item_singlerow_subselect::reset() { null_value= 1; @@ -245,7 +265,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) @@ -365,6 +385,7 @@ String *Item_singlerow_subselect::val_str (String *str) } } + Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): Item_subselect() { @@ -379,6 +400,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", 6); + Item_subselect::print(str); +} + + bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) { if (unit->fake_select_lex && @@ -396,7 +425,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; @@ -412,8 +441,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; @@ -800,6 +830,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); @@ -807,12 +838,82 @@ Item_in_subselect::select_transformer(JOIN *join) } +void Item_in_subselect::print(String *str) +{ + if (transformed) + str->append("<exists>", 8); + else + { + left_expr->print(str); + str->append(" in ", 4); + } + 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>", 8); + else + { + left_expr->print(str); + str->append(' '); + if (all) + { + if (func == &Item_bool_func2::lt_creator) + str->append(">=", 2); + else if (func == &Item_bool_func2::gt_creator) + str->append("<=", 2); + 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("<>", 2); + else if (func == &Item_bool_func2::ne_creator) + str->append('='); + else + { + DBUG_ASSERT(0); // Impossible + } + str->append(" all ", 5); + } + 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("<=", 2); + else if (func == &Item_bool_func2::ge_creator) + str->append(">=", 2); + else if (func == &Item_bool_func2::eq_creator) + str->append('='); + else if (func == &Item_bool_func2::ne_creator) + str->append("<>", 2); + else + { + DBUG_ASSERT(0); // Impossible + } + str->append(" any ", 5); + } + } + Item_subselect::print(str); +} + + subselect_single_select_engine:: subselect_single_select_engine(st_select_lex *select, select_subselect *result, @@ -1140,11 +1241,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; @@ -1155,16 +1258,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(); @@ -1175,6 +1281,7 @@ void subselect_union_engine::exclude() unit->exclude_level(); } + void subselect_uniquesubquery_engine::exclude() { //this never should be called @@ -1201,8 +1308,59 @@ table_map subselect_single_select_engine::upper_select_const_tables() table_list.first); } + table_map subselect_union_engine::upper_select_const_tables() { return calc_const_tables((TABLE_LIST *) unit->outer_select()-> table_list.first); } + + +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>(", 23); + tab->ref.items[0]->print(str); + str->append(" in ", 4); + str->append(tab->table->real_name); + KEY *key_info= tab->table->key_info+ tab->ref.key; + str->append(" on ", 4); + str->append(key_info->name); + if (cond) + { + str->append(" where ", 7); + cond->print(str); + } + str->append(')'); +} + + +void subselect_indexsubquery_engine::print(String *str) +{ + str->append("<index_lookup>(", 15); + tab->ref.items[0]->print(str); + str->append(" in ", 4); + str->append(tab->table->real_name); + KEY *key_info= tab->table->key_info+ tab->ref.key; + str->append(" on ", 4); + str->append(key_info->name); + if (check_null) + str->append(" chicking NULL", 14); + if (cond) + { + str->append(" where ", 7); + cond->print(str); + } + str->append(')'); +} diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 7e735165c02..8d438d0e72f 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -92,13 +92,7 @@ public: inline table_map get_used_tables_cache() { return used_tables_cache; } inline bool get_const_item_cache() { return const_item_cache; } void update_used_tables(); - 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; @@ -147,9 +141,11 @@ public: /* used in static ALL/ANY optimisation */ class Item_maxmin_subselect :public Item_singlerow_subselect { + bool max; public: Item_maxmin_subselect(Item_subselect *parent, st_select_lex *select_lex, bool max); + void print(String *str); }; /* exists subselect */ @@ -174,6 +170,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; @@ -194,12 +191,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() @@ -219,6 +219,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; @@ -233,12 +234,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); }; @@ -276,6 +280,7 @@ public: bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; static table_map calc_const_tables(TABLE_LIST *); + virtual void print(String *str)= 0; }; @@ -298,6 +303,7 @@ public: bool uncacheable(); void exclude(); table_map upper_select_const_tables(); + void print (String *str); }; @@ -316,6 +322,7 @@ public: bool uncacheable(); void exclude(); table_map upper_select_const_tables(); + void print (String *str); }; @@ -343,6 +350,7 @@ public: bool uncacheable() { return 1; } void exclude(); table_map upper_select_const_tables() { return 0; } + void print (String *str); }; @@ -359,4 +367,5 @@ public: check_null(chk_null) {} int exec(); + void print (String *str); }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ed2a03beccf..74dd95bf0ab 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1366,6 +1366,14 @@ longlong Item_sum_count_distinct::val_int() return table->file->records; } + +void Item_sum_count_distinct::print(String *str) +{ + str->append("count(distinct ", 15); + args[0]->print(str); + str->append(')'); +} + /**************************************************************************** ** Functions to handle dynamic loadable aggregates ** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su> @@ -1960,3 +1968,29 @@ String* Item_func_group_concat::val_str(String* str) } return &result; } + +void Item_func_group_concat::print(String *str) +{ + str->append("group_concat(", 13); + if (distinct) + str->append("distinct ", 9); + for (uint i= 0; i < arg_count; i++) + { + if (i) + str->append(','); + args[i]->print(str); + } + if (arg_count_order) + { + str->append(" order by ", 10); + for (uint i= 0 ; i < arg_count_order ; i++) + { + if (i) + str->append(','); + (*order[i]->item)->print(str); + } + } + str->append(" seperator \'", 12); + str->append(*separator); + str->append("\')", 2); +} diff --git a/sql/item_sum.h b/sql/item_sum.h index e5061e1e05a..d454f06ccde 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -238,6 +238,7 @@ class Item_sum_count_distinct :public Item_sum_int void make_unique(); Item *copy_or_same(THD* thd); void no_rows_in_result() {} + void print(String *str); }; @@ -748,4 +749,5 @@ class Item_func_group_concat : public Item_sum String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} + void print(String *str); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 4009256ee17..4f1d6c5d63e 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -433,7 +433,7 @@ String *make_datetime(String *str, TIME *l_time, length= int10_to_str(l_time->day, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); if (l_time->day >= 10 && l_time->day <= 19) - str->append("th"); + str->append("th", 2); else { switch (l_time->day %10) { @@ -531,7 +531,7 @@ String *make_datetime(String *str, TIME *l_time, str->append_with_prefill(intbuff, length, 2, '0'); if (add_second_frac) { - str->append(".", 1); + str->append('.'); length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 6, '0'); } @@ -1644,6 +1644,36 @@ longlong Item_date_add_interval::val_int() ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second; } +static const char *interval_names[]= +{ + "year", "month", "day", "hour", "minute", + "second", "microsecond", "year_month", + "day_hour", "day_minute", "day_second", + "hour_minute", "hour_second", "minute_second", + "day_microsecond", "hour_microsecond", + "minute_microsecond", "second_microsecond" +}; + +void Item_date_add_interval::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(date_sub_interval?" - interval ":" + interval "); + args[1]->print(str); + str->append(' '); + str->append(interval_names[int_type]); + str->append(')'); +} + +void Item_extract::print(String *str) +{ + str->append("extract(", 8); + str->append(interval_names[int_type]); + str->append(" from ", 6); + args[0]->print(str); + str->append(')'); +} + void Item_extract::fix_length_and_dec() { value.alloc(32); // alloc buffer @@ -1751,10 +1781,33 @@ bool Item_extract::eq(const Item *item, bool binary_cmp) const void Item_typecast::print(String *str) { - str->append("CAST("); + str->append("cast(", 5); + args[0]->print(str); + str->append(" as ", 4); + str->append(cast_type()); + str->append(')'); +} + +void Item_char_typecast::print(String *str) +{ + str->append("cast(", 5); args[0]->print(str); - str->append(" AS "); - str->append(func_name()); + str->append(" as char", 8); + if (cast_length >= 0) + { + str->append('('); + char buffer[20]; + // latin1 is good enough for numbers + String st(buffer, sizeof(buffer), &my_charset_latin1); + st.set((ulonglong)cast_length, &my_charset_latin1); + str->append(st); + str->append(')'); + } + if (cast_cs) + { + str->append(" charset ", 9); + str->append(cast_cs->name); + } str->append(')'); } @@ -2039,6 +2092,28 @@ null_date: return 0; } + +void Item_func_add_time::print(String *str) +{ + if (is_date) + { + DBUG_ASSERT(sign > 0); + str->append("timestamp(", 10); + } + else + { + if (sign > 0) + str->append("addtime(", 8); + else + str->append("subtime(", 8); + } + args[0]->print(str); + str->append(','); + args[0]->print(str); + str->append(')'); +} + + /* TIMEDIFF(t,s) is a time function that calculates the time value between a start and end time. diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index b7bf294b83d..af71322ff0c 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -285,7 +285,7 @@ public: Item_func_unix_timestamp() :Item_int_func() {} Item_func_unix_timestamp(Item *a) :Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "timestamp"; } + const char *func_name() const { return "unix_timestamp"; } void fix_length_and_dec() { decimals=0; @@ -544,13 +544,13 @@ public: enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR, INTERVAL_MINUTE, - INTERVAL_SECOND, INTERVAL_MICROSECOND ,INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, - INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, - INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, - INTERVAL_HOUR_MICROSECOND, INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND + INTERVAL_SECOND, INTERVAL_MICROSECOND ,INTERVAL_YEAR_MONTH, + INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, + INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND, + INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND, + INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND }; - class Item_date_add_interval :public Item_date_func { const interval_type int_type; @@ -568,6 +568,7 @@ public: double val() { return (double) val_int(); } longlong val_int(); bool get_date(TIME *res,bool fuzzy_date); + void print(String *str); }; @@ -583,6 +584,7 @@ class Item_extract :public Item_int_func const char *func_name() const { return "extract"; } void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; + void print(String *str); }; @@ -590,7 +592,6 @@ class Item_typecast :public Item_str_func { public: Item_typecast(Item *a) :Item_str_func(a) {} - const char *func_name() const { return "char"; } String *val_str(String *a) { String *tmp=args[0]->val_str(a); @@ -604,6 +605,7 @@ public: collation.set(default_charset()); max_length=args[0]->max_length; } + virtual const char* cast_type() const= 0; void print(String *str); }; @@ -617,8 +619,10 @@ class Item_char_typecast :public Item_typecast public: Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg) :Item_typecast(a), cast_length(length_arg), cast_cs(cs_arg) {} + const char* cast_type() const { return "char"; }; String *val_str(String *a); void fix_length_and_dec(); + void print(String *str); }; @@ -628,7 +632,7 @@ public: Item_date_typecast(Item *a) :Item_typecast(a) {} String *val_str(String *str); bool get_date(TIME *ltime, bool fuzzy_date); - const char *func_name() const { return "date"; } + const char *cast_type() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field(TABLE *t_arg) { @@ -643,7 +647,7 @@ public: Item_time_typecast(Item *a) :Item_typecast(a) {} String *val_str(String *str); bool get_time(TIME *ltime); - const char *func_name() const { return "time"; } + const char *cast_type() const { return "time"; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } Field *tmp_table_field(TABLE *t_arg) { @@ -657,7 +661,7 @@ class Item_datetime_typecast :public Item_typecast public: Item_datetime_typecast(Item *a) :Item_typecast(a) {} String *val_str(String *str); - const char *func_name() const { return "datetime"; } + const char *cast_type() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { @@ -694,7 +698,6 @@ public: Item_func_add_time(Item *a, Item *b, bool type_arg, bool neg_arg) :Item_str_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } String *val_str(String *str); - const char *func_name() const { return "addtime"; } enum_field_types field_type() const { return cached_field_type; } void fix_length_and_dec(); @@ -711,6 +714,7 @@ public: return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin)); } + void print(String *str); }; class Item_func_timediff :public Item_str_func diff --git a/sql/item_uniq.h b/sql/item_uniq.h index 9b370b70181..5c6f6eefb6b 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -29,6 +29,7 @@ public: :Item_real_func(list) {} double val() { return 0.0; } void fix_length_and_dec() { decimals=0; max_length=6; } + void print(String *str) { str->append("0.0", 3); } }; @@ -54,4 +55,5 @@ public: { return new Item_sum_unique_users(thd, *this); } + void print(String *str) { str->append("0.0", 3); } }; diff --git a/sql/key.cc b/sql/key.cc index 37ef6339f20..639b1e535a6 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -227,7 +227,7 @@ void key_unpack(String *to,TABLE *table,uint idx) { if (table->record[0][key_part->null_offset] & key_part->null_bit) { - to->append("NULL"); + to->append("NULL", 4); continue; } } @@ -239,7 +239,7 @@ void key_unpack(String *to,TABLE *table,uint idx) to->append(tmp); } else - to->append("???"); + to->append("???", 3); } DBUG_VOID_RETURN; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f7b12bd959c..88061354b68 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -204,6 +204,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 7fd2b751c1d..719686a56c3 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_tree(); 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 c3ff69184e6..5aaeef57669 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1502,7 +1502,75 @@ 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 ", 7); + if (union_option & UNION_ALL) + str->append("all ", 4); + } + 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 ", 10); + 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", 5); + 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 ", 7); + char buff[20]; + // latin1 is good enough for numbers + String st(buff, sizeof(buff), &my_charset_latin1); + st.set((ulonglong)select_limit, &my_charset_latin1); + str->append(st); + if (offset_limit) + { + str->append(','); + st.set((ulonglong)select_limit, &my_charset_latin1); + str->append(st); + } + } +} + /* 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 c31420b951c..20b796bb1ba 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -80,6 +80,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 @@ -335,7 +339,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: @@ -476,6 +482,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; @@ -550,9 +559,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 704ac726fa6..5a69a3a1017 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1777,6 +1777,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; } @@ -4687,7 +4697,7 @@ Item * all_any_subquery_creator(Item *left_expr, return new Item_func_not(new Item_in_subselect(left_expr, select_lex)); Item_allany_subselect *it= - new Item_allany_subselect(left_expr, (*cmp)(all), select_lex); + new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all); if (all) return it->upper_not= new Item_func_not_all(it); /* ALL */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 5db3be7599b..ecad84ba0cb 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -625,7 +625,7 @@ Increase max_allowed_packet on master"; goto err; } packet->length(0); - packet->append("\0",1); + packet->append('\0'); } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 222f5707c69..00d8ea4c114 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -331,6 +331,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; @@ -883,12 +897,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 */ @@ -1550,11 +1564,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) { @@ -9001,3 +9027,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 ", 7); + + //options + if (options & SELECT_STRAIGHT_JOIN) + str->append("straight_join ", 14); + if ((thd->lex.lock_option & TL_READ_HIGH_PRIORITY) && + (this == &thd->lex.select_lex)) + str->append("high_priority ", 14); + if (options & SELECT_DISTINCT) + str->append("distinct ", 9); + if (options & SELECT_SMALL_RESULT) + str->append("small_result ", 13); + if (options & SELECT_BIG_RESULT) + str->append("big_result ", 11); + if (options & OPTION_BUFFER_RESULT) + str->append("buffer_result ", 14); + if (options & OPTION_FOUND_ROWS) + str->append("calc_found_rows ", 16); + if (!thd->lex.safe_to_cache_query) + str->append("no_cache ", 9); + if (options & OPTION_TO_QUERY_CACHE) + str->append("cache ", 6); + + //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 ", 6); + 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(", 4); + 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 ", 12); + if (!(table->outer_join & JOIN_TYPE_LEFT) && + table->on_expr) + next_on= table->on_expr; + } + else if (next->straight) + str->append(" straight_join ", 15); + else if (next->outer_join & JOIN_TYPE_LEFT) + str->append(" left join ", 11); + else + str->append(" join ", 6); + } + } + } + + //where + Item *where= this->where; + if (join) + where= join->conds; + if (where) + { + str->append(" where ", 7); + where->print(str); + } + + //group by & olap + if (group_list.elements) + { + str->append(" group by ", 10); + print_order(str, (ORDER *) group_list.first); + switch (olap) + { + case CUBE_TYPE: + str->append(" with cube", 10); + break; + case ROLLUP_TYPE: + str->append(" with rollup", 12); + break; + default: + ; //satisfy compiler + } + } + + //having + Item *having= this->having; + if (join) + having= join->having; + + if (having) + { + str->append(" having ", 8); + having->print(str); + } + + if (order_list.elements) + { + str->append(" order by ", 10); + 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 7306f609f66..cdf528060f7 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_show.cc b/sql/sql_show.cc index 4f453bce903..95a6ebb36fb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1111,12 +1111,12 @@ store_create_info(THD *thd, TABLE *table, String *packet) if (field->has_charset()) { if (field->charset() == &my_charset_bin) - packet->append(" binary"); + packet->append(" binary", 7); else if (!limited_mysql_mode && !foreign_db_mode) { if (field->charset() != table->table_charset) { - packet->append(" character set "); + packet->append(" character set ", 15); packet->append(field->charset()->csname); } /* @@ -1253,32 +1253,32 @@ store_create_info(THD *thd, TABLE *table, String *packet) !(thd->variables.sql_mode & MODE_MYSQL323) && !(thd->variables.sql_mode & MODE_MYSQL40)) { - packet->append(" CHARSET="); + packet->append(" CHARSET=", 9); packet->append(table->table_charset->csname); if (!(table->table_charset->state & MY_CS_PRIMARY)) { - packet->append(" COLLATE="); + packet->append(" COLLATE=", 9); packet->append(table->table_charset->name); } } if (table->min_rows) { - packet->append(" MIN_ROWS="); + packet->append(" MIN_ROWS=", 10); end= longlong10_to_str(table->min_rows, buff, 10); packet->append(buff, (uint) (end- buff)); } if (table->max_rows) { - packet->append(" MAX_ROWS="); + packet->append(" MAX_ROWS=", 10); end= longlong10_to_str(table->max_rows, buff, 10); packet->append(buff, (uint) (end - buff)); } if (table->avg_row_length) { - packet->append(" AVG_ROW_LENGTH="); + packet->append(" AVG_ROW_LENGTH=", 16); end= longlong10_to_str(table->avg_row_length, buff,10); packet->append(buff, (uint) (end - buff)); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 00277759763..997e2122e2b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -713,6 +713,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> @@ -2924,17 +2925,19 @@ opt_gconcat_separator: opt_gorder_clause: - /* empty */ - { - LEX *lex=Lex; - lex->gorder_list = NULL; - } - | order_clause - { - LEX *lex=Lex; - lex->gorder_list= (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list,sizeof(st_sql_list)); - lex->current_select->order_list.empty(); - }; + /* empty */ + { + LEX *lex=Lex; + lex->gorder_list = NULL; + } + | order_clause + { + LEX *lex=Lex; + lex->gorder_list= + (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list, + sizeof(st_sql_list)); + lex->current_select->order_list.empty(); + }; in_sum_expr: @@ -4073,7 +4076,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; @@ -4084,6 +4089,11 @@ describe_command: DESC | DESCRIBE; +opt_extended_describe: + /* empty */ {} + | EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } + ; + opt_describe_column: /* empty */ {} | text_string { Lex->wild= $1; } @@ -4339,8 +4349,9 @@ literal: { Item *tmp= new Item_varbinary($2.str,$2.length); String *str= tmp ? tmp->val_str((String*) 0) : (String*) 0; - $$ = new Item_string(str ? str->ptr() : "", str ? str->length() : - 0, Lex->charset); + $$= new Item_string(str ? str->ptr() : "", + str ? str->length() : 0, + Lex->charset); } | DATE_SYM text_literal { $$ = $2; } | TIME_SYM text_literal { $$ = $2; } @@ -5399,7 +5410,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 |