aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--manifest39
-rw-r--r--manifest.uuid2
-rw-r--r--src/expr.c98
-rw-r--r--src/insert.c236
-rw-r--r--src/parse.y35
-rw-r--r--src/printf.c4
-rw-r--r--src/select.c8
-rw-r--r--src/sqliteInt.h18
-rw-r--r--src/where.c17
-rw-r--r--src/whereexpr.c2
-rw-r--r--src/window.c2
-rw-r--r--test/altertab3.test27
-rw-r--r--test/in4.test4
-rw-r--r--test/sqllimits1.test2
-rw-r--r--test/values.test583
-rw-r--r--test/valuesfault.test37
-rw-r--r--test/whereL.test27
17 files changed, 1051 insertions, 90 deletions
diff --git a/manifest b/manifest
index 345be7312..55bb6354b 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C New\soptions\sfor\stestrunner.tcl:\s\s--stop-on-error\sand\s--stop-on-coredump.
-D 2024-03-15T17:57:58.502
+C Add\sthe\s"VALUES-as-coroutine"\soptimization.\s\sLarge\sVALUES\sclauses\son\san\nINSERT,\sfor\sexample,\sprepare\sand\srun\sin\sabout\shalf\sthe\stime\sand\swith\shalf\nthe\smemory.\s\sThis\scheck-in\salso\sincludes\senhancements\sto\sthe\sinternal\nsqlite3ExprIsConstant()\sroutine\sto\srecognize\spure\sSQL\sfunctions\sas\sconstant\nif\sthey\shave\sconstant\sarguments.
+D 2024-03-18T18:00:17.106
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -700,7 +700,7 @@ F src/date.c 126ba2ab10aeb2e7ba6e089b5f07b747c0625b8287f78b60da346eda8d23c875
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
-F src/expr.c 05516e8b7d7d22f98160a0360fde69edce3304a430600567ed33e66d588ca59b
+F src/expr.c d7cfe9b9fe7ab47b254706589467d2e65fec3536b936d6f4eb28b84da6726ecc
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
F src/func.c 4204c56196847faefef57fa14e43b8e4d65eb8d7e65318abe463472e3fd148cb
@@ -709,7 +709,7 @@ F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c eb33ea46dcab93e90f112fced343aaf41f59cbd2e951d5066f1f9302be1c2f34
+F src/insert.c 06ce505713e86172612f9e01febefd2d3331d1f70461b4ada0eae5a76bb6349f
F src/json.c e2e40760d6689134c3e2ece38c6a496b34ff5e2661a8f238444a119af666fdce
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
@@ -739,23 +739,23 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
-F src/parse.y 6209f01e8e7495379571454744fa82a5cfc2e7eeb89e46dee3f410d73ea6252d
+F src/parse.y 5bcef16094213efcc365a9d4dc4e3131f09251dc8838dce4a9e5f9764bff5b82
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
F src/pragma.c e8221d6310c9923c80f6fa6d09b7ea7c5263a671f53db8d0894df23efcdb617b
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
-F src/printf.c 10e8bad30042f8bd6114a013b4afc229ec8ad255ab27518d7d9f52e8cbc5cd0a
+F src/printf.c 87b67bba3662a0523f39ae6b084a3907109702f717c654d6cecb838af5cd57f1
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c ef87e3bc7700bfe761a7bbee2ce6084f1766dc816dd82a3ae77c133eec898432
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c 43fabfc01bf87addd15e39f112f1e2ade15b19594835ab8a9e5bd50839d4e1b1
+F src/select.c df2bf515fc36e02e97959a70e82da8a4967d6c85590646a7fda2926a734c81ce
F src/shell.c.in cf80c636bccb0ff9db46995e39d69ca21fde2a8a331d1691e4d62a69d7841c8a
F src/sqlite.h.in 19a2db3995a699bd7f6dfb423856242bfceb7ec849a93c91d241d19fc28d9f0f
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h 6123ce6ca6a1ef351c3b87189e92c92042728f16c088de56b9b5bc2552d0ae33
+F src/sqliteInt.h a58b4a33a9807667503a053721a4cd736cda8b60daae896a1b04f120a64c9fd2
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -835,11 +835,11 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
-F src/where.c 33eaaeef3aef10c2b9e82096e70a174d6636e35cb0b180321b8ddf804590e5cd
+F src/where.c 5e9a5d642cceb666152c59091a3dbb645a9dda209b4e65a2f9215ee9298d26cf
F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
-F src/whereexpr.c 6ebd90b553f4bb5c7df5a4b2f39b6a7c81a67484353827cdd2048f2514ec6f30
-F src/window.c 5b1387d59df30d481ed14cceef5f4d1dab1f8752aa106ba72c8b62777bd139d2
+F src/whereexpr.c 7b64295f1d82ad0928df435925dd7bbd5997b44a026153113eace0d9e71ff435
+F src/window.c 5d95122dd330bfaebd732358c8ef067c5a9394a53ac249470d611d0ce2c52be2
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
@@ -867,7 +867,7 @@ F test/altermalloc3.test 8040e486368403f2fdd6fc3998258b499bd4cc2f3ddbb5f8f874cd4
F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834ccba
F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27
F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0
-F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e556481df16
+F test/altertab3.test e167ce3b8e243b52306c1e40b13eb868f402a969513c063998593862cc643b44
F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
@@ -1271,7 +1271,7 @@ F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test d1cad4ededd425568b2e39fb0c31fa9a3772311dd595801ff13ba3912b69bba6
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
-F test/in4.test fdd1d8134da8376985c2edba6035a2de1f6c731524d2ffa651419e8fe2cd1c5a
+F test/in4.test bb767ec1cfd1730256f0a83219f0acda36bc251b63f8b8bb7d8c7cff17875a4f
F test/in5.test b32ce7f4a93f44c5dee94af16886d922cc16ebe33c8e1765c73d4049d0f4b40f
F test/in6.test f5f40d6816a8bb7c784424b58a10ac38efb76ab29127a2c17399e0cbeeda0e4b
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
@@ -1648,7 +1648,7 @@ F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae6a41fb
F test/sqldiff1.test 1b7ab4f312442c5cc6b3a5f299fa8ca051416d1dd173cb1126fd51bf64f2c3fb
-F test/sqllimits1.test 5880a2f107185744ba4d93637f44c78d17706a9899a38b694d50f209735c81cc
+F test/sqllimits1.test dee96a51b83ef866d06ec3c687d4c951d97b02549facc5be88c9dfcb215b98bf
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805
F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac8408
@@ -1921,6 +1921,8 @@ F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7
F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c
F test/vacuum6.test b137b04bf3392d3f5c3b8fda0ce85a6775a70ca112f6559f74ff52dc9ce042fd
F test/vacuummem.test 4b30f5b95a9ff86e9d5c20741e50a898b2dc10b0962a3211571eb165357003fb
+F test/values.test e7c156f92d32ed645908fbad0a1144f0f31650376cdcb212fde701978c89d3b1
+F test/valuesfault.test 2ef23ed965e3bd08e268cdc38a0d11653390ddbbe1e8e2e98d16f55edd30f6e8
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test d4c4281e1679245829db35597817282f60dc513fc39cc5439078f009bd118487
@@ -2009,7 +2011,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test c4bb7e2ca56d49bd8ab5c7bd085b8b83e353922b46904d68aefb3c7468643581
F test/whereJ.test fc05e374cc9f2dc204148d6c06822c380ad388895fe97a6d335b94a26a08aecf
F test/whereK.test 0270ab7f04ba5436fb9156d31d642a1c82727f4c4bfe5ba90d435c78cf44684a
-F test/whereL.test f0e9585623af522ee9f382f8f945ad4b7eb7d806d18746f33f00c374acf6ab65
+F test/whereL.test 438a397fa883b77bb6361c08a8befa41b52e9cfbe15a2a43715d122f8cfa8649
F test/whereM.test 0dbc9998783458ddcf3cc078ca7c2951d8b2677d472ecf0028f449ed327c0250
F test/wherefault.test 6cf2a9c5712952d463d3f45ebee7f6caf400984df51a195d884cfb7eb0e837a7
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
@@ -2177,8 +2179,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P ce009205a8edc02b7d45ac01bd0e692c3d2c3ffeadb68e4f1bad20c39075e692
-R 6f65d3d8f9136f71ba32b06be27a8871
+P 82035b9cfd28ef6b0ecc6f469f03d2b001189aa4925147cdb784b6b1964eb3b2 c86f9f2a15ffc726b7f0d9bba5a8c4dfdaeea6a297e0b591c554fff3d1fe6e1c
+R d086636689a6bb7c4b198edffb3a7c63
+T +closed c86f9f2a15ffc726b7f0d9bba5a8c4dfdaeea6a297e0b591c554fff3d1fe6e1c
U drh
-Z 3ec0c84d38eb2a8a3a9b0c26445e8068
+Z 48e8dd6fe42c5583ed5ba3f909ede536
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 39c5e3d4e..82d6efaee 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-82035b9cfd28ef6b0ecc6f469f03d2b001189aa4925147cdb784b6b1964eb3b2 \ No newline at end of file
+a120c9235f125e05be494038c16a9dd326fd79837698bef17e7879cd0cd75831 \ No newline at end of file
diff --git a/src/expr.c b/src/expr.c
index 6640d1907..3a7065b21 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -218,9 +218,10 @@ Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
assert( pExpr->x.pList->nExpr>0 );
assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr;
- }else{
- assert( pExpr->op==TK_COLLATE );
+ }else if( pExpr->op==TK_COLLATE ){
pExpr = pExpr->pLeft;
+ }else{
+ break;
}
}
return pExpr;
@@ -1869,6 +1870,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
pNewItem->iCursor = pOldItem->iCursor;
pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn;
+ pNewItem->regResult = pOldItem->regResult;
if( pNewItem->fg.isIndexedBy ){
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
}
@@ -2345,6 +2347,54 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
return pExpr;
}
+/*
+** pExpr is a TK_FUNCTION node. Try to determine whether or not the
+** function is a constant function. A function is constant if all of
+** the following are true:
+**
+** (1) It is a scalar function (not an aggregate or window function)
+** (2) It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG
+** property.
+** (3) All of its arguments are constants
+**
+** This routine sets pWalker->eCode to 0 if pExpr is not a constant.
+** It makes no changes to pWalker->eCode if pExpr is constant. In
+** every case, it returns WRC_Abort.
+**
+** Called as a service subroutine from exprNodeIsConstant().
+*/
+static SQLITE_NOINLINE int exprNodeIsConstantFunction(
+ Walker *pWalker,
+ Expr *pExpr
+){
+ int n; /* Number of arguments */
+ ExprList *pList; /* List of arguments */
+ FuncDef *pDef; /* The function */
+ sqlite3 *db; /* The database */
+
+ assert( pExpr->op==TK_FUNCTION );
+ if( ExprHasProperty(pExpr, EP_TokenOnly)
+ || (pList = pExpr->x.pList)==0
+ ){;
+ n = 0;
+ }else{
+ n = pList->nExpr;
+ sqlite3WalkExprList(pWalker, pList);
+ if( pWalker->eCode==0 ) return WRC_Abort;
+ }
+ db = pWalker->pParse->db;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( pDef==0
+ || pDef->xFinalize!=0
+ || (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
+ || ExprHasProperty(pExpr, EP_WinFunc)
+ ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Continue;
+}
+
/*
** These routines are Walker callbacks used to check expressions to
@@ -2373,6 +2423,7 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
+ assert( pWalker->eCode>0 );
/* If pWalker->eCode is 2 then any term of the expression that comes from
** the ON or USING clauses of an outer join disqualifies the expression
@@ -2392,6 +2443,8 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
){
if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
return WRC_Continue;
+ }else if( pWalker->pParse ){
+ return exprNodeIsConstantFunction(pWalker, pExpr);
}else{
pWalker->eCode = 0;
return WRC_Abort;
@@ -2444,9 +2497,10 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
}
-static int exprIsConst(Expr *p, int initFlag, int iCur){
+static int exprIsConst(Parse *pParse, Expr *p, int initFlag, int iCur){
Walker w;
w.eCode = initFlag;
+ w.pParse = pParse;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
@@ -2464,9 +2518,15 @@ static int exprIsConst(Expr *p, int initFlag, int iCur){
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
+**
+** The pParse parameter may be NULL. But if it is NULL, there is no way
+** to determine if function calls are constant or not, and hence all
+** function calls will be considered to be non-constant. If pParse is
+** not NULL, then a function call might be constant, depending on the
+** function and on its parameters.
*/
-int sqlite3ExprIsConstant(Expr *p){
- return exprIsConst(p, 1, 0);
+int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
+ return exprIsConst(pParse, p, 1, 0);
}
/*
@@ -2482,8 +2542,8 @@ int sqlite3ExprIsConstant(Expr *p){
** can be added to the pParse->pConstExpr list and evaluated once when
** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce().
*/
-int sqlite3ExprIsConstantNotJoin(Expr *p){
- return exprIsConst(p, 2, 0);
+static int sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
+ return exprIsConst(pParse, p, 2, 0);
}
/*
@@ -2493,7 +2553,7 @@ int sqlite3ExprIsConstantNotJoin(Expr *p){
** table other than iCur.
*/
int sqlite3ExprIsTableConstant(Expr *p, int iCur){
- return exprIsConst(p, 3, iCur);
+ return exprIsConst(0, p, 3, iCur);
}
/*
@@ -2650,7 +2710,7 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
*/
int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
assert( isInit==0 || isInit==1 );
- return exprIsConst(p, 4+isInit, 0);
+ return exprIsConst(0, p, 4+isInit, 0);
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -2895,13 +2955,13 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
** The argument is an IN operator with a list (not a subquery) on the
** right-hand side. Return TRUE if that list is constant.
*/
-static int sqlite3InRhsIsConstant(Expr *pIn){
+static int sqlite3InRhsIsConstant(Parse *pParse, Expr *pIn){
Expr *pLHS;
int res;
assert( !ExprHasProperty(pIn, EP_xIsSelect) );
pLHS = pIn->pLeft;
pIn->pLeft = 0;
- res = sqlite3ExprIsConstant(pIn);
+ res = sqlite3ExprIsConstant(pParse, pIn);
pIn->pLeft = pLHS;
return res;
}
@@ -3170,7 +3230,7 @@ int sqlite3FindInIndex(
if( eType==0
&& (inFlags & IN_INDEX_NOOP_OK)
&& ExprUseXList(pX)
- && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
+ && (!sqlite3InRhsIsConstant(pParse,pX) || pX->x.pList->nExpr<=2)
){
pParse->nTab--; /* Back out the allocation of the unused cursor */
iTab = -1; /* Cursor is not allocated */
@@ -3453,7 +3513,7 @@ void sqlite3CodeRhsOfIN(
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
- if( addrOnce && !sqlite3ExprIsConstant(pE2) ){
+ if( addrOnce && !sqlite3ExprIsConstant(pParse, pE2) ){
sqlite3VdbeChangeToNoop(v, addrOnce-1);
sqlite3VdbeChangeToNoop(v, addrOnce);
ExprClearProperty(pExpr, EP_Subrtn);
@@ -4790,7 +4850,9 @@ expr_code_doover:
}
#endif
- if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
+ if( ConstFactorOk(pParse)
+ && sqlite3ExprIsConstantNotJoin(pParse,pExpr)
+ ){
/* SQL functions can be expensive. So try to avoid running them
** multiple times if we know they always give the same result */
return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -4821,7 +4883,7 @@ expr_code_doover:
}
for(i=0; i<nFarg; i++){
- if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
+ if( i<32 && sqlite3ExprIsConstant(pParse, pFarg->a[i].pExpr) ){
testcase( i==31 );
constMask |= MASKBIT32(i);
}
@@ -5288,7 +5350,7 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
if( ConstFactorOk(pParse)
&& ALWAYS(pExpr!=0)
&& pExpr->op!=TK_REGISTER
- && sqlite3ExprIsConstantNotJoin(pExpr)
+ && sqlite3ExprIsConstantNotJoin(pParse, pExpr)
){
*pReg = 0;
r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -5352,7 +5414,7 @@ void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
** might choose to code the expression at initialization time.
*/
void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
- if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){
+ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pParse,pExpr) ){
sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
}else{
sqlite3ExprCodeCopy(pParse, pExpr, target);
@@ -5411,7 +5473,7 @@ int sqlite3ExprCodeExprList(
sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
}
}else if( (flags & SQLITE_ECEL_FACTOR)!=0
- && sqlite3ExprIsConstantNotJoin(pExpr)
+ && sqlite3ExprIsConstantNotJoin(pParse,pExpr)
){
sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
}else{
diff --git a/src/insert.c b/src/insert.c
index 095298b90..fe7ba05dc 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -577,6 +577,193 @@ void sqlite3AutoincrementEnd(Parse *pParse){
# define autoIncStep(A,B,C)
#endif /* SQLITE_OMIT_AUTOINCREMENT */
+/*
+** If argument pVal is a Select object returned by an sqlite3MultiValues()
+** that was able to use the co-routine optimization, finish coding the
+** co-routine.
+*/
+void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
+ if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
+ SrcItem *pItem = &pVal->pSrc->a[0];
+ sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
+ sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
+ }
+}
+
+/*
+** Return true if all expressions in the expression-list passed as the
+** only argument are constant.
+*/
+static int exprListIsConstant(Parse *pParse, ExprList *pRow){
+ int ii;
+ for(ii=0; ii<pRow->nExpr; ii++){
+ if( 0==sqlite3ExprIsConstant(pParse, pRow->a[ii].pExpr) ) return 0;
+ }
+ return 1;
+}
+
+/*
+** Return true if all expressions in the expression-list passed as the
+** only argument are both constant and have no affinity.
+*/
+static int exprListIsNoAffinity(Parse *pParse, ExprList *pRow){
+ int ii;
+ if( exprListIsConstant(pParse,pRow)==0 ) return 0;
+ for(ii=0; ii<pRow->nExpr; ii++){
+ assert( pRow->a[ii].pExpr->affExpr==0 );
+ if( 0!=sqlite3ExprAffinity(pRow->a[ii].pExpr) ) return 0;
+ }
+ return 1;
+
+}
+
+/*
+** This function is called by the parser for the second and subsequent
+** rows of a multi-row VALUES clause. Argument pLeft is the part of
+** the VALUES clause already parsed, argument pRow is the vector of values
+** for the new row. The Select object returned represents the complete
+** VALUES clause, including the new row.
+**
+** There are two ways in which this may be achieved - by incremental
+** coding of a co-routine (the "co-routine" method) or by returning a
+** Select object equivalent to the following (the "UNION ALL" method):
+**
+** "pLeft UNION ALL SELECT pRow"
+**
+** If the VALUES clause contains a lot of rows, this compound Select
+** object may consume a lot of memory.
+**
+** When the co-routine method is used, each row that will be returned
+** by the VALUES clause is coded into part of a co-routine as it is
+** passed to this function. The returned Select object is equivalent to:
+**
+** SELECT * FROM (
+** Select object to read co-routine
+** )
+**
+** The co-routine method is used in most cases. Exceptions are:
+**
+** a) If the current statement has a WITH clause. This is to avoid
+** statements like:
+**
+** WITH cte AS ( VALUES('x'), ('y') ... )
+** SELECT * FROM cte AS a, cte AS b;
+**
+** This will not work, as the co-routine uses a hard-coded register
+** for its OP_Yield instructions, and so it is not possible for two
+** cursors to iterate through it concurrently.
+**
+** b) The schema is currently being parsed (i.e. the VALUES clause is part
+** of a schema item like a VIEW or TRIGGER). In this case there is no VM
+** being generated when parsing is taking place, and so generating
+** a co-routine is not possible.
+**
+** c) There are non-constant expressions in the VALUES clause (e.g.
+** the VALUES clause is part of a correlated sub-query).
+**
+** d) One or more of the values in the first row of the VALUES clause
+** has an affinity (i.e. is a CAST expression). This causes problems
+** because the complex rules SQLite uses (see function
+** sqlite3SubqueryColumnTypes() in select.c) to determine the effective
+** affinity of such a column for all rows require access to all values in
+** the column simultaneously.
+*/
+Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
+
+ if( pParse->bHasWith /* condition (a) above */
+ || pParse->db->init.busy /* condition (b) above */
+ || exprListIsConstant(pParse,pRow)==0 /* condition (c) above */
+ || (pLeft->pSrc->nSrc==0 &&
+ exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */
+ || IN_SPECIAL_PARSE
+ ){
+ /* The co-routine method cannot be used. Fall back to UNION ALL. */
+ Select *pSelect = 0;
+ int f = SF_Values | SF_MultiValue;
+ if( pLeft->pSrc->nSrc ){
+ sqlite3MultiValuesEnd(pParse, pLeft);
+ f = SF_Values;
+ }else if( pLeft->pPrior ){
+ /* In this case set the SF_MultiValue flag only if it was set on pLeft */
+ f = (f & pLeft->selFlags);
+ }
+ pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
+ pLeft->selFlags &= ~SF_MultiValue;
+ if( pSelect ){
+ pSelect->op = TK_ALL;
+ pSelect->pPrior = pLeft;
+ pLeft = pSelect;
+ }
+ }else{
+ SrcItem *p = 0; /* SrcItem that reads from co-routine */
+
+ if( pLeft->pSrc->nSrc==0 ){
+ /* Co-routine has not yet been started and the special Select object
+ ** that accesses the co-routine has not yet been created. This block
+ ** does both those things. */
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ Select *pRet = sqlite3SelectNew(pParse, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Ensure the database schema has been read. This is to ensure we have
+ ** the correct text encoding. */
+ if( (pParse->db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ){
+ sqlite3ReadSchema(pParse);
+ }
+
+ if( pRet ){
+ SelectDest dest;
+ pRet->pSrc->nSrc = 1;
+ pRet->pPrior = pLeft->pPrior;
+ pRet->op = pLeft->op;
+ pLeft->pPrior = 0;
+ pLeft->op = TK_SELECT;
+ assert( pLeft->pNext==0 );
+ assert( pRet->pNext==0 );
+ p = &pRet->pSrc->a[0];
+ p->pSelect = pLeft;
+ p->fg.viaCoroutine = 1;
+ p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
+ p->regReturn = ++pParse->nMem;
+ p->iCursor = -1;
+ p->u1.nRow = 2;
+ sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);
+
+ /* Allocate registers for the output of the co-routine. Do so so
+ ** that there are two unused registers immediately before those
+ ** used by the co-routine. This allows the code in sqlite3Insert()
+ ** to use these registers directly, instead of copying the output
+ ** of the co-routine to a separate array for processing. */
+ dest.iSdst = pParse->nMem + 3;
+ dest.nSdst = pLeft->pEList->nExpr;
+ pParse->nMem += 2 + dest.nSdst;
+
+ pLeft->selFlags |= SF_MultiValue;
+ sqlite3Select(pParse, pLeft, &dest);
+ p->regResult = dest.iSdst;
+ assert( pParse->nErr || dest.iSdst>0 );
+ pLeft = pRet;
+ }
+ }else{
+ p = &pLeft->pSrc->a[0];
+ assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
+ p->u1.nRow++;
+ }
+
+ if( pParse->nErr==0 ){
+ assert( p!=0 );
+ if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
+ sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
+ }else{
+ sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
+ sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
+ }
+ }
+ sqlite3ExprListDelete(pParse->db, pRow);
+ }
+
+ return pLeft;
+}
/* Forward declaration */
static int xferOptimization(
@@ -913,25 +1100,40 @@ void sqlite3Insert(
if( pSelect ){
/* Data is coming from a SELECT or from a multi-row VALUES clause.
** Generate a co-routine to run the SELECT. */
- int regYield; /* Register holding co-routine entry-point */
- int addrTop; /* Top of the co-routine */
int rc; /* Result code */
- regYield = ++pParse->nMem;
- addrTop = sqlite3VdbeCurrentAddr(v) + 1;
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
- sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
- dest.iSdst = bIdListInOrder ? regData : 0;
- dest.nSdst = pTab->nCol;
- rc = sqlite3Select(pParse, pSelect, &dest);
- regFromSelect = dest.iSdst;
- assert( db->pParse==pParse );
- if( rc || pParse->nErr ) goto insert_cleanup;
- assert( db->mallocFailed==0 );
- sqlite3VdbeEndCoroutine(v, regYield);
- sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
- assert( pSelect->pEList );
- nColumn = pSelect->pEList->nExpr;
+ if( pSelect->pSrc->nSrc==1
+ && pSelect->pSrc->a[0].fg.viaCoroutine
+ && pSelect->pPrior==0
+ ){
+ SrcItem *pItem = &pSelect->pSrc->a[0];
+ dest.iSDParm = pItem->regReturn;
+ regFromSelect = pItem->regResult;
+ nColumn = pItem->pSelect->pEList->nExpr;
+ ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
+ if( bIdListInOrder && nColumn==pTab->nCol ){
+ regData = regFromSelect;
+ regRowid = regData - 1;
+ regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
+ }
+ }else{
+ int addrTop; /* Top of the co-routine */
+ int regYield = ++pParse->nMem;
+ addrTop = sqlite3VdbeCurrentAddr(v) + 1;
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
+ dest.iSdst = bIdListInOrder ? regData : 0;
+ dest.nSdst = pTab->nCol;
+ rc = sqlite3Select(pParse, pSelect, &dest);
+ regFromSelect = dest.iSdst;
+ assert( db->pParse==pParse );
+ if( rc || pParse->nErr ) goto insert_cleanup;
+ assert( db->mallocFailed==0 );
+ sqlite3VdbeEndCoroutine(v, regYield);
+ sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
+ assert( pSelect->pEList );
+ nColumn = pSelect->pEList->nExpr;
+ }
/* Set useTempTable to TRUE if the result of the SELECT statement
** should be written into a temporary table (template 4). Set to
diff --git a/src/parse.y b/src/parse.y
index 37c9fa8bc..d22c8e6fc 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -565,6 +565,7 @@ cmd ::= select(X). {
select(A) ::= WITH wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);}
select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X).
{A = attachWithToSelect(pParse,X,W);}
+
%endif /* SQLITE_OMIT_CTE */
select(A) ::= selectnowith(A). {
Select *p = A;
@@ -622,24 +623,27 @@ oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
%endif
-oneselect(A) ::= values(A).
-
+// Single row VALUES clause.
+//
%type values {Select*}
+oneselect(A) ::= values(A).
%destructor values {sqlite3SelectDelete(pParse->db, $$);}
values(A) ::= VALUES LP nexprlist(X) RP. {
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0);
}
-values(A) ::= values(A) COMMA LP nexprlist(Y) RP. {
- Select *pRight, *pLeft = A;
- pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0);
- if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
- if( pRight ){
- pRight->op = TK_ALL;
- pRight->pPrior = pLeft;
- A = pRight;
- }else{
- A = pLeft;
- }
+
+// Multiple row VALUES clause.
+//
+%type mvalues {Select*}
+oneselect(A) ::= mvalues(A). {
+ sqlite3MultiValuesEnd(pParse, A);
+}
+%destructor mvalues {sqlite3SelectDelete(pParse->db, $$);}
+mvalues(A) ::= values(A) COMMA LP nexprlist(Y) RP. {
+ A = sqlite3MultiValues(pParse, A, Y);
+}
+mvalues(A) ::= mvalues(A) COMMA LP nexprlist(Y) RP. {
+ A = sqlite3MultiValues(pParse, A, Y);
}
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
@@ -1321,7 +1325,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
if( A ) sqlite3ExprIdToTrueFalse(A);
}else{
Expr *pRHS = Y->a[0].pExpr;
- if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){
+ if( Y->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && A->op!=TK_VECTOR ){
Y->a[0].pExpr = 0;
sqlite3ExprListDelete(pParse->db, Y);
pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
@@ -1761,9 +1765,10 @@ with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W, 1); }
wqas(A) ::= AS. {A = M10d_Any;}
wqas(A) ::= AS MATERIALIZED. {A = M10d_Yes;}
wqas(A) ::= AS NOT MATERIALIZED. {A = M10d_No;}
-wqitem(A) ::= nm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. {
+wqitem(A) ::= withnm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. {
A = sqlite3CteNew(pParse, &X, Y, Z, M); /*A-overwrites-X*/
}
+withnm(A) ::= nm(A). {pParse->bHasWith = 1;}
wqlist(A) ::= wqitem(X). {
A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/
}
diff --git a/src/printf.c b/src/printf.c
index 186e95bb8..eb22ee320 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -860,6 +860,10 @@ void sqlite3_str_vappendf(
assert( pSel!=0 );
if( pSel->selFlags & SF_NestedFrom ){
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
+ }else if( pSel->selFlags & SF_MultiValue ){
+ assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
+ sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
+ pItem->u1.nRow);
}else{
sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
}
diff --git a/src/select.c b/src/select.c
index 81e802d6e..1085b9943 100644
--- a/src/select.c
+++ b/src/select.c
@@ -4776,7 +4776,7 @@ static void constInsert(
){
int i;
assert( pColumn->op==TK_COLUMN );
- assert( sqlite3ExprIsConstant(pValue) );
+ assert( sqlite3ExprIsConstant(pConst->pParse, pValue) );
if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
if( sqlite3ExprAffinity(pValue)!=0 ) return;
@@ -4834,10 +4834,10 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
pLeft = pExpr->pLeft;
assert( pRight!=0 );
assert( pLeft!=0 );
- if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){
+ if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pLeft) ){
constInsert(pConst,pRight,pLeft,pExpr);
}
- if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){
+ if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pRight) ){
constInsert(pConst,pLeft,pRight,pExpr);
}
}
@@ -7636,7 +7636,7 @@ int sqlite3Select(
/* Generate code for all sub-queries in the FROM clause
*/
pSub = pItem->pSelect;
- if( pSub==0 ) continue;
+ if( pSub==0 || pItem->addrFillSub!=0 ) continue;
/* The code for a subquery should only be generated once. */
assert( pItem->addrFillSub==0 );
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e11b5b3a4..8d18bfdfb 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3270,10 +3270,12 @@ struct IdList {
**
** Union member validity:
**
-** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
-** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
-** u2.pIBIndex fg.isIndexedBy && !fg.isCte
-** u2.pCteUse fg.isCte && !fg.isIndexedBy
+** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
+** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
+** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
+**
+** u2.pIBIndex fg.isIndexedBy && !fg.isCte
+** u2.pCteUse fg.isCte && !fg.isIndexedBy
*/
struct SrcItem {
Schema *pSchema; /* Schema to which this item is fixed */
@@ -3311,6 +3313,7 @@ struct SrcItem {
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
ExprList *pFuncArg; /* Arguments to table-valued-function */
+ u32 nRow; /* Number of rows in a VALUES clause */
} u1;
union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
@@ -3812,6 +3815,7 @@ struct Parse {
u8 disableLookaside; /* Number of times lookaside has been disabled */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
+ u8 bHasWith; /* True if statement contains WITH */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif
@@ -4486,6 +4490,9 @@ struct Window {
** due to the SQLITE_SUBTYPE flag */
};
+Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow);
+void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal);
+
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3WindowDelete(sqlite3*, Window*);
void sqlite3WindowUnlinkFromSelect(Window*);
@@ -5054,8 +5061,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
u32 sqlite3IsTrueOrFalse(const char*);
int sqlite3ExprIdToTrueFalse(Expr*);
int sqlite3ExprTruthValue(const Expr*);
-int sqlite3ExprIsConstant(Expr*);
-int sqlite3ExprIsConstantNotJoin(Expr*);
+int sqlite3ExprIsConstant(Parse*,Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
int sqlite3ExprIsTableConstant(Expr*,int);
diff --git a/src/where.c b/src/where.c
index 9850d22cc..2463e823c 100644
--- a/src/where.c
+++ b/src/where.c
@@ -1329,7 +1329,7 @@ static sqlite3_index_info *allocateIndexInfo(
Expr *pE2;
/* Skip over constant terms in the ORDER BY clause */
- if( sqlite3ExprIsConstant(pExpr) ){
+ if( sqlite3ExprIsConstant(0, pExpr) ){
continue;
}
@@ -1441,7 +1441,7 @@ static sqlite3_index_info *allocateIndexInfo(
pIdxInfo->nConstraint = j;
for(i=j=0; i<nOrderBy; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
- if( sqlite3ExprIsConstant(pExpr) ) continue;
+ if( sqlite3ExprIsConstant(0, pExpr) ) continue;
assert( pExpr->op==TK_COLUMN
|| (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
&& pExpr->iColumn==pExpr->pLeft->iColumn) );
@@ -3623,7 +3623,7 @@ static void wherePartIdxExpr(
u8 aff;
if( pLeft->op!=TK_COLUMN ) return;
- if( !sqlite3ExprIsConstant(pRight) ) return;
+ if( !sqlite3ExprIsConstant(0, pRight) ) return;
if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
if( pLeft->iColumn<0 ) return;
aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
@@ -4997,7 +4997,7 @@ static i8 wherePathSatisfiesOrderBy(
if( MASKBIT(i) & obSat ) continue;
p = pOrderBy->a[i].pExpr;
mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p);
- if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue;
+ if( mTerm==0 && !sqlite3ExprIsConstant(0,p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i);
}
@@ -5866,7 +5866,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
}else{
continue;
}
- if( sqlite3ExprIsConstant(pExpr) ) continue;
+ if( sqlite3ExprIsConstant(0,pExpr) ) continue;
if( pExpr->op==TK_FUNCTION ){
/* Functions that might set a subtype should not be replaced by the
** value taken from an expression index since the index omits the
@@ -6144,7 +6144,11 @@ WhereInfo *sqlite3WhereBegin(
){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
- ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
+ if( ALWAYS(pWInfo->pSelect)
+ && (pWInfo->pSelect->selFlags & SF_MultiValue)==0
+ ){
+ ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
+ }
}else{
/* Assign a bit from the bitmask to every term in the FROM clause.
**
@@ -6896,6 +6900,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
*/
if( pTabItem->fg.viaCoroutine ){
testcase( pParse->db->mallocFailed );
+ assert( pTabItem->regResult>=0 );
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
pTabItem->regResult, 0);
continue;
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 25db8f396..9d1f947a0 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -989,7 +989,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
assert( pIdx->bHasExpr );
if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
- && !sqlite3ExprIsConstant(pIdx->aColExpr->a[i].pExpr)
+ && !sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr)
){
aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR;
diff --git a/src/window.c b/src/window.c
index 62df349fb..bcee65d92 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1164,7 +1164,7 @@ void sqlite3WindowListDelete(sqlite3 *db, Window *p){
** variable values in the expression tree.
*/
static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
- if( 0==sqlite3ExprIsConstant(pExpr) ){
+ if( 0==sqlite3ExprIsConstant(0,pExpr) ){
if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr);
sqlite3ExprDelete(pParse->db, pExpr);
pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
diff --git a/test/altertab3.test b/test/altertab3.test
index 5fd17f3a2..cb6f00de4 100644
--- a/test/altertab3.test
+++ b/test/altertab3.test
@@ -736,4 +736,31 @@ do_execsql_test 29.7 {
END}
}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 30.0 {
+ CREATE TABLE t1(a, b);
+ CREATE VIEW v1 AS
+ SELECT ( VALUES(a), (b) ) FROM (
+ SELECT a, b FROM t1
+ )
+ ;
+}
+
+do_execsql_test 30.1 {
+ SELECT * FROM v1
+}
+
+do_execsql_test 30.1 {
+ ALTER TABLE t1 RENAME TO t2;
+}
+do_execsql_test 30.2 {
+ SELECT sql FROM sqlite_schema WHERE type='view'
+} {
+ {CREATE VIEW v1 AS
+ SELECT ( VALUES(a), (b) ) FROM (
+ SELECT a, b FROM "t2"
+ )}
+}
+
finish_test
diff --git a/test/in4.test b/test/in4.test
index a3fe22e78..71993e700 100644
--- a/test/in4.test
+++ b/test/in4.test
@@ -458,14 +458,14 @@ do_execsql_test 11.0 {
do_execsql_test 11.1 {
SELECT * FROM t1
WHERE b IN (345, (SELECT 1 FROM t1
- WHERE b IN (345 NOT GLOB 510)
+ WHERE b IN (coalesce(1,random()))
AND c GLOB 'abc*xyz'))
AND c BETWEEN 'abc' AND 'xyz';
} {xyz 1 abcdefxyz 99}
do_execsql_test 11.2 {
EXPLAIN SELECT * FROM t1
WHERE b IN (345, (SELECT 1 FROM t1
- WHERE b IN (345 NOT GLOB 510)
+ WHERE b IN (coalesce(1,random()))
AND c GLOB 'abc*xyz'))
AND c BETWEEN 'abc' AND 'xyz';
} {/ SeekScan /}
diff --git a/test/sqllimits1.test b/test/sqllimits1.test
index e9e20f40c..14d39e691 100644
--- a/test/sqllimits1.test
+++ b/test/sqllimits1.test
@@ -922,7 +922,7 @@ do_catchsql_test sqllimits1-18.1 {
do_catchsql_test sqllimits1-18.2 {
INSERT INTO b1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
UNION VALUES(11);
-} {1 {too many terms in compound SELECT}}
+} {0 {}}
#-------------------------------------------------------------------------
#
diff --git a/test/values.test b/test/values.test
new file mode 100644
index 000000000..43f8e0e6f
--- /dev/null
+++ b/test/values.test
@@ -0,0 +1,583 @@
+# 2024 March 3
+#
+# 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.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix values
+
+
+do_execsql_test 1.0 {
+ CREATE TABLE x1(a, b, c);
+}
+
+
+explain_i {
+ INSERT INTO x1(a, b, c) VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
+}
+do_execsql_test 1.1.1 {
+ INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
+}
+do_execsql_test 1.1.2 {
+ SELECT * FROM x1;
+} {
+ 1 1 1
+ 2 2 2
+ 3 3 3
+ 4 4 4
+}
+
+do_execsql_test 1.2.0 {
+ DELETE FROM x1
+}
+do_execsql_test 1.2.1 {
+ INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 4, 4, 4;
+ SELECT * FROM x1;
+} {1 1 1 2 2 2 3 3 3 4 4 4}
+
+sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 4
+
+do_execsql_test 1.2.2 {
+ DELETE FROM x1;
+ INSERT INTO x1
+ VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)
+ UNION ALL SELECT 6, 6, 6;
+ SELECT * FROM x1;
+} {1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6}
+
+do_execsql_test 1.2.3 {
+ DELETE FROM x1;
+ INSERT INTO x1
+ VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)
+ UNION ALL SELECT 6, 6, 6;
+ SELECT * FROM x1;
+} {1 1 1 2 2 2 3 3 3 4 4 4 6 6 6}
+
+do_execsql_test 1.2.4 {
+ DELETE FROM x1;
+ INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 6, 6, 6;
+ SELECT * FROM x1;
+} {
+ 1 1 1
+ 2 2 2
+ 3 3 3
+ 6 6 6
+}
+
+set a 4
+set b 5
+set c 6
+do_execsql_test 1.2.5 {
+ DELETE FROM x1;
+ INSERT INTO x1
+ VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3),
+ (4, 4, $a), (5, 5, $b), (6, 6, $c)
+}
+
+do_execsql_test 1.2.6 {
+ SELECT * FROM x1;
+} {
+ 1 1 1
+ 2 2 2
+ 3 3 3
+ 4 4 4
+ 5 5 5
+ 6 6 6
+}
+
+#-------------------------------------------------------------------------
+# SQLITE_LIMIT_COMPOUND_SELECT set to 0.
+#
+reset_db
+
+do_execsql_test 2.0 {
+ CREATE TABLE x1(a, b, c);
+}
+
+sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 3
+
+do_catchsql_test 2.1.1 {
+ INSERT INTO x1 VALUES
+ (1, 1, 1),
+ (2, 2, 2),
+ (3, 3, 3),
+ (4, 4, 4),
+ (5, 5, 5),
+ (6, 6, 6),
+ (7, 7, 7),
+ (8, 8, 8),
+ (9, 9, 9),
+ (10, 10, 10, 10)
+} {1 {all VALUES must have the same number of terms}}
+
+do_catchsql_test 2.1.2 {
+ INSERT INTO x1 VALUES
+ (1, 1, 1),
+ (2, 2, 2, 2),
+ (3, 3, 3),
+ (4, 4, 4),
+ (5, 5, 5),
+ (6, 6, 6),
+ (7, 7, 7),
+ (8, 8, 8),
+ (9, 9, 9),
+ (10, 10, 10)
+} {1 {all VALUES must have the same number of terms}}
+
+sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 0
+
+do_execsql_test 2.2 {
+ INSERT INTO x1 VALUES
+ (1, 1, 1),
+ (2, 2, 2),
+ (3, 3, 3),
+ (4, 4, 4),
+ (5, 5, 5),
+ (6, 6, 6),
+ (7, 7, 7),
+ (8, 8, 8),
+ (9, 9, 9),
+ (10, 10, 10)
+} {}
+do_execsql_test 2.3 {
+ INSERT INTO x1 VALUES
+ (1, 1, 1),
+ (2, 2, 2),
+ (3, 3, 3),
+ (4, 4, 4),
+ (5, 5, 5),
+ (6, 6, 6),
+ (7, 7, 7),
+ (8, 8, 8),
+ (9, 9, 9),
+ (10, 10, 10)
+ UNION ALL
+ SELECT 5, 12, 12
+ ORDER BY 1
+} {}
+
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 3.0 {
+ CREATE TABLE y1(x, y);
+}
+
+do_execsql_test 3.1.1 {
+ DELETE FROM y1;
+ INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 5);
+}
+do_execsql_test 3.1.2 {
+ SELECT * FROM y1;
+} {1 2 3 4 1 5}
+do_execsql_test 3.2.1 {
+ DELETE FROM y1;
+ INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 6)
+ , (row_number() OVER (), 7)
+}
+do_execsql_test 3.1.2 {
+ SELECT * FROM y1;
+} {1 2 3 4 1 6 1 7}
+
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 4.0 {
+ CREATE TABLE x1(a PRIMARY KEY, b) WITHOUT ROWID;
+}
+
+foreach {tn iLimit} {1 0 2 3} {
+ sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT $iLimit
+
+ do_execsql_test 4.1.1 {
+ DELETE FROM x1;
+ INSERT INTO x1 VALUES
+ (1, 1),
+ (2, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d')) ))
+ }
+ do_execsql_test 4.1.2 {
+ SELECT * FROM x1
+ } {1 1 2 a}
+
+ do_execsql_test 4.2.1 {
+ DELETE FROM x1;
+ INSERT INTO x1 VALUES
+ (1, 1),
+ (2, 2),
+ (3, 3),
+ (4, 4),
+ (5, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d')) ))
+ }
+ do_execsql_test 4.2.2 {
+ SELECT * FROM x1
+ } {1 1 2 2 3 3 4 4 5 a}
+
+ do_execsql_test 4.3.1 {
+ DELETE FROM x1;
+ INSERT INTO x1 VALUES
+ (1, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d'), ('e')) ))
+ }
+ do_execsql_test 4.3.2 {
+ SELECT * FROM x1
+ } {1 a}
+}
+
+#------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 5.0 {
+ CREATE VIEW v1 AS VALUES(1, 2, 3), (4, 5, 6), (7, 8, 9);
+}
+do_execsql_test 5.1 {
+ SELECT * FROM v1
+} {1 2 3 4 5 6 7 8 9}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 6.0 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES(1), (2);
+}
+
+do_execsql_test 6.1 {
+ SELECT ( VALUES( x ), ( x ) ) FROM t1;
+} {1 2}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 6.0 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES('x'), ('y');
+}
+
+do_execsql_test 6.1 {
+ SELECT * FROM t1, (VALUES(1), (2))
+} {x 1 x 2 y 1 y 2}
+
+do_execsql_test 6.2 {
+ VALUES(CAST(44 AS REAL)),(55);
+} {44.0 55}
+
+#------------------------------------------------------------------------
+do_execsql_test 7.1 {
+ WITH x1(a, b) AS (
+ VALUES(1, 2), ('a', 'b')
+ )
+ SELECT * FROM x1 one, x1 two
+} {
+ 1 2 1 2
+ 1 2 a b
+ a b 1 2
+ a b a b
+}
+
+#-------------------------------------------------------------------------
+reset_db
+
+set VVV {
+ ( VALUES('a', 'b'), ('c', 'd'), (123, NULL) )
+}
+set VVV2 {
+ (
+ SELECT 'a' AS column1, 'b' AS column2
+ UNION ALL SELECT 'c', 'd' UNION ALL SELECT 123, NULL
+ )
+}
+
+do_execsql_test 8.0 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES('d'), (NULL), (123)
+}
+foreach {tn q res} {
+ 1 "SELECT * FROM t1 LEFT JOIN VVV" {
+ d a b d c d d 123 {}
+ {} a b {} c d {} 123 {}
+ 123 a b 123 c d 123 123 {}
+ }
+
+ 2 "SELECT * FROM t1 LEFT JOIN VVV ON (column1=x)" {
+ d {} {}
+ {} {} {}
+ 123 123 {}
+ }
+
+ 3 "SELECT * FROM t1 RIGHT JOIN VVV" {
+ d a b d c d d 123 {}
+ {} a b {} c d {} 123 {}
+ 123 a b 123 c d 123 123 {}
+ }
+
+ 4 "SELECT * FROM t1 RIGHT JOIN VVV ON (column1=x)" {
+ 123 123 {}
+ {} a b
+ {} c d
+ }
+
+ 5 "SELECT * FROM t1 FULL OUTER JOIN VVV ON (column1=x)" {
+ d {} {}
+ {} {} {}
+ 123 123 {}
+ {} a b
+ {} c d
+ }
+
+ 6 "SELECT count(*) FROM VVV" { 3 }
+
+ 7 "SELECT (SELECT column1 FROM VVV)" { a }
+
+ 8 "SELECT * FROM VVV UNION ALL SELECT * FROM VVV" {
+ a b c d 123 {}
+ a b c d 123 {}
+ }
+
+ 9 "SELECT * FROM VVV INTERSECT SELECT * FROM VVV" {
+ 123 {} a b c d
+ }
+
+ 10 "SELECT * FROM VVV eXCEPT SELECT * FROM VVV" { }
+
+ 11 "SELECT * FROM VVV eXCEPT SELECT 'a', 'b'" { 123 {} c d }
+
+} {
+ set q1 [string map [list VVV $VVV] $q]
+ set q2 [string map [list VVV $VVV2] $q]
+ set q3 "WITH VVV AS $VVV $q"
+
+ do_execsql_test 8.1.$tn.1 $q1 $res
+ do_execsql_test 8.1.$tn.2 $q2 $res
+ do_execsql_test 8.1.$tn.3 $q3 $res
+}
+
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 9.1 {
+ VALUES(456), (123), (NULL) UNION ALL SELECT 122 ORDER BY 1
+} { {} 122 123 456 }
+
+do_execsql_test 9.2 {
+ VALUES (1, 2), (3, 4), (
+ ( SELECT column1 FROM ( VALUES (5, 6), (7, 8) ) ),
+ ( SELECT max(column2) FROM ( VALUES (5, 1), (7, 6) ) )
+ )
+} { 1 2 3 4 5 6 }
+
+do_execsql_test 10.1 {
+ CREATE TABLE a2(a, b, c DEFAULT 'xyz');
+}
+do_execsql_test 10.2 {
+ INSERT INTO a2(a) VALUES(3),(4);
+}
+
+#-------------------------------------------------------------------------
+reset_db
+ifcapable fts5 {
+ do_execsql_test 11.0 {
+ CREATE VIRTUAL TABLE ft USING fts3(x);
+ }
+ do_execsql_test 11.1 {
+ INSERT INTO ft VALUES('one'), ('two');
+ }
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 12.0 {
+ CREATE TABLE t1(a, b);
+}
+do_execsql_test 12.1 {
+ INSERT INTO t1 SELECT 1, 2 UNION ALL VALUES(3, 4), (5, 6);
+}
+do_execsql_test 12.2 {
+ SELECT * FROM t1
+} {1 2 3 4 5 6}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 13.0 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES('xyz');
+
+ SELECT (
+ VALUES( (max(substr('abc', 1, 1), x)) ),
+ (123),
+ (456)
+ )
+ FROM t1;
+} {xyz}
+
+do_catchsql_test 13.1 {
+ VALUES(300), (zeroblob(300) OVER win);
+} {1 {zeroblob() may not be used as a window function}}
+
+#--------------------------------------------------------------------------
+reset_db
+do_execsql_test 14.1 {
+ PRAGMA encoding = utf16;
+ CREATE TABLE t1(a, b);
+} {}
+
+db close
+sqlite3 db test.db
+
+do_execsql_test 14.2 {
+ INSERT INTO t1 VALUES
+ (17, 'craft'),
+ (16, 'urtlek' IN(1,2,3));
+}
+
+#--------------------------------------------------------------------------
+#
+reset_db
+do_eqp_test 15.1 {
+ VALUES(1),(2),(3),(4),(5);
+} {
+ QUERY PLAN
+ `--SCAN 5-ROW VALUES CLAUSE
+}
+do_execsql_test 15.2 {
+ CREATE TABLE t1(a,b);
+}
+do_eqp_test 15.3 {
+ INSERT INTO t1 VALUES
+ (1,2),(3,4),(7,8);
+} {
+ QUERY PLAN
+ `--SCAN 3-ROW VALUES CLAUSE
+}
+do_eqp_test 15.4 {
+ INSERT INTO t1 VALUES
+ (1,2),(3,4),(7,8),
+ (5,row_number()OVER());
+} {
+ QUERY PLAN
+ `--COMPOUND QUERY
+ |--LEFT-MOST SUBQUERY
+ | `--SCAN 3-ROW VALUES CLAUSE
+ `--UNION ALL
+ |--CO-ROUTINE (subquery-xxxxxx)
+ | `--SCAN CONSTANT ROW
+ `--SCAN (subquery-xxxxxx)
+}
+do_eqp_test 15.5 {
+ SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6)), (VALUES('a'),('b'),('c'));
+} {
+ QUERY PLAN
+ |--SCAN 6-ROW VALUES CLAUSE
+ `--SCAN 3-ROW VALUES CLAUSE
+}
+do_execsql_test 15.6 {
+ CREATE TABLE t2(x,y);
+}
+do_eqp_test 15.7 {
+ SELECT * FROM t2 UNION ALL VALUES(1,2),(3,4),(5,6),(7,8);
+} {
+ QUERY PLAN
+ `--COMPOUND QUERY
+ |--LEFT-MOST SUBQUERY
+ | `--SCAN t2
+ `--UNION ALL
+ `--SCAN 4-ROW VALUES CLAUSE
+}
+
+#--------------------------------------------------------------------------
+# The VALUES-as-coroutine optimization can be applied to later rows of
+# a VALUES clause even if earlier rows do not qualify.
+#
+reset_db
+do_execsql_test 16.1 {
+ CREATE TABLE t1(a,b);
+}
+do_execsql_test 16.2 {
+ BEGIN;
+ INSERT INTO t1 VALUES(1,2),(3,4),(5,6),
+ (7,row_number()OVER()),
+ (9,10), (11,12), (13,14), (15,16);
+ SELECT * FROM t1 ORDER BY a, b;
+ ROLLBACK;
+} {1 2 3 4 5 6 7 1 9 10 11 12 13 14 15 16}
+do_eqp_test 16.3 {
+ INSERT INTO t1 VALUES(1,2),(3,4),(5,6),
+ (7,row_number()OVER()),
+ (9,10), (11,12), (13,14), (15,16);
+} {
+ QUERY PLAN
+ `--COMPOUND QUERY
+ |--LEFT-MOST SUBQUERY
+ | `--SCAN 3-ROW VALUES CLAUSE
+ |--UNION ALL
+ | |--CO-ROUTINE (subquery-xxxxxx)
+ | | `--SCAN CONSTANT ROW
+ | `--SCAN (subquery-xxxxxx)
+ `--UNION ALL
+ `--SCAN 4-ROW VALUES CLAUSE
+}
+do_execsql_test 16.4 {
+ BEGIN;
+ INSERT INTO t1 VALUES
+ (1,row_number()OVER()),
+ (2,3), (4,5), (6,7);
+ SELECT * FROM t1 ORDER BY a, b;
+ ROLLBACK;
+} {1 1 2 3 4 5 6 7}
+do_eqp_test 16.5 {
+ INSERT INTO t1 VALUES
+ (1,row_number()OVER()),
+ (2,3), (4,5), (6,7);
+} {
+ QUERY PLAN
+ `--COMPOUND QUERY
+ |--LEFT-MOST SUBQUERY
+ | |--CO-ROUTINE (subquery-xxxxxx)
+ | | `--SCAN CONSTANT ROW
+ | `--SCAN (subquery-xxxxxx)
+ `--UNION ALL
+ `--SCAN 3-ROW VALUES CLAUSE
+}
+do_execsql_test 16.6 {
+ BEGIN;
+ INSERT INTO t1 VALUES
+ (1,2),(3,4),
+ (5,row_number()OVER()),
+ (7,8),(9,10),(11,12),
+ (13,row_number()OVER()),
+ (15,16),(17,18),(19,20),(21,22);
+ SELECT * FROM t1 ORDER BY a, b;
+ ROLLBACK;
+} { 1 2 3 4 5 1 7 8 9 10 11 12 13 1 15 16 17 18 19 20 21 22}
+do_eqp_test 16.7 {
+ INSERT INTO t1 VALUES
+ (1,2),(3,4),
+ (5,row_number()OVER()),
+ (7,8),(9,10),(11,12),
+ (13,row_number()OVER()),
+ (15,16),(17,18),(19,20),(21,22);
+} {
+ QUERY PLAN
+ `--COMPOUND QUERY
+ |--LEFT-MOST SUBQUERY
+ | `--SCAN 2-ROW VALUES CLAUSE
+ |--UNION ALL
+ | |--CO-ROUTINE (subquery-xxxxxx)
+ | | `--SCAN CONSTANT ROW
+ | `--SCAN (subquery-xxxxxx)
+ |--UNION ALL
+ | `--SCAN 3-ROW VALUES CLAUSE
+ |--UNION ALL
+ | |--CO-ROUTINE (subquery-xxxxxx)
+ | | `--SCAN CONSTANT ROW
+ | `--SCAN (subquery-xxxxxx)
+ `--UNION ALL
+ `--SCAN 4-ROW VALUES CLAUSE
+}
+
+finish_test
diff --git a/test/valuesfault.test b/test/valuesfault.test
new file mode 100644
index 000000000..bc5dddfb0
--- /dev/null
+++ b/test/valuesfault.test
@@ -0,0 +1,37 @@
+# 2024 March 3
+#
+# 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.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix valuesfault
+source $testdir/malloc_common.tcl
+
+
+do_execsql_test 1.0 {
+ CREATE TABLE x1(a, b, c);
+}
+faultsim_save_and_close
+
+do_faultsim_test 1 -prep {
+ faultsim_restore_and_reopen
+ sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 2
+} -body {
+ execsql {
+ INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
+ }
+} -test {
+ faultsim_test_result {0 {}}
+}
+
+
+finish_test
diff --git a/test/whereL.test b/test/whereL.test
index 068ee05cd..2e9ae219e 100644
--- a/test/whereL.test
+++ b/test/whereL.test
@@ -49,6 +49,33 @@ do_eqp_test 120 {
|--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
`--SCAN t3
}
+do_eqp_test 121 {
+ SELECT * FROM t1, t2, t3
+ WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=abs(5)
+ ORDER BY t1.a;
+} {
+ QUERY PLAN
+ |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
+ |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
+ `--SCAN t3
+}
+
+# The sqlite3ExprIsConstant() routine does not believe that
+# the expression "coalesce(5,random())" is constant. So the
+# optimization does not apply in this case.
+#
+sqlite3_create_function db
+do_eqp_test 122 {
+ SELECT * FROM t1, t2, t3
+ WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=coalesce(5,random())
+ ORDER BY t1.a;
+} {
+ QUERY PLAN
+ |--SCAN t3
+ |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
+ |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
+ `--USE TEMP B-TREE FOR ORDER BY
+}
# Constant propagation in the face of collating sequences:
#