diff options
author | unknown <bell@sanja.is.com.ua> | 2002-05-26 22:50:32 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2002-05-26 22:50:32 +0300 |
commit | 02d8b9ba56082d26b14808f6618e098c72e083fb (patch) | |
tree | 78961c1f59544bcab13595bc9f6600a163d632ff /sql | |
parent | 3a6483fe4bfc53293b4b7e03f6fda7515bcf9b7f (diff) | |
download | mariadb-git-02d8b9ba56082d26b14808f6618e098c72e083fb.tar.gz |
added depended subselect processing
mysql-test/r/subselect.result:
depended subselect test
mysql-test/t/subselect.test:
depended subselect test
sql/item.cc:
resolving field names in depended queries
sql/item_subselect.cc:
move optimization just before execution, because we can't optimize inner depended subselect if have not optimized outer subselect
sql/item_subselect.h:
move optimization just before execution
sql/sql_lex.h:
some inline methods to hide internal SELECT_LEX structures
sql/sql_select.cc:
fixed error
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 29 | ||||
-rw-r--r-- | sql/item_subselect.cc | 28 | ||||
-rw-r--r-- | sql/item_subselect.h | 5 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 8 | ||||
-rw-r--r-- | sql/sql_select.cc | 42 | ||||
-rw-r--r-- | sql/sql_select.h | 3 |
7 files changed, 99 insertions, 17 deletions
diff --git a/sql/item.cc b/sql/item.cc index 84f4624a248..13141ade2a8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -320,7 +320,34 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) { Field *tmp; if (!(tmp=find_field_in_tables(thd,this,tables))) - return 1; + { + /* + We can't find table field in table list of current select, + consequently we have to find it in outer subselect(s). + We can't join lists of outer & current select, because of scope + of view rules. For example if both tables (outer & current) have + field 'field' it is not mistake to refer to this field without + mention of table name, but if we join tables in one list it will + cause error ER_NON_UNIQ_ERROR in find_field_in_tables. + */ + for (SELECT_LEX *sl= thd->lex.select->outer_select(); + sl && !tmp; + sl= sl->outer_select()) + tmp=find_field_in_tables(thd, this, + (TABLE_LIST*)sl->table_list.first); + if (!tmp) + return 1; + else + if( !thd->lex.select->depended ) + { + thd->lex.select->depended= 1; //Select is depended of outer select(s) + //Tables will be reopened many times + for (TABLE_LIST *tbl= (TABLE_LIST*)thd->lex.select->table_list.first; + tbl; + tbl= tbl->next) + tbl->shared= 1; + } + } set_field(tmp); } else if (thd && thd->set_query_id && field->query_id != thd->query_id) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 286c29fec7a..d71271b98fd 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -36,7 +36,7 @@ SUBSELECT TODO: #include "sql_select.h" Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex): - executed(0) + executed(0), optimized(0), error(0) { DBUG_ENTER("Item_subselect::Item_subselect"); DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex)); @@ -48,7 +48,7 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex): item value is NULL if select_subselect not changed this value (i.e. some rows will be found returned) */ - assign_null(); + assign_null(); DBUG_VOID_RETURN; } @@ -110,17 +110,31 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables) (ORDER*) 0, select_lex, (SELECT_LEX_UNIT*) select_lex->master)) return 1; - if (join->optimize()) - { - executed= 1; - return 1; - } thd->lex.select= save_select; return 0; } int Item_subselect::exec() { + if (!optimized) + { + optimized=1; + if (join->optimize()) + { + executed= 1; + return (join->error?join->error:1); + } + } + if (join->select_lex->depended && executed) + { + if (join->reinit()) + { + error= 1; + return 1; + } + assign_null(); + executed= 0; + } if (!executed) { SELECT_LEX *save_select= join->thd->lex.select; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 096da68600c..e27f14fb83d 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -29,9 +29,11 @@ class select_subselect; class Item_subselect :public Item { protected: - my_bool executed; /* simple subselect is executed */ longlong int_value; double real_value; + my_bool executed; /* simple subselect is executed */ + my_bool optimized; /* simple subselect is optimized */ + my_bool error; /* error in query */ enum Item_result res_type; int exec(); @@ -62,6 +64,7 @@ public: join= item->join; result= item->result; name= item->name; + error= item->error; } enum Type type() const; double val (); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 134e776a15a..496d21b333c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -931,6 +931,7 @@ void st_select_lex::init_select() use_index.empty(); ftfunc_list.empty(); linkage=UNSPECIFIED_TYPE; + depended= 0; } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 876b9aa2743..32a98615390 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -208,6 +208,7 @@ private: SELECT_LEXs */ struct st_lex; +struct st_select_lex; struct st_select_lex_unit: public st_select_lex_node { /* Pointer to 'last' select or pointer to unit where stored @@ -218,6 +219,8 @@ struct st_select_lex_unit: public st_select_lex_node { ha_rows select_limit_cnt, offset_limit_cnt; void init_query(); bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result); + st_select_lex* first_select() { return (st_select_lex*) slave; } + st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; } private: bool create_total_list_n_last_return(THD *thd, st_lex *lex, TABLE_LIST ***result); @@ -240,9 +243,12 @@ struct st_select_lex: public st_select_lex_node { List<Item_func_match> ftfunc_list; uint in_sum_expr, sort_default; bool create_refs, - braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ + braces, /* SELECT ... UNION (SELECT ... ) <- this braces */ + depended; /* depended from outer select subselect */ void init_query(); void init_select(); + st_select_lex* outer_select() { return (st_select_lex*) master->master; } + st_select_lex* next_select() { return (st_select_lex*) next; } }; typedef struct st_select_lex SELECT_LEX; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c5e5e971e33..115e5a058ed 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -213,7 +213,8 @@ JOIN::prepare(TABLE_LIST *tables_init, proc_param= proc_param_init; tables_list= tables_init; select_lex= select; - + union_part= (unit->first_select()->next_select() != 0); + /* Check that all tables, fields, conds and order are ok */ if (setup_tables(tables_list) || @@ -334,7 +335,6 @@ int JOIN::optimize() { DBUG_ENTER("JOIN::optimize"); - SELECT_LEX *select_lex = &(thd->lex.select_lex); #ifdef HAVE_REF_TO_FIELDS // Not done yet /* Add HAVING to WHERE if possible */ @@ -380,7 +380,7 @@ JOIN::optimize() } if (select_options & SELECT_DESCRIBE) { - if (select_lex->next) + if (union_part) select_describe(this, false, false, false, "Select tables optimized away"); else @@ -406,6 +406,17 @@ JOIN::optimize() if (make_join_statistics(this, tables_list, conds, &keyuse) || thd->fatal_error) DBUG_RETURN(-1); + + if (select_lex->depended) + { + /* + Just remove all const-table optimization in case of depended query + TODO: optimize + */ + const_table_map= 0; + const_tables= 0; + found_const_table_map= 0; + } thd->proc_info= "preparing"; result->initialize_tables(this); if (const_table_map != found_const_table_map && @@ -576,7 +587,7 @@ JOIN::optimize() } /* - global uptimisation (with subselect) must be here (TODO) + Global optimization (with subselect) must be here (TODO) */ int @@ -585,8 +596,25 @@ JOIN::global_optimize() return 0; } +int +JOIN::reinit() +{ + DBUG_ENTER("JOIN::reinit"); + //TODO move to unit reinit + unit->offset_limit_cnt =select_lex->offset_limit; + unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit; + if (unit->select_limit_cnt < select_lex->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) + select_lex->options&= ~OPTION_FOUND_ROWS; + + if (setup_tables(tables_list)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} + /* - exec select + Exec select */ void JOIN::exec() @@ -600,7 +628,7 @@ JOIN::exec() error=0; if (select_options & SELECT_DESCRIBE) { - if (select_lex->next) + if (union_part) select_describe(this, false, false, false, "No tables used"); else describe_info(thd, "No tables used"); @@ -627,7 +655,7 @@ JOIN::exec() if (zero_result_cause) { - if (select_options & SELECT_DESCRIBE && select_lex->next) + if (select_options & SELECT_DESCRIBE && union_part) select_describe(this, false, false, false, zero_result_cause); else error=return_zero_rows(result, tables_list, fields_list, diff --git a/sql/sql_select.h b/sql/sql_select.h index ba27c5b4b3b..84d4207bdb5 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -196,6 +196,8 @@ class JOIN :public Sql_alloc{ my_bool test_function_query; // need to return select items 1 row const char *zero_result_cause; // not 0 if exec must return zero result + + my_bool union_part; // this subselect is part of union JOIN(THD *thd, List<Item> &fields, ulong select_options, select_result *result): @@ -236,6 +238,7 @@ class JOIN :public Sql_alloc{ ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit); int optimize(); int global_optimize(); + int reinit(); void exec(); int cleanup(THD *thd); }; |