Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6f7888622 | |||
| cee5cb484d | |||
| d0c7baf505 | |||
| 0ae56fbdd0 | |||
| 8f2c0b59da | |||
| 233ba1b8eb | |||
| 895bab3383 | |||
| 4b51e8bd68 | |||
| a5c9a70757 | |||
| 15b01def1e | |||
| a2417ec75c | |||
| b32b30930f | |||
| 1da88b5ce6 | |||
| 0c7d3d399d | |||
| c692df2784 | |||
| b5d4473221 | |||
| 3cdb1394b9 | |||
| f5bc444077 | |||
| d48e88e56d | |||
| bcba3655ee | |||
| 68dc8151e0 | |||
| 9b9fc74f2e | |||
| 57c58b4de8 | |||
| ec778d2724 | |||
| 4d7f335e8b | |||
| a1c8151bab | |||
| e482fde6ee | |||
| d323a3a515 |
+34
-7
@@ -40,7 +40,7 @@
|
||||
**
|
||||
** Option 1 is the default behavior. 2 is use if there is a usable
|
||||
** constraint on "flags" with an integer right-hand side that where the
|
||||
** value of the right-hand side has its 0x01 bit set.
|
||||
** value of the right-hand side has its 0x001 bit set.
|
||||
**
|
||||
** All constraints on columns "a" through "e" are marked as "omit".
|
||||
**
|
||||
@@ -48,6 +48,12 @@
|
||||
** is an integer and that integer has its 0x02 bit set, then the
|
||||
** orderByConsumed flag is set.
|
||||
**
|
||||
** FLAGS SUMMARY:
|
||||
**
|
||||
** 0x001 Columns 'a' through 'e' have INT values
|
||||
** 0x002 orderByConsumed is set
|
||||
** 0x004 OFFSET and LIMIT have omit set
|
||||
**
|
||||
** COMPILE:
|
||||
**
|
||||
** gcc -Wall -g -shared -fPIC -I. qpvtab.c -o qqvtab.so
|
||||
@@ -103,7 +109,8 @@ static const char *azColname[] = {
|
||||
"ux",
|
||||
"rhs",
|
||||
"a", "b", "c", "d", "e",
|
||||
"flags"
|
||||
"flags",
|
||||
""
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -143,6 +150,7 @@ static int qpvtabConnect(
|
||||
#define QPVTAB_D 9
|
||||
#define QPVTAB_E 10
|
||||
#define QPVTAB_FLAGS 11
|
||||
#define QPVTAB_NONE 12
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
@@ -226,7 +234,7 @@ static int qpvtabColumn(
|
||||
sqlite3_result_text64(ctx, z, zEnd-z, SQLITE_TRANSIENT, SQLITE_UTF8);
|
||||
}
|
||||
}else if( i>=QPVTAB_A && i<=QPVTAB_E ){
|
||||
if( pCur->flags & 1 ){
|
||||
if( pCur->flags & 0x001 ){
|
||||
sqlite3_result_int(ctx, i-QPVTAB_A+1);
|
||||
}else{
|
||||
char x = 'a'+i-QPVTAB_A;
|
||||
@@ -338,19 +346,25 @@ static int qpvtabBestIndex(
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
sqlite3_value *pVal;
|
||||
int iCol = pIdxInfo->aConstraint[i].iColumn;
|
||||
int op = pIdxInfo->aConstraint[i].op;
|
||||
if( iCol==QPVTAB_FLAGS && pIdxInfo->aConstraint[i].usable ){
|
||||
pVal = 0;
|
||||
rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal);
|
||||
assert( rc==SQLITE_OK || pVal==0 );
|
||||
if( pVal ){
|
||||
pIdxInfo->idxNum = sqlite3_value_int(pVal);
|
||||
if( pIdxInfo->idxNum & 2 ) pIdxInfo->orderByConsumed = 1;
|
||||
if( pIdxInfo->idxNum & 0x002 ) pIdxInfo->orderByConsumed = 1;
|
||||
}
|
||||
}
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_LIMIT
|
||||
|| op==SQLITE_INDEX_CONSTRAINT_OFFSET
|
||||
){
|
||||
iCol = QPVTAB_NONE;
|
||||
}
|
||||
sqlite3_str_appendf(pStr,"aConstraint,%d,%s,%d,%d,",
|
||||
i,
|
||||
azColname[iCol],
|
||||
pIdxInfo->aConstraint[i].op,
|
||||
op,
|
||||
pIdxInfo->aConstraint[i].usable);
|
||||
pVal = 0;
|
||||
rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal);
|
||||
@@ -359,9 +373,20 @@ static int qpvtabBestIndex(
|
||||
qpvtabStrAppendValue(pStr, pVal);
|
||||
}
|
||||
sqlite3_str_append(pStr, "\n", 1);
|
||||
}
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
int iCol = pIdxInfo->aConstraint[i].iColumn;
|
||||
int op = pIdxInfo->aConstraint[i].op;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_LIMIT
|
||||
|| op==SQLITE_INDEX_CONSTRAINT_OFFSET
|
||||
){
|
||||
iCol = QPVTAB_NONE;
|
||||
}
|
||||
if( iCol>=QPVTAB_A && pIdxInfo->aConstraint[i].usable ){
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = ++k;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = ++k;
|
||||
if( iCol<=QPVTAB_FLAGS || (pIdxInfo->idxNum & 0x004)!=0 ){
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_str_appendf(pStr, "nOrderBy,%d,,,,\n", pIdxInfo->nOrderBy);
|
||||
@@ -372,6 +397,8 @@ static int qpvtabBestIndex(
|
||||
pIdxInfo->aOrderBy[i].desc
|
||||
);
|
||||
}
|
||||
sqlite3_str_appendf(pStr, "sqlite3_vtab_distinct,%d,,,,\n",
|
||||
sqlite3_vtab_distinct(pIdxInfo));
|
||||
sqlite3_str_appendf(pStr, "idxFlags,%d,,,,\n", pIdxInfo->idxFlags);
|
||||
sqlite3_str_appendf(pStr, "colUsed,%d,,,,\n", (int)pIdxInfo->colUsed);
|
||||
pIdxInfo->estimatedCost = (double)10;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Add\srequirements\smarks\sand\stuning.
|
||||
D 2022-01-21T00:38:49.617
|
||||
C Add\sa\sNEVER()\son\san\sunreachable\sbranch.
|
||||
D 2022-01-28T23:19:01.285
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -316,7 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1
|
||||
F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f
|
||||
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
|
||||
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
|
||||
F ext/misc/qpvtab.c d40b07a8c341d16629010c3e8d8801f1477f70d6257e052973a8ddf14c07cd8d
|
||||
F ext/misc/qpvtab.c 09738419e25f603a35c0ac8bd0a04daab794f48d08a9bc07a6085b9057b99009
|
||||
F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
@@ -485,39 +485,39 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c e3943d8fbcaf60f79f39d4aecc56a6a8092f51f93d6a7c5b1db2633c5fa10c30
|
||||
F src/alter.c e8ac1df663bf4ec74920edd1299435f2a616d2404de0ac4013c151ea4e7a11f2
|
||||
F src/analyze.c 7518b99e07c5494111fe3bd867f28f804b6c5c1ad0703ec3d116de9bab3fa516
|
||||
F src/attach.c e3f9d9a2a4a844750f3f348f37afb244535f21382cbfcd840152cb21cb41cfaf
|
||||
F src/attach.c f26d400f3ffe2cdca01406bca70e5f58c5488bf165b4fc37c228136dfcf1b583
|
||||
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
|
||||
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
|
||||
F src/backup.c 58880b9a9adf88f1a57cb3b0db6b891626ae76113ebd0f2417a87c2634edfc65
|
||||
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c ddab31c38d5f16114bc68392430556b1063fe14e0020f9a56d2c35ddd58ba7e3
|
||||
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
|
||||
F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7
|
||||
F src/build.c c72407a27a28982a384cd453a3a6b6992a1ceae8bd8d95e96d7fb9c0d645a32f
|
||||
F src/build.c 9329120c4522d1ad881b9e62108870c8a5e994e31f4d813d0eb3de323d25e362
|
||||
F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1
|
||||
F src/date.c ab8e01d928f201f5dee0bc6d54d6702fdcec96dff4d58c387447671f6a46d191
|
||||
F src/date.c 41627dec396f3d33e2c317a065f9d59bb535982b2ea3a561c96e4d4cf1137b65
|
||||
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
|
||||
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
|
||||
F src/delete.c 19814f621cde10b1771a0dea7fe25d3d7d39975b8d4be4888537d30860e7c08c
|
||||
F src/expr.c 827179c78d2ca7cc318392811de8151c60eacf7ce804b13e61bb7ef38f954846
|
||||
F src/delete.c b5f1716b4d723db48254ee0f896e362cd029e865e05414139ea7f539f3884e1d
|
||||
F src/expr.c 9658bccd1598211ace848c8ca9480dbf8be08dfee1db5cf03897b34b7b6e8fef
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560
|
||||
F src/fkey.c 06e4ac33031b02dde7130c12e79cddf4dc5cfa72b23d8e63a3c26878fc9c1d3c
|
||||
F src/func.c 8fddc42bce95d17938252a543f86fe29e479366e80fbd112a1822913b6247776
|
||||
F src/global.c 1f56aead86e8a18c4415638f5e6c4d0a0550427f4b3f5d065ba5164cc09c22e8
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743
|
||||
F src/insert.c 1eea44389de3768ac98588c1410171cd53e7c6ad1af74049983dcbac82093de0
|
||||
F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 9a693eb89575af5d54b025c1e927b2ea8114bbeee3db346e8abc81676dd82160
|
||||
F src/loadext.c 657534339585ac234839e5187aa51d8802f292e0771c4f874b3af1f1223f81e2
|
||||
F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960
|
||||
F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b
|
||||
F src/malloc.c fec841aa0a0400a6f7d20706178a5d8e8219a6bf562b6fe712c17f6c26813266
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
|
||||
@@ -545,19 +545,19 @@ F src/parse.y 04f61db1cdd7036c6d74baad1c342d3e3110cb0765c48fcfd3bdf4e974a1e5bb
|
||||
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
|
||||
F src/pragma.c c536665ce8431c8b1efbf7e0a5c01852f49f7bf28f1954f8118b2d28e4a3797f
|
||||
F src/pragma.c 7c024d690a3dc93f61830f11f900e4af2357f31d081b0c79099ca5e28919cba7
|
||||
F src/pragma.h 87330ed2fbfa2a1274de93ca0ab850fba336189228cb256089202c3b52766fad
|
||||
F src/prepare.c 45fe7408eb78d80eca8392669070a6e5caf231b09e5c7b1ff65c1ad64a3734c5
|
||||
F src/prepare.c 1e23522c934d90ff42de1b9b4f782fdf0fb690b06b92d7480b471ccb2b5899ea
|
||||
F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a
|
||||
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
|
||||
F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
|
||||
F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027
|
||||
F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e
|
||||
F src/sqlite.h.in 67e49a50bb29e3af86d2b3606af6b3fe20a0d09cf326cc574d632d878c0696d6
|
||||
F src/select.c a6d2d4bed279d7fe4fcedaf297eaf6441e8e17c6e3947a32d24d23be52ac02f2
|
||||
F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2
|
||||
F src/sqlite.h.in da0e94f140f3f054f0eca8fc4a183167bedc7ae9c51822390c62369455eae5f8
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 234b5ff5c20512a116b14d6d08e23caeb68667749f8a94117779a9d38afc7e5c
|
||||
F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30
|
||||
F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
|
||||
F src/sqliteInt.h 8ef2996e02476f73e41ba977f819bda0cc68b7ce238cf404b9b8930df57bc1d0
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -574,7 +574,7 @@ F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
|
||||
F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a
|
||||
F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871
|
||||
F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
|
||||
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
|
||||
F src/test_bestindex.c ba0314d3bca8b00fa0daaf113a314986f73ea8ad85a7562f983638d09a29045c
|
||||
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c 284c29912736f68b0a583a920bf63fd8f9125dffb8a75cb0676e58502b2f7908
|
||||
@@ -618,32 +618,32 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446
|
||||
F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc
|
||||
F src/trigger.c 40e7c3dcff57a770d5fa38ba21ed4725572fd2e224c58af61eb980598b60f9c8
|
||||
F src/update.c d6f5c7b9e072660757ac7d58175aca11c07cb95ebbb297ae7f38853700f52328
|
||||
F src/trigger.c 692972e4393dfc8017a1a527c1ea1b96ce3d101e84584cd832fcfb83d22b50b2
|
||||
F src/update.c f875b0d59da5c3055a0b2ac20560e1650229c6787e78de5e9836267b5cbb8359
|
||||
F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 89e51820bcb468ff3877a8d942f5cc807208087f021227e0927693e928a195bc
|
||||
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
|
||||
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
|
||||
F src/vdbe.c cfe1980fbeb87eb35297b4a41808034761f26277cf45c9cf3e4eac20edcba1d5
|
||||
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
|
||||
F src/vdbeInt.h d89d5d2150500cfb08615329fd20aea9d746bba5f2c3ecb8a17e2d2d9be029e5
|
||||
F src/vdbeapi.c 22c79072ae7d8a01e9bcae8ba16e918d60d202eaa9553b5fda38f99f7464d99a
|
||||
F src/vdbeaux.c c1b452cc17f5887b3d36bc277a2181914d6bed508ea45827b5f348160491e6a6
|
||||
F src/vdbeblob.c 29c4118f7ee615cdee829e8401f6ead1b96b95d545b4de0042f6de39c962c652
|
||||
F src/vdbemem.c da4d594084d581be6436582bb44bb128feeb138a3e6c313eda6749ebdc3a65ec
|
||||
F src/vdbeaux.c e761b8011baec7a4773f0a7594783f2cd71f699ab187c4aad917529ab8acd3fe
|
||||
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
||||
F src/vdbemem.c eb6042667c02c3ef1f968235b4a170e31b23a4b6a57f65a8454eab4d36f14b7f
|
||||
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
|
||||
F src/vtab.c a47cc12ebaa350800c0c87b6b0095debbb5a6ed32727bcab9d82ad070a81b738
|
||||
F src/vtab.c e0eaf5b8f7f8929088485a76bea2ff6124adb12e0eb5c0997287ff5e0e4c0517
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
|
||||
F src/where.c 6b4cd84869dafc250d2b0f47a2c190759904a4bb6a31fc930bc8e6a9fd9a8d77
|
||||
F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be
|
||||
F src/wherecode.c 6a594ed25bfbeb60d455868b7be62637575e4f1949152de4336e4825e0c54ba6
|
||||
F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3
|
||||
F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e
|
||||
F src/where.c f61ca6dbb4bbb7171aa5f5459982d8d98aac24852572bcee250f9c469a1963ba
|
||||
F src/whereInt.h 0748a6fce98b41862445906922a809146ff7ef4de16ed9022b0bc4e5c43aa60a
|
||||
F src/wherecode.c c313ccf5ed13dc7e88c64f93733f414dee369a212508a866878696d83c64fc36
|
||||
F src/whereexpr.c becee225f104abd0253e0ceecd2a6253589f269395d98fc3ff98fdd64fecb34c
|
||||
F src/window.c dfaec4abc6012cbc18e4a202ca3a5d5a0efcc4011d86a06d882ddaab8aedee4d
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7
|
||||
@@ -837,6 +837,7 @@ F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee
|
||||
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1
|
||||
F test/date3.test a1b77abf05c6772fe5ca2337cac1398892f2a41e62bce7e6be0f4a08a0e64ae5
|
||||
F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8603
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbfuzz001.test 55e1a3504f8dea84155e09912fe3b1c3ad77e0b1a938ec42ca03b8e51b321e30
|
||||
@@ -868,8 +869,8 @@ F test/e_createtable.test 04c50b7fe41c12ed9cd88fbbc09b4900bcfc66f98ad198874fc993
|
||||
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
|
||||
F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa
|
||||
F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7
|
||||
F test/e_expr.test e164550b9f8fd9c130283d1eae692dff9e2ba67f4dbd35f7325021f5d4b8851c
|
||||
F test/e_fkey.test ee321dbca3c53204da46cb40b8ec80192e995035f9ea26576ddcd842b1f0877f
|
||||
F test/e_expr.test bc6aa5906ba967587525bc746ea403011557cf6d8e4fc9efb1fab5dae7fb4fd6
|
||||
F test/e_fkey.test feeba6238aeff9d809fb6236b351da8df4ae9bda89e088e54526b31a0cbfeec5
|
||||
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
|
||||
@@ -1069,7 +1070,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
|
||||
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
|
||||
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
|
||||
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
|
||||
F test/fuzzdata8.db a0c7af954bcbb226ed7ae087b3b6d6e48eaac8fac5671150ffd23c35b55bffe6
|
||||
F test/fuzzdata8.db 738ed275638f2423cdef240a44eba3b9bc272eec619e68b00429d4575a15e50b
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
|
||||
@@ -1292,7 +1293,7 @@ F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
|
||||
F test/printf.test 390d0d7fcffc3c4ea3c1bb4cbb267444e32b33b048ae21895f23a291844fe1da
|
||||
F test/printf2.test 30b5dd0b4b992dc5626496846ecce17ff592cacbcb11c3e589f3ac4d7e129dae
|
||||
F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/pushdown.test 5e72c51c5e33253ed639ccee1e01ce62d62b6eee5ca893cd82334e4ee7b1d7fc
|
||||
@@ -1322,7 +1323,7 @@ F test/round1.test 768018b04522ca420b1aba8a24bd76091d269f3bce3902af3ec6ebcee41ab
|
||||
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test e29025be95baf6b32f0d5edef59a7633028325896a98f1caa8019559ca910350
|
||||
F test/rowvalue.test 37effea4dd83555ea969a9461dfcffb25e6731a5db7c388e232410999c100853
|
||||
F test/rowvalue.test 02214016f747854ef636e64ff204778649937aa801ca78e2495a960f8e0d509d
|
||||
F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b
|
||||
F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256
|
||||
F test/rowvalue4.test 441e7e366ac6d939a3a95a574031c56ec2a854077a91d66eee5ff1d86cb5be58
|
||||
@@ -1388,7 +1389,7 @@ F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test 70f46b5d07776a107335c3c2c9cbd0431d44637bfeae1f6b9ded5e33b4c7c0bf
|
||||
F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c
|
||||
F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566
|
||||
F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be
|
||||
F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759
|
||||
F test/shell5.test b85069bfcf3159b225228629ab2c3e69aa923d098fea8ea074b5dcd743522e2c
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
|
||||
@@ -1724,6 +1725,7 @@ F test/vtabK.test 13293177528fada1235c0112db0d187d754af1355c5a39371abd365104e3af
|
||||
F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783
|
||||
F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
|
||||
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
|
||||
F test/vtabdistinct.test 7688f0889358f849fd60bbfde1ded38b014b18066076d4bfbb75395804dfe072
|
||||
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
|
||||
F test/vtabrhs1.test c138346be341916ecc9d918dcfc2657d27bce211a350a82b01d62d224b167b56
|
||||
F test/wal.test b7cc6984709f54afbf8441747ced1f646af120bf0c1b1d847bfa39306fbea089
|
||||
@@ -1940,8 +1942,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 577d3d66558368c34acab8a9e552957cf3fa054c348f1383a9121de6e8b281b7
|
||||
R 90012b52ae4dda5b0e0f59cd4c524b70
|
||||
P 8f8cab0d0e219f0c4bc2b8061c0013d90a2a5e598dd6cf420d302dfd1b7cbe11
|
||||
R 2886f1ce9cf06aa83d320b384893e940
|
||||
U drh
|
||||
Z 0ca7e1064e9e25edf7c6ed09bdf60dba
|
||||
Z 20c096da0533f9910b77ed2d57db0dcc
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
ac951490fd7d5864fe422a80ee8557478e823e79461bec2ee538f57b6733eb5a
|
||||
388926254b9da6169da7267bd4d5a1a66a26576be435c88269ab8db9eaedc079
|
||||
+8
-4
@@ -324,7 +324,9 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
int r1; /* Temporary registers */
|
||||
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ) return;
|
||||
assert( db->pParse==pParse );
|
||||
if( pParse->nErr ) return;
|
||||
assert( db->mallocFailed==0 );
|
||||
pNew = pParse->pNewTable;
|
||||
assert( pNew );
|
||||
|
||||
@@ -735,7 +737,9 @@ struct RenameCtx {
|
||||
** following a valid object, it may not be used in comparison operations.
|
||||
*/
|
||||
static void renameTokenCheckAll(Parse *pParse, const void *pPtr){
|
||||
if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){
|
||||
assert( pParse==pParse->db->pParse );
|
||||
assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
|
||||
if( pParse->nErr==0 ){
|
||||
const RenameToken *p;
|
||||
u8 i = 0;
|
||||
for(p=pParse->pRename; p; p=p->pNext){
|
||||
@@ -1132,7 +1136,7 @@ static int renameParseSql(
|
||||
/* Parse the SQL statement passed as the first argument. If no error
|
||||
** occurs and the parse does not result in a new table, index or
|
||||
** trigger object, the database must be corrupt. */
|
||||
memset(p, 0, sizeof(Parse));
|
||||
sqlite3ParseObjectInit(p, db);
|
||||
p->eParseMode = PARSE_MODE_RENAME;
|
||||
p->db = db;
|
||||
p->nQueryLoop = 1;
|
||||
@@ -1417,7 +1421,7 @@ static void renameParseCleanup(Parse *pParse){
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
sqlite3DbFree(db, pParse->zErrMsg);
|
||||
renameTokenFree(db, pParse->pRename);
|
||||
sqlite3ParserReset(pParse);
|
||||
sqlite3ParseObjectReset(pParse);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -354,7 +354,7 @@ static void codeAttach(
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( pAuthArg ){
|
||||
if( ALWAYS(pAuthArg) ){
|
||||
char *zAuthArg;
|
||||
if( pAuthArg->op==TK_STRING ){
|
||||
assert( !ExprHasProperty(pAuthArg, EP_IntValue) );
|
||||
|
||||
+2
-3
@@ -85,14 +85,13 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
if( i==1 ){
|
||||
Parse sParse;
|
||||
int rc = 0;
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = pDb;
|
||||
sqlite3ParseObjectInit(&sParse,pErrorDb);
|
||||
if( sqlite3OpenTempDatabase(&sParse) ){
|
||||
sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3DbFree(pErrorDb, sParse.zErrMsg);
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
if( rc ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
+16
-10
@@ -143,11 +143,13 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
|
||||
assert( pParse->pToplevel==0 );
|
||||
db = pParse->db;
|
||||
assert( db->pParse==pParse );
|
||||
if( pParse->nested ) return;
|
||||
if( db->mallocFailed || pParse->nErr ){
|
||||
if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR;
|
||||
if( pParse->nErr ){
|
||||
if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM;
|
||||
return;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
|
||||
/* Begin by generating some termination code at the end of the
|
||||
** vdbe program
|
||||
@@ -280,7 +282,9 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
|
||||
/* Get the VDBE program ready for execution
|
||||
*/
|
||||
if( v && pParse->nErr==0 && !db->mallocFailed ){
|
||||
assert( v!=0 || pParse->nErr );
|
||||
assert( db->mallocFailed==0 || pParse->nErr );
|
||||
if( pParse->nErr==0 ){
|
||||
/* A minimum of one cursor is required if autoincrement is used
|
||||
* See ticket [a696379c1f08866] */
|
||||
assert( pParse->pAinc==0 || pParse->nTab>0 );
|
||||
@@ -2384,10 +2388,11 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
pTab->iPKey = -1;
|
||||
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
|
||||
SQLITE_IDXTYPE_PRIMARYKEY);
|
||||
if( db->mallocFailed || pParse->nErr ){
|
||||
if( pParse->nErr ){
|
||||
pTab->tabFlags &= ~TF_WithoutRowid;
|
||||
return;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pPk->nKeyCol==1 );
|
||||
}else{
|
||||
@@ -3128,10 +3133,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
*/
|
||||
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
||||
&pTable->nCol, &pTable->aCol);
|
||||
if( db->mallocFailed==0
|
||||
&& pParse->nErr==0
|
||||
if( pParse->nErr==0
|
||||
&& pTable->nCol==pSel->pEList->nExpr
|
||||
){
|
||||
assert( db->mallocFailed==0 );
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
|
||||
SQLITE_AFF_NONE);
|
||||
}
|
||||
@@ -3750,7 +3755,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
tnum = pIndex->tnum;
|
||||
}
|
||||
pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
|
||||
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
|
||||
assert( pKey!=0 || pParse->nErr );
|
||||
|
||||
/* Open the sorter cursor if we are to use one. */
|
||||
iSorter = pParse->nTab++;
|
||||
@@ -3914,9 +3919,11 @@ void sqlite3CreateIndex(
|
||||
char *zExtra = 0; /* Extra space after the Index object */
|
||||
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
|
||||
|
||||
if( db->mallocFailed || pParse->nErr>0 ){
|
||||
assert( db->pParse==pParse );
|
||||
if( pParse->nErr ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
@@ -3980,7 +3987,6 @@ void sqlite3CreateIndex(
|
||||
pDb = &db->aDb[iDb];
|
||||
|
||||
assert( pTab!=0 );
|
||||
assert( pParse->nErr==0 );
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
||||
&& db->init.busy==0
|
||||
&& pTblName!=0
|
||||
@@ -4544,10 +4550,10 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb;
|
||||
|
||||
assert( pParse->nErr==0 ); /* Never called with prior errors */
|
||||
if( db->mallocFailed ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
|
||||
assert( pName->nSrc==1 );
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto exit_drop_index;
|
||||
|
||||
+6
-2
@@ -658,7 +658,8 @@ static int parseModifier(
|
||||
sqlite3_context *pCtx, /* Function context */
|
||||
const char *z, /* The text of the modifier */
|
||||
int n, /* Length of zMod in bytes */
|
||||
DateTime *p /* The date/time value to be modified */
|
||||
DateTime *p, /* The date/time value to be modified */
|
||||
int idx /* Parameter index of the modifier */
|
||||
){
|
||||
int rc = 1;
|
||||
double r;
|
||||
@@ -671,6 +672,7 @@ static int parseModifier(
|
||||
** a unix timestamp, depending on its magnitude.
|
||||
*/
|
||||
if( sqlite3_stricmp(z, "auto")==0 ){
|
||||
if( idx>1 ) return 1; /* IMP: R-33611-57934 */
|
||||
if( !p->rawS || p->validJD ){
|
||||
rc = 0;
|
||||
p->rawS = 0;
|
||||
@@ -695,6 +697,7 @@ static int parseModifier(
|
||||
** SQLite (0..5373484.5) then the result will be NULL.
|
||||
*/
|
||||
if( sqlite3_stricmp(z, "julianday")==0 ){
|
||||
if( idx>1 ) return 1; /* IMP: R-31176-64601 */
|
||||
if( p->validJD && p->rawS ){
|
||||
rc = 0;
|
||||
p->rawS = 0;
|
||||
@@ -725,6 +728,7 @@ static int parseModifier(
|
||||
** seconds since 1970. Convert to a real julian day number.
|
||||
*/
|
||||
if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
|
||||
if( idx>1 ) return 1; /* IMP: R-49255-55373 */
|
||||
r = p->s*1000.0 + 210866760000000.0;
|
||||
if( r>=0.0 && r<464269060800000.0 ){
|
||||
clearYMD_HMS_TZ(p);
|
||||
@@ -938,7 +942,7 @@ static int isDate(
|
||||
for(i=1; i<argc; i++){
|
||||
z = sqlite3_value_text(argv[i]);
|
||||
n = sqlite3_value_bytes(argv[i]);
|
||||
if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
|
||||
if( z==0 || parseModifier(context, (char*)z, n, p, i) ) return 1;
|
||||
}
|
||||
computeJD(p);
|
||||
if( p->isError || !validJulianDay(p->iJD) ) return 1;
|
||||
|
||||
+4
-2
@@ -293,9 +293,11 @@ void sqlite3DeleteFrom(
|
||||
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
assert( db->pParse==pParse );
|
||||
if( pParse->nErr ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
|
||||
@@ -476,7 +478,7 @@ void sqlite3DeleteFrom(
|
||||
** ONEPASS_SINGLE: One-pass approach - at most one row deleted.
|
||||
** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted.
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,0,wcf,iTabCur+1);
|
||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
||||
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
|
||||
|
||||
+5
-8
@@ -2803,8 +2803,7 @@ int sqlite3FindInIndex(
|
||||
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
|
||||
int j;
|
||||
|
||||
assert( pReq!=0 || pRhs->iColumn==XN_ROWID
|
||||
|| pParse->nErr || db->mallocFailed );
|
||||
assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
|
||||
for(j=0; j<nExpr; j++){
|
||||
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
|
||||
assert( pIdx->azColl[j] );
|
||||
@@ -3280,10 +3279,8 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
pSel->iLimit = 0;
|
||||
if( sqlite3Select(pParse, pSel, &dest) ){
|
||||
if( pParse->nErr ){
|
||||
pExpr->op2 = pExpr->op;
|
||||
pExpr->op = TK_ERROR;
|
||||
}
|
||||
pExpr->op2 = pExpr->op;
|
||||
pExpr->op = TK_ERROR;
|
||||
return 0;
|
||||
}
|
||||
pExpr->iTable = rReg = dest.iSDParm;
|
||||
@@ -3500,10 +3497,10 @@ static void sqlite3ExprCodeIN(
|
||||
}else{
|
||||
destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse);
|
||||
}
|
||||
if( pParse->nErr ) goto sqlite3ExprCodeIN_finished;
|
||||
// if( pParse->nErr ) goto sqlite3ExprCodeIN_finished;
|
||||
for(i=0; i<nVector; i++){
|
||||
Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
|
||||
if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
|
||||
if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error;
|
||||
if( sqlite3ExprCanBeNull(p) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
|
||||
VdbeCoverage(v);
|
||||
|
||||
+1
-1
@@ -651,7 +651,7 @@ static void fkScanChildren(
|
||||
** clause. For each row found, increment either the deferred or immediate
|
||||
** foreign key constraint counter. */
|
||||
if( pParse->nErr==0 ){
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
|
||||
if( pWInfo ){
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
+6
-2
@@ -715,9 +715,11 @@ void sqlite3Insert(
|
||||
#endif
|
||||
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
assert( db->pParse==pParse );
|
||||
if( pParse->nErr ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
dest.iSDParm = 0; /* Suppress a harmless compiler warning */
|
||||
|
||||
/* If the Select object is really just a simple VALUES() list with a
|
||||
@@ -893,7 +895,9 @@ void sqlite3Insert(
|
||||
dest.nSdst = pTab->nCol;
|
||||
rc = sqlite3Select(pParse, pSelect, &dest);
|
||||
regFromSelect = dest.iSdst;
|
||||
if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
|
||||
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 );
|
||||
|
||||
@@ -488,6 +488,7 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
/* Version 3.38.0 and later */
|
||||
sqlite3_error_offset,
|
||||
sqlite3_vtab_rhs_value,
|
||||
sqlite3_vtab_distinct,
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
|
||||
+10
-1
@@ -759,8 +759,15 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
|
||||
** has happened. This routine will set db->mallocFailed, and also
|
||||
** temporarily disable the lookaside memory allocator and interrupt
|
||||
** any running VDBEs.
|
||||
**
|
||||
** Always return a NULL pointer so that this routine can be invoked using
|
||||
**
|
||||
** return sqlite3OomFault(db);
|
||||
**
|
||||
** and thereby avoid unnecessary stack frame allocations for the overwhelmingly
|
||||
** common case where no OOM occurs.
|
||||
*/
|
||||
void sqlite3OomFault(sqlite3 *db){
|
||||
void *sqlite3OomFault(sqlite3 *db){
|
||||
if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
|
||||
db->mallocFailed = 1;
|
||||
if( db->nVdbeExec>0 ){
|
||||
@@ -768,9 +775,11 @@ void sqlite3OomFault(sqlite3 *db){
|
||||
}
|
||||
DisableLookaside;
|
||||
if( db->pParse ){
|
||||
sqlite3ErrorMsg(db->pParse, "out of memory");
|
||||
db->pParse->rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1250,6 +1250,10 @@ void sqlite3Pragma(
|
||||
(void)sqlite3_finalize(pDummy);
|
||||
sqlite3DbFree(db, zSql);
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ErrorMsg(db->pParse, "out of memory");
|
||||
db->pParse->rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
pHash = &db->aDb[ii].pSchema->tblHash;
|
||||
break;
|
||||
}
|
||||
|
||||
+34
-10
@@ -568,8 +568,10 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
/*
|
||||
** Free all memory allocations in the pParse object
|
||||
*/
|
||||
void sqlite3ParserReset(Parse *pParse){
|
||||
void sqlite3ParseObjectReset(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( db!=0 );
|
||||
assert( db->pParse==pParse );
|
||||
assert( pParse->nested==0 );
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
sqlite3DbFree(db, pParse->aTableLock);
|
||||
@@ -584,11 +586,12 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
if( pParse->pConstExpr ){
|
||||
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
||||
}
|
||||
if( db ){
|
||||
assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
||||
db->lookaside.bDisable -= pParse->disableLookaside;
|
||||
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
|
||||
}
|
||||
assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
||||
db->lookaside.bDisable -= pParse->disableLookaside;
|
||||
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
|
||||
assert( pParse->db->pParse==pParse );
|
||||
db->pParse = pParse->pOuterParse;
|
||||
pParse->db = 0;
|
||||
pParse->disableLookaside = 0;
|
||||
}
|
||||
|
||||
@@ -601,7 +604,7 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
** cost for this mechansim (an extra malloc), so it should not be used
|
||||
** for common cleanups that happen on most calls. But for less
|
||||
** common cleanups, we save a single NULL-pointer comparison in
|
||||
** sqlite3ParserReset(), which reduces the total CPU cycle count.
|
||||
** sqlite3ParseObjectReset(), which reduces the total CPU cycle count.
|
||||
**
|
||||
** If a memory allocation error occurs, then the cleanup happens immediately.
|
||||
** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
|
||||
@@ -641,6 +644,24 @@ void *sqlite3ParserAddCleanup(
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Turn bulk memory into a valid Parse object and link that Parse object
|
||||
** into database connection db.
|
||||
**
|
||||
** Call sqlite3ParseObjectReset() to undo this operation.
|
||||
**
|
||||
** Caution: Do not confuse this routine with sqlite3ParseObjectInit() which
|
||||
** is generated by Lemon.
|
||||
*/
|
||||
void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){
|
||||
memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ);
|
||||
memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
|
||||
assert( db->pParse!=pParse );
|
||||
pParse->pOuterParse = db->pParse;
|
||||
db->pParse = pParse;
|
||||
pParse->db = db;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
@@ -657,8 +678,12 @@ static int sqlite3Prepare(
|
||||
int i; /* Loop counter */
|
||||
Parse sParse; /* Parsing context */
|
||||
|
||||
memset(&sParse, 0, PARSE_HDR_SZ);
|
||||
/* sqlite3ParseObjectInit(&sParse, db); // inlined for performance */
|
||||
memset(PARSE_HDR(&sParse), 0, PARSE_HDR_SZ);
|
||||
memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
|
||||
sParse.pOuterParse = db->pParse;
|
||||
db->pParse = &sParse;
|
||||
sParse.db = db;
|
||||
sParse.pReprepare = pReprepare;
|
||||
assert( ppStmt && *ppStmt==0 );
|
||||
/* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
|
||||
@@ -714,7 +739,6 @@ static int sqlite3Prepare(
|
||||
|
||||
sqlite3VtabUnlockList(db);
|
||||
|
||||
sParse.db = db;
|
||||
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
|
||||
char *zSqlCopy;
|
||||
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
||||
@@ -781,7 +805,7 @@ static int sqlite3Prepare(
|
||||
|
||||
end_prepare:
|
||||
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
return rc;
|
||||
}
|
||||
static int sqlite3LockAndPrepare(
|
||||
|
||||
+5
-3
@@ -1214,7 +1214,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
|
||||
assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
|
||||
return pParse->nErr ? WRC_Abort : WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1628,7 +1629,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
*/
|
||||
if( (p->selFlags & SF_Expanded)==0 ){
|
||||
sqlite3SelectPrep(pParse, p, pOuterNC);
|
||||
return (pParse->nErr || db->mallocFailed) ? WRC_Abort : WRC_Prune;
|
||||
return pParse->nErr ? WRC_Abort : WRC_Prune;
|
||||
}
|
||||
|
||||
isCompound = p->pPrior!=0;
|
||||
@@ -1676,7 +1677,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
|
||||
sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
|
||||
pParse->zAuthContext = zSavedContext;
|
||||
if( pParse->nErr || db->mallocFailed ) return WRC_Abort;
|
||||
if( pParse->nErr ) return WRC_Abort;
|
||||
assert( db->mallocFailed==0 );
|
||||
|
||||
/* If the number of references to the outer context changed when
|
||||
** expressions in the sub-select were resolved, the sub-select
|
||||
|
||||
+19
-12
@@ -1404,7 +1404,7 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
||||
p->nRef = 1;
|
||||
memset(&p[1], 0, nExtra);
|
||||
}else{
|
||||
sqlite3OomFault(db);
|
||||
return (KeyInfo*)sqlite3OomFault(db);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@@ -5588,7 +5588,8 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
|
||||
/* Process NATURAL keywords, and ON and USING clauses of joins.
|
||||
*/
|
||||
if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){
|
||||
assert( db->mallocFailed==0 || pParse->nErr!=0 );
|
||||
if( pParse->nErr || sqliteProcessJoin(pParse, p) ){
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
@@ -5885,12 +5886,13 @@ void sqlite3SelectPrep(
|
||||
NameContext *pOuterNC /* Name context for container */
|
||||
){
|
||||
assert( p!=0 || pParse->db->mallocFailed );
|
||||
assert( pParse->db->pParse==pParse );
|
||||
if( pParse->db->mallocFailed ) return;
|
||||
if( p->selFlags & SF_HasTypeInfo ) return;
|
||||
sqlite3SelectExpand(pParse, p);
|
||||
if( pParse->nErr || pParse->db->mallocFailed ) return;
|
||||
if( pParse->nErr ) return;
|
||||
sqlite3ResolveSelectNames(pParse, p, pOuterNC);
|
||||
if( pParse->nErr || pParse->db->mallocFailed ) return;
|
||||
if( pParse->nErr ) return;
|
||||
sqlite3SelectAddTypeInfo(pParse, p);
|
||||
}
|
||||
|
||||
@@ -5907,8 +5909,10 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
int i;
|
||||
struct AggInfo_func *pFunc;
|
||||
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
|
||||
assert( pParse->db->pParse==pParse );
|
||||
assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
|
||||
if( nReg==0 ) return;
|
||||
if( pParse->nErr || pParse->db->mallocFailed ) return;
|
||||
if( pParse->nErr ) return;
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Verify that all AggInfo registers are within the range specified by
|
||||
** AggInfo.mnReg..AggInfo.mxReg */
|
||||
@@ -6331,10 +6335,12 @@ int sqlite3Select(
|
||||
u8 minMaxFlag; /* Flag for min/max queries */
|
||||
|
||||
db = pParse->db;
|
||||
assert( pParse==db->pParse );
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( p==0 || db->mallocFailed || pParse->nErr ){
|
||||
if( p==0 || pParse->nErr ){
|
||||
return 1;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
|
||||
@@ -6369,9 +6375,10 @@ int sqlite3Select(
|
||||
p->selFlags |= SF_NoopOrderBy;
|
||||
}
|
||||
sqlite3SelectPrep(pParse, p, 0);
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
if( pParse->nErr ){
|
||||
goto select_end;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
assert( p->pEList!=0 );
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x104 ){
|
||||
@@ -6415,7 +6422,7 @@ int sqlite3Select(
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( sqlite3WindowRewrite(pParse, p) ){
|
||||
assert( db->mallocFailed || pParse->nErr>0 );
|
||||
assert( pParse->nErr );
|
||||
goto select_end;
|
||||
}
|
||||
#if SELECTTRACE_ENABLED
|
||||
@@ -6891,7 +6898,7 @@ int sqlite3Select(
|
||||
/* Begin the database scan. */
|
||||
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
|
||||
p->pEList, wctrlFlags, p->nSelectRow);
|
||||
p->pEList, p, wctrlFlags, p->nSelectRow);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
||||
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
||||
@@ -7155,7 +7162,7 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
||||
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
|
||||
WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0
|
||||
0, (WHERE_GROUPBY|(orderByGrp ? WHERE_SORTBYGROUP : 0)|distFlag), 0
|
||||
);
|
||||
if( pWInfo==0 ){
|
||||
sqlite3ExprListDelete(db, pDistinct);
|
||||
@@ -7453,7 +7460,7 @@ int sqlite3Select(
|
||||
|
||||
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
|
||||
pDistinct, minMaxFlag|distFlag, 0);
|
||||
pDistinct, 0, minMaxFlag|distFlag, 0);
|
||||
if( pWInfo==0 ){
|
||||
goto select_end;
|
||||
}
|
||||
@@ -7510,7 +7517,7 @@ int sqlite3Select(
|
||||
*/
|
||||
select_end:
|
||||
assert( db->mallocFailed==0 || db->mallocFailed==1 );
|
||||
pParse->nErr += db->mallocFailed;
|
||||
assert( db->mallocFailed==0 || pParse->nErr!=0 );
|
||||
sqlite3ExprListDelete(db, pMinMaxOrderBy);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pAggInfo && !db->mallocFailed ){
|
||||
|
||||
@@ -1086,6 +1086,7 @@ struct ShellState {
|
||||
u8 bSafeModePersist; /* The long-term value of bSafeMode */
|
||||
unsigned statsOn; /* True to display memory stats before each finalize */
|
||||
unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
|
||||
int inputNesting; /* Track nesting level of .read and other redirects */
|
||||
int outCount; /* Revert to stdout when reaching zero */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
int lineno; /* Line number of last line read from in */
|
||||
@@ -1250,6 +1251,12 @@ static const char *modeDescr[] = {
|
||||
#define SEP_Unit "\x1F"
|
||||
#define SEP_Record "\x1E"
|
||||
|
||||
/*
|
||||
** Limit input nesting via .read or any other input redirect.
|
||||
** It's not too expensive, so a generous allowance can be made.
|
||||
*/
|
||||
#define MAX_INPUT_NESTING 25
|
||||
|
||||
/*
|
||||
** A callback for the sqlite3_log() interface.
|
||||
*/
|
||||
@@ -10940,6 +10947,13 @@ static int process_input(ShellState *p){
|
||||
int startline = 0; /* Line number for start of current input */
|
||||
QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
|
||||
|
||||
if( p->inputNesting==MAX_INPUT_NESTING ){
|
||||
/* This will be more informative in a later version. */
|
||||
utf8_printf(stderr,"Input nesting limit (%d) reached at line %d."
|
||||
" Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
|
||||
return 1;
|
||||
}
|
||||
++p->inputNesting;
|
||||
p->lineno = 0;
|
||||
while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
|
||||
fflush(p->out);
|
||||
@@ -11022,6 +11036,7 @@ static int process_input(ShellState *p){
|
||||
}
|
||||
free(zSql);
|
||||
free(zLine);
|
||||
--p->inputNesting;
|
||||
return errCnt>0;
|
||||
}
|
||||
|
||||
|
||||
+71
-3
@@ -7148,6 +7148,8 @@ struct sqlite3_index_info {
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
||||
#define SQLITE_INDEX_CONSTRAINT_IS 72
|
||||
#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
|
||||
#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
|
||||
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
||||
|
||||
/*
|
||||
@@ -9471,13 +9473,14 @@ int sqlite3_vtab_nochange(sqlite3_context*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
|
||||
** METHOD: sqlite3_index_info
|
||||
**
|
||||
** This function may only be called from within a call to the [xBestIndex]
|
||||
** method of a [virtual table]. This function returns a pointer to a string
|
||||
** that is the name of the appropriate collation sequence to use for text
|
||||
** comparisons on the constraint identified by its arguments.
|
||||
**
|
||||
** The first argument must be the pointer to the sqlite3_index_info object
|
||||
** The first argument must be the pointer to the [sqlite3_index_info] object
|
||||
** that is the first parameter to the xBestIndex() method. The second argument
|
||||
** must be an index into the aConstraint[] array belonging to the
|
||||
** sqlite3_index_info structure passed to xBestIndex.
|
||||
@@ -9485,7 +9488,7 @@ int sqlite3_vtab_nochange(sqlite3_context*);
|
||||
** Important:
|
||||
** The first parameter must be the same pointer that is passed into the
|
||||
** xBestMethod() method. The first parameter may not be a pointer to a
|
||||
** different sqlite3_index_info object, even an exact copy.
|
||||
** different [sqlite3_index_info] object, even an exact copy.
|
||||
**
|
||||
** The return value is computed as follows:
|
||||
**
|
||||
@@ -9503,6 +9506,71 @@ int sqlite3_vtab_nochange(sqlite3_context*);
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine if a virtual table query is DISTINCT
|
||||
** METHOD: sqlite3_index_info
|
||||
**
|
||||
** This API may only be used from within an xBestIndex() callback. The
|
||||
** results of calling it from outside of an xBestIndex() callback are
|
||||
** undefined and probably harmful.
|
||||
**
|
||||
** ^The sqlite3_vtab_distinct() returns an integer that is either 0, 1, or
|
||||
** 2. The integer returned by sqlite3_vtab_distinct() gives the virtual table
|
||||
** additional information about how the query planner wants the output to be
|
||||
** ordered. As long as the virtual table can meet the ordering requirements
|
||||
** of the query planner, it may set the "orderByConsumed" flag.
|
||||
**
|
||||
** <ol><li value="0"><p>
|
||||
** ^If the sqlite3_vtab_distinct() interface returns 0, that means
|
||||
** that the query planner needs the virtual table to return all rows in the
|
||||
** sort order defined by the "nOrderBy" and "aOrderBy" fields of the
|
||||
** [sqlite3_index_info] object. This is the default expectation. If the
|
||||
** virtual table outputs all rows in sorted order, then it is always safe for
|
||||
** the xBestIndex method to set the "orderByConsumed" flag, regardless of
|
||||
** what the return value from sqlite3_vtab_distinct().
|
||||
** <li value="1"><p>
|
||||
** ^(If the sqlite3_vtab_distinct() interface returns 1, that means
|
||||
** that the query planner does not need the rows to be returned in sorted order
|
||||
** as long as all rows with the same values in all columns identified by the
|
||||
** "aOrderBy" field are adjacent.)^ This mode is used when the query planner
|
||||
** is doing a GROUP BY.
|
||||
** <li value="2"><p>
|
||||
** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
|
||||
** that the query planner does not need the rows returned in any particular
|
||||
** order, as long as rows with the same values in all "aOrderBy" columns
|
||||
** are adjacent.)^ ^(Furthermore, only a single row for each particular
|
||||
** combination of values in the columns identified by the "aOrderBy" field
|
||||
** needs to be returned.)^ ^It is ok always for two or more rows with the same
|
||||
** values in all "aOrderBy" columns to be returned, as long as all such rows
|
||||
** are adjacent. ^The virtual table may, if it chooses, omit extra rows
|
||||
** that have the same value for all columns identified by "aOrderBy".
|
||||
** ^However omitting the extra rows is optional.
|
||||
** This mode is used for a DISTINCT query.
|
||||
** </ol>
|
||||
**
|
||||
** ^For the purposes of comparing virtual table output values to see if the
|
||||
** values are same value for sorting purposes, two NULL values are considered
|
||||
** to be the same. In other words, the comparison operator is "IS"
|
||||
** (or "IS NOT DISTINCT FROM") and not "==".
|
||||
**
|
||||
** If a virtual table implementation is unable to meet the requirements
|
||||
** specified above, then it must not set the "orderByConsumed" flag in the
|
||||
** [sqlite3_index_info] object or an incorrect answer may result.
|
||||
**
|
||||
** ^A virtual table implementation is always free to return rows in any order
|
||||
** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
||||
** the "orderByConsumed" flag is unset, the query planner will add extra
|
||||
** [bytecode] to ensure that the final results returned by the SQL query are
|
||||
** ordered correctly. The use of the "orderByConsumed" flag and the
|
||||
** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
||||
** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed"
|
||||
** flag might help queries against a virtual table to run faster. Being
|
||||
** overly aggressive and setting the "orderByConsumed" flag when it is not
|
||||
** valid to do so, on the other hand, might cause SQLite to return incorrect
|
||||
** results.
|
||||
*/
|
||||
int sqlite3_vtab_distinct(sqlite3_index_info*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Constraint values in xBestIndex()
|
||||
** METHOD: sqlite3_index_info
|
||||
@@ -9513,7 +9581,7 @@ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
**
|
||||
** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
|
||||
** the [xBestIndex] method of a [virtual table] implementation, with P being
|
||||
** a copy of the sqlite3_index_info object pointer passed into xBestIndex and
|
||||
** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and
|
||||
** J being a 0-based index into P->aConstraint[], then this routine
|
||||
** attempts to set *V to be the value on the right-hand side of
|
||||
** that constraint if the right-hand side is a known constant. ^If the
|
||||
|
||||
@@ -347,6 +347,7 @@ struct sqlite3_api_routines {
|
||||
/* Version 3.38.0 and later */
|
||||
int (*error_offset)(sqlite3*);
|
||||
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
||||
int (*vtab_distinct)(sqlite3_index_info*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -661,6 +662,7 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
/* Version 3.38.0 and later */
|
||||
#define sqlite3_error_offset sqlite3_api->error_offset
|
||||
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
||||
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+8
-4
@@ -3585,6 +3585,7 @@ struct Parse {
|
||||
**************************************************************************/
|
||||
|
||||
int aTempReg[8]; /* Holding area for temporary registers */
|
||||
Parse *pOuterParse; /* Outer Parse object when nested */
|
||||
Token sNameToken; /* Token with unqualified schema object name */
|
||||
|
||||
/************************************************************************
|
||||
@@ -3635,7 +3636,8 @@ struct Parse {
|
||||
/*
|
||||
** Sizes and pointers of various parts of the Parse object.
|
||||
*/
|
||||
#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/
|
||||
#define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg))
|
||||
#define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/
|
||||
#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */
|
||||
#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
|
||||
#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */
|
||||
@@ -4575,7 +4577,8 @@ void sqlite3CodeChangeCount(Vdbe*,int,const char*);
|
||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
|
||||
void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*,
|
||||
Upsert*);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,
|
||||
ExprList*,Select*,u16,int);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
LogEst sqlite3WhereOutputRowCount(WhereInfo*);
|
||||
int sqlite3WhereIsDistinct(WhereInfo*);
|
||||
@@ -4975,7 +4978,7 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
|
||||
FuncDestructor *pDestructor
|
||||
);
|
||||
void sqlite3NoopDestructor(void*);
|
||||
void sqlite3OomFault(sqlite3*);
|
||||
void *sqlite3OomFault(sqlite3*);
|
||||
void sqlite3OomClear(sqlite3*);
|
||||
int sqlite3ApiExit(sqlite3 *db, int);
|
||||
int sqlite3OpenTempDatabase(Parse *);
|
||||
@@ -5096,7 +5099,8 @@ FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
|
||||
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||
void sqlite3ParserReset(Parse*);
|
||||
void sqlite3ParseObjectInit(Parse*,sqlite3*);
|
||||
void sqlite3ParseObjectReset(Parse*);
|
||||
void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
char *sqlite3Normalize(Vdbe*, const char*);
|
||||
|
||||
@@ -424,6 +424,10 @@ static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
zOp = "isnull"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_IS:
|
||||
zOp = "is"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LIMIT:
|
||||
zOp = "limit"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_OFFSET:
|
||||
zOp = "offset"; break;
|
||||
}
|
||||
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
|
||||
|
||||
+29
-28
@@ -918,6 +918,7 @@ static void codeReturningTrigger(
|
||||
|
||||
assert( v!=0 );
|
||||
assert( pParse->bReturning );
|
||||
assert( db->pParse==pParse );
|
||||
pReturning = pParse->u1.pReturning;
|
||||
assert( pTrigger == &(pReturning->retTrig) );
|
||||
memset(&sSelect, 0, sizeof(sSelect));
|
||||
@@ -928,7 +929,8 @@ static void codeReturningTrigger(
|
||||
sFrom.a[0].pTab = pTab;
|
||||
sFrom.a[0].iCursor = -1;
|
||||
sqlite3SelectPrep(pParse, &sSelect, 0);
|
||||
if( db->mallocFailed==0 && pParse->nErr==0 ){
|
||||
if( pParse->nErr==0 ){
|
||||
assert( db->mallocFailed==0 );
|
||||
sqlite3GenerateColumnNames(pParse, &sSelect);
|
||||
}
|
||||
sqlite3ExprListDelete(db, sSelect.pEList);
|
||||
@@ -946,7 +948,7 @@ static void codeReturningTrigger(
|
||||
pParse->eTriggerOp = pTrigger->op;
|
||||
pParse->pTriggerTab = pTab;
|
||||
if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK
|
||||
&& !db->mallocFailed
|
||||
&& ALWAYS(!db->mallocFailed)
|
||||
){
|
||||
int i;
|
||||
int nCol = pNew->nExpr;
|
||||
@@ -1110,8 +1112,8 @@ static TriggerPrg *codeRowTrigger(
|
||||
Vdbe *v; /* Temporary VM */
|
||||
NameContext sNC; /* Name context for sub-vdbe */
|
||||
SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */
|
||||
Parse *pSubParse; /* Parse context for sub-vdbe */
|
||||
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
|
||||
Parse sSubParse; /* Parse context for sub-vdbe */
|
||||
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
||||
assert( pTop->pVdbe );
|
||||
@@ -1133,19 +1135,17 @@ static TriggerPrg *codeRowTrigger(
|
||||
|
||||
/* Allocate and populate a new Parse context to use for coding the
|
||||
** trigger sub-program. */
|
||||
pSubParse = sqlite3StackAllocZero(db, sizeof(Parse));
|
||||
if( !pSubParse ) return 0;
|
||||
sqlite3ParseObjectInit(&sSubParse, db);
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pSubParse;
|
||||
pSubParse->db = db;
|
||||
pSubParse->pTriggerTab = pTab;
|
||||
pSubParse->pToplevel = pTop;
|
||||
pSubParse->zAuthContext = pTrigger->zName;
|
||||
pSubParse->eTriggerOp = pTrigger->op;
|
||||
pSubParse->nQueryLoop = pParse->nQueryLoop;
|
||||
pSubParse->disableVtab = pParse->disableVtab;
|
||||
sNC.pParse = &sSubParse;
|
||||
sSubParse.pTriggerTab = pTab;
|
||||
sSubParse.pToplevel = pTop;
|
||||
sSubParse.zAuthContext = pTrigger->zName;
|
||||
sSubParse.eTriggerOp = pTrigger->op;
|
||||
sSubParse.nQueryLoop = pParse->nQueryLoop;
|
||||
sSubParse.disableVtab = pParse->disableVtab;
|
||||
|
||||
v = sqlite3GetVdbe(pSubParse);
|
||||
v = sqlite3GetVdbe(&sSubParse);
|
||||
if( v ){
|
||||
VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
|
||||
pTrigger->zName, onErrorText(orconf),
|
||||
@@ -1171,14 +1171,14 @@ static TriggerPrg *codeRowTrigger(
|
||||
if( db->mallocFailed==0
|
||||
&& SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen)
|
||||
){
|
||||
iEndTrigger = sqlite3VdbeMakeLabel(pSubParse);
|
||||
sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
|
||||
iEndTrigger = sqlite3VdbeMakeLabel(&sSubParse);
|
||||
sqlite3ExprIfFalse(&sSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
sqlite3ExprDelete(db, pWhen);
|
||||
}
|
||||
|
||||
/* Code the trigger program into the sub-vdbe. */
|
||||
codeTriggerProgram(pSubParse, pTrigger->step_list, orconf);
|
||||
codeTriggerProgram(&sSubParse, pTrigger->step_list, orconf);
|
||||
|
||||
/* Insert an OP_Halt at the end of the sub-program. */
|
||||
if( iEndTrigger ){
|
||||
@@ -1186,23 +1186,24 @@ static TriggerPrg *codeRowTrigger(
|
||||
}
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
|
||||
transferParseError(pParse, &sSubParse);
|
||||
|
||||
transferParseError(pParse, pSubParse);
|
||||
if( db->mallocFailed==0 && pParse->nErr==0 ){
|
||||
if( pParse->nErr==0 ){
|
||||
assert( db->mallocFailed==0 );
|
||||
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
|
||||
}
|
||||
pProgram->nMem = pSubParse->nMem;
|
||||
pProgram->nCsr = pSubParse->nTab;
|
||||
pProgram->nMem = sSubParse.nMem;
|
||||
pProgram->nCsr = sSubParse.nTab;
|
||||
pProgram->token = (void *)pTrigger;
|
||||
pPrg->aColmask[0] = pSubParse->oldmask;
|
||||
pPrg->aColmask[1] = pSubParse->newmask;
|
||||
pPrg->aColmask[0] = sSubParse.oldmask;
|
||||
pPrg->aColmask[1] = sSubParse.newmask;
|
||||
sqlite3VdbeDelete(v);
|
||||
}else{
|
||||
transferParseError(pParse, &sSubParse);
|
||||
}
|
||||
|
||||
assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
|
||||
sqlite3ParserReset(pSubParse);
|
||||
sqlite3StackFree(db, pSubParse);
|
||||
|
||||
assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg );
|
||||
sqlite3ParseObjectReset(&sSubParse);
|
||||
return pPrg;
|
||||
}
|
||||
|
||||
@@ -1257,7 +1258,7 @@ void sqlite3CodeRowTriggerDirect(
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */
|
||||
TriggerPrg *pPrg;
|
||||
pPrg = getRowTrigger(pParse, p, pTab, orconf);
|
||||
assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
|
||||
assert( pPrg || pParse->nErr );
|
||||
|
||||
/* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
|
||||
** is a pointer to the sub-vdbe containing the trigger program. */
|
||||
|
||||
+7
-3
@@ -347,9 +347,11 @@ void sqlite3Update(
|
||||
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
assert( db->pParse==pParse );
|
||||
if( pParse->nErr ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
|
||||
/* Locate the table which we want to update.
|
||||
*/
|
||||
@@ -721,7 +723,7 @@ void sqlite3Update(
|
||||
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
|
||||
flags |= WHERE_ONEPASS_MULTIROW;
|
||||
}
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags,iIdxCur);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* A one-pass strategy that might update more than one row may not
|
||||
@@ -1243,7 +1245,9 @@ static void updateVirtualTable(
|
||||
regRowid = ++pParse->nMem;
|
||||
|
||||
/* Start scanning the virtual table */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc,pWhere,0,0,WHERE_ONEPASS_DESIRED,0);
|
||||
pWInfo = sqlite3WhereBegin(
|
||||
pParse, pSrc, pWhere, 0, 0, 0, WHERE_ONEPASS_DESIRED, 0
|
||||
);
|
||||
if( pWInfo==0 ) return;
|
||||
|
||||
/* Populate the argument registers. */
|
||||
|
||||
@@ -189,6 +189,8 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
||||
char *zMsg;
|
||||
va_list ap;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( db!=0 );
|
||||
assert( db->pParse==pParse );
|
||||
db->errByteOffset = -2;
|
||||
va_start(ap, zFormat);
|
||||
zMsg = sqlite3VMPrintf(db, zFormat, ap);
|
||||
@@ -196,6 +198,10 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
||||
if( db->errByteOffset<-1 ) db->errByteOffset = -1;
|
||||
if( db->suppressErr ){
|
||||
sqlite3DbFree(db, zMsg);
|
||||
if( db->mallocFailed ){
|
||||
pParse->nErr++;
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}
|
||||
}else{
|
||||
pParse->nErr++;
|
||||
sqlite3DbFree(db, pParse->zErrMsg);
|
||||
|
||||
+1
-2
@@ -1378,8 +1378,7 @@ void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
|
||||
*/
|
||||
static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
|
||||
assert( p->nOp>0 || p->aOp==0 );
|
||||
assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed
|
||||
|| p->pParse->nErr>0 );
|
||||
assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->pParse->nErr>0 );
|
||||
if( p->nOp ){
|
||||
assert( p->aOp );
|
||||
sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
|
||||
|
||||
+6
-5
@@ -152,10 +152,9 @@ int sqlite3_blob_open(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
|
||||
do {
|
||||
memset(&sParse, 0, sizeof(Parse));
|
||||
while(1){
|
||||
sqlite3ParseObjectInit(&sParse,db);
|
||||
if( !pBlob ) goto blob_open_out;
|
||||
sParse.db = db;
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = 0;
|
||||
|
||||
@@ -332,7 +331,9 @@ int sqlite3_blob_open(
|
||||
goto blob_open_out;
|
||||
}
|
||||
rc = blobSeekToRow(pBlob, iRow, &zErr);
|
||||
} while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
|
||||
if( (++nAttempt)>=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break;
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
}
|
||||
|
||||
blob_open_out:
|
||||
if( rc==SQLITE_OK && db->mallocFailed==0 ){
|
||||
@@ -343,7 +344,7 @@ blob_open_out:
|
||||
}
|
||||
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
|
||||
@@ -1530,11 +1530,7 @@ static int valueFromExpr(
|
||||
|
||||
assert( pExpr!=0 );
|
||||
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
|
||||
#if defined(SQLITE_ENABLE_STAT4)
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#else
|
||||
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
||||
#endif
|
||||
|
||||
/* Compressed expressions only appear when parsing the DEFAULT clause
|
||||
** on a table column definition, and hence only when pCtx==0. This
|
||||
|
||||
+2
-3
@@ -825,9 +825,8 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pTab = pCtx->pTab;
|
||||
assert( IsVirtual(pTab) );
|
||||
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sqlite3ParseObjectInit(&sParse, db);
|
||||
sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
|
||||
sParse.db = db;
|
||||
/* We should never be able to reach this point while loading the
|
||||
** schema. Nevertheless, defend against that (turn off db->init.busy)
|
||||
** in case a bug arises. */
|
||||
@@ -881,7 +880,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
}
|
||||
sqlite3DeleteTable(db, sParse.pNewTable);
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
db->init.busy = initBusy;
|
||||
|
||||
assert( (rc&0xff)==rc );
|
||||
|
||||
+77
-17
@@ -32,6 +32,7 @@ typedef struct HiddenIndexInfo HiddenIndexInfo;
|
||||
struct HiddenIndexInfo {
|
||||
WhereClause *pWC; /* The Where clause being analyzed */
|
||||
Parse *pParse; /* The parsing context */
|
||||
int eDistinct; /* Value to return from sqlite3_vtab_distinct() */
|
||||
sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST
|
||||
** because extra space is allocated to hold up
|
||||
** to nTerm such values */
|
||||
@@ -1101,15 +1102,15 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
** by passing the pointer returned by this function to freeIndexInfo().
|
||||
*/
|
||||
static sqlite3_index_info *allocateIndexInfo(
|
||||
Parse *pParse, /* The parsing context */
|
||||
WhereInfo *pWInfo, /* The WHERE clause */
|
||||
WhereClause *pWC, /* The WHERE clause being analyzed */
|
||||
Bitmask mUnusable, /* Ignore terms with these prereqs */
|
||||
SrcItem *pSrc, /* The FROM clause term that is the vtab */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||
u16 *pmNoOmit /* Mask of terms not to omit */
|
||||
){
|
||||
int i, j;
|
||||
int nTerm;
|
||||
Parse *pParse = pWInfo->pParse;
|
||||
struct sqlite3_index_constraint *pIdxCons;
|
||||
struct sqlite3_index_orderby *pIdxOrderBy;
|
||||
struct sqlite3_index_constraint_usage *pUsage;
|
||||
@@ -1119,7 +1120,9 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
sqlite3_index_info *pIdxInfo;
|
||||
u16 mNoOmit = 0;
|
||||
const Table *pTab;
|
||||
|
||||
int eDistinct = 0;
|
||||
ExprList *pOrderBy = pWInfo->pOrderBy;
|
||||
|
||||
assert( pSrc!=0 );
|
||||
pTab = pSrc->pTab;
|
||||
assert( pTab!=0 );
|
||||
@@ -1203,6 +1206,9 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
}
|
||||
if( i==n){
|
||||
nOrderBy = n;
|
||||
if( (pWInfo->wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY)) ){
|
||||
eDistinct = 1 + ((pWInfo->wctrlFlags & WHERE_DISTINCTBY)!=0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1225,6 +1231,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
pIdxInfo->aConstraintUsage = pUsage;
|
||||
pHidden->pWC = pWC;
|
||||
pHidden->pParse = pParse;
|
||||
pHidden->eDistinct = eDistinct;
|
||||
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
||||
u16 op;
|
||||
if( (pTerm->wtFlags & TERM_OK)==0 ) continue;
|
||||
@@ -3452,6 +3459,15 @@ static int whereLoopAddBtree(
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Return true if pTerm is a virtual table LIMIT or OFFSET term.
|
||||
*/
|
||||
static int isLimitTerm(WhereTerm *pTerm){
|
||||
assert( pTerm->eOperator==WO_AUX || pTerm->eMatchOp==0 );
|
||||
return pTerm->eMatchOp>=SQLITE_INDEX_CONSTRAINT_LIMIT
|
||||
&& pTerm->eMatchOp<=SQLITE_INDEX_CONSTRAINT_OFFSET;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument pIdxInfo is already populated with all constraints that may
|
||||
** be used by the virtual table identified by pBuilder->pNew->iTab. This
|
||||
@@ -3479,7 +3495,8 @@ static int whereLoopAddVirtualOne(
|
||||
u16 mExclude, /* Exclude terms using these operators */
|
||||
sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */
|
||||
u16 mNoOmit, /* Do not omit these constraints */
|
||||
int *pbIn /* OUT: True if plan uses an IN(...) op */
|
||||
int *pbIn, /* OUT: True if plan uses an IN(...) op */
|
||||
int *pbRetryLimit /* OUT: Retry without LIMIT/OFFSET */
|
||||
){
|
||||
WhereClause *pWC = pBuilder->pWC;
|
||||
struct sqlite3_index_constraint *pIdxCons;
|
||||
@@ -3504,6 +3521,7 @@ static int whereLoopAddVirtualOne(
|
||||
pIdxCons->usable = 0;
|
||||
if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
|
||||
&& (pTerm->eOperator & mExclude)==0
|
||||
&& (pbRetryLimit || !isLimitTerm(pTerm))
|
||||
){
|
||||
pIdxCons->usable = 1;
|
||||
}
|
||||
@@ -3536,8 +3554,8 @@ static int whereLoopAddVirtualOne(
|
||||
|
||||
mxTerm = -1;
|
||||
assert( pNew->nLSlot>=nConstraint );
|
||||
for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
|
||||
pNew->u.vtab.omitMask = 0;
|
||||
memset(pNew->aLTerm, 0, sizeof(pNew->aLTerm[0])*nConstraint );
|
||||
memset(&pNew->u.vtab, 0, sizeof(pNew->u.vtab));
|
||||
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
|
||||
for(i=0; i<nConstraint; i++, pIdxCons++){
|
||||
int iTerm;
|
||||
@@ -3571,6 +3589,9 @@ static int whereLoopAddVirtualOne(
|
||||
}else{
|
||||
testcase( i!=iTerm );
|
||||
}
|
||||
if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET ){
|
||||
pNew->u.vtab.bOmitOffset = 1;
|
||||
}
|
||||
}
|
||||
if( (pTerm->eOperator & WO_IN)!=0 ){
|
||||
/* A virtual table that is constrained by an IN clause may not
|
||||
@@ -3582,6 +3603,21 @@ static int whereLoopAddVirtualOne(
|
||||
pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
|
||||
*pbIn = 1; assert( (mExclude & WO_IN)==0 );
|
||||
}
|
||||
|
||||
if( isLimitTerm(pTerm) && *pbIn ){
|
||||
/* If there is an IN(...) term handled as an == (separate call to
|
||||
** xFilter for each value on the RHS of the IN) and a LIMIT or
|
||||
** OFFSET term handled as well, the plan is unusable. Set output
|
||||
** variable *pbRetryLimit to true to tell the caller to retry with
|
||||
** LIMIT and OFFSET disabled. */
|
||||
if( pIdxInfo->needToFreeIdxStr ){
|
||||
sqlite3_free(pIdxInfo->idxStr);
|
||||
pIdxInfo->idxStr = 0;
|
||||
pIdxInfo->needToFreeIdxStr = 0;
|
||||
}
|
||||
*pbRetryLimit = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3684,13 +3720,25 @@ int sqlite3_vtab_rhs_value(
|
||||
}
|
||||
*ppVal = pVal;
|
||||
|
||||
if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-60459-24801 */
|
||||
if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-19933-32160 */
|
||||
rc = SQLITE_NOTFOUND; /* IMP: R-36424-56542 */
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return true if ORDER BY clause may be handled as DISTINCT.
|
||||
*/
|
||||
int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
|
||||
HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
||||
assert( pHidden->eDistinct==0
|
||||
|| pHidden->eDistinct==1
|
||||
|| pHidden->eDistinct==2 );
|
||||
return pHidden->eDistinct;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add all WhereLoop objects for a table of the join identified by
|
||||
** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
|
||||
@@ -3732,6 +3780,7 @@ static int whereLoopAddVirtual(
|
||||
WhereLoop *pNew;
|
||||
Bitmask mBest; /* Tables used by best possible plan */
|
||||
u16 mNoOmit;
|
||||
int bRetry = 0; /* True to retry with LIMIT/OFFSET disabled */
|
||||
|
||||
assert( (mPrereq & mUnusable)==0 );
|
||||
pWInfo = pBuilder->pWInfo;
|
||||
@@ -3740,8 +3789,7 @@ static int whereLoopAddVirtual(
|
||||
pNew = pBuilder->pNew;
|
||||
pSrc = &pWInfo->pTabList->a[pNew->iTab];
|
||||
assert( IsVirtual(pSrc->pTab) );
|
||||
p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy,
|
||||
&mNoOmit);
|
||||
p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
|
||||
if( p==0 ) return SQLITE_NOMEM_BKPT;
|
||||
pNew->rSetup = 0;
|
||||
pNew->wsFlags = WHERE_VIRTUALTABLE;
|
||||
@@ -3756,7 +3804,15 @@ static int whereLoopAddVirtual(
|
||||
/* First call xBestIndex() with all constraints usable. */
|
||||
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
|
||||
WHERETRACE(0x40, (" VirtualOne: all usable\n"));
|
||||
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
|
||||
rc = whereLoopAddVirtualOne(
|
||||
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
|
||||
);
|
||||
if( bRetry ){
|
||||
assert( rc==SQLITE_OK );
|
||||
rc = whereLoopAddVirtualOne(
|
||||
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, 0
|
||||
);
|
||||
}
|
||||
|
||||
/* If the call to xBestIndex() with all terms enabled produced a plan
|
||||
** that does not require any source tables (IOW: a plan with mBest==0)
|
||||
@@ -3774,7 +3830,7 @@ static int whereLoopAddVirtual(
|
||||
if( bIn ){
|
||||
WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
|
||||
rc = whereLoopAddVirtualOne(
|
||||
pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn);
|
||||
pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0);
|
||||
assert( bIn==0 );
|
||||
mBestNoIn = pNew->prereq & ~mPrereq;
|
||||
if( mBestNoIn==0 ){
|
||||
@@ -3801,7 +3857,7 @@ static int whereLoopAddVirtual(
|
||||
WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
|
||||
(sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
|
||||
rc = whereLoopAddVirtualOne(
|
||||
pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn);
|
||||
pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn, 0);
|
||||
if( pNew->prereq==mPrereq ){
|
||||
seenZero = 1;
|
||||
if( bIn==0 ) seenZeroNoIN = 1;
|
||||
@@ -3814,7 +3870,7 @@ static int whereLoopAddVirtual(
|
||||
if( rc==SQLITE_OK && seenZero==0 ){
|
||||
WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
|
||||
rc = whereLoopAddVirtualOne(
|
||||
pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn);
|
||||
pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0);
|
||||
if( bIn==0 ) seenZeroNoIN = 1;
|
||||
}
|
||||
|
||||
@@ -3824,7 +3880,7 @@ static int whereLoopAddVirtual(
|
||||
if( rc==SQLITE_OK && seenZeroNoIN==0 ){
|
||||
WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
|
||||
rc = whereLoopAddVirtualOne(
|
||||
pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn);
|
||||
pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3873,7 +3929,6 @@ static int whereLoopAddOr(
|
||||
int i, j;
|
||||
|
||||
sSubBuild = *pBuilder;
|
||||
sSubBuild.pOrderBy = 0;
|
||||
sSubBuild.pOrSet = &sCur;
|
||||
|
||||
WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm));
|
||||
@@ -5231,6 +5286,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
|
||||
ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
|
||||
Select *pLimit, /* Use this LIMIT/OFFSET clause, if any */
|
||||
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
|
||||
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
|
||||
** If WHERE_USE_LIMIT, then the limit amount */
|
||||
@@ -5265,7 +5321,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
|
||||
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
|
||||
if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
|
||||
sWLB.pOrderBy = pOrderBy;
|
||||
|
||||
/* The number of tables in the FROM clause is limited by the number of
|
||||
** bits in a Bitmask
|
||||
@@ -5308,6 +5363,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pWInfo->wctrlFlags = wctrlFlags;
|
||||
pWInfo->iLimit = iAuxArg;
|
||||
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
pWInfo->pLimit = pLimit;
|
||||
#endif
|
||||
memset(&pWInfo->nOBSat, 0,
|
||||
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
|
||||
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
|
||||
@@ -5376,6 +5434,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
|
||||
/* Analyze all of the subexpressions. */
|
||||
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
|
||||
sqlite3WhereAddLimit(&pWInfo->sWC, pLimit);
|
||||
if( db->mallocFailed ) goto whereBeginError;
|
||||
|
||||
/* Special case: WHERE terms that do not refer to any tables in the join
|
||||
@@ -5475,9 +5534,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
|
||||
pWInfo->revMask = ALLBITS;
|
||||
}
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
if( pParse->nErr ){
|
||||
goto whereBeginError;
|
||||
}
|
||||
assert( db->mallocFailed==0 );
|
||||
#ifdef WHERETRACE_ENABLED
|
||||
if( sqlite3WhereTrace ){
|
||||
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
|
||||
|
||||
+7
-2
@@ -123,7 +123,8 @@ struct WhereLoop {
|
||||
} btree;
|
||||
struct { /* Information for virtual tables */
|
||||
int idxNum; /* Index number */
|
||||
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
|
||||
u8 needFree : 1; /* True if sqlite3_free(idxStr) is needed */
|
||||
u8 bOmitOffset : 1; /* True to let virtual table handle offset */
|
||||
i8 isOrdered; /* True if satisfies ORDER BY */
|
||||
u16 omitMask; /* Terms that may be omitted */
|
||||
char *idxStr; /* Index identifier string */
|
||||
@@ -386,7 +387,6 @@ struct WhereMaskSet {
|
||||
struct WhereLoopBuilder {
|
||||
WhereInfo *pWInfo; /* Information about this WHERE */
|
||||
WhereClause *pWC; /* WHERE clause terms */
|
||||
ExprList *pOrderBy; /* ORDER BY clause */
|
||||
WhereLoop *pNew; /* Template WhereLoop */
|
||||
WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
@@ -454,6 +454,9 @@ struct WhereInfo {
|
||||
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
|
||||
ExprList *pResultSet; /* Result set of the query */
|
||||
Expr *pWhere; /* The complete WHERE clause */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
Select *pLimit; /* Used to access LIMIT expr/registers for vtabs */
|
||||
#endif
|
||||
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
int iBreak; /* Jump here to break out of the loop */
|
||||
@@ -539,6 +542,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
|
||||
void sqlite3WhereClauseClear(WhereClause*);
|
||||
void sqlite3WhereSplit(WhereClause*,Expr*,u8);
|
||||
void sqlite3WhereAddLimit(WhereClause*, Select*);
|
||||
Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
|
||||
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
|
||||
Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
|
||||
@@ -609,5 +613,6 @@ void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
|
||||
#define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */
|
||||
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
|
||||
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
|
||||
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
|
||||
|
||||
#endif /* !defined(SQLITE_WHEREINT_H) */
|
||||
|
||||
+16
-3
@@ -824,6 +824,9 @@ static int codeAllEqualityTerms(
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(j=nSkip; j<nEq; j++){
|
||||
pTerm = pLoop->aLTerm[j];
|
||||
if( pTerm->eOperator & WO_IN ){
|
||||
if( pTerm->pExpr->flags & EP_xIsSelect ){
|
||||
/* No affinity ever needs to be (or should be) applied to a value
|
||||
@@ -838,7 +841,8 @@ static int codeAllEqualityTerms(
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
if( pParse->db->mallocFailed==0 && pParse->nErr==0 ){
|
||||
if( pParse->nErr==0 ){
|
||||
assert( pParse->db->mallocFailed==0 );
|
||||
if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){
|
||||
zAff[j] = SQLITE_AFF_BLOB;
|
||||
}
|
||||
@@ -1533,6 +1537,15 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}else{
|
||||
Expr *pRight = pTerm->pExpr->pRight;
|
||||
codeExprOrVector(pParse, pRight, iTarget, 1);
|
||||
if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET
|
||||
&& pLoop->u.vtab.bOmitOffset
|
||||
){
|
||||
assert( pTerm->eOperator==WO_AUX );
|
||||
assert( pWInfo->pLimit!=0 );
|
||||
assert( pWInfo->pLimit->iOffset>0 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pLimit->iOffset);
|
||||
VdbeComment((v,"Zero OFFSET counter"));
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
|
||||
@@ -2354,9 +2367,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
/* Loop through table entries that match term pOrTerm. */
|
||||
ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
|
||||
WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0,
|
||||
WHERE_OR_SUBCLAUSE, iCovCur);
|
||||
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
|
||||
assert( pSubWInfo || pParse->nErr );
|
||||
if( pSubWInfo ){
|
||||
WhereLoop *pSubLoop;
|
||||
int addrExplain = sqlite3WhereExplainOneScan(
|
||||
|
||||
+113
-1
@@ -1379,7 +1379,10 @@ static void exprAnalyze(
|
||||
** no longer used.
|
||||
**
|
||||
** This is only required if at least one side of the comparison operation
|
||||
** is not a sub-select. */
|
||||
** is not a sub-select.
|
||||
**
|
||||
** tag-20220128a
|
||||
*/
|
||||
if( (pExpr->op==TK_EQ || pExpr->op==TK_IS)
|
||||
&& (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
|
||||
&& sqlite3ExprVectorSize(pExpr->pRight)==nLeft
|
||||
@@ -1522,6 +1525,113 @@ void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add either a LIMIT (if eMatchOp==SQLITE_INDEX_CONSTRAINT_LIMIT) or
|
||||
** OFFSET (if eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET) term to the
|
||||
** where-clause passed as the first argument. The value for the term
|
||||
** is found in register iReg.
|
||||
**
|
||||
** In the common case where the value is a simple integer
|
||||
** (example: "LIMIT 5 OFFSET 10") then the expression codes as a
|
||||
** TK_INTEGER so that it will be available to sqlite3_vtab_rhs_value().
|
||||
** If not, then it codes as a TK_REGISTER expression.
|
||||
*/
|
||||
void whereAddLimitExpr(
|
||||
WhereClause *pWC, /* Add the constraint to this WHERE clause */
|
||||
int iReg, /* Register that will hold value of the limit/offset */
|
||||
Expr *pExpr, /* Expression that defines the limit/offset */
|
||||
int iCsr, /* Cursor to which the constraint applies */
|
||||
int eMatchOp /* SQLITE_INDEX_CONSTRAINT_LIMIT or _OFFSET */
|
||||
){
|
||||
Parse *pParse = pWC->pWInfo->pParse;
|
||||
sqlite3 *db = pParse->db;
|
||||
Expr *pNew;
|
||||
int iVal = 0;
|
||||
|
||||
if( sqlite3ExprIsInteger(pExpr, &iVal) && iVal>=0 ){
|
||||
Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0);
|
||||
if( pVal==0 ) return;
|
||||
ExprSetProperty(pVal, EP_IntValue);
|
||||
pVal->u.iValue = iVal;
|
||||
pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal);
|
||||
}else{
|
||||
Expr *pVal = sqlite3Expr(db, TK_REGISTER, 0);
|
||||
if( pVal==0 ) return;
|
||||
pVal->iTable = iReg;
|
||||
pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal);
|
||||
}
|
||||
if( pNew ){
|
||||
WhereTerm *pTerm;
|
||||
int idx;
|
||||
idx = whereClauseInsert(pWC, pNew, TERM_DYNAMIC|TERM_VIRTUAL);
|
||||
pTerm = &pWC->a[idx];
|
||||
pTerm->leftCursor = iCsr;
|
||||
pTerm->eOperator = WO_AUX;
|
||||
pTerm->eMatchOp = eMatchOp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Possibly add terms corresponding to the LIMIT and OFFSET clauses of the
|
||||
** SELECT statement passed as the second argument. These terms are only
|
||||
** added if:
|
||||
**
|
||||
** 1. The SELECT statement has a LIMIT clause, and
|
||||
** 2. The SELECT statement is not an aggregate or DISTINCT query, and
|
||||
** 3. The SELECT statement has exactly one object in its from clause, and
|
||||
** that object is a virtual table, and
|
||||
** 4. There are no terms in the WHERE clause that will not be passed
|
||||
** to the virtual table xBestIndex method.
|
||||
** 5. The ORDER BY clause, if any, will be made available to the xBestIndex
|
||||
** method.
|
||||
**
|
||||
** LIMIT and OFFSET terms are ignored by most of the planner code. They
|
||||
** exist only so that they may be passed to the xBestIndex method of the
|
||||
** single virtual table in the FROM clause of the SELECT.
|
||||
*/
|
||||
void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
||||
assert( p==0 || (p->pGroupBy==0 && (p->selFlags & SF_Aggregate)==0) );
|
||||
if( (p && p->pLimit) /* 1 */
|
||||
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
|
||||
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
|
||||
){
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
int iCsr = p->pSrc->a[0].iCursor;
|
||||
int ii;
|
||||
|
||||
/* Check condition (4). Return early if it is not met. */
|
||||
for(ii=0; ii<pWC->nTerm; ii++){
|
||||
if( pWC->a[ii].wtFlags & TERM_CODED ){
|
||||
/* This term is a vector operation that has been decomposed into
|
||||
** other, subsequent terms. It can be ignored. See tag-20220128a */
|
||||
assert( pWC->a[ii].wtFlags & TERM_VIRTUAL );
|
||||
assert( pWC->a[ii].eOperator==0 );
|
||||
continue;
|
||||
}
|
||||
if( pWC->a[ii].leftCursor!=iCsr ) return;
|
||||
}
|
||||
|
||||
/* Check condition (5). Return early if it is not met. */
|
||||
if( pOrderBy ){
|
||||
for(ii=0; ii<pOrderBy->nExpr; ii++){
|
||||
Expr *pExpr = pOrderBy->a[ii].pExpr;
|
||||
if( pExpr->op!=TK_COLUMN ) return;
|
||||
if( NEVER(pExpr->iTable!=iCsr) ) return;
|
||||
if( pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_BIGNULL ) return;
|
||||
}
|
||||
}
|
||||
|
||||
/* All conditions are met. Add the terms to the where-clause object. */
|
||||
assert( p->pLimit->op==TK_LIMIT );
|
||||
whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
|
||||
iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
|
||||
if( p->iOffset>0 ){
|
||||
whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight,
|
||||
iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a preallocated WhereClause structure.
|
||||
*/
|
||||
@@ -1557,6 +1667,7 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
|
||||
}
|
||||
#endif
|
||||
while(1){
|
||||
assert( a->eMatchOp==0 || a->eOperator==WO_AUX );
|
||||
if( a->wtFlags & TERM_DYNAMIC ){
|
||||
sqlite3ExprDelete(db, a->pExpr);
|
||||
}
|
||||
@@ -1714,6 +1825,7 @@ void sqlite3WhereTabFuncArgs(
|
||||
pColRef->iColumn = k++;
|
||||
assert( ExprUseYTab(pColRef) );
|
||||
pColRef->y.pTab = pTab;
|
||||
pItem->colUsed |= sqlite3ExprColUsed(pColRef);
|
||||
pRhs = sqlite3PExpr(pParse, TK_UPLUS,
|
||||
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
|
||||
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
|
||||
|
||||
+1
-6
@@ -1106,12 +1106,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pTab);
|
||||
}
|
||||
|
||||
if( rc ){
|
||||
if( pParse->nErr==0 ){
|
||||
assert( pParse->db->mallocFailed );
|
||||
sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
|
||||
}
|
||||
}
|
||||
assert( rc==SQLITE_OK || pParse->nErr!=0 );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
# 2022-01-27
|
||||
#
|
||||
# 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 file is testing date and time functions.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Skip this whole file if date and time functions are omitted
|
||||
# at compile-time
|
||||
#
|
||||
ifcapable {!datetime} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc datetest {tnum expr result} {
|
||||
do_test date3-$tnum [subst {
|
||||
execsql "SELECT coalesce($expr,'NULL')"
|
||||
}] [list $result]
|
||||
}
|
||||
set tcl_precision 15
|
||||
|
||||
# EVIDENCE-OF: R-45708-63005 unixepoch(time-value, modifier, modifier,
|
||||
# ...)
|
||||
#
|
||||
datetest 1.1 {unixepoch('1970-01-01')} {0}
|
||||
datetest 1.2 {unixepoch('1969-12-31 23:59:59')} {-1}
|
||||
datetest 1.3 {unixepoch('2106-02-07 06:28:15')} {4294967295}
|
||||
datetest 1.4 {unixepoch('2106-02-07 06:28:16')} {4294967296}
|
||||
datetest 1.5 {unixepoch('9999-12-31 23:59:59')} {253402300799}
|
||||
datetest 1.6 {unixepoch('0000-01-01 00:00:00')} {-62167219200}
|
||||
|
||||
# EVIDENCE-OF: R-30877-63179 The unixepoch() function returns a unix
|
||||
# timestamp - the number of seconds since 1970-01-01 00:00:00 UTC.
|
||||
#
|
||||
for {set i 1} {$i<=100} {incr i} {
|
||||
set x [expr {int(rand()*0xfffffffff)-0xffffffff}]
|
||||
datetest 1.7.$i "unixepoch($x,'unixepoch')==$x" {1}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-62992-54137 The unixepoch() always returns an integer,
|
||||
# even if the input time-value has millisecond precision.
|
||||
#
|
||||
datetest 1.8 {unixepoch('2022-01-27 12:59:28.052')} {1643288368}
|
||||
|
||||
# EVIDENCE-OF: R-05412-24332 If the time-value is numeric (the
|
||||
# DDDDDDDDDD format) then the 'auto' modifier causes the time-value to
|
||||
# interpreted as either a julian day number or a unix timestamp,
|
||||
# depending on its magnitude.
|
||||
#
|
||||
# EVIDENCE-OF: R-56763-40111 If the value is between 0.0 and
|
||||
# 5373484.499999, then it is interpreted as a julian day number
|
||||
# (corresponding to dates between -4713-11-24 12:00:00 and 9999-12-31
|
||||
# 23:59:59, inclusive).
|
||||
#
|
||||
# EVIDENCE-OF: R-07289-49223 For numeric values outside of the range of
|
||||
# valid julian day numbers, but within the range of -210866760000 to
|
||||
# 253402300799, the 'auto' modifier causes the value to be interpreted
|
||||
# as a unix timestamp.
|
||||
#
|
||||
# EVIDENCE-OF: R-20795-34947 Other numeric values are out of range and
|
||||
# cause a NULL return.
|
||||
#
|
||||
foreach {tn jd date} {
|
||||
2.1 0.0 {-4713-11-24 12:00:00}
|
||||
2.2 5373484.4999999 {9999-12-31 23:59:59}
|
||||
2.3 2440587.5 {1970-01-01 00:00:00}
|
||||
2.4 2440587.49998843 {1969-12-31 23:59:59}
|
||||
2.5 2440615.7475463 {1970-01-29 05:56:28}
|
||||
|
||||
2.10 -1 {1969-12-31 23:59:59}
|
||||
2.11 5373485 {1970-03-04 04:38:05}
|
||||
2.12 -210866760000 {-4713-11-24 12:00:00}
|
||||
2.13 253402300799 {9999-12-31 23:59:59}
|
||||
|
||||
2.20 -210866760001 {NULL}
|
||||
2.21 253402300800 {NULL}
|
||||
} {
|
||||
datetest $tn "datetime($jd,'auto')" $date
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-38886-35357 The 'auto' modifier is a no-op for text
|
||||
# time-values.
|
||||
#
|
||||
datetest 2.30 {date('2022-01-29','auto')==date('2022-01-29')} {1}
|
||||
|
||||
# EVIDENCE-OF: R-53132-26856 The 'auto' modifier can be used to work
|
||||
# with date/time values even in cases where it is not known if the
|
||||
# julian day number or unix timestamp formats are in use.
|
||||
#
|
||||
do_execsql_test date3-2.40 {
|
||||
WITH tx(timeval,datetime) AS (
|
||||
VALUES('2022-01-27 13:15:44','2022-01-27 13:15:44'),
|
||||
(2459607.05260275,'2022-01-27 13:15:44'),
|
||||
(1643289344,'2022-01-27 13:15:44')
|
||||
)
|
||||
SELECT datetime(timeval,'auto') == datetime FROM tx;
|
||||
} {1 1 1}
|
||||
|
||||
# EVIDENCE-OF: R-49255-55373 The "unixepoch" modifier (11) only works if
|
||||
# it immediately follows a time value in the DDDDDDDDDD format.
|
||||
#
|
||||
# EVIDENCE-OF: R-23075-39245 This modifier causes the DDDDDDDDDD to be
|
||||
# interpreted not as a Julian day number as it normally would be, but as
|
||||
# Unix Time - the number of seconds since 1970.
|
||||
#
|
||||
datetest 3.1 {datetime(2459607.05,'+1 hour','unixepoch')} {NULL}
|
||||
datetest 3.2 {datetime(2459607.05,'unixepoch','+1 hour')} {1970-01-29 12:13:27}
|
||||
|
||||
# EVIDENCE-OF: R-21150-52363 The "julianday" modifier must immediately
|
||||
# follow the initial time-value which must be of the form DDDDDDDDD.
|
||||
#
|
||||
# EVIDENCE-OF: R-31176-64601 Any other use of the 'julianday' modifier
|
||||
# is an error and causes the function to return NULL.
|
||||
#
|
||||
# EVIDENCE-OF: R-32483-36353 The 'julianday' modifier forces the
|
||||
# time-value number to be interpreted as a julian-day number.
|
||||
#
|
||||
# EVIDENCE-OF: R-25859-20124 The only difference is that adding
|
||||
# 'julianday' forces the DDDDDDDDD time-value format, and causes a NULL
|
||||
# to be returned if any other time-value format is used.
|
||||
#
|
||||
datetest 4.1 {datetime(2459607,'julianday')} {2022-01-27 12:00:00}
|
||||
datetest 4.2 {datetime(2459607,'+1 hour','julianday')} {NULL}
|
||||
datetest 4.3 {datetime('2022-01-27','julianday')} {NULL}
|
||||
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-33431-18865 Unix timestamps for the first 63 days of
|
||||
# 1970 will be interpreted as julian day numbers.
|
||||
#
|
||||
do_execsql_test date3-5.0 {
|
||||
WITH inc(x) AS (VALUES(-10) UNION ALL SELECT x+1 FROM inc WHERE x<100)
|
||||
SELECT count(*) FROM inc
|
||||
WHERE datetime('1970-01-01',format('%+d days',x))
|
||||
<> datetime(unixepoch('1970-01-01',format('%+d days',x)),'auto');
|
||||
} {63}
|
||||
|
||||
finish_test
|
||||
+4
-7
@@ -265,13 +265,10 @@ do_execsql_test e_expr-6.4 {SELECT -72%5} {-2}
|
||||
do_execsql_test e_expr-6.5 {SELECT 72.35%5} {2.0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that the results of all binary operators are either numeric or
|
||||
# NULL, except for the || operator, which may evaluate to either a text
|
||||
# value or NULL.
|
||||
#
|
||||
# EVIDENCE-OF: R-20665-17792 The result of any binary operator is either
|
||||
# a numeric value or NULL, except for the || concatenation operator
|
||||
# which always evaluates to either NULL or a text value.
|
||||
# EVIDENCE-OF: R-15904-00746 The result of any binary operator is either
|
||||
# a numeric value or NULL, except for the || concatenation operator, and
|
||||
# the -> and ->> extract operators which evaluate to either
|
||||
# NULL or a text value.
|
||||
#
|
||||
set literals {
|
||||
1 'abc' 2 'hexadecimal' 3 ''
|
||||
|
||||
+2
-2
@@ -48,9 +48,9 @@ proc do_detail_test {tn sql res} {
|
||||
###########################################################################
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-33710-56344 In order to use foreign key constraints in
|
||||
# EVIDENCE-OF: R-37672-59189 In order to use foreign key constraints in
|
||||
# SQLite, the library must be compiled with neither
|
||||
# SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER defined.
|
||||
# SQLITE_OMIT_FOREIGN_KEY nor SQLITE_OMIT_TRIGGER defined.
|
||||
#
|
||||
ifcapable trigger&&foreignkey {
|
||||
do_test e_fkey-1 {
|
||||
|
||||
Binary file not shown.
+11
-8
@@ -12,10 +12,13 @@
|
||||
# focus of this file is testing the printf() SQL function.
|
||||
#
|
||||
#
|
||||
# EVIDENCE-OF: R-63057-40065 The printf(FORMAT,...) SQL function works
|
||||
# EVIDENCE-OF: R-32560-14372 The format(FORMAT,...) SQL function works
|
||||
# like the sqlite3_mprintf() C-language function and the printf()
|
||||
# function from the standard C library.
|
||||
#
|
||||
# EVIDENCE-OF: R-64900-53159 The printf() SQL function is an alias for
|
||||
# the format() SQL function.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -24,7 +27,7 @@ source $testdir/tester.tcl
|
||||
# then the result is NULL.
|
||||
#
|
||||
do_execsql_test printf2-1.1 {
|
||||
SELECT quote(printf()), quote(printf(NULL,1,2,3));
|
||||
SELECT quote(format()), quote(format(NULL,1,2,3));
|
||||
} {NULL NULL}
|
||||
|
||||
|
||||
@@ -32,31 +35,31 @@ do_execsql_test printf2-1.2 {
|
||||
SELECT printf('hello');
|
||||
} {hello}
|
||||
do_execsql_test printf2-1.3 {
|
||||
SELECT printf('%d,%d,%d',55,-11,3421);
|
||||
SELECT format('%d,%d,%d',55,-11,3421);
|
||||
} {55,-11,3421}
|
||||
do_execsql_test printf2-1.4 {
|
||||
SELECT printf('%d,%d,%d',55,'-11',3421);
|
||||
} {55,-11,3421}
|
||||
do_execsql_test printf2-1.5 {
|
||||
SELECT printf('%d,%d,%d,%d',55,'-11',3421);
|
||||
SELECT format('%d,%d,%d,%d',55,'-11',3421);
|
||||
} {55,-11,3421,0}
|
||||
do_execsql_test printf2-1.6 {
|
||||
SELECT printf('%.2f',3.141592653);
|
||||
} {3.14}
|
||||
do_execsql_test printf2-1.7 {
|
||||
SELECT printf('%.*f',2,3.141592653);
|
||||
SELECT format('%.*f',2,3.141592653);
|
||||
} {3.14}
|
||||
do_execsql_test printf2-1.8 {
|
||||
SELECT printf('%*.*f',5,2,3.141592653);
|
||||
} {{ 3.14}}
|
||||
do_execsql_test printf2-1.9 {
|
||||
SELECT printf('%d',314159.2653);
|
||||
SELECT format('%d',314159.2653);
|
||||
} {314159}
|
||||
do_execsql_test printf2-1.10 {
|
||||
SELECT printf('%lld',314159.2653);
|
||||
} {314159}
|
||||
do_execsql_test printf2-1.11 {
|
||||
SELECT printf('%lld%n',314159.2653,'hi');
|
||||
SELECT format('%lld%n',314159.2653,'hi');
|
||||
} {314159}
|
||||
do_execsql_test printf2-1.12 {
|
||||
SELECT printf('%n',0);
|
||||
@@ -65,7 +68,7 @@ do_execsql_test printf2-1.12 {
|
||||
# EVIDENCE-OF: R-17002-27534 The %z format is interchangeable with %s.
|
||||
#
|
||||
do_execsql_test printf2-1.12 {
|
||||
SELECT printf('%.*z',5,'abcdefghijklmnop');
|
||||
SELECT format('%.*z',5,'abcdefghijklmnop');
|
||||
} {abcde}
|
||||
do_execsql_test printf2-1.13 {
|
||||
SELECT printf('%c','abcdefghijklmnop');
|
||||
|
||||
@@ -692,6 +692,21 @@ do_execsql_test 30.3 {
|
||||
UPDATE t2 SET (d,d,a)=(SELECT EXISTS(SELECT 1 IN(SELECT max( 1 IN(SELECT x ORDER BY 1)) OVER(PARTITION BY sum((SELECT y FROM t1 UNION SELECT x ORDER BY 1)))INTERSECT SELECT EXISTS(SELECT 1 FROM t1 UNION SELECT x ORDER BY 1) ORDER BY 1) ORDERa)|9 AS blob, 2, 3) FROM t1 WHERE x<a;
|
||||
}
|
||||
|
||||
# 2022-01-21 https://sqlite.org/forum/forumpost/ab95010d410a0a55
|
||||
reset_db
|
||||
do_execsql_test 31.1 {
|
||||
CREATE TABLE a(a1 PRIMARY KEY,a2);
|
||||
INSERT INTO a VALUES(1,5);
|
||||
CREATE TABLE b(b1 UNIQUE,b2);
|
||||
SELECT * FROM a LEFT JOIN b ON b2=NULL AND b2=5 WHERE (b1,substr(b.b1,1,1))==(SELECT 1024,'b');
|
||||
} {}
|
||||
do_execsql_test 31.2 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(0);
|
||||
CREATE TABLE t2(b,c,d);
|
||||
INSERT INTO t2 VALUES(NULL,123,456);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON b=NULL WHERE (c,d)==(SELECT 123, 456+a);
|
||||
} {}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
# shell4-1.*: Basic tests specific to the "stats" command.
|
||||
# shell4-2.*: Basic tests for ".trace"
|
||||
# shell4-3.*: The ".read" command takes the shell out of interactive mode
|
||||
# shell4-4.*: Input redirects cannot recurse too much
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -138,4 +139,11 @@ do_test shell4-3.2 {
|
||||
exec $::CLI :memory: --interactive ".read t1.txt"
|
||||
} {pound: £}
|
||||
|
||||
do_test shell4-4.1 {
|
||||
set fd [open t1.txt wb]
|
||||
puts $fd ".read t1.txt"
|
||||
close $fd
|
||||
catchcmd ":memory:" ".read t1.txt"
|
||||
} {1 {Input nesting limit (25) reached at line 1. Check recursion.}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# 2022-01-21
|
||||
#
|
||||
# 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 tests for sqlite3_vtab_distinct() interface.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix vtabdistinct
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
load_static_extension db qpvtab
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT ix FROM qpvtab WHERE vn='sqlite3_vtab_distinct';
|
||||
} {0}
|
||||
do_execsql_test 1.2 {
|
||||
SELECT DISTINCT ix FROM qpvtab WHERE vn='sqlite3_vtab_distinct';
|
||||
} {2}
|
||||
do_execsql_test 1.3 {
|
||||
SELECT distinct vn, ix FROM qpvtab(3)
|
||||
WHERE +vn IN ('sqlite3_vtab_distinct','nOrderBy');
|
||||
} {nOrderBy 2 sqlite3_vtab_distinct 2}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT vn, ix FROM qpvtab
|
||||
GROUP BY vn
|
||||
HAVING vn='sqlite3_vtab_distinct';
|
||||
} {sqlite3_vtab_distinct 1}
|
||||
|
||||
finish_test
|
||||
Reference in New Issue
Block a user