diff --git a/manifest b/manifest index 883ad2f581..b3dd4e89fa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\slatest\schanges\sfrom\sthe\strunk\sinto\sthe\ssessions\sbranch. -D 2011-09-14T19:41:44.795 +C Merge\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch. +D 2011-09-16T19:40:24.719 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in d314143fa6be24828021d3f583ad37d9afdce505 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -145,7 +145,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c e3132ec65240b2e2f3d50831021eac387f27584d F src/date.c a3c6842bad7ae632281811de112a8ba63ff08ab3 F src/delete.c 614d6e012aa5b624e78f3b556243497825de196b -F src/expr.c cbcd8c2f1588a9862291a081699854c5e1cb28ab +F src/expr.c fd54c517869919c9b0b11dcadd43c66540ffa682 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 9f00ea98f6b360d477b5a78b5b59a1fbde82431c F src/func.c 59bb046d7e3df1ab512ac339ccb0a6f996a17cb7 @@ -191,11 +191,11 @@ F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 -F src/select.c bf7b7ea6befb483619da5f597b0864668b828c3c +F src/select.c d9b7d20b0365f80761846f00ef3638d4b33eeaf2 F src/shell.c bbe7818ff5bc8614105ceb81ad67b8bdc0b671dd F src/sqlite.h.in 355493ac9492746a0bbd17a4fd40911aa89b5a3a F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93 -F src/sqliteInt.h 68a33c1d88051fae92a9528f198fbcaf3ddb3b39 +F src/sqliteInt.h 2c05edf4b8155bf4ef0775a9c30e4b57d7527af3 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -250,12 +250,12 @@ F src/update.c 2d67e24d5a44d8b1c0839bf2ee0c391593e852bf F src/utf.c c53eb7404b3eb5c1cbb5655c6a7a0e0ce6bd50f0 F src/util.c 06302ffd2b80408d4f6c7af71f7090e0cf8d8ff7 F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e -F src/vdbe.c f03941d4126e2484a52652081a73f2e2e4d4eda1 -F src/vdbe.h a3308e58577f1586e4b0afb5e08b1fb6ac743d0d +F src/vdbe.c a4d43779fd31b00cc7c6e1717e4b6cfacf499e66 +F src/vdbe.h 226d4bc726b3597c35be155a4342db290601d67c F src/vdbeInt.h 1400515b37a4863cdda4601abc0f76eca846c9f5 F src/vdbeapi.c c969d467817ca90f99f3d3b46d115fbec08aeb4c -F src/vdbeaux.c b09cc16325b4faad109fb3e59d393019d1600e55 -F src/vdbeblob.c fde0374afb0c512614aed191ac2683f6772d2b8f +F src/vdbeaux.c 61701754a1528451ddb6e55e9d353e35ea940492 +F src/vdbeblob.c 11248c6362389569764682eb0f59ce910f3cc381 F src/vdbemem.c 5e6effb96dd53d233361cbfaa3f0a43b9af689e9 F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790 F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 @@ -263,7 +263,7 @@ F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582 F src/wal.c 3154756177d6219e233d84291d5b05f4e06ff5e9 F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c 7d09f4c1512affb60cc1190a4b33d121d4ce039a +F src/where.c b641d399cfd8588d0e20d9790d1582b663a732a8 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 @@ -700,6 +700,7 @@ F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 F test/stat.test 0997f6a57a35866b14111ed361ed8851ce7978ae F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796 +F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082 @@ -728,7 +729,7 @@ F test/tkt-02a8e81d44.test 58494de77be2cf249228ada3f313fa399821c6ab F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-2d1a5c67d.test b028a811049eb472cb2d3a43fc8ce4f6894eebda F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 -F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e +F test/tkt-31338dca7e.test 1f714c14b6682c5db715e0bda347926a3456f7a9 F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac F test/tkt-38cb5df375.test 9e9b19857dba0896a8efdaf334d405ba423492f2 F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7 @@ -963,7 +964,7 @@ F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02 F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9 F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b -F tool/spaceanal.tcl 1ee4df4e190675ba67b8c60cf304496d0021cfb4 +F tool/spaceanal.tcl fe02dede3d29ef0fefcf80a685644fdf4d9a768e F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355 F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff @@ -974,7 +975,7 @@ F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5 F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings.sh b7fdb2cc525f5ef4fa43c80e771636dd3690f9d2 -P eb036d6f81e15bac013316bf5b1b2ba3e0bd4605 3035dc1c7398791d550f4c02774ef7f961b4bb02 -R 807d1da65636d94548ad55811c85e6a7 -U dan -Z e140cc97ae2304f1c705299d75477c59 +P c00e45ede7cbf71a3a6d1ccad0b9275010ca8493 cf51ef8ab8a610ddf64f66970dd689fe1df405b8 +R 8f9c10e95fc4061078755c289f7e07d0 +U drh +Z 423f374ece1297d22d3fad8417996b4a diff --git a/manifest.uuid b/manifest.uuid index 39610efda7..a912068f8e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c00e45ede7cbf71a3a6d1ccad0b9275010ca8493 \ No newline at end of file +5efb02949dbeabccfe1d848d275529f03f3dfc84 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index ab218078db..6fd08b27f1 100644 --- a/src/expr.c +++ b/src/expr.c @@ -901,7 +901,8 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; - pNewItem->isPopulated = pOldItem->isPopulated; + pNewItem->addrFillSub = pOldItem->addrFillSub; + pNewItem->regReturn = pOldItem->regReturn; pNewItem->isCorrelated = pOldItem->isCorrelated; pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); pNewItem->notIndexed = pOldItem->notIndexed; @@ -1461,8 +1462,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ int iMem = ++pParse->nMem; int iAddr; - iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); - sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); + iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; @@ -1493,8 +1493,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ char *pKey; pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); - iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); - sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); + iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); @@ -1579,6 +1578,7 @@ int sqlite3CodeSubselect( int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; + assert( sqlite3VdbeCurrentAddr(v)>0 ); sqlite3ExprCachePush(pParse); /* This code must be run in its entirety every time it is encountered @@ -1593,8 +1593,7 @@ int sqlite3CodeSubselect( */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){ int mem = ++pParse->nMem; - sqlite3VdbeAddOp1(v, OP_If, mem); - testAddr = sqlite3VdbeAddOp2(v, OP_Integer, 1, mem); + testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem); assert( testAddr>0 || pParse->db->mallocFailed ); } @@ -1694,7 +1693,7 @@ int sqlite3CodeSubselect( ** expression we need to rerun this code each time. */ if( testAddr && !sqlite3ExprIsConstant(pE2) ){ - sqlite3VdbeChangeToNoop(v, testAddr-1, 2); + sqlite3VdbeChangeToNoop(v, testAddr); testAddr = 0; } @@ -1765,7 +1764,7 @@ int sqlite3CodeSubselect( } if( testAddr ){ - sqlite3VdbeJumpHere(v, testAddr-1); + sqlite3VdbeJumpHere(v, testAddr); } sqlite3ExprCachePop(pParse, 1); diff --git a/src/select.c b/src/select.c index a8ea08a781..89c6b251c3 100644 --- a/src/select.c +++ b/src/select.c @@ -89,6 +89,8 @@ Select *sqlite3SelectNew( clearSelect(db, pNew); if( pNew!=&standin ) sqlite3DbFree(db, pNew); pNew = 0; + }else{ + assert( pNew->pSrc!=0 || pParse->nErr>0 ); } return pNew; } @@ -3801,7 +3803,11 @@ int sqlite3Select( Select *pSub = pItem->pSelect; int isAggSub; - if( pSub==0 || pItem->isPopulated ) continue; + if( pSub==0 ) continue; + if( pItem->addrFillSub ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); + continue; + } /* Increment Parse.nHeight by the height of the largest expression ** tree refered to by this, the parent select. The child select @@ -3812,21 +3818,44 @@ int sqlite3Select( */ pParse->nHeight += sqlite3SelectExprHeight(p); - /* Check to see if the subquery can be absorbed into the parent. */ isAggSub = (pSub->selFlags & SF_Aggregate)!=0; if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ + /* This subquery can be absorbed into its parent. */ if( isAggSub ){ isAgg = 1; p->selFlags |= SF_Aggregate; } i = -1; }else{ + /* Generate a subroutine that will fill an ephemeral table with + ** the content of this subquery. pItem->addrFillSub will point + ** to the address of the generated subroutine. pItem->regReturn + ** is a register allocated to hold the subroutine return address + */ + int topAddr; + int onceAddr = 0; + int retAddr; + assert( pItem->addrFillSub==0 ); + pItem->regReturn = ++pParse->nMem; + topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); + pItem->addrFillSub = topAddr+1; + VdbeNoopComment((v, "materialize %s", pItem->pTab->zName)); + if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){ + /* If the subquery is no correlated and if we are not inside of + ** a trigger, then we only need to compute the value of the subquery + ** once. */ + int regOnce = ++pParse->nMem; + onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce); + } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - assert( pItem->isPopulated==0 ); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->isPopulated = 1; pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; + if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); + retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); + VdbeComment((v, "end %s", pItem->pTab->zName)); + sqlite3VdbeChangeP1(v, topAddr, retAddr); + } if( /*pParse->nErr ||*/ db->mallocFailed ){ goto select_end; @@ -3967,7 +3996,7 @@ int sqlite3Select( ** into an OP_Noop. */ if( addrSortIndex>=0 && pOrderBy==0 ){ - sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); + sqlite3VdbeChangeToNoop(v, addrSortIndex); p->addrOpenEphm[2] = -1; } @@ -4250,7 +4279,7 @@ int sqlite3Select( sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop); }else{ sqlite3WhereEnd(pWInfo); - sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1); + sqlite3VdbeChangeToNoop(v, addrSortingIdx); } /* Output the final row of result diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 390e40e31b..b1cc524377 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1860,7 +1860,8 @@ struct SrcList { char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ - u8 isPopulated; /* Temporary table associated with SELECT is populated */ + int addrFillSub; /* Address of subroutine to manifest a subquery */ + int regReturn; /* Register holding return address of addrFillSub */ u8 jointype; /* Type of join between this able and the previous */ u8 notIndexed; /* True if there is a NOT INDEXED clause */ u8 isCorrelated; /* True if sub-query is correlated */ diff --git a/src/vdbe.c b/src/vdbe.c index b6bf463047..1822cea785 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2031,6 +2031,16 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ break; } +/* Opcode: Once P1 P2 * * * +** +** Jump to P2 if the value in register P1 is a not null or zero. If +** the value is NULL or zero, fall through and change the P1 register +** to an integer 1. +** +** When P1 is not used otherwise in a program, this opcode falls through +** once and jumps on all subsequent invocations. It is the equivalent +** of "OP_If P1 P2", followed by "OP_Integer 1 P1". +*/ /* Opcode: If P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is true. The value @@ -2043,6 +2053,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ ** is considered true if it has a numeric value of zero. If the value ** in P1 is NULL then take the jump if P3 is true. */ +case OP_Once: /* jump, in1 */ case OP_If: /* jump, in1 */ case OP_IfNot: { /* jump, in1 */ int c; @@ -2059,6 +2070,12 @@ case OP_IfNot: { /* jump, in1 */ } if( c ){ pc = pOp->p2-1; + }else if( pOp->opcode==OP_Once ){ + assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 ); + memAboutToChange(p, pIn1); + pIn1->flags = MEM_Int; + pIn1->u.i = 1; + REGISTER_TRACE(pOp->p1, pIn1); } break; } diff --git a/src/vdbe.h b/src/vdbe.h index 9332b9851d..990cb1790e 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -182,7 +182,7 @@ void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u8 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); -void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); +void sqlite3VdbeChangeToNoop(Vdbe*, int addr); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index b7239bb684..7092724403 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -671,18 +671,15 @@ void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ } /* -** Change N opcodes starting at addr to No-ops. +** Change the opcode at addr into OP_Noop */ -void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){ +void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ if( p->aOp ){ VdbeOp *pOp = &p->aOp[addr]; sqlite3 *db = p->db; - while( N-- ){ - freeP4(db, pOp->p4type, pOp->p4.p); - memset(pOp, 0, sizeof(pOp[0])); - pOp->opcode = OP_Noop; - pOp++; - } + freeP4(db, pOp->p4type, pOp->p4.p); + memset(pOp, 0, sizeof(pOp[0])); + pOp->opcode = OP_Noop; } } diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 2f37ad933b..995c08d166 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -277,7 +277,7 @@ int sqlite3_blob_open( /* Configure the OP_TableLock instruction */ #ifdef SQLITE_OMIT_SHARED_CACHE - sqlite3VdbeChangeToNoop(v, 2, 1); + sqlite3VdbeChangeToNoop(v, 2); #else sqlite3VdbeChangeP1(v, 2, iDb); sqlite3VdbeChangeP2(v, 2, pTab->tnum); @@ -287,7 +287,7 @@ int sqlite3_blob_open( /* Remove either the OP_OpenWrite or OpenRead. Set the P2 ** parameter of the other to pTab->tnum. */ - sqlite3VdbeChangeToNoop(v, 4 - flags, 1); + sqlite3VdbeChangeToNoop(v, 4 - flags); sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum); sqlite3VdbeChangeP3(v, 3 + flags, iDb); diff --git a/src/where.c b/src/where.c index 21fb7f45f4..fd7da6274d 100644 --- a/src/where.c +++ b/src/where.c @@ -467,11 +467,19 @@ static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){ static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){ Bitmask mask = 0; while( pS ){ + SrcList *pSrc = pS->pSrc; mask |= exprListTableUsage(pMaskSet, pS->pEList); mask |= exprListTableUsage(pMaskSet, pS->pGroupBy); mask |= exprListTableUsage(pMaskSet, pS->pOrderBy); mask |= exprTableUsage(pMaskSet, pS->pWhere); mask |= exprTableUsage(pMaskSet, pS->pHaving); + if( ALWAYS(pSrc!=0) ){ + int i; + for(i=0; inSrc; i++){ + mask |= exprSelectTableUsage(pMaskSet, pSrc->a[i].pSelect); + mask |= exprTableUsage(pMaskSet, pSrc->a[i].pOn); + } + } pS = pS->pPrior; } return mask; @@ -1994,8 +2002,7 @@ static void constructAutomaticIndex( v = pParse->pVdbe; assert( v!=0 ); regIsInit = ++pParse->nMem; - addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit); - sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit); + addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit); /* Count the number of columns that will be added to the index ** and used to match WHERE clause constraints */ diff --git a/test/subquery2.test b/test/subquery2.test new file mode 100644 index 0000000000..04200046f9 --- /dev/null +++ b/test/subquery2.test @@ -0,0 +1,86 @@ +# 2011 September 16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing correlated subqueries +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !subquery { + finish_test + return +} + +do_test subquery2-1.1 { + execsql { + BEGIN; + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(3,4); + INSERT INTO t1 VALUES(5,6); + INSERT INTO t1 VALUES(7,8); + CREATE TABLE t2(c,d); + INSERT INTO t2 VALUES(1,1); + INSERT INTO t2 VALUES(3,9); + INSERT INTO t2 VALUES(5,25); + INSERT INTO t2 VALUES(7,49); + CREATE TABLE t3(e,f); + INSERT INTO t3 VALUES(1,1); + INSERT INTO t3 VALUES(3,27); + INSERT INTO t3 VALUES(5,125); + INSERT INTO t3 VALUES(7,343); + COMMIT; + } + execsql { + SELECT a FROM t1 + WHERE b IN (SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1 3 5 7} +do_test subquery2-1.2 { + execsql { + CREATE INDEX t1b ON t1(b); + SELECT a FROM t1 + WHERE b IN (SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1 3 5 7} + +do_test subquery2-1.11 { + execsql { + SELECT a FROM t1 + WHERE +b=(SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1} +do_test subquery2-1.12 { + execsql { + SELECT a FROM t1 + WHERE b=(SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1} + +do_test subquery2-1.21 { + execsql { + SELECT a FROM t1 + WHERE +b=(SELECT x+1 FROM + (SELECT DISTINCT f/d AS x FROM t2 JOIN t3 ON d*a=f)) + } +} {1 3 5 7} +do_test subquery2-1.22 { + execsql { + SELECT a FROM t1 + WHERE b=(SELECT x+1 FROM + (SELECT DISTINCT f/d AS x FROM t2 JOIN t3 ON d*a=f)) + } +} {1 3 5 7} + + +finish_test diff --git a/test/tkt-31338dca7e.test b/test/tkt-31338dca7e.test index 3f66816d64..9423c684e9 100644 --- a/test/tkt-31338dca7e.test +++ b/test/tkt-31338dca7e.test @@ -74,4 +74,105 @@ do_test tkt-31338-2.2 { } {111 222 222 333 888 333 444 444 555 888 333 444 444 555 999} +# Ticket [2c2de252666662f5459904fc33a9f2956cbff23c] +# +do_test tkt-31338-3.1 { + foreach x [db eval {SELECT name FROM sqlite_master WHERE type='table'}] { + db eval "DROP TABLE $x" + } + db eval { + CREATE TABLE t1(a,b,c,d); + CREATE TABLE t2(e,f); + INSERT INTO t1 VALUES(1,2,3,4); + INSERT INTO t2 VALUES(10,-8); + CREATE INDEX t1a ON t1(a); + CREATE INDEX t1b ON t1(b); + CREATE TABLE t3(g); + INSERT INTO t3 VALUES(4); + CREATE TABLE t4(h); + INSERT INTO t4 VALUES(5); + + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} +do_test tkt-31338-3.2 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b=2 AND b NOT IN ( + SELECT x+1 FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} +do_test tkt-31338-3.3 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (+a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} +do_test tkt-31338-3.4 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (+b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} + +do_test tkt-31338-3.5 { + db eval { + CREATE TABLE t5(a,b,c,d,e,f); + CREATE TABLE t6(g,h); + CREATE TRIGGER t6r AFTER INSERT ON t6 BEGIN + INSERT INTO t5 + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + END; + INSERT INTO t6 VALUES(88,99); + SELECT * FROM t5; + } +} {4 1 2 3 4 {}} + +do_test tkt-31338-3.6 { + db eval { + INSERT INTO t1 VALUES(2,4,3,4); + INSERT INTO t1 VALUES(99,101,3,4); + INSERT INTO t1 VALUES(98,97,3,4); + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x+a FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 2 4 3 4 {} 4 99 101 3 4 {}} + +do_test tkt-31338-3.7 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f+a AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 2 4 3 4 {} 4 99 101 3 4 {}} + + finish_test diff --git a/tool/spaceanal.tcl b/tool/spaceanal.tcl index 13ab1af5f7..52e825b798 100644 --- a/tool/spaceanal.tcl +++ b/tool/spaceanal.tcl @@ -4,11 +4,14 @@ # if {[catch { +if {![info exists argv0]} { + set argv0 [file rootname [file tail [info nameofexecutable]]] +} # Get the name of the database to analyze # #set argv $argv0 -if {[llength $argv]!=1} { +if {![info exists argv] || [llength $argv]!=1} { puts stderr "Usage: $argv0 database-name" exit 1 } @@ -28,12 +31,12 @@ if {[file size $file_to_analyze]<512} { # Open the database # -sqlite3 db [lindex $argv 0] +sqlite3 db $file_to_analyze register_dbstat_vtab db set pageSize [db one {PRAGMA page_size}] -#set DB [btree_open [lindex $argv 0] 1000 0] +#set DB [btree_open $file_to_analyze 1000 0] # In-memory database for collecting statistics. This script loops through # the tables and indices in the database being analyzed, adding a row for each