Commit 753c8112 authored by unknown's avatar unknown

Derived tables !


mysql-test/r/union.result:
  small bug fixes in unions
BitKeeper/etc/ignore:
  Added Docs/manual.texi.orig Docs/manual.texi.rej to the ignore list
mysql-test/t/union.test:
  test for a bug fix in union's
sql/sql_union.cc:
  bug fix for unions
parent 08ba9d73
...@@ -466,3 +466,5 @@ vio/viotest-ssl ...@@ -466,3 +466,5 @@ vio/viotest-ssl
libmysqld/gstream.cc libmysqld/gstream.cc
libmysqld/spatial.cc libmysqld/spatial.cc
sql/sql_yacc.yy.orig sql/sql_yacc.yy.orig
Docs/manual.texi.orig
Docs/manual.texi.rej
drop table if exists t1,t2;
CREATE TABLE t1 (a int not null, b char (10) not null);
insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
CREATE TABLE t2 (a int not null, b char (10) not null);
insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e');
select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a = t3.y;
a y
3 3
3 3
drop table if exists t1.t2;
...@@ -177,4 +177,14 @@ a ...@@ -177,4 +177,14 @@ a
11 11
12 12
13 13
(select * from t1 limit 2) union (select * from t2 limit 20,3);
a
1
2
set SQL_SELECT_LIMIT=2;
(select * from t1 limit 2) union (select * from t2 limit 3);
a
1
2
set SQL_SELECT_LIMIT=DEFAULT;
drop table t1,t2; drop table t1,t2;
drop table if exists t1,t2;
CREATE TABLE t1 (a int not null, b char (10) not null);
insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
CREATE TABLE t2 (a int not null, b char (10) not null);
insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e');
select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a = t3.y;
drop table if exists t1.t2;
\ No newline at end of file
...@@ -84,4 +84,8 @@ insert into t1 values (1),(2),(3),(4),(5); ...@@ -84,4 +84,8 @@ insert into t1 values (1),(2),(3),(4),(5);
insert into t2 values (11),(12),(13),(14),(15); insert into t2 values (11),(12),(13),(14),(15);
(select * from t1 limit 2) union (select * from t2 limit 3) limit 4; (select * from t1 limit 2) union (select * from t2 limit 3) limit 4;
(select * from t1 limit 2) union (select * from t2 limit 3); (select * from t1 limit 2) union (select * from t2 limit 3);
(select * from t1 limit 2) union (select * from t2 limit 20,3);
set SQL_SELECT_LIMIT=2;
(select * from t1 limit 2) union (select * from t2 limit 3);
set SQL_SELECT_LIMIT=DEFAULT;
drop table t1,t2; drop table t1,t2;
...@@ -335,6 +335,7 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds, ...@@ -335,6 +335,7 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param, ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
ulong select_type,select_result *result); ulong select_type,select_result *result);
int mysql_union(THD *thd,LEX *lex,select_result *result); int mysql_union(THD *thd,LEX *lex,select_result *result);
int mysql_derived(THD *thd,LEX *lex,SELECT_LEX *s, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field, Item_result_field ***copy_func, Field **from_field,
bool group,bool modify_item); bool group,bool modify_item);
......
...@@ -659,15 +659,17 @@ class Table_ident :public Sql_alloc { ...@@ -659,15 +659,17 @@ class Table_ident :public Sql_alloc {
public: public:
LEX_STRING db; LEX_STRING db;
LEX_STRING table; LEX_STRING table;
SELECT_LEX *sel;
inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force) inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force)
:table(table_arg) :table(table_arg), sel((SELECT_LEX *)0)
{ {
if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA)) if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA))
db.str=0; db.str=0;
else else
db= db_arg; db= db_arg;
} }
inline Table_ident(LEX_STRING table_arg) :table(table_arg) {db.str=0;} inline Table_ident(LEX_STRING table_arg) :table(table_arg), sel((SELECT_LEX *)0) {db.str=0;}
inline Table_ident(SELECT_LEX *s) : sel(s) {db.str=0; table.str=(char *)""; table.length=0;}
inline void change_db(char *db_name) inline void change_db(char *db_name)
{ db.str= db_name; db.length=(uint) strlen(db_name); } { db.str= db_name; db.length=(uint) strlen(db_name); }
}; };
......
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Derived tables
These were introduced by Monty and Sinisa <sinisa@mysql.com>
*/
#include "mysql_priv.h"
#include "sql_select.h"
#include "sql_acl.h"
static const char *any_db="*any*"; // Special symbol for check_access
int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
{
SELECT_LEX *sl=s;
List<Item> item_list;
TABLE *table;
int res;
select_union *derived_result;
TABLE_LIST *tables=(TABLE_LIST *)sl->table_list.first;
TMP_TABLE_PARAM tmp_table_param;
DBUG_ENTER("mysql_derived");
if (tables)
res=check_table_access(thd,SELECT_ACL, tables);
else
res=check_access(thd, SELECT_ACL, any_db);
if (res)
DBUG_RETURN(-1);
for (TABLE_LIST *cursor= (TABLE_LIST *)tables;
cursor;
cursor=cursor->next)
{
if (cursor->derived)
{
res=mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor);
if (res) DBUG_RETURN(res);
}
}
Item *item;
List_iterator<Item> it(sl->item_list);
while ((item= it++))
item_list.push_back(item);
if (!(res=open_and_lock_tables(thd,tables)))
{
if (tables && setup_fields(thd,tables,item_list,0,0,1))
{
res=-1;
goto exit;
}
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements;
if (!(table=create_tmp_table(thd, &tmp_table_param, sl->item_list,
(ORDER*) 0, 0, 1, 0,
(sl->options | thd->options | TMP_TABLE_ALL_COLUMNS))))
{
res=-1;
goto exit;
}
if ((derived_result=new select_union(table)))
{
thd->offset_limit=sl->offset_limit;
thd->select_limit=sl->select_limit+sl->offset_limit;
if (thd->select_limit < sl->select_limit)
thd->select_limit= HA_POS_ERROR;
if (thd->select_limit == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
res=mysql_select(thd, tables, sl->item_list,
sl->where, (ORDER *) sl->order_list.first,
(ORDER*) sl->group_list.first,
sl->having, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK,
derived_result);
if (!res)
{
// Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables
if (derived_result->flush())
res=1;
else
{
t->real_name=table->real_name;
t->table=table;
sl->prev->next=sl->next;
t->derived=(SELECT_LEX *)0; // just in case ...
if (!sl->next) lex->last_select = sl;
}
}
delete derived_result;
}
if (res)
free_tmp_table(thd,table);
exit:
close_thread_tables(thd);
if (res > 0)
send_error(&thd->net, ER_UNKNOWN_COM_ERROR); // temporary only ...
}
DBUG_RETURN(res);
}
...@@ -101,7 +101,7 @@ typedef struct st_lex_master_info ...@@ -101,7 +101,7 @@ typedef struct st_lex_master_info
} LEX_MASTER_INFO; } LEX_MASTER_INFO;
enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, NOT_A_SELECT}; enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, NOT_A_SELECT, DERIVED_TABLE_TYPE};
/* The state of the lex parsing for selects */ /* The state of the lex parsing for selects */
...@@ -120,7 +120,7 @@ typedef struct st_select_lex { ...@@ -120,7 +120,7 @@ typedef struct st_select_lex {
List<Item_func_match> ftfunc_list; List<Item_func_match> ftfunc_list;
uint in_sum_expr, sort_default; uint in_sum_expr, sort_default;
bool create_refs, braces; bool create_refs, braces;
st_select_lex *next; st_select_lex *next, *prev;
} SELECT_LEX; } SELECT_LEX;
...@@ -141,7 +141,7 @@ class Set_option :public Sql_alloc { ...@@ -141,7 +141,7 @@ class Set_option :public Sql_alloc {
typedef struct st_lex { typedef struct st_lex {
uint yylineno,yytoklen; /* Simulate lex */ uint yylineno,yytoklen; /* Simulate lex */
LEX_YYSTYPE yylval; LEX_YYSTYPE yylval;
SELECT_LEX select_lex, *select; SELECT_LEX select_lex, *select, *last_select;
uchar *ptr,*tok_start,*tok_end,*end_of_query; uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name; char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */ char *backup_dir; /* For RESTORE/BACKUP */
...@@ -185,7 +185,7 @@ typedef struct st_lex { ...@@ -185,7 +185,7 @@ typedef struct st_lex {
uint grant,grant_tot_col,which_columns, union_option, mqh; uint grant,grant_tot_col,which_columns, union_option, mqh;
thr_lock_type lock_option; thr_lock_type lock_option;
bool drop_primary,drop_if_exists,local_file; bool drop_primary,drop_if_exists,local_file;
bool in_comment,ignore_space,verbose,simple_alter, option_type; bool in_comment,ignore_space,verbose,simple_alter, option_type, derived_tables;
} LEX; } LEX;
......
...@@ -1226,6 +1226,14 @@ mysql_execute_command(void) ...@@ -1226,6 +1226,14 @@ mysql_execute_command(void)
Skip if we are in the slave thread, some table rules have been given Skip if we are in the slave thread, some table rules have been given
and the table list says the query should not be replicated and the table list says the query should not be replicated
*/ */
if (lex->derived_tables)
{
for (TABLE_LIST *cursor= tables;
cursor;
cursor=cursor->next)
if (cursor->derived && mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor))
DBUG_VOID_RETURN;
}
if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) || if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) ||
(table_rules_on && tables && thd->slave_thread && (table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables))) !tables_ok(thd,tables)))
...@@ -2648,7 +2656,7 @@ mysql_init_query(THD *thd) ...@@ -2648,7 +2656,7 @@ mysql_init_query(THD *thd)
thd->lex.value_list.empty(); thd->lex.value_list.empty();
thd->lex.select_lex.table_list.elements=0; thd->lex.select_lex.table_list.elements=0;
thd->free_list=0; thd->lex.union_option=0; thd->free_list=0; thd->lex.union_option=0;
thd->lex.select = &thd->lex.select_lex; thd->lex.select = thd->lex.last_select = &thd->lex.select_lex;
thd->lex.select_lex.table_list.first=0; thd->lex.select_lex.table_list.first=0;
thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first; thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first;
thd->lex.select_lex.next=0; thd->lex.select_lex.next=0;
...@@ -2675,7 +2683,7 @@ mysql_init_select(LEX *lex) ...@@ -2675,7 +2683,7 @@ mysql_init_select(LEX *lex)
select_lex->order_list.next= (byte**) &select_lex->order_list.first; select_lex->order_list.next= (byte**) &select_lex->order_list.first;
select_lex->group_list.first=0; select_lex->group_list.first=0;
select_lex->group_list.next= (byte**) &select_lex->group_list.first; select_lex->group_list.next= (byte**) &select_lex->group_list.first;
select_lex->next = (SELECT_LEX *)NULL; select_lex->next = select_lex->prev = (SELECT_LEX *)NULL;
} }
bool bool
...@@ -2684,8 +2692,9 @@ mysql_new_select(LEX *lex) ...@@ -2684,8 +2692,9 @@ mysql_new_select(LEX *lex)
SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX)); SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
if (!select_lex) if (!select_lex)
return 1; return 1;
lex->select=lex->last_select;
lex->select->next=select_lex; lex->select->next=select_lex;
lex->select=select_lex; lex->select=lex->last_select=select_lex;
select_lex->table_list.next= (byte**) &select_lex->table_list.first; select_lex->table_list.next= (byte**) &select_lex->table_list.first;
select_lex->item_list.empty(); select_lex->item_list.empty();
select_lex->when_list.empty(); select_lex->when_list.empty();
...@@ -3099,7 +3108,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, ...@@ -3099,7 +3108,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
DBUG_RETURN(0); // End of memory DBUG_RETURN(0); // End of memory
alias_str= alias ? alias->str : table->table.str; alias_str= alias ? alias->str : table->table.str;
if (table->table.length > NAME_LEN || if (table->table.length > NAME_LEN ||
check_table_name(table->table.str,table->table.length) || (table->table.length && check_table_name(table->table.str,table->table.length)) ||
table->db.str && check_db_name(table->db.str)) table->db.str && check_db_name(table->db.str))
{ {
net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str); net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
...@@ -3122,6 +3131,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, ...@@ -3122,6 +3131,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
ptr->real_name=table->table.str; ptr->real_name=table->table.str;
ptr->lock_type=flags; ptr->lock_type=flags;
ptr->updating=updating; ptr->updating=updating;
ptr->derived=(SELECT_LEX *)table->sel;
if (use_index) if (use_index)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index, ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
sizeof(*use_index)); sizeof(*use_index));
......
...@@ -126,8 +126,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -126,8 +126,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
} }
union_result->save_time_stamp=!describe; union_result->save_time_stamp=!describe;
for (sl=lex->select=&lex->select_lex;sl;sl=lex->select=sl->next) for (sl= &lex->select_lex; sl; sl=sl->next)
{ {
lex->select=sl;
thd->offset_limit=sl->offset_limit; thd->offset_limit=sl->offset_limit;
thd->select_limit=sl->select_limit+sl->offset_limit; thd->select_limit=sl->select_limit+sl->offset_limit;
if (thd->select_limit < sl->select_limit) if (thd->select_limit < sl->select_limit)
...@@ -185,7 +186,10 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -185,7 +186,10 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
thd->options&= ~OPTION_FOUND_ROWS; thd->options&= ~OPTION_FOUND_ROWS;
} }
else else
thd->select_limit= HA_POS_ERROR; // no limit {
thd->offset_limit= 0;
thd->select_limit= thd->default_select_limit;
}
if (describe) if (describe)
thd->select_limit= HA_POS_ERROR; // no limit thd->select_limit= HA_POS_ERROR; // no limit
res=mysql_select(thd,&result_table_list, res=mysql_select(thd,&result_table_list,
......
...@@ -2099,6 +2099,30 @@ join_table: ...@@ -2099,6 +2099,30 @@ join_table:
} }
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}' | '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; } { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
| '(' SELECT_SYM select_part3 ')' opt_table_alias
{
LEX *lex=Lex;
lex->select=lex->select->prev;
if (!($$=add_table_to_list(new Table_ident(Lex->last_select),$5,0,TL_UNLOCK)))
YYABORT;
}
select_part3:
{
LEX *lex=Lex;
lex->derived_tables=true;
SELECT_LEX *tmp=lex->select;
if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex))
YYABORT;
mysql_init_select(lex);
lex->select->linkage=DERIVED_TABLE_TYPE;
lex->select->prev=tmp;
}
select_options select_item_list select_intoto
select_intoto:
limit_clause {}
| select_from
opt_outer: opt_outer:
/* empty */ {} /* empty */ {}
......
...@@ -147,6 +147,7 @@ typedef struct st_table_list { ...@@ -147,6 +147,7 @@ typedef struct st_table_list {
bool straight; /* optimize with prev table */ bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */ bool updating; /* for replicate-do/ignore table */
bool shared; /* Used twice in union */ bool shared; /* Used twice in union */
void *derived;
} TABLE_LIST; } TABLE_LIST;
typedef struct st_open_table_list typedef struct st_open_table_list
......
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