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
This commit is contained in:
unknown 2002-03-26 15:06:05 +02:00
parent c9ba7c5f21
commit 2ec108107d
13 changed files with 208 additions and 12 deletions

View File

@ -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

View File

@ -0,0 +1,10 @@
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;

View File

@ -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;

View File

@ -0,0 +1,7 @@
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;

View File

@ -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;

View File

@ -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);

View File

@ -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); }
}; };

121
sql/sql_derived.cc Normal file
View File

@ -0,0 +1,121 @@
/* 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);
}

View File

@ -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 {
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 @@ public:
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 {
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;

View File

@ -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)
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)
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)
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,
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,
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));

View File

@ -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)
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,

View File

@ -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 */ {}

View File

@ -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