Continued refactoring of the name resolution logic and query optimizer. (CVS 2236)
FossilOrigin-Name: d8b2a7e09187564fe66a2b4bf0992c6a017146cf
This commit is contained in:
parent
76b047d957
commit
1398ad3639
40
manifest
40
manifest
@ -1,5 +1,5 @@
|
||||
C Another\sfix\salong\sthe\ssame\slines\sas\s(2234)\s(CVS\s2235)
|
||||
D 2005-01-19T03:52:55
|
||||
C Continued\srefactoring\sof\sthe\sname\sresolution\slogic\sand\squery\soptimizer.\s(CVS\s2236)
|
||||
D 2005-01-19T23:24:50
|
||||
F Makefile.in ffd81f5e926d40b457071b4de8d7c1fa18f39b5a
|
||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
|
||||
@ -31,15 +31,15 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
|
||||
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
|
||||
F src/btree.c 97101cce85304edbaedafc5f39ab12e2dc78b076
|
||||
F src/btree.h 74d19cf40ab49fd69abe9e4e12a6c321ad86c497
|
||||
F src/build.c 608ea54aab8f561da99c8a40c3ab6b26b7fc91e9
|
||||
F src/build.c da5ecd9880f2d19d5e77fe48b722577494dd3290
|
||||
F src/cursor.c f883813759742068890b1f699335872bfa8fdf41
|
||||
F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f
|
||||
F src/delete.c 728a02e5b5c62d294f8cdbdb21dbaa3e188983ab
|
||||
F src/expr.c fdacfb27a5803eadda1a14980553ca394d1d5612
|
||||
F src/delete.c cbf54c0634c53ef683f7af8ad5c5d5637c9efb90
|
||||
F src/expr.c 7e26c70d6e9d5f6cd65da2d75fd31c87598d9e02
|
||||
F src/func.c dc188d862d7276ea897655b248e2cb17022686e3
|
||||
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
F src/insert.c 18d506e14d200378902747d13d7fb2a43fb3d31d
|
||||
F src/insert.c e5f9a24e892259c4b1da5699f3d87287150b5e21
|
||||
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
|
||||
F src/main.c b489aae242a6123b111f125633799e37c0bab2a8
|
||||
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
||||
@ -47,30 +47,30 @@ F src/os.h ae44064dc118b20d39450cb331409a775e8bb1c6
|
||||
F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73
|
||||
F src/os_test.c 91e5f22dd89491e5e1554820e715805f43fa4ece
|
||||
F src/os_test.h 6a26a4978492e4bbdbf385554958418ff02db162
|
||||
F src/os_unix.c 08340c864822115bf87c6c1735780a0996278b81
|
||||
F src/os_unix.c 77319e31f5284c5714239cf50ae28552286414df
|
||||
F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
|
||||
F src/os_win.c 3c0b0a3bc33318cf555a1cd130232ad1b9a5a711
|
||||
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||
F src/pager.c 6319578f176cbc53eb044940ce484fae244ba6c5
|
||||
F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862
|
||||
F src/parse.y ceba179b9703657180963568f54b0e75f33e36e1
|
||||
F src/parse.y a1084470b331c1dc434e180ca888d15907bdc1cf
|
||||
F src/pragma.c ac594f74c90ffec043c43e49358719ffeb491eec
|
||||
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
|
||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||
F src/select.c 29bc58118d75071d1fd4f412581fde82e3e77b7d
|
||||
F src/select.c e147c81d57f7146d90a4d5a01f523dfec43808f4
|
||||
F src/shell.c 591364a0e9ca4ce53873e21e0294476c0c2b4770
|
||||
F src/sqlite.h.in 0d5e48e506845b74a845c9470e01d3f472b59611
|
||||
F src/sqliteInt.h c6414179a23cab108b4b07e8665f30829ce47f2a
|
||||
F src/sqliteInt.h a79a526b2f3c695226add233a41a5c8be3251a09
|
||||
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
||||
F src/tclsqlite.c fd27457b228118be96524dae285146c76efe032b
|
||||
F src/test1.c 2e27b110ba5aa16977bad1cc2388553479d73793
|
||||
F src/test1.c b2fd5e50457b82eff4916d1c62bd0caa10f7f4c3
|
||||
F src/test2.c bbc2ecc58ceeab12d1e40970f831b1017524e40d
|
||||
F src/test3.c a72f20066cccd5a7b9f20b7b78fa9b05b47b3020
|
||||
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
|
||||
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
|
||||
F src/tokenize.c 88bef43fe3e3c8865a7447f934296ac13238c4f6
|
||||
F src/trigger.c 7b5da6613419da37e5b3e1c6151c7dff95fd4ee0
|
||||
F src/update.c 48da25249d33c32fa1e55c66c5a01ec0d182b203
|
||||
F src/trigger.c b3de66150300026f21522bb273bbc413a80f427d
|
||||
F src/update.c 6e5c6eb660a5508c449c6d637571e24ef13f70a1
|
||||
F src/utf.c 9bece2c7b94d9002ab1bb900a7658c6f826b0f74
|
||||
F src/util.c 63e8d77659df88b292ac2a9dbd4766419b0ea158
|
||||
F src/vacuum.c 1a9db113a027461daaf44724c71dd1ebbd064203
|
||||
@ -80,7 +80,7 @@ F src/vdbeInt.h f2b5f54d9881bbc89fff02d95f3f825ade68bce2
|
||||
F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd
|
||||
F src/vdbeaux.c 6c294f7390880a7bb4795c9e0bc605b1a416579a
|
||||
F src/vdbemem.c 62fe89471b656a922e9879be005abf690509ead3
|
||||
F src/where.c 09defb7d1efb150d323fc253c6534d23e8a73ce6
|
||||
F src/where.c 06aa612bd0bc2634a53e541c4ed9874b814e82d1
|
||||
F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432
|
||||
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
|
||||
F test/alter.test 95c57a4f461fa81293e0dccef7f83889aadb169a
|
||||
@ -140,7 +140,7 @@ F test/intpkey.test b57cf5236fde1bd8cbc1388fa0c91908f6fd9194
|
||||
F test/ioerr.test fb507c2596bb07aeaff257cb48fcc93340159f0c
|
||||
F test/join.test 59e5abff5965016e3c75996f1019e2e91664647f
|
||||
F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8
|
||||
F test/join3.test 67dc0d7c8dab3fff25796d0f3c3fd9c999aeded3
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 8dec387d06b3a4685e1104048065cf5236b99b93
|
||||
F test/lastinsert.test b6a1db3e1ce2d3f0d6afe99d445084f543b6feaa
|
||||
F test/laststmtchanges.test 07cbdabc52407c29e40abc25050f2434f044a6b1
|
||||
@ -192,7 +192,7 @@ F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b
|
||||
F test/trace.test a54fa8df0d01cf827289a7659d78959e8fd2f955
|
||||
F test/trans.test 29645b344d2b9b6792793562b12340177ddd8f96
|
||||
F test/trigger1.test 0c60435fb26db41bb2feb9549119e80857decdf1
|
||||
F test/trigger1.test 98239dd6a8baf6817a028aa8d41c7da17c6824b1
|
||||
F test/trigger2.test 534390be509127859fee7c23018f03b9bf21a88f
|
||||
F test/trigger3.test 9102fd3933db294dc654b5aee9edfe9e94f2b9e2
|
||||
F test/trigger4.test e7c0812b14750754602468f15495260e8c6625e0
|
||||
@ -269,7 +269,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
|
||||
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
|
||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||
F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746
|
||||
P 441316f1af076fef42055d6abe524f2a8c5ced63
|
||||
R b54c6e325ef9790c3c13207e79568c30
|
||||
U danielk1977
|
||||
Z 27809fc51e58df3a44c41e452ce19dca
|
||||
P 27cf83224c69e661c19f9a09f39bfdae75e3b0a4
|
||||
R 331c9226a76190b62ab0ac4aa62a5446
|
||||
U drh
|
||||
Z 621c5ade2211fc9721f7fb4569d83e10
|
||||
|
@ -1 +1 @@
|
||||
27cf83224c69e661c19f9a09f39bfdae75e3b0a4
|
||||
d8b2a7e09187564fe66a2b4bf0992c6a017146cf
|
@ -22,7 +22,7 @@
|
||||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.294 2005/01/18 14:45:48 drh Exp $
|
||||
** $Id: build.c,v 1.295 2005/01/19 23:24:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -884,7 +884,7 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
|
||||
}else{
|
||||
sqlite3ExprDelete(pCol->pDflt);
|
||||
pCol->pDflt = sqlite3ExprDup(pExpr);
|
||||
sqlite3ExprResolveNames(pParse,0,0,pExpr,0,0);
|
||||
sqlite3ExprResolveNames(pParse,0,0,0,pExpr,0,0);
|
||||
}
|
||||
sqlite3ExprDelete(pExpr);
|
||||
}
|
||||
@ -1423,7 +1423,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
|
||||
pParse->nTab = 2;
|
||||
sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 1, 0);
|
||||
if( pParse->nErr==0 ){
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect);
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.97 2005/01/18 04:00:44 drh Exp $
|
||||
** $Id: delete.c,v 1.98 2005/01/19 23:24:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -150,7 +150,7 @@ void sqlite3DeleteFrom(
|
||||
*/
|
||||
assert( pTabList->nSrc==1 );
|
||||
iCur = pTabList->a[0].iCursor = pParse->nTab++;
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0, pWhere, 0, 1) ){
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pWhere, 0, 1) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ void sqlite3DeleteFrom(
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView = sqlite3SelectDup(pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
|
74
src/expr.c
74
src/expr.c
@ -12,7 +12,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.181 2005/01/18 17:20:10 drh Exp $
|
||||
** $Id: expr.c,v 1.182 2005/01/19 23:24:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -1095,6 +1095,9 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static int sqlite3ExprCodeSubquery(Parse*, NameContext*, Expr*);
|
||||
|
||||
/*
|
||||
** This routine walks an expression tree and resolves references to
|
||||
** table columns. Nodes of the form ID.ID or ID resolve into an
|
||||
@ -1117,12 +1120,13 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
|
||||
** property on the expression.
|
||||
*/
|
||||
int sqlite3ExprResolveNames(
|
||||
Parse *pParse, /* The parser context */
|
||||
SrcList *pSrcList, /* List of tables used to resolve column names */
|
||||
ExprList *pEList, /* List of expressions used to resolve "AS" */
|
||||
Expr *pExpr, /* The expression to be analyzed. */
|
||||
int allowAgg, /* True to allow aggregate expressions */
|
||||
int codeSubquery /* If true, then generate code for subqueries too */
|
||||
Parse *pParse, /* The parser context */
|
||||
SrcList *pSrcList, /* List of tables used to resolve column names */
|
||||
ExprList *pEList, /* List of expressions used to resolve "AS" */
|
||||
NameContext *pNC, /* Namespace of enclosing statement */
|
||||
Expr *pExpr, /* The expression to be analyzed. */
|
||||
int allowAgg, /* True to allow aggregate expressions */
|
||||
int codeSubquery /* If true, then generate code for subqueries too */
|
||||
){
|
||||
NameContext sNC;
|
||||
|
||||
@ -1132,18 +1136,29 @@ int sqlite3ExprResolveNames(
|
||||
sNC.pParse = pParse;
|
||||
sNC.pEList = pEList;
|
||||
sNC.allowAgg = allowAgg;
|
||||
sNC.pNext = pNC;
|
||||
walkExprTree(pExpr, nameResolverStep, &sNC);
|
||||
if( sNC.hasAgg ){
|
||||
ExprSetProperty(pExpr, EP_Agg);
|
||||
}
|
||||
if( sNC.nErr>0 ){
|
||||
ExprSetProperty(pExpr, EP_Error);
|
||||
}else if( codeSubquery && sqlite3ExprCodeSubquery(pParse, pExpr) ){
|
||||
}else if( codeSubquery && sqlite3ExprCodeSubquery(pParse, &sNC, pExpr) ){
|
||||
return 1;
|
||||
}
|
||||
return ExprHasProperty(pExpr, EP_Error);
|
||||
}
|
||||
|
||||
/*
|
||||
** A pointer instance of this structure is used to pass information
|
||||
** through walkExprTree into codeSubqueryStep().
|
||||
*/
|
||||
typedef struct QueryCoder QueryCoder;
|
||||
struct QueryCoder {
|
||||
Parse *pParse; /* The parsing context */
|
||||
NameContext *pNC; /* Namespace of first enclosing query */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Generate code for subqueries and IN operators.
|
||||
@ -1167,7 +1182,8 @@ int sqlite3ExprResolveNames(
|
||||
** additional information.
|
||||
*/
|
||||
static int codeSubqueryStep(void *pArg, Expr *pExpr){
|
||||
Parse *pParse = (Parse*)pArg;
|
||||
QueryCoder *pCoder = (QueryCoder*)pArg;
|
||||
Parse *pParse = pCoder->pParse;
|
||||
|
||||
switch( pExpr->op ){
|
||||
case TK_IN: {
|
||||
@ -1207,7 +1223,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
|
||||
int iParm = pExpr->iTable + (((int)affinity)<<16);
|
||||
ExprList *pEList;
|
||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0, 0);
|
||||
pEList = pExpr->pSelect->pEList;
|
||||
if( pEList && pEList->nExpr>0 ){
|
||||
keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
|
||||
@ -1237,7 +1253,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
|
||||
"right-hand side of IN operator must be constant");
|
||||
return 2;
|
||||
}
|
||||
if( sqlite3ExprResolveNames(pParse, 0, 0, pE2, 0, 0) ){
|
||||
if( sqlite3ExprResolveNames(pParse, 0, 0, 0, pE2, 0, 0) ){
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -1257,8 +1273,27 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
|
||||
** value of this select in a memory cell and record the number
|
||||
** of the memory cell in iColumn.
|
||||
*/
|
||||
NameContext *pNC;
|
||||
int nRef;
|
||||
Vdbe *v;
|
||||
int addr;
|
||||
|
||||
pNC = pCoder->pNC;
|
||||
if( pNC ) nRef = pNC->nRef;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
addr = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||
pExpr->iColumn = pParse->nMem++;
|
||||
sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0);
|
||||
sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0,pNC);
|
||||
if( pNC && pNC->nRef>nRef ){
|
||||
/* Subquery value changes. Evaluate at each use */
|
||||
pExpr->iTable = addr+1;
|
||||
sqlite3VdbeAddOp(v, OP_Return, 0, 0);
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||
}else{
|
||||
/* Subquery value is constant. evaluate only once. */
|
||||
pExpr->iTable = -1;
|
||||
sqlite3VdbeChangeP2(v, addr, addr+1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -1269,8 +1304,15 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
|
||||
** Generate code to evaluate subqueries and IN operators contained
|
||||
** in expression pExpr.
|
||||
*/
|
||||
int sqlite3ExprCodeSubquery(Parse *pParse, Expr *pExpr){
|
||||
walkExprTree(pExpr, codeSubqueryStep, pParse);
|
||||
static int sqlite3ExprCodeSubquery(
|
||||
Parse *pParse, /* Parser */
|
||||
NameContext *pNC, /* First enclosing namespace. Often NULL */
|
||||
Expr *pExpr /* Subquery to be coded */
|
||||
){
|
||||
QueryCoder sCoder;
|
||||
sCoder.pParse = pParse;
|
||||
sCoder.pNC = pNC;
|
||||
walkExprTree(pExpr, codeSubqueryStep, &sCoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1478,6 +1520,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
break;
|
||||
}
|
||||
case TK_SELECT: {
|
||||
if( pExpr->iTable>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Gosub, 0, pExpr->iTable);
|
||||
VdbeComment((v, "# run subquery"));
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
|
||||
VdbeComment((v, "# load subquery result"));
|
||||
break;
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.132 2005/01/18 04:00:44 drh Exp $
|
||||
** $Id: insert.c,v 1.133 2005/01/19 23:24:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -312,7 +312,7 @@ void sqlite3Insert(
|
||||
iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||
iSelectLoop = sqlite3VdbeCurrentAddr(v);
|
||||
iInsertBlock = sqlite3VdbeMakeLabel(v);
|
||||
rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0,0);
|
||||
rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0,0);
|
||||
if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
|
||||
iCleanup = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
|
||||
@ -380,7 +380,7 @@ void sqlite3Insert(
|
||||
nColumn = pList->nExpr;
|
||||
dummy.nSrc = 0;
|
||||
for(i=0; i<nColumn; i++){
|
||||
if( sqlite3ExprResolveNames(pParse,&dummy,0,pList->a[i].pExpr,0,1) ){
|
||||
if( sqlite3ExprResolveNames(pParse,&dummy,0,0,pList->a[i].pExpr,0,1) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
|
@ -691,8 +691,17 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||
** The fsync() system call does not work as advertised on many
|
||||
** unix systems. The following procedure is an attempt to make
|
||||
** it work better.
|
||||
**
|
||||
** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
|
||||
** for testing when we want to run through the test suite quickly.
|
||||
** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
|
||||
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
|
||||
** or power failure will likely corrupt the database file.
|
||||
*/
|
||||
static int full_fsync(int fd){
|
||||
#ifdef SQLITE_NO_SYNC
|
||||
return SQLITE_OK;
|
||||
#else
|
||||
int rc;
|
||||
#ifdef F_FULLFSYNC
|
||||
rc = fcntl(fd, F_FULLFSYNC, 0);
|
||||
@ -701,6 +710,7 @@ static int full_fsync(int fd){
|
||||
rc = fsync(fd);
|
||||
#endif
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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.158 2004/11/22 19:12:21 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.159 2005/01/19 23:24:50 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@ -317,7 +317,7 @@ cmd ::= DROP VIEW fullname(X). {
|
||||
//////////////////////// The SELECT statement /////////////////////////////////
|
||||
//
|
||||
cmd ::= select(X). {
|
||||
sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(X);
|
||||
}
|
||||
|
||||
|
34
src/select.c
34
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.228 2005/01/18 17:40:04 drh Exp $
|
||||
** $Id: select.c,v 1.229 2005/01/19 23:24:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -664,7 +664,7 @@ static const char *columnType(Parse *pParse, SrcList *pTabList, Expr *pExpr){
|
||||
int j;
|
||||
if( pExpr==0 || pTabList==0 ) return 0;
|
||||
|
||||
sqlite3ExprResolveNames(pParse, pTabList, 0, pExpr, 1, 0);
|
||||
sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pExpr, 1, 0);
|
||||
switch( pExpr->op ){
|
||||
case TK_COLUMN: {
|
||||
Table *pTab;
|
||||
@ -1468,7 +1468,7 @@ static int multiSelect(
|
||||
if( p->pOrderBy==0 ){
|
||||
pPrior->nLimit = p->nLimit;
|
||||
pPrior->nOffset = p->nOffset;
|
||||
rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
|
||||
rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff, 0);
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
@ -1477,7 +1477,7 @@ static int multiSelect(
|
||||
p->iOffset = pPrior->iOffset;
|
||||
p->nLimit = -1;
|
||||
p->nOffset = 0;
|
||||
rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
|
||||
rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff, 0);
|
||||
p->pPrior = pPrior;
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
@ -1526,7 +1526,7 @@ static int multiSelect(
|
||||
|
||||
/* Code the SELECT statements to our left
|
||||
*/
|
||||
rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
|
||||
rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff, 0);
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
@ -1545,7 +1545,7 @@ static int multiSelect(
|
||||
p->nLimit = -1;
|
||||
nOffset = p->nOffset;
|
||||
p->nOffset = 0;
|
||||
rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
|
||||
rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff, 0);
|
||||
p->pPrior = pPrior;
|
||||
p->pOrderBy = pOrderBy;
|
||||
p->nLimit = nLimit;
|
||||
@ -1614,7 +1614,7 @@ static int multiSelect(
|
||||
|
||||
/* Code the SELECTs to our left into temporary table "tab1".
|
||||
*/
|
||||
rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
|
||||
rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff, 0);
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
@ -1634,7 +1634,7 @@ static int multiSelect(
|
||||
p->nLimit = -1;
|
||||
nOffset = p->nOffset;
|
||||
p->nOffset = 0;
|
||||
rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
|
||||
rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff, 0);
|
||||
p->pPrior = pPrior;
|
||||
p->nLimit = nLimit;
|
||||
p->nOffset = nOffset;
|
||||
@ -2216,6 +2216,7 @@ static int processOrderGroupBy(
|
||||
ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */
|
||||
SrcList *pTabList, /* The FROM clause */
|
||||
ExprList *pEList, /* The result set */
|
||||
NameContext *pNC, /* Name context for enclosing query */
|
||||
int isAgg, /* True if aggregate functions are involved */
|
||||
const char *zType /* Either "ORDER" or "GROUP", as appropriate */
|
||||
){
|
||||
@ -2228,7 +2229,7 @@ static int processOrderGroupBy(
|
||||
sqlite3ExprDelete(pE);
|
||||
pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
|
||||
}
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pE, isAgg, 1) ){
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pE, isAgg, 1) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3ExprIsConstant(pE) ){
|
||||
@ -2307,7 +2308,8 @@ int sqlite3Select(
|
||||
Select *pParent, /* Another SELECT for which this is a sub-query */
|
||||
int parentTab, /* Index in pParent->pSrc of this query */
|
||||
int *pParentAgg, /* True if pParent uses aggregate functions */
|
||||
char *aff /* If eDest is SRT_Union, the affinity string */
|
||||
char *aff, /* If eDest is SRT_Union, the affinity string */
|
||||
NameContext *pNC /* Namespace of the next outer query */
|
||||
){
|
||||
int i;
|
||||
WhereInfo *pWInfo;
|
||||
@ -2390,12 +2392,12 @@ int sqlite3Select(
|
||||
*/
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
Expr *pX = pEList->a[i].pExpr;
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0, pX, 1, 1) ){
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0, pNC, pX, 1, 1) ){
|
||||
goto select_end;
|
||||
}
|
||||
if( ExprHasProperty(pX, EP_Agg) ) isAgg = 1;
|
||||
}
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pWhere, 0, 1) ){
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pWhere, 0, 1) ){
|
||||
goto select_end;
|
||||
}
|
||||
if( pHaving ){
|
||||
@ -2403,7 +2405,7 @@ int sqlite3Select(
|
||||
sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
|
||||
goto select_end;
|
||||
}
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pHaving, 1, 1) ){
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pHaving, 1, 1) ){
|
||||
goto select_end;
|
||||
}
|
||||
if( ExprHasProperty(pHaving, EP_Agg) ) isAgg = 1;
|
||||
@ -2412,8 +2414,8 @@ int sqlite3Select(
|
||||
sqlite3ErrorMsg(pParse, "GROUP BY may only be used on aggregate queries");
|
||||
goto select_end;
|
||||
}
|
||||
if( processOrderGroupBy(pParse, pOrderBy, pTabList, pEList, isAgg, "ORDER")
|
||||
|| processOrderGroupBy(pParse, pGroupBy, pTabList, pEList, isAgg, "GROUP")
|
||||
if( processOrderGroupBy(pParse,pOrderBy,pTabList,pEList,pNC,isAgg,"ORDER")
|
||||
|| processOrderGroupBy(pParse,pGroupBy,pTabList,pEList,pNC,isAgg,"GROUP")
|
||||
){
|
||||
goto select_end;
|
||||
}
|
||||
@ -2465,7 +2467,7 @@ int sqlite3Select(
|
||||
needRestoreContext = 0;
|
||||
}
|
||||
sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable,
|
||||
pTabList->a[i].iCursor, p, i, &isAgg, 0);
|
||||
pTabList->a[i].iCursor, p, i, &isAgg, 0, 0);
|
||||
if( needRestoreContext ){
|
||||
pParse->zAuthContext = zSavedAuthContext;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.356 2005/01/18 14:45:48 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.357 2005/01/19 23:24:51 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@ -787,6 +787,12 @@ struct Token {
|
||||
** marker (a question mark character '?' in the original SQL) then the
|
||||
** Expr.iTable holds the index number for that variable.
|
||||
**
|
||||
** If the expression is a subquery then Expr.iColumn holds an integer
|
||||
** register number containing the result of the subquery. If the
|
||||
** subquery gives a constant result, then iTable is -1. If the subquery
|
||||
** gives a different answer at different times during statement processing
|
||||
** then iTable is the address of a subroutine that computes the subquery.
|
||||
**
|
||||
** The Expr.pSelect field points to a SELECT statement. The SELECT might
|
||||
** be the right operand of an IN operator. Or, if a scalar SELECT appears
|
||||
** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
|
||||
@ -1392,7 +1398,8 @@ void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
||||
void sqlite3DropIndex(Parse*, SrcList*);
|
||||
void sqlite3AddKeyType(Vdbe*, ExprList*);
|
||||
void sqlite3AddIdxKeyType(Vdbe*, Index*);
|
||||
int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
|
||||
int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*,
|
||||
char *aff, NameContext*);
|
||||
Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
|
||||
int,int,int);
|
||||
void sqlite3SelectDelete(Select*);
|
||||
@ -1422,8 +1429,8 @@ char *sqlite3NameFromToken(Token*);
|
||||
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*);
|
||||
int sqliteFuncId(Token*);
|
||||
int sqlite3ExprResolveNames(Parse*, SrcList*, ExprList*, Expr*, int, int);
|
||||
int sqlite3ExprCodeSubquery(Parse*, Expr*);
|
||||
int sqlite3ExprResolveNames(Parse*, SrcList*, ExprList*, NameContext*,
|
||||
Expr*, int, int);
|
||||
int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
|
||||
Vdbe *sqlite3GetVdbe(Parse*);
|
||||
void sqlite3Randomness(int, void*);
|
||||
|
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test1.c,v 1.122 2005/01/13 02:14:25 danielk1977 Exp $
|
||||
** $Id: test1.c,v 1.123 2005/01/19 23:24:51 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@ -2830,8 +2830,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_test_errstr", test_errstr, 0 },
|
||||
{ "tcl_variable_type", tcl_variable_type, 0 },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
extern int sqlite3_os_trace;
|
||||
|
||||
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
||||
@ -2856,6 +2858,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
(char*)&sqlite_static_bind_value, TCL_LINK_STRING);
|
||||
Tcl_LinkVar(interp, "sqlite_temp_directory",
|
||||
(char*)&sqlite3_temp_directory, TCL_LINK_STRING);
|
||||
Tcl_LinkVar(interp, "bitmask_size",
|
||||
(char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
|
||||
set_options(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -643,7 +643,7 @@ static int codeTriggerProgram(
|
||||
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
|
||||
assert(ss);
|
||||
assert(ss->pSrc);
|
||||
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(ss);
|
||||
break;
|
||||
}
|
||||
@ -766,7 +766,7 @@ int sqlite3CodeRowTrigger(
|
||||
/* code the WHEN clause */
|
||||
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
||||
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
|
||||
if( sqlite3ExprResolveNames(pParse, &dummyTablist, 0, whenExpr, 0, 1) ){
|
||||
if( sqlite3ExprResolveNames(pParse, &dummyTablist, 0, 0, whenExpr, 0,1) ){
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
return 1;
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.102 2005/01/18 04:00:44 drh Exp $
|
||||
** $Id: update.c,v 1.103 2005/01/19 23:24:51 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -121,7 +121,7 @@ void sqlite3Update(
|
||||
*/
|
||||
chngRecno = 0;
|
||||
for(i=0; i<pChanges->nExpr; i++){
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0,
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0,
|
||||
pChanges->a[i].pExpr, 0, 1) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
@ -198,7 +198,7 @@ void sqlite3Update(
|
||||
/* Resolve the column names in all the expressions in the
|
||||
** WHERE clause.
|
||||
*/
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0, pWhere, 0, 1) ){
|
||||
if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pWhere, 0, 1) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ void sqlite3Update(
|
||||
if( isView ){
|
||||
Select *pView;
|
||||
pView = sqlite3SelectDup(pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
|
58
src/where.c
58
src/where.c
@ -16,7 +16,7 @@
|
||||
** so is applicable. Because this module is responsible for selecting
|
||||
** indices, you might also think of this module as the "query optimizer".
|
||||
**
|
||||
** $Id: where.c,v 1.129 2005/01/17 22:08:19 drh Exp $
|
||||
** $Id: where.c,v 1.130 2005/01/19 23:24:51 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -103,8 +103,8 @@ struct ExprInfo {
|
||||
*/
|
||||
typedef struct ExprMaskSet ExprMaskSet;
|
||||
struct ExprMaskSet {
|
||||
int n; /* Number of assigned cursor values */
|
||||
int ix[sizeof(Bitmask)*8-1]; /* Cursor assigned to each bit */
|
||||
int n; /* Number of assigned cursor values */
|
||||
int ix[sizeof(Bitmask)*8]; /* Cursor assigned to each bit */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -152,8 +152,8 @@ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
|
||||
#define initMaskSet(P) memset(P, 0, sizeof(*P))
|
||||
|
||||
/*
|
||||
** Return the bitmask for the given cursor number. Assign a new bitmask
|
||||
** if this is the first time the cursor has been seen.
|
||||
** Return the bitmask for the given cursor number. Return 0 if
|
||||
** iCursor is not in the set.
|
||||
*/
|
||||
static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
|
||||
int i;
|
||||
@ -162,14 +162,18 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
|
||||
return ((Bitmask)1)<<i;
|
||||
}
|
||||
}
|
||||
if( i==pMaskSet->n && i<ARRAYSIZE(pMaskSet->ix) ){
|
||||
pMaskSet->n++;
|
||||
pMaskSet->ix[i] = iCursor;
|
||||
return ((Bitmask)1)<<i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new mask for cursor iCursor.
|
||||
*/
|
||||
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
|
||||
if( pMaskSet->n<ARRAYSIZE(pMaskSet->ix) ){
|
||||
pMaskSet->ix[pMaskSet->n++] = iCursor;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy an expression mask set
|
||||
*/
|
||||
@ -192,7 +196,6 @@ static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
|
||||
if( p==0 ) return 0;
|
||||
if( p->op==TK_COLUMN ){
|
||||
mask = getMask(pMaskSet, p->iTable);
|
||||
if( mask==0 ) mask = -1;
|
||||
return mask;
|
||||
}
|
||||
if( p->pRight ){
|
||||
@ -598,6 +601,15 @@ WhereInfo *sqlite3WhereBegin(
|
||||
struct SrcList_item *pTabItem; /* A single entry from pTabList */
|
||||
WhereLevel *pLevel; /* A single level in the pWInfo list */
|
||||
|
||||
/* The number of terms in the FROM clause is limited by the number of
|
||||
** bits in a Bitmask
|
||||
*/
|
||||
if( pTabList->nSrc>sizeof(Bitmask)*8 ){
|
||||
sqlite3ErrorMsg(pParse, "at most %d tables in a join",
|
||||
sizeof(Bitmask)*8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Split the WHERE clause into separate subexpressions where each
|
||||
** subexpression is separated by an AND operator. If the aExpr[]
|
||||
** array fills up, the last entry might point to an expression which
|
||||
@ -611,7 +623,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
"than %d terms allowed", (int)ARRAYSIZE(aExpr)-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate and initialize the WhereInfo structure that will become the
|
||||
** return value.
|
||||
*/
|
||||
@ -634,28 +646,12 @@ WhereInfo *sqlite3WhereBegin(
|
||||
|
||||
/* Analyze all of the subexpressions.
|
||||
*/
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
createMask(&maskSet, pTabList->a[i].iCursor);
|
||||
}
|
||||
for(pTerm=aExpr, i=0; i<nExpr; i++, pTerm++){
|
||||
TriggerStack *pStack;
|
||||
exprAnalyze(pTabList, &maskSet, pTerm);
|
||||
|
||||
/* If we are executing a trigger body, remove all references to
|
||||
** new.* and old.* tables from the prerequisite masks.
|
||||
*/
|
||||
if( (pStack = pParse->trigStack)!=0 ){
|
||||
int x;
|
||||
if( (x=pStack->newIdx) >= 0 ){
|
||||
Bitmask mask = ~getMask(&maskSet, x);
|
||||
pTerm->prereqRight &= mask;
|
||||
pTerm->prereqLeft &= mask;
|
||||
pTerm->prereqAll &= mask;
|
||||
}
|
||||
if( (x=pStack->oldIdx) >= 0 ){
|
||||
Bitmask mask = ~getMask(&maskSet, x);
|
||||
pTerm->prereqRight &= mask;
|
||||
pTerm->prereqLeft &= mask;
|
||||
pTerm->prereqAll &= mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Figure out what index to use (if any) for each nested loop.
|
||||
|
@ -13,7 +13,7 @@
|
||||
# This file implements tests for joins, including outer joins, where
|
||||
# there are a large number of tables involved in the join.
|
||||
#
|
||||
# $Id: join3.test,v 1.3 2004/07/20 12:45:22 drh Exp $
|
||||
# $Id: join3.test,v 1.4 2005/01/19 23:24:51 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -22,7 +22,7 @@ source $testdir/tester.tcl
|
||||
#
|
||||
catch {unset ::result}
|
||||
set result {}
|
||||
for {set N 1} {$N<=40} {incr N} {
|
||||
for {set N 1} {$N<=$bitmask_size} {incr N} {
|
||||
lappend result $N
|
||||
do_test join3-1.$N {
|
||||
execsql "CREATE TABLE t${N}(x);"
|
||||
@ -36,7 +36,7 @@ for {set N 1} {$N<=40} {incr N} {
|
||||
# Joins with a comparison
|
||||
#
|
||||
set result {}
|
||||
for {set N 1} {$N<=40} {incr N} {
|
||||
for {set N 1} {$N<=$bitmask_size} {incr N} {
|
||||
lappend result $N
|
||||
do_test join3-2.$N {
|
||||
set sql "SELECT * FROM t1"
|
||||
@ -50,4 +50,13 @@ for {set N 1} {$N<=40} {incr N} {
|
||||
} $result
|
||||
}
|
||||
|
||||
# Error of too many tables in the join
|
||||
#
|
||||
do_test join3-3.1 {
|
||||
set sql "SELECT * FROM t1 AS t0, t1"
|
||||
for {set i 2} {$i<=$bitmask_size} {incr i} {append sql ", t$i"}
|
||||
catchsql $sql
|
||||
} [list 1 "at most $bitmask_size tables in a join"]
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -146,6 +146,7 @@ do_test trigger1-1.10 {
|
||||
drop table t1;
|
||||
}
|
||||
} {2 b 4 d}
|
||||
|
||||
do_test trigger1-1.11 {
|
||||
execsql {
|
||||
create table t1(a,b);
|
||||
|
Loading…
Reference in New Issue
Block a user