summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorigor@rurik.mysql.com <>2006-04-21 00:36:20 -0700
committerigor@rurik.mysql.com <>2006-04-21 00:36:20 -0700
commit37ac7822065195d0bf7061d947306f2481c7191c (patch)
tree12430c67bf33ee7014ca554819c453fb616380b5 /sql
parent4cbad914ca5a4978e21e424f0c68cbb3185e0073 (diff)
parentfd3e9241647e70139a44baca9be5e336bc22e6da (diff)
downloadmariadb-git-37ac7822065195d0bf7061d947306f2481c7191c.tar.gz
Merge rurik.mysql.com:/home/igor/dev/mysql-4.1-0
into rurik.mysql.com:/home/igor/dev/mysql-5.0-0
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc102
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_yacc.yy24
5 files changed, 90 insertions, 41 deletions
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 8512c075f69..34e7ee969b6 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -454,6 +454,7 @@ public:
void print(String *str);
+ bool add_fake_select_lex(THD *thd);
void init_prepare_fake_select_lex(THD *thd);
inline bool is_prepared() { return prepared; }
bool change_result(select_subselect *result, select_subselect *old_result);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 38eadb5a738..3752fc62d02 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5544,48 +5544,17 @@ mysql_new_select(LEX *lex, bool move_down)
}
else
{
- Name_resolution_context *outer_context;
if (lex->current_select->order_list.first && !lex->current_select->braces)
{
my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
DBUG_RETURN(1);
}
select_lex->include_neighbour(lex->current_select);
- /*
- we are not sure that we have one level of SELECTs above, so we take
- outer_context address from first select of unit
- */
- outer_context=
- select_lex->master_unit()->first_select()->context.outer_context;
- SELECT_LEX_UNIT *unit= select_lex->master_unit();
- SELECT_LEX *fake= unit->fake_select_lex;
- if (!fake)
- {
- /*
- as far as we included SELECT_LEX for UNION unit should have
- fake SELECT_LEX for UNION processing
- */
- if (!(fake= unit->fake_select_lex= new (thd->mem_root) SELECT_LEX()))
- DBUG_RETURN(1);
- fake->include_standalone(unit,
- (SELECT_LEX_NODE**)&unit->fake_select_lex);
- fake->select_number= INT_MAX;
- fake->parent_lex= lex; /* Used in init_query. */
- fake->make_empty_select();
- fake->linkage= GLOBAL_OPTIONS_TYPE;
- fake->select_limit= 0;
-
- fake->context.outer_context= outer_context;
- /* allow item list resolving in fake select for ORDER BY */
- fake->context.resolve_in_select_list= TRUE;
- fake->context.select_lex= fake;
- /*
- Remove the name resolution context of the fake select from the
- context stack.
- */
- lex->pop_context();
- }
- select_lex->context.outer_context= outer_context;
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
+ DBUG_RETURN(1);
+ select_lex->context.outer_context=
+ unit->first_select()->context.outer_context;
}
select_lex->master_unit()->global_parameters= select_lex;
@@ -6358,6 +6327,67 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
/*
+ Create a fake SELECT_LEX for a unit
+
+ SYNOPSIS:
+ add_fake_select_lex()
+ thd thread handle
+
+ DESCRIPTION
+ The method create a fake SELECT_LEX object for a unit.
+ This object is created for any union construct containing a union
+ operation and also for any single select union construct of the form
+ (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ...
+ or of the form
+ (SELECT ... ORDER BY LIMIT n) ORDER BY ...
+
+ NOTES
+ The object is used to retrieve rows from the temporary table
+ where the result on the union is obtained.
+
+ RETURN VALUES
+ 1 on failure to create the object
+ 0 on success
+*/
+
+bool st_select_lex_unit::add_fake_select_lex(THD *thd)
+{
+ SELECT_LEX *first_sl= first_select();
+ DBUG_ENTER("add_fake_select_lex");
+ DBUG_ASSERT(!fake_select_lex);
+
+ if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX()))
+ DBUG_RETURN(1);
+ fake_select_lex->include_standalone(this,
+ (SELECT_LEX_NODE**)&fake_select_lex);
+ fake_select_lex->select_number= INT_MAX;
+ fake_select_lex->make_empty_select();
+ fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
+ fake_select_lex->select_limit= 0;
+
+ fake_select_lex->context.outer_context= first_sl->context.outer_context;
+ /* allow item list resolving in fake select for ORDER BY */
+ fake_select_lex->context.resolve_in_select_list= TRUE;
+ fake_select_lex->context.select_lex= fake_select_lex;
+
+ if (!first_sl->next_select())
+ {
+ /*
+ This works only for
+ (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m],
+ (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m]
+ just before the parser starts processing order_list
+ */
+ global_parameters= fake_select_lex;
+ fake_select_lex->no_table_names_allowed= 1;
+ thd->lex->current_select= fake_select_lex;
+ }
+ thd->lex->pop_context();
+ DBUG_RETURN(0);
+}
+
+
+/*
Push a new name resolution context for a JOIN ... ON clause to the
context stack of a query block.
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0211539e784..47c5281b258 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -224,7 +224,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
register SELECT_LEX *select_lex = &lex->select_lex;
DBUG_ENTER("handle_select");
- if (select_lex->next_select())
+ if (select_lex->next_select() || select_lex->master_unit()->fake_select_lex)
res= mysql_union(thd, lex, result, &lex->unit, setup_tables_done_option);
else
{
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index dee88af7d83..68036f76e96 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -202,7 +202,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= sl= first_sl;
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
- is_union= test(first_sl->next_select());
+ is_union= test(first_select->next_select() || fake_select_lex);
/* Global option */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 31dcb982cbb..a911ad41cd7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5697,14 +5697,32 @@ order_clause:
ORDER_SYM BY
{
LEX *lex=Lex;
- if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- lex->current_select->olap !=
- UNSPECIFIED_OLAP_TYPE)
+ SELECT_LEX *sel= lex->current_select;
+ SELECT_LEX_UNIT *unit= sel-> master_unit();
+ if (sel->linkage != GLOBAL_OPTIONS_TYPE &&
+ sel->olap != UNSPECIFIED_OLAP_TYPE)
{
my_error(ER_WRONG_USAGE, MYF(0),
"CUBE/ROLLUP", "ORDER BY");
YYABORT;
}
+ if (lex->sql_command != SQLCOM_ALTER_TABLE && !unit->fake_select_lex)
+ {
+ /*
+ A query of the of the form (SELECT ...) ORDER BY order_list is
+ executed in the same way as the query
+ SELECT ... ORDER BY order_list
+ unless the SELECT construct contains ORDER BY or LIMIT clauses.
+ Otherwise we create a fake SELECT_LEX if it has not been created
+ yet.
+ */
+ SELECT_LEX *first_sl= unit->first_select();
+ if (!first_sl->next_select() &&
+ (first_sl->order_list.elements ||
+ first_sl->select_limit != HA_POS_ERROR) &&
+ unit->add_fake_select_lex(lex->thd))
+ YYABORT;
+ }
} order_list;
order_list: