summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <bell@sanja.is.com.ua>2003-10-22 20:52:47 +0300
committerunknown <bell@sanja.is.com.ua>2003-10-22 20:52:47 +0300
commit47f3a4fd4aa4ac7f2944c85aa20333fa0259ac77 (patch)
tree094f3d63a932eeaa346520cc5605255beab9debe /sql
parent9a4aa99769b29cb4084b3b16d2bfb7067d817d2c (diff)
parentb7aac7df29e716ab0bfd95e2c7349287912dcbf6 (diff)
downloadmariadb-git-47f3a4fd4aa4ac7f2944c85aa20333fa0259ac77.tar.gz
Merge
mysql-test/t/subselect.test: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_func.cc: Auto merged sql/item_strfunc.cc: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/item_timefunc.cc: Auto merged sql/item_timefunc.h: Auto merged sql/mysql_priv.h: Auto merged sql/sql_derived.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_yacc.yy: Auto merged mysql-test/r/subselect.result: SCCS merged
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc92
-rw-r--r--sql/item.h36
-rw-r--r--sql/item_cmpfunc.cc62
-rw-r--r--sql/item_cmpfunc.h14
-rw-r--r--sql/item_func.cc38
-rw-r--r--sql/item_func.h8
-rw-r--r--sql/item_geofunc.h3
-rw-r--r--sql/item_row.cc12
-rw-r--r--sql/item_row.h1
-rw-r--r--sql/item_strfunc.cc8
-rw-r--r--sql/item_strfunc.h9
-rw-r--r--sql/item_subselect.cc167
-rw-r--r--sql/item_subselect.h27
-rw-r--r--sql/item_sum.cc33
-rw-r--r--sql/item_sum.h2
-rw-r--r--sql/item_timefunc.cc78
-rw-r--r--sql/item_timefunc.h24
-rw-r--r--sql/item_uniq.h2
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_derived.cc4
-rw-r--r--sql/sql_lex.cc66
-rw-r--r--sql/sql_lex.h14
-rw-r--r--sql/sql_parse.cc10
-rw-r--r--sql/sql_select.cc184
-rw-r--r--sql/sql_select.h7
-rw-r--r--sql/sql_yacc.yy47
26 files changed, 850 insertions, 101 deletions
diff --git a/sql/item.cc b/sql/item.cc
index ea1eaf29373..c6a27234304 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 `");
+ 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),
@@ -445,12 +458,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)
@@ -461,12 +470,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);
}
@@ -478,8 +483,10 @@ String *Item_real::val_str(String *str)
void Item_string::print(String *str)
{
+ str->append('_');
+ str->append(collation.collation->csname);
str->append('\'');
- str->append(full_name());
+ str->append(str_value);
str->append('\'');
}
@@ -777,7 +784,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 +1501,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 +1750,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 +1828,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 c738f92124f..5f691c9e4e4 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);
@@ -315,6 +316,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
@@ -365,6 +367,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
@@ -637,6 +640,7 @@ public:
(*ref)->save_in_field(result_field, no_conversions);
}
Item *real_item() { return *ref; }
+ void print(String *str);
};
class Item_in_subselect;
@@ -652,15 +656,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
@@ -672,6 +668,7 @@ public:
:Item_ref_null_helper(master, &store, table_name_par, field_name_par),
store(item)
{}
+ void print(String *str);
};
/*
@@ -853,14 +850,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)
{
@@ -870,6 +869,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
@@ -878,12 +878,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; }
@@ -896,12 +891,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 4e6301d2626..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
@@ -704,6 +712,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 ");
+ args[1]->print(str);
+ str->append(" and ");
+ args[2]->print(str);
+ str->append(')');
+}
+
void
Item_func_ifnull::fix_length_and_dec()
{
@@ -1097,7 +1117,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 ");
+ if (first_expr_num != -1)
+ {
+ args[first_expr_num]->print(str);
+ str->append(' ');
+ }
+ for (uint i=0 ; i < ncases ; i+=2)
+ {
+ str->append("when ");
+ args[i]->print(str);
+ str->append(" then ");
+ args[i+1]->print(str);
+ str->append(' ');
+ }
+ if (else_expr_num != -1)
+ {
+ str->append("else ");
+ args[else_expr_num]->print(str);
+ str->append(' ');
+ }
+ str->append("end)");
}
/*
@@ -1504,8 +1544,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 (");
+ for (uint i=1 ; i < arg_count ; i++)
+ {
+ if (i > 1)
+ str->append(',');
+ args[i]->print(str);
+ }
+ str->append("))");
}
@@ -1866,12 +1913,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)");
+}
+
+
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 42b73c48606..eb473a1a73d 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; }
};
@@ -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
@@ -262,6 +266,7 @@ public:
enum Functype functype() const { return BETWEEN; }
const char *func_name() const { return "between"; }
void fix_length_and_dec();
+ void print(String *str);
};
@@ -704,7 +709,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();
};
@@ -722,6 +727,7 @@ public:
const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
table_map not_null_tables() const { return 0; }
+ void print(String *str);
};
@@ -775,6 +781,7 @@ public:
longlong val_int();
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
const char *func_name() const { return "regex"; }
+ void print(String *str) { print_op(str); }
};
#else
@@ -785,6 +792,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_func.cc b/sql/item_func.cc
index 929f85a112d..e615167fa90 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -462,6 +462,24 @@ String *Item_num_op::val_str(String *str)
}
+void Item_func_signed::print(String *str)
+{
+ str->append("cast(");
+ args[0]->print(str);
+ str->append("as signed)");
+
+}
+
+
+void Item_func_unsigned::print(String *str)
+{
+ str->append("cast(");
+ args[0]->print(str);
+ str->append("as unsigned)");
+
+}
+
+
double Item_func_plus::val()
{
double value=args[0]->val()+args[1]->val();
@@ -2771,6 +2789,26 @@ double Item_func_match::val()
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, record, 0));
}
+void Item_func_match::print(String *str)
+{
+ str->append("(match ");
+ 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 (");
+ args[0]->print(str);
+ if (mode == FT_BOOL)
+ str->append(" in boolean mode");
+ str->append("))");
+}
longlong Item_func_bit_xor::val_int()
{
diff --git a/sql/item_func.h b/sql/item_func.h
index 8086e65786d..2e275c1a3f7 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -214,6 +214,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);
};
@@ -225,6 +226,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);
};
@@ -662,6 +664,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
@@ -671,6 +674,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
@@ -689,6 +693,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
@@ -697,6 +702,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
@@ -996,6 +1002,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);
@@ -1031,6 +1038,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
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..5afd52e3738 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -2271,6 +2271,14 @@ String *Item_func_hex::val_str(String *str)
}
+void Item_func_binary::print(String *str)
+{
+ str->append("cast(");
+ args[0]->print(str);
+ str->append("as binary)");
+}
+
+
#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..51dff0fbaf2 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -120,6 +120,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 +325,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 +340,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"; }
};
@@ -520,7 +526,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 +539,7 @@ public:
collation.set(&my_charset_bin);
max_length=args[0]->max_length;
}
- void print(String *str) { print_op(str); }
+ void print(String *str);
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 5e0221ad6c7..3653823254e 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,59 @@ 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);
+ KEY *key_info= tab->table->key_info+ tab->ref.key;
+ str->append(" on ");
+ str->append(key_info->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);
+ KEY *key_info= tab->table->key_info+ tab->ref.key;
+ str->append(" on ");
+ str->append(key_info->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/item_sum.cc b/sql/item_sum.cc
index 672126a2664..c26ed45d0cb 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 ");
+ args[0]->print(str);
+ str->append(')');
+}
+
/****************************************************************************
** Functions to handle dynamic loadable aggregates
** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
@@ -1959,3 +1967,28 @@ String* Item_func_group_concat::val_str(String* str)
}
return &result;
}
+
+void Item_func_group_concat::print(String *str)
+{
+ str->append("group concat(");
+ if (distinct)
+ str->append(" distinct ");
+ for (uint i= 0; i < arg_count; i++)
+ {
+ if (i)
+ str->append(',');
+ args[i]->print(str);
+ }
+ if (arg_count_order)
+ {
+ for (uint i= 0 ; i < arg_count_order ; i++)
+ {
+ if (i)
+ str->append(',');
+ (*order[i]->item)->print(str);
+ }
+ }
+ str->append(" seperator \'");
+ str->append(*separator);
+ str->append("\')");
+}
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..a8c8f9bcf7f 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1644,6 +1644,35 @@ 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(interval_names[int_type]);
+ str->append(')');
+}
+
+void Item_extract::print(String *str)
+{
+ str->append("extract(");
+ str->append(interval_names[int_type]);
+ str->append(' ');
+ args[0]->print(str);
+ str->append(')');
+}
+
void Item_extract::fix_length_and_dec()
{
value.alloc(32); // alloc buffer
@@ -1751,10 +1780,31 @@ bool Item_extract::eq(const Item *item, bool binary_cmp) const
void Item_typecast::print(String *str)
{
- str->append("CAST(");
+ str->append("cast(");
args[0]->print(str);
- str->append(" AS ");
- str->append(func_name());
+ str->append(" as ");
+ str->append(cast_type());
+ str->append(')');
+}
+
+void Item_char_typecast::print(String *str)
+{
+ str->append("cast(");
+ args[0]->print(str);
+ str->append(" as char");
+ if (cast_length >= 0)
+ {
+ str->append('(');
+ char buff[10];
+ snprintf(buff, 10, "%d", cast_length);
+ str->append(buff);
+ str->append(')');
+ }
+ if (cast_cs)
+ {
+ str->append(" charset ");
+ str->append(cast_cs->name);
+ }
str->append(')');
}
@@ -2039,6 +2089,28 @@ null_date:
return 0;
}
+
+void Item_func_add_time::print(String *str)
+{
+ if (is_date)
+ {
+ DBUG_ASSERT(sign > 0);
+ str->append("timestamp(");
+ }
+ else
+ {
+ if (sign > 0)
+ str->append("addtime(");
+ else
+ str->append("subtime(");
+ }
+ 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..ea1e51614c7 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -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..2101fc4e45a 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"); }
};
@@ -54,4 +55,5 @@ public:
{
return new Item_sum_unique_users(thd, *this);
}
+ void print(String *str) { str->append("0.0"); }
};
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 83cd303b438..4b22d30fc46 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -199,6 +199,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 5b05bf096cb..ee9831c1f5b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1454,7 +1454,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 7545f525082..f78f1171d06 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
@@ -327,7 +331,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:
@@ -468,6 +474,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;
@@ -542,9 +551,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 e8870b20d99..5af944dac87 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 9bdb989b6a1..278839442e3 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)
{
@@ -8915,3 +8941,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 8491ba7675d..01cec47f717 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -711,6 +711,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>
@@ -2273,7 +2274,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
@@ -2319,7 +2320,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
@@ -2374,7 +2375,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
@@ -2893,17 +2894,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:
@@ -4042,7 +4045,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;
@@ -4053,6 +4058,11 @@ describe_command:
DESC
| DESCRIBE;
+opt_extended_describe:
+ /* empty */ {}
+ | EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
+ ;
+
opt_describe_column:
/* empty */ {}
| text_string { Lex->wild= $1; }
@@ -4308,8 +4318,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; }
@@ -5367,7 +5378,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