Commit a32b868c authored by unknown's avatar unknown

subselect transformation moved in after-fix_field place

removed "of is null" if it is possible
  (this cset should be SCRUM related, but not approved as scrum task yet)


mysql-test/r/subselect.result:
  new subselect test result (new place of error detecting & and more subselect reducing)
sql/item.cc:
  layout fix
sql/item.h:
  unneed ';'
  fixed print pethod
sql/item_cmpfunc.cc:
  new method to support transformation after fix_fields
sql/item_cmpfunc.h:
  new method to support transformation after fix_fields
  fixed Item printing
sql/item_subselect.cc:
  new transformation
sql/item_subselect.h:
  new transformation
sql/sql_derived.cc:
  'table' & 'table_list' now is not union
sql/sql_lex.cc:
  'table' & 'table_list' now is not union to support reinit only shared tables (but all)
sql/sql_lex.h:
  mark fake st_select_lex
sql/sql_olap.cc:
  fixed table assignment
  TODO added
sql/sql_select.cc:
  'table' & 'table_list' now is not union
  transforming subselect
sql/sql_union.cc:
  prepare make on fix_fields
sql/sql_yacc.yy:
  fixed layout
sql/table.h:
  'table & 'table_list' now is different fields
parent 79c53934
......@@ -46,7 +46,7 @@ SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1;
1
1
SELECT (SELECT 1), a;
Unknown column 'a' in 'field list'
Unknown column 'a' in 'checking transformed subquery'
SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1;
a
1
......@@ -668,7 +668,6 @@ id
EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ref id id 5 const 1 Using where; Using index
3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1247 Select 3 was reduced during optimisation
Note 1247 Select 2 was reduced during optimisation
......@@ -1008,7 +1007,7 @@ CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(1) NOT NULL default '0'
`a` bigint(17) NOT NULL default '0'
) TYPE=MyISAM CHARSET=latin1
drop table t1;
create table t1 (a int);
......
......@@ -1324,17 +1324,15 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
}
}
/*
* The following conditional is changed as to correctly identify
* incorrect references in group functions or forward references
* with sub-select's / derived tables, while it prevents this
* check when Item_ref is created in an expression involving
* summing function, which is to be placed in the user variable.
*
*/
/*
The following conditional is changed as to correctly identify
incorrect references in group functions or forward references
with sub-select's / derived tables, while it prevents this
check when Item_ref is created in an expression involving
summing function, which is to be placed in the user variable.
*/
if (((*ref)->with_sum_func && name &&
(depended_from ||
(depended_from ||
!(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
thd->lex.current_select->select_lex()->having_fix_field))) ||
!(*ref)->fixed)
......
......@@ -100,7 +100,7 @@ class Item {
virtual bool get_time(TIME *ltime);
virtual bool get_date_result(TIME *ltime,bool fuzzydate)
{ return get_date(ltime,fuzzydate); }
virtual bool is_null() { return 0; };
virtual bool is_null() { return 0; }
virtual void top_level_item() {}
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
......@@ -560,6 +560,15 @@ class Item_ref_null_helper: public Item_ref
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(')');
}
};
......@@ -605,6 +614,15 @@ class Item_asterisk_remover :public Item_ref_null_helper
{}
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
Item **storage() {return &item;}
void print(String *str)
{
str->append("ref_null_helper('");
if (item)
item->print(str);
else
str->append('?');
str->append(')');
}
};
/*
......
......@@ -318,16 +318,24 @@ int Arg_comparator::compare_e_row()
return 1;
}
bool Item_in_optimizer::preallocate_row()
bool Item_in_optimizer::fix_left(THD *thd,
struct st_table_list *tables,
Item **ref)
{
return (!(cache= Item_cache::get_cache(ROW_RESULT)));
if (args[0]->fix_fields(thd, tables, ref) ||
(!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))))
return 1;
cache->setup(args[0]);
return 0;
}
bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref)
{
if (args[0]->fix_fields(thd, tables, args))
if (fix_left(thd, tables, ref))
return 1;
if (args[0]->maybe_null)
maybe_null=1;
......@@ -340,9 +348,6 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
with_sum_func= args[0]->with_sum_func;
used_tables_cache= args[0]->used_tables();
const_item_cache= args[0]->const_item();
if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
return 1;
cache->setup(args[0]);
if (cache->cols() == 1)
{
if (args[0]->used_tables())
......@@ -361,7 +366,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
((Item_cache *)cache->el(i))->set_used_tables(0);
}
}
if (args[1]->fix_fields(thd, tables, args))
if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args))
return 1;
Item_in_subselect * sub= (Item_in_subselect *)args[1];
if (args[0]->cols() != sub->engine->cols())
......@@ -1592,7 +1597,8 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
if (abort_on_null)
item->top_level_item();
if (item->fix_fields(thd, tables, li.ref()) || item->check_cols(1))
if ((!item->fixed &&
item->fix_fields(thd, tables, li.ref())) || item->check_cols(1))
return 1; /* purecov: inspected */
used_tables_cache|=item->used_tables();
with_sum_func= with_sum_func || item->with_sum_func;
......
......@@ -91,9 +91,8 @@ class Item_in_optimizer: public Item_bool_func
public:
Item_in_optimizer(Item *a, Item_in_subselect *b):
Item_bool_func(a, (Item *)b), cache(0) {}
// used by row in transformer
bool preallocate_row();
bool fix_fields(THD *, struct st_table_list *, Item **);
bool fix_left(THD *thd, struct st_table_list *tables, Item **ref);
bool is_null();
/*
Item_in_optimizer item is special boolean function. On value request
......@@ -103,7 +102,7 @@ class Item_in_optimizer: public Item_bool_func
Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
*/
longlong val_int();
const char *func_name() const { return "IN_OPTIMIZER"; }
Item_cache **get_cache() { return &cache; }
};
......
This diff is collapsed.
......@@ -46,6 +46,8 @@ class Item_subselect :public Item_result_field
bool have_to_be_excluded;
public:
enum trans_res {OK, REDUCE, ERROR};
Item_subselect();
Item_subselect(Item_subselect *item)
{
......@@ -71,7 +73,7 @@ class Item_subselect :public Item_result_field
{
null_value= 1;
}
virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
virtual trans_res select_transformer(THD *thd, JOIN *join);
bool assigned() { return value_assigned; }
void assigned(bool a) { value_assigned= a; }
enum Type type() const;
......@@ -83,6 +85,13 @@ class Item_subselect :public Item_result_field
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
virtual void fix_length_and_dec();
table_map used_tables() const;
void print(String *str)
{
if (name)
str->append(name);
else
str->append("-subselect-");
}
friend class select_subselect;
friend class Item_in_optimizer;
......@@ -105,7 +114,7 @@ class Item_singlerow_subselect :public Item_subselect
decimals= item->decimals;
}
void reset();
void select_transformer(THD *thd, st_select_lex_unit *unit);
trans_res select_transformer(THD *thd, JOIN *join);
void store(uint i, Item* item);
double val();
longlong val_int ();
......@@ -161,25 +170,35 @@ class Item_in_subselect :public Item_exists_subselect
{
protected:
Item * left_expr;
/*
expr & optinizer used in subselect rewriting to store Item for
all JOIN in UNION
*/
Item *expr;
Item_in_optimizer *optimizer;
bool was_null;
bool abort_on_null;
public:
Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
Item_in_subselect(Item_in_subselect *item);
Item_in_subselect(): Item_exists_subselect() {}
Item_in_subselect(): Item_exists_subselect(), abort_on_null(0) {}
void reset()
{
value= 0;
null_value= 0;
was_null= 0;
}
virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
void single_value_transformer(THD *thd, st_select_lex_unit *unit,
Item *left_expr, compare_func_creator func);
void row_value_transformer(THD *thd, st_select_lex_unit *unit,
Item *left_expr);
trans_res select_transformer(THD *thd, JOIN *join);
trans_res single_value_transformer(THD *thd, JOIN *join,
Item *left_expr,
compare_func_creator func);
trans_res row_value_transformer(THD *thd, JOIN * join,
Item *left_expr);
longlong val_int();
double val();
String *val_str(String*);
void top_level_item() { abort_on_null=1; }
bool test_limit(st_select_lex_unit *unit);
friend class Item_asterisk_remover;
friend class Item_ref_null_helper;
......@@ -196,7 +215,7 @@ class Item_allany_subselect :public Item_in_subselect
Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f,
st_select_lex *select_lex);
Item_allany_subselect(Item_allany_subselect *item);
virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
trans_res select_transformer(THD *thd, JOIN *join);
};
class subselect_engine: public Sql_alloc
......
......@@ -196,7 +196,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if (tables)
{
for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
cursor->table_list->table=cursor->table;
if (cursor->table_list)
cursor->table_list->table=cursor->table;
}
}
else
......
......@@ -1302,11 +1302,13 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
return 1;
}
*new_table_list= cursor;
cursor->table_list= aux; //to be able mark this table as shared
new_table_list= &cursor->next;
*new_table_list= 0; // end result list
}
else
aux->shared= 1; // Mark that it's used twice
// Mark that it's used twice
cursor->table_list->shared= aux->shared= 1;
aux->table_list= cursor;
}
}
......@@ -1403,6 +1405,7 @@ ulong st_select_lex::get_table_join_options()
}
st_select_lex::st_select_lex(struct st_lex *lex)
:fake_select(0)
{
select_number= ++lex->thd->select_number;
init_query();
......
......@@ -352,6 +352,8 @@ class st_select_lex: public st_select_lex_node
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
/* TRUE for fake select, which used in UNION processing */
bool fake_select;
void init_query();
void init_select();
......@@ -405,7 +407,7 @@ class st_select_lex: public st_select_lex_node
friend void mysql_init_query(THD *thd);
st_select_lex(struct st_lex *lex);
st_select_lex() {}
st_select_lex() :fake_select(0) {}
void make_empty_select(st_select_lex *last_select)
{
select_number=INT_MAX;
......
......@@ -150,7 +150,8 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
{
if (cursor->do_redirect)
{
cursor->table= ((TABLE_LIST*) cursor->table)->table;
//Sinisa TODO: there are function for this purpose: fix_tables_pointers
cursor->table= cursor->table_list->table;
cursor->do_redirect= 0;
}
}
......
......@@ -201,7 +201,8 @@ void relink_tables(SELECT_LEX *select_lex)
for (TABLE_LIST *cursor= (TABLE_LIST *) select_lex->table_list.first;
cursor;
cursor=cursor->next)
cursor->table= cursor->table_list->table;
if (cursor->table_list)
cursor->table= cursor->table_list->table;
}
......@@ -314,6 +315,19 @@ JOIN::prepare(Item ***rref_pointer_array,
having->split_sum_func(ref_pointer_array, all_fields);
}
// Is it subselect
{
Item_subselect *subselect;
if ((subselect= select_lex->master_unit()->item) &&
!select_lex->fake_select)
{
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(thd, this)) !=
Item_subselect::OK)
DBUG_RETURN((res == Item_subselect::ERROR));
}
}
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
/*
......
......@@ -188,42 +188,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
union_result->not_describe=1;
union_result->tmp_table_param=tmp_table_param;
/*
The following piece of code is placed here solely for the purpose of
getting correct results with EXPLAIN when UNION is withing a sub-select
or derived table ...
*/
if (thd->lex.describe)
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK,
union_result);
thd->lex.current_select= sl;
offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild,
sl->where,
((sl->braces) ? sl->order_list.elements : 0) +
sl->group_list.elements,
(sl->braces) ?
(ORDER *)sl->order_list.first : (ORDER *) 0,
(ORDER*) sl->group_list.first,
sl->having,
(ORDER*) NULL,
sl, this, t_and_f);
t_and_f= 0;
if (res || thd->is_fatal_error)
goto err;
}
JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK,
union_result);
thd->lex.current_select= sl;
offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild,
sl->where,
((sl->braces) ? sl->order_list.elements : 0) +
sl->group_list.elements,
(sl->braces) ?
(ORDER *)sl->order_list.first : (ORDER *) 0,
(ORDER*) sl->group_list.first,
sl->having,
(ORDER*) NULL,
sl, this, t_and_f);
t_and_f= 0;
if (res || thd->is_fatal_error)
goto err;
}
item_list.empty();
......@@ -268,14 +259,12 @@ int st_select_lex_unit::exec()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
thd->lex.current_select= sl;
if (optimized)
res= sl->join->reinit();
else
{
JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK,
union_result);
thd->lex.current_select= sl;
offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit)
......@@ -283,22 +272,36 @@ int st_select_lex_unit::exec()
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild,
sl->where,
((sl->braces) ? sl->order_list.elements : 0) +
sl->group_list.elements,
(sl->braces) ?
(ORDER *)sl->order_list.first : (ORDER *) 0,
(ORDER*) sl->group_list.first,
sl->having,
(ORDER*) NULL,
sl, this, t_and_f);
t_and_f=0;
if (res | thd->is_fatal_error)
/*
As far as union share table space we should reassign table map,
which can be spoiled by 'prepare' of JOIN of other UNION parts
if it use same tables
*/
uint tablenr=0;
for (TABLE_LIST *table_list= (TABLE_LIST*) sl->table_list.first;
table_list;
table_list= table_list->next, tablenr++)
{
thd->lex.current_select= lex_select_save;
DBUG_RETURN(res);
if (table_list->shared)
{
/*
review notes: Check it carefully. I still can't understand
why I should not touch table->used_keys. For my point of
view we should do here same procedura as it was done by
setup_table
*/
DBUG_PRINT("SUBS", ("shared %s", table_list->real_name));
TABLE *table= table_list->table;
table->used_fields=0;
table->const_table=0;
table->outer_join=table->null_row=0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->keys_in_use;
table->maybe_null=test(table->outer_join=table_list->outer_join);
table->tablenr=tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
}
}
res= sl->join->optimize();
}
......@@ -334,6 +337,7 @@ int st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
SELECT_LEX *fake_select = new SELECT_LEX(&thd->lex);
fake_select->fake_select= 1;
offset_limit_cnt= (select_cursor->braces ?
global_parameters->offset_limit : 0);
select_limit_cnt= (select_cursor->braces ?
......
......@@ -5003,7 +5003,9 @@ subselect_start:
{
LEX *lex=Lex;
if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) {
lex->sql_command <= (int)SQLCOM_HA_READ) ||
lex->sql_command == (int)SQLCOM_KILL)
{
send_error(lex->thd, ER_SYNTAX_ERROR);
YYABORT;
}
......
......@@ -163,15 +163,8 @@ typedef struct st_table_list
struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */
List<String> *use_index, *ignore_index;
/*
Usually hold reference on opened table, but may hold reference
to node of complete list of tables used in UNION & subselect.
*/
union
{
TABLE *table; /* opened table */
st_table_list *table_list; /* pointer to node of list of all tables */
};
TABLE *table; /* opened table */
st_table_list *table_list; /* pointer to node of list of all tables */
class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
GRANT_INFO grant;
thr_lock_type lock_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment