mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Merge the latest enhancements from trunk.
FossilOrigin-Name: a7dcf6a79f7e1c5884baee2909a4bf3174ae06d561dae87b390856e573f81b49
This commit is contained in:
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_WHEREINFO_HOOK)
|
#if defined(SQLITE_TEST)
|
||||||
|
|
||||||
#include "sqlite3expert.h"
|
#include "sqlite3expert.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -212,8 +212,4 @@ int TestExpert_Init(Tcl_Interp *interp){
|
|||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* defined(SQLITE_TEST) && defined(SQLITE_ENABLE_WHEREINFO_HOOK) */
|
|
||||||
int TestExpert_Init(Tcl_Interp *interp){
|
|
||||||
return TCL_OK;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4787,7 +4787,6 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
|||||||
** data stored in all rows of each column of the table, from left
|
** data stored in all rows of each column of the table, from left
|
||||||
** to right.
|
** to right.
|
||||||
*/
|
*/
|
||||||
int rc;
|
|
||||||
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
|
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
|
||||||
sqlite3_stmt *pStmt;
|
sqlite3_stmt *pStmt;
|
||||||
sqlite3_int64 nDoc = 0;
|
sqlite3_int64 nDoc = 0;
|
||||||
|
33
manifest
33
manifest
@ -1,5 +1,5 @@
|
|||||||
C Update\sthis\sbranch\swith\slatest\strunk\schanges.
|
C Merge\sthe\slatest\senhancements\sfrom\strunk.
|
||||||
D 2017-05-01T14:25:34.571
|
D 2017-05-02T19:45:14.234
|
||||||
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
|
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc 6a8c838220f7c00820e1fc0ac1bccaaa8e5676067e1dbfa1bafa7a4ffecf8ae6
|
F Makefile.msc 6a8c838220f7c00820e1fc0ac1bccaaa8e5676067e1dbfa1bafa7a4ffecf8ae6
|
||||||
@ -45,7 +45,7 @@ F ext/expert/expert.c 33842ef151d84c5f8000f9c7b938998c6b999eaef7ce1f4eeb0df8ffe6
|
|||||||
F ext/expert/expert1.test 1033e43071b69dc2f4e88fbf03fc7f18846c9865cac14f28c80f581437f09acb
|
F ext/expert/expert1.test 1033e43071b69dc2f4e88fbf03fc7f18846c9865cac14f28c80f581437f09acb
|
||||||
F ext/expert/sqlite3expert.c 4bc1820a70d68b478884a26a2215df8c1f2d44fb40d9cd8c47d2046c8ce0c8bc
|
F ext/expert/sqlite3expert.c 4bc1820a70d68b478884a26a2215df8c1f2d44fb40d9cd8c47d2046c8ce0c8bc
|
||||||
F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811
|
F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811
|
||||||
F ext/expert/test_expert.c b01a5115f9444a9b416582c985138f5dfdb279848ce8b7452be383530be27f01
|
F ext/expert/test_expert.c 85f5c743a899063fa48296d21de2f32c26d09a21c8582b2a0bc482e8de183e7a
|
||||||
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
|
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
|
||||||
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
|
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
|
||||||
F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea
|
F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea
|
||||||
@ -76,7 +76,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
|||||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||||
F ext/fts3/fts3.c 10fc22119e3d91997eb5820d96ff709ca7c61b6f767e09b360b986b897ad74c6
|
F ext/fts3/fts3.c 88ea5c444fdf262b4eb7b5872b9a3192b8b8d0df8cc9735c5aed159ec5dae02a
|
||||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||||
F ext/fts3/fts3Int.h eb2502000148e80913b965db3e59f29251266d0a
|
F ext/fts3/fts3Int.h eb2502000148e80913b965db3e59f29251266d0a
|
||||||
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||||
@ -351,7 +351,7 @@ F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
|
|||||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||||
F src/btree.c a0d9a1c782ff3d22df5d217a4fa7125dd69ad5849caa51c4442c10246ca8ae27
|
F src/btree.c 8c1fd4cfa2b0bf021386e0a1f4e30b64eea7a2c1bc2e0c3e5901a626b1ab6aa9
|
||||||
F src/btree.h 80f518c0788be6cec8d9f8e13bd8e380df299d2b5e4ac340dc887b0642647cfc
|
F src/btree.h 80f518c0788be6cec8d9f8e13bd8e380df299d2b5e4ac340dc887b0642647cfc
|
||||||
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
|
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
|
||||||
F src/build.c 3fd46781483b527ee18508e7854e87e60a259211bb9bbf16b6fafaf08a043a64
|
F src/build.c 3fd46781483b527ee18508e7854e87e60a259211bb9bbf16b6fafaf08a043a64
|
||||||
@ -361,7 +361,7 @@ F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c
|
|||||||
F src/date.c cc42a41c7422389860d40419a5e3bce5eaf6e7835c3ba2677751dc653550a5c7
|
F src/date.c cc42a41c7422389860d40419a5e3bce5eaf6e7835c3ba2677751dc653550a5c7
|
||||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||||
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
||||||
F src/expr.c f10e35dc50be4c8f82eb99bf5d8530229d1d60957cc3c9473ffe584d0444087c
|
F src/expr.c 965f5e6074ee61cf933be079c6a443c88414490c13ec270b5baaacaa920280fa
|
||||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||||
F src/fkey.c db65492ae549c3b548c9ef1f279ce1684f1c473b116e1c56a90878cd5dcf968d
|
F src/fkey.c db65492ae549c3b548c9ef1f279ce1684f1c473b116e1c56a90878cd5dcf968d
|
||||||
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
|
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
|
||||||
@ -408,12 +408,12 @@ F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
|
|||||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||||
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
||||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||||
F src/select.c 478e95d424bb86d34c7c95d20872cbd78df97af5f83c3fd7de55d5b2413f927d
|
F src/select.c 4f0adefaa5e9417459b07757e0f6060cac97930a86f0fba9797bab233ced66c0
|
||||||
F src/shell.c 21b79c0e1b93f8e35fd7b4087d6ba438326c3d7e285d0dd51dfd741475f858a1
|
F src/shell.c 21b79c0e1b93f8e35fd7b4087d6ba438326c3d7e285d0dd51dfd741475f858a1
|
||||||
F src/sqlite.h.in 900a07463a87be50b9954817f4c24a0660b4c4ddc1bfe83dedea484c6ac98425
|
F src/sqlite.h.in 8872d1f5e0f04bd441620ea6db856a84de219798a5d385b862a54d27892d68e8
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
|
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
|
||||||
F src/sqliteInt.h 0e520ab49f019221dd5a17b6e4006523ce4f33d88b20bcf9115d11952a487c39
|
F src/sqliteInt.h a8be6c63ce04fc759e3d8ca2dee2fa2d4128b0a4bf2031c3f6e482fd5c5abdfe
|
||||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||||
@ -475,11 +475,11 @@ F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc
|
|||||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||||
F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6
|
F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6
|
||||||
F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
|
F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
|
||||||
F src/vdbe.c a4e1810c3b2a8119d08746d20ac9bab5d15c0ebed319ea1f57910948414ed114
|
F src/vdbe.c 356042d11e05064c43242020e8de97acef9fc8931cfc39ae7cf4cf91d6e42c19
|
||||||
F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848
|
F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848
|
||||||
F src/vdbeInt.h c070bc5c8b913bda0ceaa995cd4d939ded5e4fc96cf7c3c1c602d41b871f8ade
|
F src/vdbeInt.h c070bc5c8b913bda0ceaa995cd4d939ded5e4fc96cf7c3c1c602d41b871f8ade
|
||||||
F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
|
F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
|
||||||
F src/vdbeaux.c 526b617ac6b5e167a6bd581e067f1ee1dbcb06e7802cff46b76fb1c02ed7d34e
|
F src/vdbeaux.c 98ced78bb4d8f1c66a4519591804cbf34530f19c295a8589833aaa6004ea8731
|
||||||
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
||||||
F src/vdbemem.c 2c70f8f5de6c71fb99a22c5b83be9fab5c47cdd8e279fa44a8c00cfed06d7e89
|
F src/vdbemem.c 2c70f8f5de6c71fb99a22c5b83be9fab5c47cdd8e279fa44a8c00cfed06d7e89
|
||||||
F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c
|
F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c
|
||||||
@ -610,7 +610,7 @@ F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
|
|||||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||||
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
|
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
|
||||||
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
|
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
|
||||||
F test/conflict3.test dec0634c0f31dec9a4b01c63063e939f0cd21b6b
|
F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9
|
||||||
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
|
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
|
||||||
F test/corrupt.test 141c39ea650c1365e85a49e402fa05cb9617fb97
|
F test/corrupt.test 141c39ea650c1365e85a49e402fa05cb9617fb97
|
||||||
F test/corrupt2.test e4964cee73dda57a90958e0087a6b388b1d9cb58
|
F test/corrupt2.test e4964cee73dda57a90958e0087a6b388b1d9cb58
|
||||||
@ -856,6 +856,7 @@ F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
|||||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||||
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||||
|
F test/having.test 30a02b8a9a47cba7bdb5281999c5cbff407c2ac296511ee64dd0b418fe38eb0f
|
||||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||||
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
||||||
@ -1584,7 +1585,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 9fa2ce3c2b75408594d387684984cd946765776d30bc622a1f4e64d6fe1856d5 4e1df76e3d85922648e0e1cce73a266c3b1ed4511ace259ec0a01d7693af9e6f
|
P 11f4761c3a84e2cc9df62f117a003af8c57f3d226eec5a40d6241b121e78d002 430f539cbb3f806fb89191e0b759a5f8b49d9e5b6c95fe9a4b55a1aa0875762a
|
||||||
R c99d2e434f8eea958d565fc3fbededc3
|
R c37204de6c890801155672b7d23b8abd
|
||||||
U dan
|
U drh
|
||||||
Z e2770623607bd1150c892792253a1e62
|
Z 640e08616c5ac7ee4ced91411da47a09
|
||||||
|
@ -1 +1 @@
|
|||||||
11f4761c3a84e2cc9df62f117a003af8c57f3d226eec5a40d6241b121e78d002
|
a7dcf6a79f7e1c5884baee2909a4bf3174ae06d561dae87b390856e573f81b49
|
@ -8190,6 +8190,7 @@ int sqlite3BtreeInsert(
|
|||||||
}else if( loc<0 && pPage->nCell>0 ){
|
}else if( loc<0 && pPage->nCell>0 ){
|
||||||
assert( pPage->leaf );
|
assert( pPage->leaf );
|
||||||
idx = ++pCur->ix;
|
idx = ++pCur->ix;
|
||||||
|
pCur->curFlags &= ~BTCF_ValidNKey;
|
||||||
}else{
|
}else{
|
||||||
assert( pPage->leaf );
|
assert( pPage->leaf );
|
||||||
}
|
}
|
||||||
@ -9314,6 +9315,7 @@ static int checkTreePage(
|
|||||||
checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
|
checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
|
||||||
}
|
}
|
||||||
maxKey = info.nKey;
|
maxKey = info.nKey;
|
||||||
|
keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the content overflow list */
|
/* Check the content overflow list */
|
||||||
|
59
src/expr.c
59
src/expr.c
@ -1815,6 +1815,65 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
|||||||
return exprIsConst(p, 3, iCur);
|
return exprIsConst(p, 3, iCur);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
|
||||||
|
*/
|
||||||
|
static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
||||||
|
ExprList *pGroupBy = pWalker->u.pGroupBy;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Check if pExpr is identical to any GROUP BY term. If so, consider
|
||||||
|
** it constant. */
|
||||||
|
for(i=0; i<pGroupBy->nExpr; i++){
|
||||||
|
Expr *p = pGroupBy->a[i].pExpr;
|
||||||
|
if( sqlite3ExprCompare(pExpr, p, -1)<2 ){
|
||||||
|
CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p);
|
||||||
|
if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){
|
||||||
|
return WRC_Prune;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if pExpr is a sub-select. If so, consider it variable. */
|
||||||
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
|
pWalker->eCode = 0;
|
||||||
|
return WRC_Abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exprNodeIsConstant(pWalker, pExpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Walk the expression tree passed as the first argument. Return non-zero
|
||||||
|
** if the expression consists entirely of constants or copies of terms
|
||||||
|
** in pGroupBy that sort with the BINARY collation sequence.
|
||||||
|
**
|
||||||
|
** This routine is used to determine if a term of the HAVING clause can
|
||||||
|
** be promoted into the WHERE clause. In order for such a promotion to work,
|
||||||
|
** the value of the HAVING clause term must be the same for all members of
|
||||||
|
** a "group". The requirement that the GROUP BY term must be BINARY
|
||||||
|
** assumes that no other collating sequence will have a finer-grained
|
||||||
|
** grouping than binary. In other words (A=B COLLATE binary) implies
|
||||||
|
** A=B in every other collating sequence. The requirement that the
|
||||||
|
** GROUP BY be BINARY is stricter than necessary. It would also work
|
||||||
|
** to promote HAVING clauses that use the same alternative collating
|
||||||
|
** sequence as the GROUP BY term, but that is much harder to check,
|
||||||
|
** alternative collating sequences are uncommon, and this is only an
|
||||||
|
** optimization, so we take the easy way out and simply require the
|
||||||
|
** GROUP BY to use the BINARY collating sequence.
|
||||||
|
*/
|
||||||
|
int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
|
||||||
|
Walker w;
|
||||||
|
memset(&w, 0, sizeof(w));
|
||||||
|
w.eCode = 1;
|
||||||
|
w.xExprCallback = exprNodeIsConstantOrGroupBy;
|
||||||
|
w.u.pGroupBy = pGroupBy;
|
||||||
|
w.pParse = pParse;
|
||||||
|
sqlite3WalkExpr(&w, p);
|
||||||
|
return w.eCode;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Walk an expression tree. Return non-zero if the expression is constant
|
** Walk an expression tree. Return non-zero if the expression is constant
|
||||||
** or a function call with constant arguments. Return and 0 if there
|
** or a function call with constant arguments. Return and 0 if there
|
||||||
|
115
src/select.c
115
src/select.c
@ -4879,6 +4879,103 @@ static void explainSimpleCount(
|
|||||||
# define explainSimpleCount(a,b,c)
|
# define explainSimpleCount(a,b,c)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Context object for havingToWhereExprCb().
|
||||||
|
*/
|
||||||
|
struct HavingToWhereCtx {
|
||||||
|
Expr **ppWhere;
|
||||||
|
ExprList *pGroupBy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** sqlite3WalkExpr() callback used by havingToWhere().
|
||||||
|
**
|
||||||
|
** If the node passed to the callback is a TK_AND node, return
|
||||||
|
** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
|
||||||
|
**
|
||||||
|
** Otherwise, return WRC_Prune. In this case, also check if the
|
||||||
|
** sub-expression matches the criteria for being moved to the WHERE
|
||||||
|
** clause. If so, add it to the WHERE clause and replace the sub-expression
|
||||||
|
** within the HAVING expression with a constant "1".
|
||||||
|
*/
|
||||||
|
static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
|
||||||
|
if( pExpr->op!=TK_AND ){
|
||||||
|
struct HavingToWhereCtx *p = pWalker->u.pHavingCtx;
|
||||||
|
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){
|
||||||
|
sqlite3 *db = pWalker->pParse->db;
|
||||||
|
Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
|
||||||
|
if( pNew ){
|
||||||
|
Expr *pWhere = *(p->ppWhere);
|
||||||
|
SWAP(Expr, *pNew, *pExpr);
|
||||||
|
pNew = sqlite3ExprAnd(db, pWhere, pNew);
|
||||||
|
*(p->ppWhere) = pNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WRC_Prune;
|
||||||
|
}
|
||||||
|
return WRC_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Transfer eligible terms from the HAVING clause of a query, which is
|
||||||
|
** processed after grouping, to the WHERE clause, which is processed before
|
||||||
|
** grouping. For example, the query:
|
||||||
|
**
|
||||||
|
** SELECT * FROM <tables> WHERE a=? GROUP BY b HAVING b=? AND c=?
|
||||||
|
**
|
||||||
|
** can be rewritten as:
|
||||||
|
**
|
||||||
|
** SELECT * FROM <tables> WHERE a=? AND b=? GROUP BY b HAVING c=?
|
||||||
|
**
|
||||||
|
** A term of the HAVING expression is eligible for transfer if it consists
|
||||||
|
** entirely of constants and expressions that are also GROUP BY terms that
|
||||||
|
** use the "BINARY" collation sequence.
|
||||||
|
*/
|
||||||
|
static void havingToWhere(
|
||||||
|
Parse *pParse,
|
||||||
|
ExprList *pGroupBy,
|
||||||
|
Expr *pHaving,
|
||||||
|
Expr **ppWhere
|
||||||
|
){
|
||||||
|
struct HavingToWhereCtx sCtx;
|
||||||
|
Walker sWalker;
|
||||||
|
|
||||||
|
sCtx.ppWhere = ppWhere;
|
||||||
|
sCtx.pGroupBy = pGroupBy;
|
||||||
|
|
||||||
|
memset(&sWalker, 0, sizeof(sWalker));
|
||||||
|
sWalker.pParse = pParse;
|
||||||
|
sWalker.xExprCallback = havingToWhereExprCb;
|
||||||
|
sWalker.u.pHavingCtx = &sCtx;
|
||||||
|
sqlite3WalkExpr(&sWalker, pHaving);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check to see if the pThis entry of pTabList is a self-join of a prior view.
|
||||||
|
** If it is, then return the SrcList_item for the prior view. If it is not,
|
||||||
|
** then return 0.
|
||||||
|
*/
|
||||||
|
static struct SrcList_item *isSelfJoinView(
|
||||||
|
SrcList *pTabList, /* Search for self-joins in this FROM clause */
|
||||||
|
struct SrcList_item *pThis /* Search for prior reference to this subquery */
|
||||||
|
){
|
||||||
|
struct SrcList_item *pItem;
|
||||||
|
for(pItem = pTabList->a; pItem<pThis; pItem++){
|
||||||
|
if( pItem->pSelect==0 ) continue;
|
||||||
|
if( pItem->fg.viaCoroutine ) continue;
|
||||||
|
if( pItem->zName==0 ) continue;
|
||||||
|
if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue;
|
||||||
|
if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
|
||||||
|
if( sqlite3ExprCompare(pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) ){
|
||||||
|
/* The view was modified by some other optimization such as
|
||||||
|
** pushDownWhereTerms() */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return pItem;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code for the SELECT statement given in the p argument.
|
** Generate code for the SELECT statement given in the p argument.
|
||||||
**
|
**
|
||||||
@ -5113,6 +5210,8 @@ int sqlite3Select(
|
|||||||
int topAddr;
|
int topAddr;
|
||||||
int onceAddr = 0;
|
int onceAddr = 0;
|
||||||
int retAddr;
|
int retAddr;
|
||||||
|
struct SrcList_item *pPrior;
|
||||||
|
|
||||||
assert( pItem->addrFillSub==0 );
|
assert( pItem->addrFillSub==0 );
|
||||||
pItem->regReturn = ++pParse->nMem;
|
pItem->regReturn = ++pParse->nMem;
|
||||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||||
@ -5126,9 +5225,14 @@ int sqlite3Select(
|
|||||||
}else{
|
}else{
|
||||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||||
}
|
}
|
||||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
pPrior = isSelfJoinView(pTabList, pItem);
|
||||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
if( pPrior ){
|
||||||
sqlite3Select(pParse, pSub, &dest);
|
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||||
|
}else{
|
||||||
|
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||||
|
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||||
|
sqlite3Select(pParse, pSub, &dest);
|
||||||
|
}
|
||||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||||
@ -5347,6 +5451,11 @@ int sqlite3Select(
|
|||||||
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
||||||
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
||||||
if( pHaving ){
|
if( pHaving ){
|
||||||
|
if( pGroupBy ){
|
||||||
|
assert( pWhere==p->pWhere );
|
||||||
|
havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere);
|
||||||
|
pWhere = p->pWhere;
|
||||||
|
}
|
||||||
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
||||||
}
|
}
|
||||||
sAggInfo.nAccumulator = sAggInfo.nColumn;
|
sAggInfo.nAccumulator = sAggInfo.nColumn;
|
||||||
|
@ -857,7 +857,7 @@ struct sqlite3_io_methods {
|
|||||||
** opcode allows these two values (10 retries and 25 milliseconds of delay)
|
** opcode allows these two values (10 retries and 25 milliseconds of delay)
|
||||||
** to be adjusted. The values are changed for all database connections
|
** to be adjusted. The values are changed for all database connections
|
||||||
** within the same process. The argument is a pointer to an array of two
|
** within the same process. The argument is a pointer to an array of two
|
||||||
** integers where the first integer i the new retry count and the second
|
** integers where the first integer is the new retry count and the second
|
||||||
** integer is the delay. If either integer is negative, then the setting
|
** integer is the delay. If either integer is negative, then the setting
|
||||||
** is not changed but instead the prior value of that setting is written
|
** is not changed but instead the prior value of that setting is written
|
||||||
** into the array entry, allowing the current retry settings to be
|
** into the array entry, allowing the current retry settings to be
|
||||||
|
@ -3318,15 +3318,17 @@ struct Walker {
|
|||||||
int walkerDepth; /* Number of subqueries */
|
int walkerDepth; /* Number of subqueries */
|
||||||
u8 eCode; /* A small processing code */
|
u8 eCode; /* A small processing code */
|
||||||
union { /* Extra data for callback */
|
union { /* Extra data for callback */
|
||||||
NameContext *pNC; /* Naming context */
|
NameContext *pNC; /* Naming context */
|
||||||
int n; /* A counter */
|
int n; /* A counter */
|
||||||
int iCur; /* A cursor number */
|
int iCur; /* A cursor number */
|
||||||
SrcList *pSrcList; /* FROM clause */
|
SrcList *pSrcList; /* FROM clause */
|
||||||
struct SrcCount *pSrcCount; /* Counting column references */
|
struct SrcCount *pSrcCount; /* Counting column references */
|
||||||
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
||||||
int *aiCol; /* array of column indexes */
|
int *aiCol; /* array of column indexes */
|
||||||
struct IdxCover *pIdxCover; /* Check for index coverage */
|
struct IdxCover *pIdxCover; /* Check for index coverage */
|
||||||
struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
|
struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
|
||||||
|
ExprList *pGroupBy; /* GROUP BY clause */
|
||||||
|
struct HavingToWhereCtx *pHavingCtx; /* HAVING to WHERE clause ctx */
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3796,6 +3798,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
|
|||||||
int sqlite3ExprIsConstant(Expr*);
|
int sqlite3ExprIsConstant(Expr*);
|
||||||
int sqlite3ExprIsConstantNotJoin(Expr*);
|
int sqlite3ExprIsConstantNotJoin(Expr*);
|
||||||
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
||||||
|
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
|
||||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||||
int sqlite3ExprContainsSubquery(Expr*);
|
int sqlite3ExprContainsSubquery(Expr*);
|
||||||
|
31
src/vdbe.c
31
src/vdbe.c
@ -3540,6 +3540,37 @@ open_cursor_set_hints:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Opcode: OpenDup P1 P2 * * *
|
||||||
|
**
|
||||||
|
** Open a new cursor P1 that points to the same ephemeral table as
|
||||||
|
** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral
|
||||||
|
** opcode. Only ephemeral cursors may be duplicated.
|
||||||
|
**
|
||||||
|
** Duplicate ephemeral cursors are used for self-joins of materialized views.
|
||||||
|
*/
|
||||||
|
case OP_OpenDup: {
|
||||||
|
VdbeCursor *pOrig; /* The original cursor to be duplicated */
|
||||||
|
VdbeCursor *pCx; /* The new cursor */
|
||||||
|
|
||||||
|
pOrig = p->apCsr[pOp->p2];
|
||||||
|
assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
|
||||||
|
|
||||||
|
pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
|
||||||
|
if( pCx==0 ) goto no_mem;
|
||||||
|
pCx->nullRow = 1;
|
||||||
|
pCx->isEphemeral = 1;
|
||||||
|
pCx->pKeyInfo = pOrig->pKeyInfo;
|
||||||
|
pCx->isTable = pOrig->isTable;
|
||||||
|
rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
|
||||||
|
pCx->pKeyInfo, pCx->uc.pCursor);
|
||||||
|
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
|
||||||
|
** opened for a database. Since there is already an open cursor when this
|
||||||
|
** opcode is run, the sqlite3BtreeCursor() cannot fail */
|
||||||
|
assert( rc==SQLITE_OK );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Opcode: OpenEphemeral P1 P2 * P4 P5
|
/* Opcode: OpenEphemeral P1 P2 * P4 P5
|
||||||
** Synopsis: nColumn=P2
|
** Synopsis: nColumn=P2
|
||||||
**
|
**
|
||||||
|
@ -2044,8 +2044,8 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CURTYPE_BTREE: {
|
case CURTYPE_BTREE: {
|
||||||
if( pCx->pBtx ){
|
if( pCx->isEphemeral ){
|
||||||
sqlite3BtreeClose(pCx->pBtx);
|
if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
|
||||||
/* The pCx->pCursor will be close automatically, if it exists, by
|
/* The pCx->pCursor will be close automatically, if it exists, by
|
||||||
** the call above. */
|
** the call above. */
|
||||||
}else{
|
}else{
|
||||||
|
@ -19,13 +19,14 @@
|
|||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
set testprefix conflict3
|
||||||
|
|
||||||
ifcapable !conflict {
|
ifcapable !conflict {
|
||||||
finish_test
|
finish_test
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
do_execsql_test conflict-1.1 {
|
do_execsql_test 1.1 {
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
|
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
|
||||||
b UNIQUE ON CONFLICT IGNORE,
|
b UNIQUE ON CONFLICT IGNORE,
|
||||||
@ -37,7 +38,7 @@ do_execsql_test conflict-1.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-1.2 {
|
do_execsql_test 1.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -45,16 +46,16 @@ do_execsql_test conflict-1.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-1.3 {
|
do_test 1.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-1.4 {
|
do_execsql_test 1.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Replete the tests above, but this time on a table non-INTEGER primary key.
|
# Replete the tests above, but this time on a table non-INTEGER primary key.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-2.1 {
|
do_execsql_test 2.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
||||||
@ -67,7 +68,7 @@ do_execsql_test conflict-2.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-2.2 {
|
do_execsql_test 2.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -75,16 +76,16 @@ do_execsql_test conflict-2.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-2.3 {
|
do_test 2.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-2.4 {
|
do_execsql_test 2.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Replete again on a WITHOUT ROWID table.
|
# Replete again on a WITHOUT ROWID table.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-3.1 {
|
do_execsql_test 3.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
||||||
@ -97,7 +98,7 @@ do_execsql_test conflict-3.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-3.2 {
|
do_execsql_test 3.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -105,16 +106,16 @@ do_execsql_test conflict-3.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-3.3 {
|
do_test 3.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-3.4 {
|
do_execsql_test 3.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Arrange the table rows in a different order and repeat.
|
# Arrange the table rows in a different order and repeat.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-4.1 {
|
do_execsql_test 4.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
b UNIQUE ON CONFLICT IGNORE,
|
b UNIQUE ON CONFLICT IGNORE,
|
||||||
@ -127,7 +128,7 @@ do_execsql_test conflict-4.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-4.2 {
|
do_execsql_test 4.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -135,16 +136,16 @@ do_execsql_test conflict-4.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-4.3 {
|
do_test 4.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-4.4 {
|
do_execsql_test 4.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Arrange the table rows in a different order and repeat.
|
# Arrange the table rows in a different order and repeat.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-5.1 {
|
do_execsql_test 5.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
b UNIQUE ON CONFLICT IGNORE,
|
b UNIQUE ON CONFLICT IGNORE,
|
||||||
@ -157,7 +158,7 @@ do_execsql_test conflict-5.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-5.2 {
|
do_execsql_test 5.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -165,16 +166,16 @@ do_execsql_test conflict-5.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-5.3 {
|
do_test 5.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-5.4 {
|
do_execsql_test 5.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Arrange the table rows in a different order and repeat.
|
# Arrange the table rows in a different order and repeat.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-6.1 {
|
do_execsql_test 6.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
c UNIQUE ON CONFLICT FAIL,
|
c UNIQUE ON CONFLICT FAIL,
|
||||||
@ -187,7 +188,7 @@ do_execsql_test conflict-6.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-6.2 {
|
do_execsql_test 6.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -195,16 +196,16 @@ do_execsql_test conflict-6.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-6.3 {
|
do_test 6.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-6.4 {
|
do_execsql_test 6.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Change which column is the PRIMARY KEY
|
# Change which column is the PRIMARY KEY
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-7.1 {
|
do_execsql_test 7.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a UNIQUE ON CONFLICT REPLACE,
|
a UNIQUE ON CONFLICT REPLACE,
|
||||||
@ -217,7 +218,7 @@ do_execsql_test conflict-7.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-7.2 {
|
do_execsql_test 7.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -225,16 +226,16 @@ do_execsql_test conflict-7.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-7.3 {
|
do_test 7.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-7.4 {
|
do_execsql_test 7.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Change which column is the PRIMARY KEY
|
# Change which column is the PRIMARY KEY
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-8.1 {
|
do_execsql_test 8.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a UNIQUE ON CONFLICT REPLACE,
|
a UNIQUE ON CONFLICT REPLACE,
|
||||||
@ -247,7 +248,7 @@ do_execsql_test conflict-8.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-8.2 {
|
do_execsql_test 8.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -255,16 +256,16 @@ do_execsql_test conflict-8.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-8.3 {
|
do_test 8.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-8.4 {
|
do_execsql_test 8.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Change which column is the PRIMARY KEY
|
# Change which column is the PRIMARY KEY
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-9.1 {
|
do_execsql_test 9.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a UNIQUE ON CONFLICT REPLACE,
|
a UNIQUE ON CONFLICT REPLACE,
|
||||||
@ -277,7 +278,7 @@ do_execsql_test conflict-9.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-9.2 {
|
do_execsql_test 9.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -285,16 +286,16 @@ do_execsql_test conflict-9.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-9.3 {
|
do_test 9.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-9.4 {
|
do_execsql_test 9.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Change which column is the PRIMARY KEY
|
# Change which column is the PRIMARY KEY
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-10.1 {
|
do_execsql_test 10.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a UNIQUE ON CONFLICT REPLACE,
|
a UNIQUE ON CONFLICT REPLACE,
|
||||||
@ -307,7 +308,7 @@ do_execsql_test conflict-10.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-10.2 {
|
do_execsql_test 10.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -315,16 +316,16 @@ do_execsql_test conflict-10.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-10.3 {
|
do_test 10.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-10.4 {
|
do_execsql_test 10.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
# Change which column is the PRIMARY KEY
|
# Change which column is the PRIMARY KEY
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-11.1 {
|
do_execsql_test 11.1 {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
a UNIQUE ON CONFLICT REPLACE,
|
a UNIQUE ON CONFLICT REPLACE,
|
||||||
@ -337,7 +338,7 @@ do_execsql_test conflict-11.1 {
|
|||||||
|
|
||||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||||
#
|
#
|
||||||
do_execsql_test conflict-11.2 {
|
do_execsql_test 11.2 {
|
||||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4}
|
} {1 2 3 2 3 4}
|
||||||
@ -345,12 +346,25 @@ do_execsql_test conflict-11.2 {
|
|||||||
# Insert two rows where the second conflicts on C. The first row show go
|
# Insert two rows where the second conflicts on C. The first row show go
|
||||||
# and and then there should be a constraint error.
|
# and and then there should be a constraint error.
|
||||||
#
|
#
|
||||||
do_test conflict-11.3 {
|
do_test 11.3 {
|
||||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||||
} {1 {UNIQUE constraint failed: t1.c}}
|
} {1 {UNIQUE constraint failed: t1.c}}
|
||||||
do_execsql_test conflict-11.4 {
|
do_execsql_test 11.4 {
|
||||||
SELECT a,b,c FROM t1 ORDER BY a;
|
SELECT a,b,c FROM t1 ORDER BY a;
|
||||||
} {1 2 3 2 3 4 4 5 6}
|
} {1 2 3 2 3 4 4 5 6}
|
||||||
|
|
||||||
|
# Check that ticket [f68dc596c4] has been fixed.
|
||||||
|
#
|
||||||
|
do_execsql_test 12.1 {
|
||||||
|
CREATE TABLE t2(a INTEGER PRIMARY KEY, b TEXT);
|
||||||
|
INSERT INTO t2 VALUES(111, '111');
|
||||||
|
}
|
||||||
|
do_execsql_test 12.2 {
|
||||||
|
REPLACE INTO t2 VALUES(NULL, '112'), (111, '111B');
|
||||||
|
}
|
||||||
|
do_execsql_test 12.3 {
|
||||||
|
SELECT * FROM t2;
|
||||||
|
} {111 111B 112 112}
|
||||||
|
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
154
test/having.test
Normal file
154
test/having.test
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# 2017 April 30
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
#
|
||||||
|
# Test the HAVING->WHERE optimization.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix having
|
||||||
|
|
||||||
|
do_execsql_test 1.0 {
|
||||||
|
CREATE TABLE t2(c, d);
|
||||||
|
|
||||||
|
CREATE TABLE t1(a, b);
|
||||||
|
INSERT INTO t1 VALUES(1, 1);
|
||||||
|
INSERT INTO t1 VALUES(2, 2);
|
||||||
|
INSERT INTO t1 VALUES(1, 3);
|
||||||
|
INSERT INTO t1 VALUES(2, 4);
|
||||||
|
INSERT INTO t1 VALUES(1, 5);
|
||||||
|
INSERT INTO t1 VALUES(2, 6);
|
||||||
|
} {}
|
||||||
|
|
||||||
|
foreach {tn sql res} {
|
||||||
|
1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2" {2 12}
|
||||||
|
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2 AND sum(b)>10" {2 12}
|
||||||
|
3 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>12" {}
|
||||||
|
} {
|
||||||
|
do_execsql_test 1.$tn $sql $res
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run an EXPLAIN command for both SQL statements. Return true if
|
||||||
|
# the outputs are identical, or false otherwise.
|
||||||
|
#
|
||||||
|
proc compare_vdbe {sql1 sql2} {
|
||||||
|
set r1 [list]
|
||||||
|
set r2 [list]
|
||||||
|
db eval "explain $sql1" { lappend r1 $opcode $p1 $p2 $p3 $p4 $p5}
|
||||||
|
db eval "explain $sql2" { lappend r2 $opcode $p1 $p2 $p3 $p4 $p5}
|
||||||
|
return [expr {$r1==$r2}]
|
||||||
|
}
|
||||||
|
|
||||||
|
proc do_compare_vdbe_test {tn sql1 sql2 res} {
|
||||||
|
uplevel [list do_test $tn [list compare_vdbe $sql1 $sql2] $res]
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test that various statements that are eligible for the optimization
|
||||||
|
# produce the same VDBE code as optimizing by hand does.
|
||||||
|
#
|
||||||
|
foreach {tn sql1 sql2} {
|
||||||
|
1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2"
|
||||||
|
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a"
|
||||||
|
|
||||||
|
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>5 AND a=2"
|
||||||
|
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a HAVING sum(b)>5"
|
||||||
|
|
||||||
|
3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2"
|
||||||
|
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary"
|
||||||
|
|
||||||
|
4 {
|
||||||
|
SELECT x,y FROM (
|
||||||
|
SELECT a AS x, sum(b) AS y FROM t1
|
||||||
|
GROUP BY a
|
||||||
|
) WHERE x BETWEEN 8888 AND 9999
|
||||||
|
} {
|
||||||
|
SELECT x,y FROM (
|
||||||
|
SELECT a AS x, sum(b) AS y FROM t1
|
||||||
|
WHERE x BETWEEN 8888 AND 9999
|
||||||
|
GROUP BY a
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 0"
|
||||||
|
"SELECT a, sum(b) FROM t1 WHERE 0 GROUP BY a COLLATE binary"
|
||||||
|
|
||||||
|
6 "SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d HAVING b=d"
|
||||||
|
"SELECT count(*) FROM t1,t2 WHERE a=c AND b=d GROUP BY b, d"
|
||||||
|
|
||||||
|
7 {
|
||||||
|
SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d
|
||||||
|
HAVING b=d COLLATE nocase
|
||||||
|
} {
|
||||||
|
SELECT count(*) FROM t1,t2 WHERE a=c AND b=d COLLATE nocase
|
||||||
|
GROUP BY b, d
|
||||||
|
}
|
||||||
|
|
||||||
|
8 "SELECT a, sum(b) FROM t1 GROUP BY a||b HAVING substr(a||b, 1, 1)='a'"
|
||||||
|
"SELECT a, sum(b) FROM t1 WHERE substr(a||b, 1, 1)='a' GROUP BY a||b"
|
||||||
|
} {
|
||||||
|
do_compare_vdbe_test 2.$tn $sql1 $sql2 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# 1: Test that the optimization is only applied if the GROUP BY term
|
||||||
|
# uses BINARY collation.
|
||||||
|
#
|
||||||
|
# 2: Not applied if there is a non-deterministic function in the HAVING
|
||||||
|
# term.
|
||||||
|
#
|
||||||
|
foreach {tn sql1 sql2} {
|
||||||
|
1 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE nocase HAVING a=2"
|
||||||
|
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE nocase"
|
||||||
|
|
||||||
|
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING randomblob(a)<X'88'"
|
||||||
|
"SELECT a, sum(b) FROM t1 WHERE randomblob(a)<X'88' GROUP BY a"
|
||||||
|
} {
|
||||||
|
do_compare_vdbe_test 3.$tn $sql1 $sql2 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test that non-deterministic functions disqualify a term from being
|
||||||
|
# moved from the HAVING to WHERE clause.
|
||||||
|
#
|
||||||
|
do_execsql_test 4.1 {
|
||||||
|
CREATE TABLE t3(a, b);
|
||||||
|
INSERT INTO t3 VALUES(1, 1);
|
||||||
|
INSERT INTO t3 VALUES(1, 2);
|
||||||
|
INSERT INTO t3 VALUES(1, 3);
|
||||||
|
INSERT INTO t3 VALUES(2, 1);
|
||||||
|
INSERT INTO t3 VALUES(2, 2);
|
||||||
|
INSERT INTO t3 VALUES(2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
proc nondeter {args} {
|
||||||
|
incr ::nondeter_ret
|
||||||
|
expr {$::nondeter_ret % 2}
|
||||||
|
}
|
||||||
|
db func nondeter nondeter
|
||||||
|
|
||||||
|
set ::nondeter_ret 0
|
||||||
|
do_execsql_test 4.2 {
|
||||||
|
SELECT a, sum(b) FROM t3 GROUP BY a HAVING nondeter(a)
|
||||||
|
} {1 6}
|
||||||
|
|
||||||
|
# If the term where moved, the query above would return the same
|
||||||
|
# result as the following. But it does not.
|
||||||
|
#
|
||||||
|
set ::nondeter_ret 0
|
||||||
|
do_execsql_test 4.3 {
|
||||||
|
SELECT a, sum(b) FROM t3 WHERE nondeter(a) GROUP BY a
|
||||||
|
} {1 4 2 2}
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
Reference in New Issue
Block a user