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:
20
manifest
20
manifest
@ -1,9 +1,9 @@
|
|||||||
C Added\sa\shyperlink\sto\sthe\sSQLite-PHP\sproject.\s(CVS\s517)
|
C Fix\sfor\sbug\s#2:\sAdd\ssupport\sfor\sTABLE.*\sin\sSELECT\sstatements.\s(CVS\s518)
|
||||||
D 2002-04-03T20:50:21
|
D 2002-04-04T02:10:56
|
||||||
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
|
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
|
||||||
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
|
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
|
||||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||||
F VERSION ed0299de5b86deca846fdb0f8b99aaae85f27f47
|
F VERSION bb2c45e1821c29d3e52ea953e25a4c4a2d2f15e7
|
||||||
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
||||||
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
|
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
|
||||||
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
|
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
|
||||||
@ -35,10 +35,10 @@ F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc
|
|||||||
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
|
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
|
||||||
F src/pager.c f136f5ba82c896d500a10b6a2e5caea62abf716b
|
F src/pager.c f136f5ba82c896d500a10b6a2e5caea62abf716b
|
||||||
F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
|
F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
|
||||||
F src/parse.y a0943e2774c7b0cab608640df1126f6c3ae39e90
|
F src/parse.y d63f93b67edf9e318afea87b71d69af3334a9649
|
||||||
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
||||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||||
F src/select.c 9323800e2937e84b52c198fffc51995d822b1779
|
F src/select.c 92aef3f69e90dc065d680d88b1f075409e9249bb
|
||||||
F src/shell.c b3454229599246b944cdb5b95753af3fca5d8bb0
|
F src/shell.c b3454229599246b944cdb5b95753af3fca5d8bb0
|
||||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||||
F src/sqlite.h.in 1dae50411aee9439860d7fbe315183c582d27197
|
F src/sqlite.h.in 1dae50411aee9439860d7fbe315183c582d27197
|
||||||
@ -84,7 +84,7 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
|
|||||||
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
||||||
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
|
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
|
||||||
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
||||||
F test/select1.test 572d53f7b28c35a1efdce207f7579523358ba637
|
F test/select1.test 114d4545c19f6cbbbcaa2a100f698757e6e36188
|
||||||
F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
|
F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
|
||||||
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
||||||
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
|
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
|
||||||
@ -116,7 +116,7 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
|||||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
||||||
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
||||||
F www/c_interface.tcl 567cda531aac9d68a61ef02e26c6b202bd856db2
|
F www/c_interface.tcl 567cda531aac9d68a61ef02e26c6b202bd856db2
|
||||||
F www/changes.tcl 563071eacf1c0fc03521bf874438274d83445c78
|
F www/changes.tcl 4b4a3c58c29ec56c063c6f550a3aaf70ea3bb637
|
||||||
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
||||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||||
F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49
|
F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49
|
||||||
@ -131,7 +131,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
|
|||||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||||
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P 5ae7efd87f1a8e2f3e927bf373fbcb5c692d1a02
|
P ffdeec3087e168acaa04a6331e91369e2e0f8345
|
||||||
R 97c982959534a76dbc674ad8494cc78c
|
R 2030ad886be3f6f3ab16a87454cce255
|
||||||
U drh
|
U drh
|
||||||
Z c9be79df63e845bc5fc84485638451ca
|
Z 6dbde5dc0db37de113b78d968afab2db
|
||||||
|
@ -1 +1 @@
|
|||||||
ffdeec3087e168acaa04a6331e91369e2e0f8345
|
c2320eabfe44d6eb05c02b76547e5bd48a29943c
|
@ -14,7 +14,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** 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_prefix TK_
|
||||||
%token_type {Token}
|
%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. {
|
selcollist(A) ::= sclp(P) STAR. {
|
||||||
A = sqliteExprListAppend(P, sqliteExpr(TK_ALL, 0, 0, 0), 0);
|
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 ::= 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
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** 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"
|
#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
|
** (1) Fill in the pTabList->a[].pTab fields in the IdList that
|
||||||
** defines the set of tables that should be scanned.
|
** defines the set of tables that should be scanned.
|
||||||
**
|
**
|
||||||
** (2) If the columns to be extracted variable (pEList) is NULL
|
** (2) Scan the list of columns in the result set (pEList) looking
|
||||||
** (meaning that a "*" was used in the SQL statement) then
|
** for instances of the "*" operator or the TABLE.* operator.
|
||||||
** create a fake pEList containing the names of all columns
|
** If found, expand each "*" to be every column in every table
|
||||||
** of all tables.
|
** and TABLE.* to be every column in TABLE.
|
||||||
**
|
**
|
||||||
** Return 0 on success. If there are problems, leave an error message
|
** Return 0 on success. If there are problems, leave an error message
|
||||||
** in pParse and return non-zero.
|
** in pParse and return non-zero.
|
||||||
*/
|
*/
|
||||||
static int fillInColumnList(Parse *pParse, Select *p){
|
static int fillInColumnList(Parse *pParse, Select *p){
|
||||||
int i, j, k;
|
int i, j, k, rc;
|
||||||
IdList *pTabList;
|
IdList *pTabList;
|
||||||
ExprList *pEList;
|
ExprList *pEList;
|
||||||
Table *pTab;
|
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
|
/* 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.
|
** 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
|
** The following code just has to locate the TK_ALL expressions and expand
|
||||||
** each one to the list of all columns in all tables.
|
** 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++){
|
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( 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;
|
struct ExprList_item *a = pEList->a;
|
||||||
ExprList *pNew = 0;
|
ExprList *pNew = 0;
|
||||||
for(k=0; k<pEList->nExpr; k++){
|
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 = sqliteExprListAppend(pNew, a[k].pExpr, 0);
|
||||||
pNew->a[pNew->nExpr-1].zName = a[k].zName;
|
pNew->a[pNew->nExpr-1].zName = a[k].zName;
|
||||||
a[k].pExpr = 0;
|
a[k].pExpr = 0;
|
||||||
a[k].zName = 0;
|
a[k].zName = 0;
|
||||||
}else{
|
}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++){
|
for(i=0; i<pTabList->nId; i++){
|
||||||
Table *pTab = pTabList->a[i].pTab;
|
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++){
|
for(j=0; j<pTab->nCol; j++){
|
||||||
Expr *pExpr, *pLeft, *pRight;
|
Expr *pExpr, *pLeft, *pRight;
|
||||||
pRight = sqliteExpr(TK_ID, 0, 0, 0);
|
pRight = sqliteExpr(TK_ID, 0, 0, 0);
|
||||||
if( pRight==0 ) break;
|
if( pRight==0 ) break;
|
||||||
pRight->token.z = pTab->aCol[j].zName;
|
pRight->token.z = pTab->aCol[j].zName;
|
||||||
pRight->token.n = strlen(pTab->aCol[j].zName);
|
pRight->token.n = strlen(pTab->aCol[j].zName);
|
||||||
if( pTab->zName ){
|
if( zTabName ){
|
||||||
pLeft = sqliteExpr(TK_ID, 0, 0, 0);
|
pLeft = sqliteExpr(TK_ID, 0, 0, 0);
|
||||||
if( pLeft==0 ) break;
|
if( pLeft==0 ) break;
|
||||||
if( pTabList->a[i].zAlias && pTabList->a[i].zAlias[0] ){
|
pLeft->token.z = zTabName;
|
||||||
pLeft->token.z = pTabList->a[i].zAlias;
|
pLeft->token.n = strlen(zTabName);
|
||||||
pLeft->token.n = strlen(pTabList->a[i].zAlias);
|
|
||||||
}else{
|
|
||||||
pLeft->token.z = pTab->zName;
|
|
||||||
pLeft->token.n = strlen(pTab->zName);
|
|
||||||
}
|
|
||||||
pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0);
|
pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0);
|
||||||
if( pExpr==0 ) break;
|
if( pExpr==0 ) break;
|
||||||
}else{
|
}else{
|
||||||
@ -455,12 +485,18 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
|||||||
pNew = sqliteExprListAppend(pNew, pExpr, 0);
|
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);
|
sqliteExprListDelete(pEList);
|
||||||
p->pEList = pNew;
|
p->pEList = pNew;
|
||||||
}
|
}
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing the SELECT statement.
|
# focus of this file is testing the SELECT statement.
|
||||||
#
|
#
|
||||||
# $Id: select1.test,v 1.22 2002/03/02 17:04:09 drh Exp $
|
# $Id: select1.test,v 1.23 2002/04/04 02:10:57 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@ -544,5 +544,86 @@ do_test select1-10.6 {
|
|||||||
}
|
}
|
||||||
} {11 22}
|
} {11 22}
|
||||||
|
|
||||||
|
# Check the ability to specify "TABLE.*" in the result set of a SELECT
|
||||||
|
#
|
||||||
|
do_test select1-11.1 {
|
||||||
|
execsql {
|
||||||
|
DELETE FROM t3;
|
||||||
|
DELETE FROM t4;
|
||||||
|
INSERT INTO t3 VALUES(1,2);
|
||||||
|
INSERT INTO t4 VALUES(3,4);
|
||||||
|
SELECT * FROM t3, t4;
|
||||||
|
}
|
||||||
|
} {1 2 3 4}
|
||||||
|
do_test select1-11.2 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT * FROM t3, t4;
|
||||||
|
}
|
||||||
|
} {t3.a 1 t3.b 2 t4.a 3 t4.b 4}
|
||||||
|
do_test select1-11.3 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT * FROM t3 AS x, t4 AS y;
|
||||||
|
}
|
||||||
|
} {x.a 1 x.b 2 y.a 3 y.b 4}
|
||||||
|
do_test select1-11.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT t3.*, t4.b FROM t3, t4;
|
||||||
|
}
|
||||||
|
} {1 2 4}
|
||||||
|
do_test select1-11.5 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT t3.*, t4.b FROM t3, t4;
|
||||||
|
}
|
||||||
|
} {t3.a 1 t3.b 2 t4.b 4}
|
||||||
|
do_test select1-11.6 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT x.*, y.b FROM t3 AS x, t4 AS y;
|
||||||
|
}
|
||||||
|
} {x.a 1 x.b 2 y.b 4}
|
||||||
|
do_test select1-11.7 {
|
||||||
|
execsql {
|
||||||
|
SELECT t3.b, t4.* FROM t3, t4;
|
||||||
|
}
|
||||||
|
} {2 3 4}
|
||||||
|
do_test select1-11.8 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT t3.b, t4.* FROM t3, t4;
|
||||||
|
}
|
||||||
|
} {t3.b 2 t4.a 3 t4.b 4}
|
||||||
|
do_test select1-11.9 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT x.b, y.* FROM t3 AS x, t4 AS y;
|
||||||
|
}
|
||||||
|
} {x.b 2 y.a 3 y.b 4}
|
||||||
|
do_test select1-11.10 {
|
||||||
|
catchsql {
|
||||||
|
SELECT t5.* FROM t3, t4;
|
||||||
|
}
|
||||||
|
} {1 {no such table: t5}}
|
||||||
|
do_test select1-11.11 {
|
||||||
|
catchsql {
|
||||||
|
SELECT t3.* FROM t3 AS x, t4;
|
||||||
|
}
|
||||||
|
} {1 {no such table: t3}}
|
||||||
|
do_test select1-11.12 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT t3.* FROM t3, (SELECT max(a), max(b) FROM t4)
|
||||||
|
}
|
||||||
|
} {t3.a 1 t3.b 2}
|
||||||
|
do_test select1-11.13 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT t3.* FROM (SELECT max(a), max(b) FROM t4), t3
|
||||||
|
}
|
||||||
|
} {t3.a 1 t3.b 2}
|
||||||
|
do_test select1-11.14 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT * FROM t3, (SELECT max(a), max(b) FROM t4)
|
||||||
|
}
|
||||||
|
} {t3.a 1 t3.b 2 max(a) 3 max(b) 4}
|
||||||
|
do_test select1-11.15 {
|
||||||
|
execsql2 {
|
||||||
|
SELECT y.*, t3.* FROM t3, (SELECT max(a), max(b) FROM t4) AS y
|
||||||
|
}
|
||||||
|
} {y.max(a) 3 y.max(b) 4 t3.a 1 t3.b 2}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
@ -25,6 +25,11 @@ proc chng {date desc} {
|
|||||||
puts "<DD><P><UL>$desc</UL></P></DD>"
|
puts "<DD><P><UL>$desc</UL></P></DD>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chng {2002 Apr 03 (2.4.7)} {
|
||||||
|
<li>Add the ability to put TABLE.* in the column list of a
|
||||||
|
SELECT statement.</li>
|
||||||
|
}
|
||||||
|
|
||||||
chng {2002 Apr 02 (2.4.6)} {
|
chng {2002 Apr 02 (2.4.6)} {
|
||||||
<li>Bug fix: Correctly handle terms in the WHERE clause of a join that
|
<li>Bug fix: Correctly handle terms in the WHERE clause of a join that
|
||||||
do not contain a comparison operator.</li>
|
do not contain a comparison operator.</li>
|
||||||
|
Reference in New Issue
Block a user