mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Derived tables !
This commit is contained in:
parent
8a7cd0e4df
commit
22d4f87e69
13 changed files with 208 additions and 12 deletions
|
@ -466,3 +466,5 @@ vio/viotest-ssl
|
|||
libmysqld/gstream.cc
|
||||
libmysqld/spatial.cc
|
||||
sql/sql_yacc.yy.orig
|
||||
Docs/manual.texi.orig
|
||||
Docs/manual.texi.rej
|
||||
|
|
10
mysql-test/r/derived.result
Normal file
10
mysql-test/r/derived.result
Normal 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;
|
|
@ -177,4 +177,14 @@ a
|
|||
11
|
||||
12
|
||||
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;
|
||||
|
|
7
mysql-test/t/derived.test
Normal file
7
mysql-test/t/derived.test
Normal 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;
|
|
@ -84,4 +84,8 @@ insert into t1 values (1),(2),(3),(4),(5);
|
|||
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);
|
||||
(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;
|
||||
|
|
|
@ -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,
|
||||
ulong select_type,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,
|
||||
Item_result_field ***copy_func, Field **from_field,
|
||||
bool group,bool modify_item);
|
||||
|
|
|
@ -659,15 +659,17 @@ class Table_ident :public Sql_alloc {
|
|||
public:
|
||||
LEX_STRING db;
|
||||
LEX_STRING table;
|
||||
SELECT_LEX *sel;
|
||||
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))
|
||||
db.str=0;
|
||||
else
|
||||
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)
|
||||
{ db.str= db_name; db.length=(uint) strlen(db_name); }
|
||||
};
|
||||
|
|
121
sql/sql_derived.cc
Normal file
121
sql/sql_derived.cc
Normal 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);
|
||||
}
|
|
@ -101,7 +101,7 @@ typedef struct st_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 */
|
||||
|
||||
|
@ -120,7 +120,7 @@ typedef struct st_select_lex {
|
|||
List<Item_func_match> ftfunc_list;
|
||||
uint in_sum_expr, sort_default;
|
||||
bool create_refs, braces;
|
||||
st_select_lex *next;
|
||||
st_select_lex *next, *prev;
|
||||
} SELECT_LEX;
|
||||
|
||||
|
||||
|
@ -141,7 +141,7 @@ public:
|
|||
typedef struct st_lex {
|
||||
uint yylineno,yytoklen; /* Simulate lex */
|
||||
LEX_YYSTYPE yylval;
|
||||
SELECT_LEX select_lex, *select;
|
||||
SELECT_LEX select_lex, *select, *last_select;
|
||||
uchar *ptr,*tok_start,*tok_end,*end_of_query;
|
||||
char *length,*dec,*change,*name;
|
||||
char *backup_dir; /* For RESTORE/BACKUP */
|
||||
|
@ -185,7 +185,7 @@ typedef struct st_lex {
|
|||
uint grant,grant_tot_col,which_columns, union_option, mqh;
|
||||
thr_lock_type lock_option;
|
||||
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;
|
||||
|
||||
|
|
|
@ -1226,6 +1226,14 @@ mysql_execute_command(void)
|
|||
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
|
||||
*/
|
||||
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)) ||
|
||||
(table_rules_on && tables && thd->slave_thread &&
|
||||
!tables_ok(thd,tables)))
|
||||
|
@ -2648,7 +2656,7 @@ mysql_init_query(THD *thd)
|
|||
thd->lex.value_list.empty();
|
||||
thd->lex.select_lex.table_list.elements=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.next= (byte**) &thd->lex.select_lex.table_list.first;
|
||||
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->group_list.first=0;
|
||||
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
|
||||
|
@ -2684,8 +2692,9 @@ mysql_new_select(LEX *lex)
|
|||
SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
|
||||
if (!select_lex)
|
||||
return 1;
|
||||
lex->select=lex->last_select;
|
||||
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->item_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
|
||||
alias_str= alias ? alias->str : table->table.str;
|
||||
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))
|
||||
{
|
||||
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->lock_type=flags;
|
||||
ptr->updating=updating;
|
||||
ptr->derived=(SELECT_LEX *)table->sel;
|
||||
if (use_index)
|
||||
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
|
||||
sizeof(*use_index));
|
||||
|
|
|
@ -126,8 +126,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
|
|||
}
|
||||
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->select_limit=sl->select_limit+sl->offset_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;
|
||||
}
|
||||
else
|
||||
thd->select_limit= HA_POS_ERROR; // no limit
|
||||
{
|
||||
thd->offset_limit= 0;
|
||||
thd->select_limit= thd->default_select_limit;
|
||||
}
|
||||
if (describe)
|
||||
thd->select_limit= HA_POS_ERROR; // no limit
|
||||
res=mysql_select(thd,&result_table_list,
|
||||
|
|
|
@ -2099,6 +2099,30 @@ join_table:
|
|||
}
|
||||
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
|
||||
{ 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:
|
||||
/* empty */ {}
|
||||
|
|
|
@ -147,6 +147,7 @@ typedef struct st_table_list {
|
|||
bool straight; /* optimize with prev table */
|
||||
bool updating; /* for replicate-do/ignore table */
|
||||
bool shared; /* Used twice in union */
|
||||
void *derived;
|
||||
} TABLE_LIST;
|
||||
|
||||
typedef struct st_open_table_list
|
||||
|
|
Loading…
Reference in a new issue