summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <bell@sanja.is.com.ua>2002-05-26 22:50:32 +0300
committerunknown <bell@sanja.is.com.ua>2002-05-26 22:50:32 +0300
commit02d8b9ba56082d26b14808f6618e098c72e083fb (patch)
tree78961c1f59544bcab13595bc9f6600a163d632ff /sql
parent3a6483fe4bfc53293b4b7e03f6fda7515bcf9b7f (diff)
downloadmariadb-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.cc29
-rw-r--r--sql/item_subselect.cc28
-rw-r--r--sql/item_subselect.h5
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h8
-rw-r--r--sql/sql_select.cc42
-rw-r--r--sql/sql_select.h3
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);
};