From d176611b442a37df0714e7b3f55da802a2922c61 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 17 Sep 2008 00:13:12 +0000 Subject: [PATCH] Fix for tickets #3378 and #3381 that preserves the aliasing optimization. And yet, this fix feels uncomfortable. Seeking an alternative... (CVS 5712) FossilOrigin-Name: f8b759f1977915c314be874840ebf18e6bc69b57 --- manifest | 16 +++--- manifest.uuid | 2 +- src/expr.c | 13 +++-- src/select.c | 121 +++++++++++++++++++++++++--------------------- test/selectC.test | 10 +++- 5 files changed, 90 insertions(+), 72 deletions(-) diff --git a/manifest b/manifest index 40f4d772e0..b53f3717cf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\scases\sfor\sticket\s#3378\sand\s#3381.\s\sAdd\sa\stemporary\shack\sto\sget\sthose\nto\sproblems\sfixed.\s\sThe\shack\scauses\sfailures\sin\salias.test,\sbut\sthose\sare\smuch\nless\sserious\sthan\sthe\saforementioned\stickets.\s\sThis\sis\sa\sstop-gap\suntil\swe\scan\nfigure\sout\sa\sproper\sfix.\s(CVS\s5711) -D 2008-09-16T18:02:47 +C Fix\sfor\stickets\s#3378\sand\s#3381\sthat\spreserves\sthe\saliasing\soptimization.\nAnd\syet,\sthis\sfix\sfeels\suncomfortable.\s\sSeeking\san\salternative...\s(CVS\s5712) +D 2008-09-17T00:13:12 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -107,7 +107,7 @@ F src/callback.c 7a40fd44da3eb89e7f6eff30aa6f940c45d73a97 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c F src/date.c 5c092296c03d658e84884121a694150964d6861d F src/delete.c bae6684aa02e1f7cf6328023157c91d9cf94200b -F src/expr.c e439afc46c5e859c1d6137fb447f8b5a0c05372f +F src/expr.c 04822d5c7af85fd195a5f72501ab5e8d99768fae F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff F src/func.c 8431b40a7843d1024145684d303c55b4ee087bbe F src/global.c 20a3fe46c8287a01ba3a7442558f0eb70c66b19a @@ -147,7 +147,7 @@ F src/prepare.c c7e00ed1b0bdcf699b1aad651247d4dc3d281b0b F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d F src/random.c 11bbdf7def3746a762fbdb56c9d04648135ad6d8 F src/resolve.c a6abf83125bce0c80ba04acc27c3565155ad305c -F src/select.c 9cf9aac53aae65ce519310fd86ea3d895a654d79 +F src/select.c 4d25fe8da35abb5b5317a0248bedc3c9570416e9 F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967 F src/sqlite.h.in 81dc1e8e50fb5c7cccf0a67a34cb796efc1d2a1e F src/sqlite3ext.h 1e3887c9bd3ae66cb599e922824b04cd0d0f2c3e @@ -480,7 +480,7 @@ F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d F test/select9.test b4007b15396cb7ba2615cab31e1973b572e43210 F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532 F test/selectB.test 31e81ac9af7d224850e0706350f070ecb92fcbc7 -F test/selectC.test afc5b7bb570c59b17aa0719c51ed0ff53588f8bb +F test/selectC.test 44f4e1b2c86e40f8135294a826ec4142766e21c3 F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c F test/shared.test b9f3bbd3ba727c5f1f8c815b7d0199262aacf214 F test/shared2.test 0ee9de8964d70e451936a48c41cb161d9134ccf4 @@ -637,7 +637,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P bd58be6ecf0a22f3c8404bd7094ab5e13e19b1c4 -R 2fc3441b1258e07766f97b640f95644a +P a67da9dd2ff6acc163de4ce2b836b03e3f159a88 +R 14978e8fa671319bba1736bf8a70ed4f U drh -Z e70756170cf6143ba60cbd6ecd5882c4 +Z 020ff8f35c07f9455927e2b1f65bc01f diff --git a/manifest.uuid b/manifest.uuid index 17587d03ee..31500ab308 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a67da9dd2ff6acc163de4ce2b836b03e3f159a88 \ No newline at end of file +f8b759f1977915c314be874840ebf18e6bc69b57 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 3d742cd9c8..ab0cf1e318 100644 --- a/src/expr.c +++ b/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.393 2008/09/16 18:02:47 drh Exp $ +** $Id: expr.c,v 1.394 2008/09/17 00:13:12 drh Exp $ */ #include "sqliteInt.h" #include @@ -2456,7 +2456,7 @@ int sqlite3ExprCodeExprList( Parse *pParse, /* Parsing context */ ExprList *pList, /* The expression list to be coded */ int target, /* Where to write results */ - int doHardCopy /* Call sqlite3ExprHardCopy on each element if true */ + int doHardCopy /* Make a hard copy of every element */ ){ struct ExprList_item *pItem; int i, n; @@ -2464,17 +2464,16 @@ int sqlite3ExprCodeExprList( assert( target>0 ); n = pList->nExpr; for(pItem=pList->a, i=0; iiAlias ){ int iReg = codeAlias(pParse, pItem->iAlias, pItem->pExpr); Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i); - }else -#endif - { + }else{ sqlite3ExprCode(pParse, pItem->pExpr, target+i); } - if( doHardCopy ) sqlite3ExprHardCopy(pParse, target, n); + if( doHardCopy ){ + sqlite3ExprHardCopy(pParse, target, n); + } } return n; } diff --git a/src/select.c b/src/select.c index c3442a2cd2..5871491c44 100644 --- a/src/select.c +++ b/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.474 2008/09/16 15:55:56 danielk1977 Exp $ +** $Id: select.c,v 1.475 2008/09/17 00:13:12 drh Exp $ */ #include "sqliteInt.h" @@ -2047,7 +2047,7 @@ static int multiSelectOrderBy( int labelEnd; /* Label for the end of the overall SELECT stmt */ int j1; /* Jump instructions that get retargetted */ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ - KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ + KeyInfo *pKeyDup; /* Comparison information for duplicate removal */ KeyInfo *pKeyMerge; /* Comparison information for merging rows */ sqlite3 *db; /* Database connection */ ExprList *pOrderBy; /* The ORDER BY clause */ @@ -3650,20 +3650,25 @@ int sqlite3Select( ** processed */ int iAbortFlag; /* Mem address which causes query abort if positive */ int groupBySort; /* Rows come from source in GROUP BY order */ + int addrEnd; /* End of processing for this SELECT */ + /* Remove any and all aliases between the result set and the + ** GROUP BY clause. + */ + if( pGroupBy ){ + int i; /* Loop counter */ + struct ExprList_item *pItem; /* For looping over expression in a list */ - /* The following variables hold addresses or labels for parts of the - ** virtual machine program we are putting together */ - int addrOutputRow; /* Start of subroutine that outputs a result row */ - int regOutputRow; /* Return address register for output subroutine */ - int addrSetAbort; /* Set the abort flag and return */ - int addrInitializeLoop; /* Start of code that initializes the input loop */ - int addrTopOfLoop; /* Top of the input loop */ - int addrEnd; /* End of all processing */ - int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ - int addrReset; /* Subroutine for resetting the accumulator */ - int regReset; /* Return address register for reset subroutine */ + for(i=p->pEList->nExpr, pItem=p->pEList->a; i>0; i--, pItem++){ + pItem->iAlias = 0; + } + for(i=pGroupBy->nExpr, pItem=pGroupBy->a; i>0; i--, pItem++){ + pItem->iAlias = 0; + } + } + + /* Create a label to jump to when we want to abort the query */ addrEnd = sqlite3VdbeMakeLabel(v); /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in @@ -3692,11 +3697,14 @@ int sqlite3Select( */ if( pGroupBy ){ KeyInfo *pKeyInfo; /* Keying information for the group by clause */ - int j1; - - /* Create labels that we will be needing - */ - addrInitializeLoop = sqlite3VdbeMakeLabel(v); + int j1; /* A-vs-B comparision jump */ + int addrOutputRow; /* Start of subroutine that outputs a result row */ + int regOutputRow; /* Return address register for output subroutine */ + int addrSetAbort; /* Set the abort flag and return */ + int addrTopOfLoop; /* Top of the input loop */ + int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ + int addrReset; /* Subroutine for resetting the accumulator */ + int regReset; /* Return address register for reset subroutine */ /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out @@ -3713,6 +3721,10 @@ int sqlite3Select( */ iUseFlag = ++pParse->nMem; iAbortFlag = ++pParse->nMem; + regOutputRow = ++pParse->nMem; + addrOutputRow = sqlite3VdbeMakeLabel(v); + regReset = ++pParse->nMem; + addrReset = sqlite3VdbeMakeLabel(v); iAMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; iBMem = pParse->nMem + 1; @@ -3721,47 +3733,12 @@ int sqlite3Select( VdbeComment((v, "clear abort flag")); sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); VdbeComment((v, "indicate accumulator empty")); - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrInitializeLoop); - - /* Generate a subroutine that outputs a single row of the result - ** set. This subroutine first looks at the iUseFlag. If iUseFlag - ** is less than or equal to zero, the subroutine is a no-op. If - ** the processing calls for the query to abort, this subroutine - ** increments the iAbortFlag memory location before returning in - ** order to signal the caller to abort. - */ - addrSetAbort = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_Integer, 1, iAbortFlag); - VdbeComment((v, "set abort flag")); - regOutputRow = ++pParse->nMem; - sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); - addrOutputRow = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); - VdbeComment((v, "Groupby result generator entry point")); - sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); - finalizeAggFunctions(pParse, &sAggInfo); - if( pHaving ){ - sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); - } - selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy, - distinct, pDest, - addrOutputRow+1, addrSetAbort); - sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); - VdbeComment((v, "end groupby result generator")); - - /* Generate a subroutine that will reset the group-by accumulator - */ - addrReset = sqlite3VdbeCurrentAddr(v); - regReset = ++pParse->nMem; - resetAccumulator(pParse, &sAggInfo); - sqlite3VdbeAddOp1(v, OP_Return, regReset); /* Begin a loop that will extract all source rows in GROUP BY order. ** This might involve two separate loops with an OP_Sort in between, or ** it might be a single loop that uses an index to extract information ** in the right order to begin with. */ - sqlite3VdbeResolveLabel(v, addrInitializeLoop); sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0); if( pWInfo==0 ) goto select_end; @@ -3879,7 +3856,43 @@ int sqlite3Select( */ sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); VdbeComment((v, "output final row")); - + + /* Jump over the subroutines + */ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEnd); + + /* Generate a subroutine that outputs a single row of the result + ** set. This subroutine first looks at the iUseFlag. If iUseFlag + ** is less than or equal to zero, the subroutine is a no-op. If + ** the processing calls for the query to abort, this subroutine + ** increments the iAbortFlag memory location before returning in + ** order to signal the caller to abort. + */ + addrSetAbort = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Integer, 1, iAbortFlag); + VdbeComment((v, "set abort flag")); + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); + sqlite3VdbeResolveLabel(v, addrOutputRow); + addrOutputRow = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); + VdbeComment((v, "Groupby result generator entry point")); + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); + finalizeAggFunctions(pParse, &sAggInfo); + if( pHaving ){ + sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); + } + selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy, + distinct, pDest, + addrOutputRow+1, addrSetAbort); + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); + VdbeComment((v, "end groupby result generator")); + + /* Generate a subroutine that will reset the group-by accumulator + */ + sqlite3VdbeResolveLabel(v, addrReset); + resetAccumulator(pParse, &sAggInfo); + sqlite3VdbeAddOp1(v, OP_Return, regReset); + } /* endif pGroupBy */ else { ExprList *pMinMax = 0; diff --git a/test/selectC.test b/test/selectC.test index cc3e83218b..d35ca569e0 100644 --- a/test/selectC.test +++ b/test/selectC.test @@ -10,7 +10,7 @@ #*********************************************************************** # This file implements regression tests for SQLite library. # -# $Id: selectC.test,v 1.2 2008/09/16 18:02:47 drh Exp $ +# $Id: selectC.test,v 1.3 2008/09/17 00:13:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -117,6 +117,12 @@ do_test selectC-1.13 { ORDER BY x } } {AAA CCC} - +do_test selectC-1.14 { + execsql { + SELECT upper(b) AS x + FROM t1 + ORDER BY x DESC + } +} {CCC AAA AAA} finish_test -- 2.47.2