1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Ensure that queries like "SELECT indeterministic(a) FROM tbl GROUP BY 1" invoke the indeterministic function only once for each row of tbl.

FossilOrigin-Name: 4555d66547e28cb110e1012b145bcf3aafb5d4bde05e9d27bcb4ca33837b28f5
This commit is contained in:
dan
2024-05-24 18:31:39 +00:00
parent 31079226f7
commit 89b04f3786
6 changed files with 54 additions and 15 deletions

View File

@ -1,5 +1,5 @@
C Add\sthe\sstmtrand()\sextension\sfunction\sfor\suse\sin\stesting. C Ensure\sthat\squeries\slike\s"SELECT\sindeterministic(a)\sFROM\stbl\sGROUP\sBY\s1"\sinvoke\sthe\sindeterministic\sfunction\sonly\sonce\sfor\seach\srow\sof\stbl.
D 2024-05-24T14:16:06.243 D 2024-05-24T18:31:39.505
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -705,7 +705,7 @@ F src/date.c 126ba2ab10aeb2e7ba6e089b5f07b747c0625b8287f78b60da346eda8d23c875
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43 F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500 F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
F src/expr.c 50e71ed518f1b1ba8401006922a309e200d205b2ca5b93d6fd8a006a336dbf67 F src/expr.c 585109ab97149b2d484697e7469f28c91d495cd1330cc760d24711b7be8d22fb
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 852f93c0ef995e0c2b8983059a2b97151c194cc8259e21f5bc2b7ac508348c2a F src/fkey.c 852f93c0ef995e0c2b8983059a2b97151c194cc8259e21f5bc2b7ac508348c2a
F src/func.c f1f57c6863c1380f31ecf3d61732495bfff847a8e35a832c7e306e310db5a799 F src/func.c f1f57c6863c1380f31ecf3d61732495bfff847a8e35a832c7e306e310db5a799
@ -755,12 +755,12 @@ F src/printf.c 8b250972305e14b365561be5117ed0fd364e4fd58968776df1ce64c6280b90f9
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 22f1fa3423b377c02ae78d451cfeb1c2d96dcf0389c0642cbdcd19d3bfd7ae01 F src/resolve.c 22f1fa3423b377c02ae78d451cfeb1c2d96dcf0389c0642cbdcd19d3bfd7ae01
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 1a841c38974d45cf15a7611398479182b61ad4c187423c380741d8b1688fe607 F src/select.c cbdaf9cb2d9a697ee9ce1484f27d2e96762d33cc19259aedfb818a68b9d3be10
F src/shell.c.in 31249f26684467e95e529915bf486961c535ae8288ed7e79890cc9ed3d781d8f F src/shell.c.in 31249f26684467e95e529915bf486961c535ae8288ed7e79890cc9ed3d781d8f
F src/sqlite.h.in c71d9ef76a6d32dc7ff2d373f2e57ce09056af26c1457bcadae5358b7628c7c3 F src/sqlite.h.in c71d9ef76a6d32dc7ff2d373f2e57ce09056af26c1457bcadae5358b7628c7c3
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
F src/sqliteInt.h 6a9fa3902c9faca2b57060e822f2afadfbf96d64c4ede81e201f0e0c42d7e4aa F src/sqliteInt.h 98ba756789b37f8d8217407ce077c31faf0b9b21d593b327c2b9667ad5bea1ac
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728 F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@ -1074,7 +1074,7 @@ F test/descidx2.test a0ba347037ff3b811f4c6ceca5fd0f9d5d72e74e59f2d9de346a9d2f6ad
F test/descidx3.test 953c831df7ea219c73826dfbf2f6ee02d95040725aa88ccb4fa43d1a1999b926 F test/descidx3.test 953c831df7ea219c73826dfbf2f6ee02d95040725aa88ccb4fa43d1a1999b926
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
F test/distinct.test 691c9e850b0d0b56b66e7e235453198cb4cf0760e324b7403d3c5abbeab0a014 F test/distinct.test 691c9e850b0d0b56b66e7e235453198cb4cf0760e324b7403d3c5abbeab0a014
F test/distinct2.test bb71cc7b5e58e895787f9910a788c254f679928d324732d063fe9bc202ecbe71 F test/distinct2.test c936bb8652258c04bf066706284f5cd54ec693817399dbd6503c49d41ace626e
F test/distinctagg.test 40d7169ae5846caaf62c6e307d2ca3c333daf9b6f7cde888956a339a97afe85f F test/distinctagg.test 40d7169ae5846caaf62c6e307d2ca3c333daf9b6f7cde888956a339a97afe85f
F test/e_blobbytes.test 4c01dfe4f12087b92b20705a3fdfded45dc4ed16d5a211fed4e1d2786ba68a52 F test/e_blobbytes.test 4c01dfe4f12087b92b20705a3fdfded45dc4ed16d5a211fed4e1d2786ba68a52
F test/e_blobclose.test 692fc02a058476c2222a63d97e3f3b2b809c1842e5525ded7f854d540ac2e075 F test/e_blobclose.test 692fc02a058476c2222a63d97e3f3b2b809c1842e5525ded7f854d540ac2e075
@ -2193,8 +2193,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P b8442d2a6012b1f2e15381613267db0982e36bb4c748b15b56e668e0d0a3d0d2 P 5c97a5b9d163b1c427e002f3734687ca0384bc0da6a90fc4bfd358c654d3a7b3
R 01f61db2371d56efe0fc89de21914b9a R 5fdf8e25d08374c3b6caf60dac9645e5
U drh T *branch * group-by-consistency
Z 5bafe7bbe2cfe723081ab4c42a45e0a5 T *sym-group-by-consistency *
T -sym-trunk *
U dan
Z 5149149f75ab1db4d2d6bfcada9a5ce2
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
5c97a5b9d163b1c427e002f3734687ca0384bc0da6a90fc4bfd358c654d3a7b3 4555d66547e28cb110e1012b145bcf3aafb5d4bde05e9d27bcb4ca33837b28f5

View File

@ -4243,7 +4243,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
** register iReg. The caller must ensure that iReg already contains ** register iReg. The caller must ensure that iReg already contains
** the correct value for the expression. ** the correct value for the expression.
*/ */
static void exprToRegister(Expr *pExpr, int iReg){ void sqlite3ExprToRegister(Expr *pExpr, int iReg){
Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
if( NEVER(p==0) ) return; if( NEVER(p==0) ) return;
p->op2 = p->op; p->op2 = p->op;
@ -5252,7 +5252,7 @@ expr_code_doover:
break; break;
} }
testcase( pX->op==TK_COLUMN ); testcase( pX->op==TK_COLUMN );
exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1)); sqlite3ExprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
testcase( regFree1==0 ); testcase( regFree1==0 );
memset(&opCompare, 0, sizeof(opCompare)); memset(&opCompare, 0, sizeof(opCompare));
opCompare.op = TK_EQ; opCompare.op = TK_EQ;
@ -5602,7 +5602,7 @@ static void exprCodeBetween(
compRight.op = TK_LE; compRight.op = TK_LE;
compRight.pLeft = pDel; compRight.pLeft = pDel;
compRight.pRight = pExpr->x.pList->a[1].pExpr; compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1)); sqlite3ExprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
if( xJump ){ if( xJump ){
xJump(pParse, &exprAnd, dest, jumpIfNull); xJump(pParse, &exprAnd, dest, jumpIfNull);
}else{ }else{

View File

@ -7847,12 +7847,18 @@ int sqlite3Select(
*/ */
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
&& OptimizationEnabled(db, SQLITE_GroupByOrder)
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
&& p->pWin==0 && p->pWin==0
#endif #endif
){ ){
p->selFlags &= ~SF_Distinct; p->selFlags &= ~SF_Distinct;
pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
if( pGroupBy ){
for(i=0; i<pGroupBy->nExpr; i++){
pGroupBy->a[i].u.x.iOrderByCol = i+1;
}
}
p->selFlags |= SF_Aggregate; p->selFlags |= SF_Aggregate;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags, /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the ** the sDistinct.isTnct is still set. Hence, isTnct represents the
@ -8315,12 +8321,18 @@ int sqlite3Select(
sortOut, sortPTab); sortOut, sortPTab);
} }
for(j=0; j<pGroupBy->nExpr; j++){ for(j=0; j<pGroupBy->nExpr; j++){
int iOrderByCol = pGroupBy->a[j].u.x.iOrderByCol;
if( groupBySort ){ if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
}else{ }else{
pAggInfo->directMode = 1; pAggInfo->directMode = 1;
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
} }
if( iOrderByCol ){
sqlite3ExprToRegister(p->pEList->a[iOrderByCol-1].pExpr, iAMem+j);
}
} }
sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
(char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
@ -8336,9 +8348,9 @@ int sqlite3Select(
** and resets the aggregate accumulator registers in preparation ** and resets the aggregate accumulator registers in preparation
** for the next GROUP BY batch. ** for the next GROUP BY batch.
*/ */
sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
VdbeComment((v, "output one row")); VdbeComment((v, "output one row"));
sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v);
VdbeComment((v, "check abort flag")); VdbeComment((v, "check abort flag"));
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);

View File

@ -5025,6 +5025,7 @@ void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int);
void sqlite3ExprToRegister(Expr *pExpr, int iReg);
void sqlite3ExprCode(Parse*, Expr*, int); void sqlite3ExprCode(Parse*, Expr*, int);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS #ifndef SQLITE_OMIT_GENERATED_COLUMNS
void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int);

View File

@ -313,4 +313,27 @@ do_execsql_test 4020 {
SELECT b FROM t1 UNION SELECT 1; SELECT b FROM t1 UNION SELECT 1;
} {1 { }} } {1 { }}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5010 {
CREATE TABLE cnt(a);
WITH RECURSIVE cnt2(x) AS (
VALUES(1) UNION ALL SELECT x+1 FROM cnt2 WHERE x<50
)
INSERT INTO cnt SELECT x FROM cnt2;
}
do_execsql_test 5020 {
SELECT DISTINCT abs(random())%5 AS r FROM cnt ORDER BY r;
} {0 1 2 3 4}
do_execsql_test 5030 {
SELECT abs(random())%5 AS r FROM cnt GROUP BY 1 ORDER BY 1;
} {0 1 2 3 4}
do_execsql_test 5040 {
SELECT a FROM cnt WHERE a>45 GROUP BY 1;
} {46 47 48 49 50}
finish_test finish_test