summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/subselect.result34
-rw-r--r--mysql-test/t/subselect.test16
-rw-r--r--sql/item.cc10
-rw-r--r--sql/item_subselect.cc6
-rw-r--r--sql/mysql_priv.h6
-rw-r--r--sql/sql_derived.cc27
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc18
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_union.cc64
-rw-r--r--sql/sql_update.cc2
13 files changed, 132 insertions, 59 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 5cb17e124f6..656703c1999 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -951,3 +951,37 @@ select * from t1;
mot topic date pseudo
joce 1 0000-00-00 joce
drop table t1, t2, t3;
+SELECT * FROM (SELECT 1 as a,(SELECT a)) a;
+a (SELECT a)
+1 1
+CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT 1)) a;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(1) NOT NULL default '0',
+ `(SELECT 1)` bigint(1) NOT NULL default '0'
+) TYPE=MyISAM CHARSET=latin1
+drop table t1;
+CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a)) a;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(1) NOT NULL default '0',
+ `(SELECT a)` bigint(1) NOT NULL default '0'
+) TYPE=MyISAM CHARSET=latin1
+drop table t1;
+CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a+0)) a;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(1) NOT NULL default '0',
+ `(SELECT a+0)` bigint(17) NOT NULL default '0'
+) TYPE=MyISAM CHARSET=latin1
+drop table t1;
+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(17) NOT NULL default '0'
+) TYPE=MyISAM CHARSET=latin1
+drop table t1;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index da9d7330c46..9a4c5590cc1 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -558,4 +558,18 @@ DELETE FROM t1 WHERE topic IN (SELECT DISTINCT topic FROM t2 WHERE NOT
EXISTS(SELECT * FROM t3 WHERE numeropost=topic));
select * from t1;
-drop table t1, t2, t3; \ No newline at end of file
+drop table t1, t2, t3;
+
+SELECT * FROM (SELECT 1 as a,(SELECT a)) a;
+CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT 1)) a;
+SHOW CREATE TABLE t1;
+drop table t1;
+CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a)) a;
+SHOW CREATE TABLE t1;
+drop table t1;
+CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a+0)) a;
+SHOW CREATE TABLE t1;
+drop table t1;
+CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a;
+SHOW CREATE TABLE t1;
+drop table t1;
diff --git a/sql/item.cc b/sql/item.cc
index 9f96ad0f0f5..09244d95806 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -633,7 +633,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
uint counter= 0;
// Prevent using outer fields in subselects, that is not supported now
SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
- if (cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
+ if (outer_resolving ||
+ cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select());
sl;
sl= sl->outer_select())
@@ -1184,10 +1185,6 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
}
ref= thd->lex.current_select->ref_pointer_array + counter-1;
}
-
- max_length= (*ref)->max_length;
- maybe_null= (*ref)->maybe_null;
- decimals= (*ref)->decimals;
}
if (((*ref)->with_sum_func &&
@@ -1202,6 +1199,9 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list"));
return 1;
}
+ max_length= (*ref)->max_length;
+ maybe_null= (*ref)->maybe_null;
+ decimals= (*ref)->decimals;
fixed= 1;
if (ref && (*ref)->check_cols(1))
return 1;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index ffb4d715159..9a3019ece12 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -161,7 +161,7 @@ void Item_singlerow_subselect::select_transformer(THD *thd,
select_lex->item_list.elements == 1 &&
// TODO: mark subselect items from item list separately
!(select_lex->item_list.head()->type() == FIELD_ITEM ||
- select_lex->item_list.head()->type() == REF_ITEM)
+ select_lex->item_list.head()->type() == REF_ITEM)
)
{
@@ -693,7 +693,7 @@ int subselect_single_select_engine::prepare()
(ORDER*) select_lex->group_list.first,
select_lex->having,
(ORDER*) 0, select_lex,
- select_lex->master_unit(), 0))
+ select_lex->master_unit(), 0, 0))
return 1;
thd->lex.current_select= save_select;
return 0;
@@ -701,7 +701,7 @@ int subselect_single_select_engine::prepare()
int subselect_union_engine::prepare()
{
- return unit->prepare(thd, result);
+ return unit->prepare(thd, result, 0);
}
static Item_result set_row(SELECT_LEX *select_lex, Item * item,
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 978678fa975..026c521adb5 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -403,7 +403,8 @@ int mysql_select(THD *thd, Item ***rref_pointer_array,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, ulong select_type,
select_result *result, SELECT_LEX_UNIT *unit,
- SELECT_LEX *select_lex, bool fake_select_lex);
+ SELECT_LEX *select_lex, bool fake_select_lex,
+ bool tables_OK);
void free_ulderlayed_joins(THD *thd, SELECT_LEX *select);
void fix_tables_pointers(SELECT_LEX *select_lex);
void fix_tables_pointers(SELECT_LEX_UNIT *select_lex);
@@ -411,7 +412,8 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
select_result *result);
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result);
-int mysql_union(THD *thd, LEX *lex,select_result *result,SELECT_LEX_UNIT *unit);
+int mysql_union(THD *thd, LEX *lex, select_result *result,
+ SELECT_LEX_UNIT *unit, bool tables_OK);
int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 8fc3314b69f..d1a232c35b6 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -106,17 +106,22 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
fix_tables_pointers(unit);
}
- Item *item;
- List_iterator<Item> it(sl->item_list);
-
- while ((item= it++))
- item_list.push_back(item);
-
-
lex->current_select= sl;
TABLE_LIST *first_table= (TABLE_LIST*) sl->table_list.first;
- if (setup_wild(thd, first_table, item_list, 0, sl->with_wild) ||
- setup_fields(thd, 0, first_table, item_list, 0, 0, 1))
+ if (setup_tables(first_table) ||
+ setup_wild(thd, first_table, sl->item_list, 0, sl->with_wild))
+ {
+ res= -1;
+ goto exit;
+ }
+
+ item_list= sl->item_list;
+ sl->with_wild= 0;
+ if (setup_ref_array(thd, &sl->ref_pointer_array,
+ (item_list.elements + sl->with_sum_func +
+ sl->order_list.elements + sl->group_list.elements)) ||
+ setup_fields(thd, sl->ref_pointer_array, first_table, item_list,
+ 0, 0, 1))
{
res= -1;
goto exit;
@@ -145,7 +150,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
sl->options&= ~OPTION_FOUND_ROWS;
if (is_union)
- res= mysql_union(thd, lex, derived_result, unit);
+ res= mysql_union(thd, lex, derived_result, unit, 1);
else
res= mysql_select(thd, &sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first,
@@ -156,7 +161,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
(ORDER *) sl->group_list.first,
sl->having, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK,
- derived_result, unit, sl, 0);
+ derived_result, unit, sl, 0, 1);
if (!res)
{
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 1cd38cf9f67..7e858d13ccf 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -312,7 +312,7 @@ public:
void exclude_level();
/* UNION methods */
- int prepare(THD *thd, select_result *result);
+ int prepare(THD *thd, select_result *result, bool tables_OK);
int exec();
int cleanup();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index eda2cbb69ce..430bfb35b3e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2387,7 +2387,7 @@ mysql_execute_command(THD *thd)
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
- result, unit, select_lex, 0);
+ result, unit, select_lex, 0, 0);
if (thd->net.report_error)
res= -1;
delete result;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 830848ce0c8..1d886949633 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -568,7 +568,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
if (join->prepare(&select_lex->ref_pointer_array, tables,
wild_num, conds, og_num, order, group, having, proc,
- select_lex, unit, 0))
+ select_lex, unit, 0, 0))
DBUG_RETURN(1);
/*
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e2568dda625..5417984977d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -169,7 +169,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
register SELECT_LEX *select_lex = &lex->select_lex;
fix_tables_pointers(lex->all_selects_list);
if (select_lex->next_select())
- res=mysql_union(thd,lex,result,&lex->unit);
+ res=mysql_union(thd, lex, result, &lex->unit, 0);
else
res= mysql_select(thd, &select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
@@ -182,7 +182,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
select_lex->having,
(ORDER*) lex->proc_list.first,
select_lex->options | thd->options,
- result, &(lex->unit), &(lex->select_lex), 0);
+ result, &(lex->unit), &(lex->select_lex), 0, 0);
if (res && result)
result->abort();
@@ -267,7 +267,8 @@ JOIN::prepare(Item ***rref_pointer_array,
ORDER *order_init, ORDER *group_init,
Item *having_init,
ORDER *proc_param_init, SELECT_LEX *select,
- SELECT_LEX_UNIT *unit, bool fake_select_lex)
+ SELECT_LEX_UNIT *unit,
+ bool fake_select_lex, bool tables_OK)
{
DBUG_ENTER("JOIN::prepare");
@@ -284,8 +285,9 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */
- if (setup_tables(tables_list) ||
- setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
+ if ((tables_OK?0:(setup_tables(tables_list) ||
+ setup_wild(thd, tables_list, fields_list,
+ &all_fields, wild_num))) ||
setup_ref_array(thd, rref_pointer_array, (fields_list.elements +
select_lex->with_sum_func +
og_num)) ||
@@ -1296,7 +1298,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, ulong select_options,
select_result *result, SELECT_LEX_UNIT *unit,
- SELECT_LEX *select_lex, bool fake_select_lex)
+ SELECT_LEX *select_lex, bool fake_select_lex, bool tables_OK)
{
int err;
bool free_join= 1;
@@ -1323,7 +1325,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
if (join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
- select_lex, unit, fake_select_lex))
+ select_lex, unit, fake_select_lex, tables_OK))
{
DBUG_RETURN(-1);
}
@@ -8065,7 +8067,7 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type,
select_lex->having,
(ORDER*) thd->lex.proc_list.first,
select_lex->options | thd->options | SELECT_DESCRIBE,
- result, unit, select_lex, 0);
+ result, unit, select_lex, 0, 0);
DBUG_RETURN(res);
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 934a3b72734..38e8a5d96f9 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -256,7 +256,7 @@ class JOIN :public Sql_alloc
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, SELECT_LEX *select,
- SELECT_LEX_UNIT *unit, bool fake_select_lex);
+ SELECT_LEX_UNIT *unit, bool fake_select_lex, bool tables_OK);
int optimize();
int reinit();
void exec();
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 259f6dbb4b5..dde0251d0c2 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -24,11 +24,12 @@
#include "mysql_priv.h"
#include "sql_select.h"
-int mysql_union(THD *thd, LEX *lex, select_result *result,SELECT_LEX_UNIT *unit)
+int mysql_union(THD *thd, LEX *lex, select_result *result,
+ SELECT_LEX_UNIT *unit, bool tables_OK)
{
DBUG_ENTER("mysql_union");
int res= 0;
- if (!(res= unit->prepare(thd, result)))
+ if (!(res= unit->prepare(thd, result, tables_OK)))
res= unit->exec();
res|= unit->cleanup();
DBUG_RETURN(res);
@@ -107,7 +108,8 @@ bool select_union::flush()
return 0;
}
-int st_select_lex_unit::prepare(THD *thd, select_result *result)
+int st_select_lex_unit::prepare(THD *thd, select_result *result,
+ bool tables_OK)
{
DBUG_ENTER("st_select_lex_unit::prepare");
@@ -121,7 +123,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
SELECT_LEX *sl;
- thd->lex.current_select=first_select();
+ thd->lex.current_select= sl= first_select();
/* Global option */
if (((void*)(global_parameters)) == ((void*)this))
{
@@ -130,20 +132,28 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
if (found_rows_for_union)
first_select()->options ^= OPTION_FOUND_ROWS;
}
- item_list.empty();
+ if (tables_OK)
{
- Item *item;
- List_iterator<Item> it(first_select()->item_list);
+ item_list= sl->item_list;
+ }
+ else
+ {
+ item_list.empty();
TABLE_LIST *first_table= (TABLE_LIST*) first_select()->table_list.first;
- /* Create a list of items that will be in the result set */
- while ((item= it++))
- if (item_list.push_back(item))
- goto err;
- if (setup_wild(thd, first_table, item_list, 0,
- first_select()->with_wild) ||
- setup_fields(thd, 0, first_table, item_list, 0, 0, 1))
+ if (setup_tables(first_table) ||
+ setup_wild(thd, first_table, sl->item_list, 0, sl->with_wild))
+ goto err;
+
+ item_list= sl->item_list;
+ sl->with_wild= 0;
+ if (setup_ref_array(thd, &sl->ref_pointer_array,
+ (item_list.elements + sl->with_sum_func +
+ sl->order_list.elements + sl->group_list.elements)) ||
+ setup_fields(thd, sl->ref_pointer_array, first_table, item_list,
+ 0, 0, 1))
goto err;
+ tables_OK= 1;
}
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
@@ -191,11 +201,25 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
(ORDER*) sl->group_list.first,
sl->having,
(ORDER*) NULL,
- sl, this, 0);
+ sl, this, 0, tables_OK);
+ tables_OK= 0;
if (res | thd->fatal_error)
goto err;
}
+ item_list.empty();
thd->lex.current_select= lex_select_save;
+ {
+ List_iterator<Item> it(first_select()->item_list);
+ Field **field;
+
+ for (field= table->field; *field; field++)
+ {
+ (void) it++;
+ if (item_list.push_back(new Item_field(*field)))
+ DBUG_RETURN(-1);
+ }
+ }
+
DBUG_RETURN(res | thd->fatal_error);
err:
thd->lex.current_select= lex_select_save;
@@ -260,9 +284,6 @@ int st_select_lex_unit::exec()
thd->lex.current_select = first_select();
res =-1;
{
- /* Create a list of fields in the temporary table */
- List_iterator<Item> it(item_list);
- Field **field;
#if 0
List<Item_func_match> ftfunc_list;
ftfunc_list.empty();
@@ -272,11 +293,6 @@ int st_select_lex_unit::exec()
thd->lex.select_lex.ftfunc_list= &empty_list;
#endif
- for (field=table->field ; *field ; field++)
- {
- (void) it++;
- (void) it.replace(new Item_field(*field));
- }
if (!thd->fatal_error) // Check if EOM
{
SELECT_LEX *sl=thd->lex.current_select->master_unit()->first_select();
@@ -292,7 +308,7 @@ int st_select_lex_unit::exec()
global_parameters->order_list.elements,
(ORDER*)global_parameters->order_list.first,
(ORDER*) NULL, NULL, (ORDER*) NULL,
- thd->options, result, this, first_select(), 1);
+ thd->options, result, this, first_select(), 1, 0);
if (found_rows_for_union && !res)
thd->limit_found_rows = (ulonglong)table->file->records;
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f2f1c0da0d9..8836564c6d4 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -428,7 +428,7 @@ int mysql_multi_update(THD *thd,
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
(ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE,
- result, unit, select_lex, 0);
+ result, unit, select_lex, 0, 0);
delete result;
DBUG_RETURN(res);
}