mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Fix for bug #2: Add support for TABLE.* in SELECT statements. (CVS 518)
FossilOrigin-Name: c2320eabfe44d6eb05c02b76547e5bd48a29943c
This commit is contained in:
@ -14,7 +14,7 @@
|
||||
** the parser. Lemon will also generate a header file containing
|
||||
** numeric codes for all of the tokens.
|
||||
**
|
||||
** @(#) $Id: parse.y,v 1.59 2002/03/30 15:26:51 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.60 2002/04/04 02:10:57 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@ -255,6 +255,11 @@ selcollist(A) ::= sclp(P) expr(X) as ids(Y). {A = sqliteExprListAppend(P,X,&Y);}
|
||||
selcollist(A) ::= sclp(P) STAR. {
|
||||
A = sqliteExprListAppend(P, sqliteExpr(TK_ALL, 0, 0, 0), 0);
|
||||
}
|
||||
selcollist(A) ::= sclp(P) ids(X) DOT STAR. {
|
||||
Expr *pRight = sqliteExpr(TK_ALL, 0, 0, 0);
|
||||
Expr *pLeft = sqliteExpr(TK_ID, 0, 0, &X);
|
||||
A = sqliteExprListAppend(P, sqliteExpr(TK_DOT, pLeft, pRight, 0), 0);
|
||||
}
|
||||
as ::= .
|
||||
as ::= AS.
|
||||
|
||||
|
72
src/select.c
72
src/select.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.77 2002/03/23 00:31:29 drh Exp $
|
||||
** $Id: select.c,v 1.78 2002/04/04 02:10:57 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -355,16 +355,16 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
||||
** (1) Fill in the pTabList->a[].pTab fields in the IdList that
|
||||
** defines the set of tables that should be scanned.
|
||||
**
|
||||
** (2) If the columns to be extracted variable (pEList) is NULL
|
||||
** (meaning that a "*" was used in the SQL statement) then
|
||||
** create a fake pEList containing the names of all columns
|
||||
** of all tables.
|
||||
** (2) Scan the list of columns in the result set (pEList) looking
|
||||
** for instances of the "*" operator or the TABLE.* operator.
|
||||
** If found, expand each "*" to be every column in every table
|
||||
** and TABLE.* to be every column in TABLE.
|
||||
**
|
||||
** Return 0 on success. If there are problems, leave an error message
|
||||
** in pParse and return non-zero.
|
||||
*/
|
||||
static int fillInColumnList(Parse *pParse, Select *p){
|
||||
int i, j, k;
|
||||
int i, j, k, rc;
|
||||
IdList *pTabList;
|
||||
ExprList *pEList;
|
||||
Table *pTab;
|
||||
@ -410,42 +410,72 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
||||
}
|
||||
|
||||
/* For every "*" that occurs in the column list, insert the names of
|
||||
** all columns in all tables. The parser inserted a special expression
|
||||
** all columns in all tables. And for every TABLE.* insert the names
|
||||
** of all columns in TABLE. The parser inserted a special expression
|
||||
** with the TK_ALL operator for each "*" that it found in the column list.
|
||||
** The following code just has to locate the TK_ALL expressions and expand
|
||||
** each one to the list of all columns in all tables.
|
||||
**
|
||||
** The first loop just checks to see if there are any "*" operators
|
||||
** that need expanding.
|
||||
*/
|
||||
for(k=0; k<pEList->nExpr; k++){
|
||||
if( pEList->a[k].pExpr->op==TK_ALL ) break;
|
||||
Expr *pE = pEList->a[k].pExpr;
|
||||
if( pE->op==TK_ALL ) break;
|
||||
if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL
|
||||
&& pE->pLeft && pE->pLeft->op==TK_ID ) break;
|
||||
}
|
||||
rc = 0;
|
||||
if( k<pEList->nExpr ){
|
||||
/*
|
||||
** If we get here it means the result set contains one or more "*"
|
||||
** operators that need to be expanded. Loop through each expression
|
||||
** in the result set and expand them one by one.
|
||||
*/
|
||||
struct ExprList_item *a = pEList->a;
|
||||
ExprList *pNew = 0;
|
||||
for(k=0; k<pEList->nExpr; k++){
|
||||
if( a[k].pExpr->op!=TK_ALL ){
|
||||
Expr *pE = a[k].pExpr;
|
||||
if( pE->op!=TK_ALL &&
|
||||
(pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
|
||||
/* This particular expression does not need to be expanded.
|
||||
*/
|
||||
pNew = sqliteExprListAppend(pNew, a[k].pExpr, 0);
|
||||
pNew->a[pNew->nExpr-1].zName = a[k].zName;
|
||||
a[k].pExpr = 0;
|
||||
a[k].zName = 0;
|
||||
}else{
|
||||
/* This expression is a "*" or a "TABLE.*" and needs to be
|
||||
** expanded. */
|
||||
int tableSeen = 0; /* Set to 1 when TABLE matches */
|
||||
Token *pName; /* text of name of TABLE */
|
||||
if( pE->op==TK_DOT && pE->pLeft ){
|
||||
pName = &pE->pLeft->token;
|
||||
}else{
|
||||
pName = 0;
|
||||
}
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
Table *pTab = pTabList->a[i].pTab;
|
||||
char *zTabName = pTabList->a[i].zAlias;
|
||||
if( zTabName==0 || zTabName[0]==0 ){
|
||||
zTabName = pTab->zName;
|
||||
}
|
||||
if( pName && (zTabName==0 || zTabName[0]==0 ||
|
||||
sqliteStrNICmp(pName->z, zTabName, pName->n)!=0) ){
|
||||
continue;
|
||||
}
|
||||
tableSeen = 1;
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
Expr *pExpr, *pLeft, *pRight;
|
||||
pRight = sqliteExpr(TK_ID, 0, 0, 0);
|
||||
if( pRight==0 ) break;
|
||||
pRight->token.z = pTab->aCol[j].zName;
|
||||
pRight->token.n = strlen(pTab->aCol[j].zName);
|
||||
if( pTab->zName ){
|
||||
if( zTabName ){
|
||||
pLeft = sqliteExpr(TK_ID, 0, 0, 0);
|
||||
if( pLeft==0 ) break;
|
||||
if( pTabList->a[i].zAlias && pTabList->a[i].zAlias[0] ){
|
||||
pLeft->token.z = pTabList->a[i].zAlias;
|
||||
pLeft->token.n = strlen(pTabList->a[i].zAlias);
|
||||
}else{
|
||||
pLeft->token.z = pTab->zName;
|
||||
pLeft->token.n = strlen(pTab->zName);
|
||||
}
|
||||
pLeft->token.z = zTabName;
|
||||
pLeft->token.n = strlen(zTabName);
|
||||
pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0);
|
||||
if( pExpr==0 ) break;
|
||||
}else{
|
||||
@ -455,12 +485,18 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
||||
pNew = sqliteExprListAppend(pNew, pExpr, 0);
|
||||
}
|
||||
}
|
||||
if( !tableSeen ){
|
||||
assert( pName!=0 );
|
||||
sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1,
|
||||
pName->z, pName->n, 0);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqliteExprListDelete(pEList);
|
||||
p->pEList = pNew;
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user