1
0
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:
drh
2017-05-02 19:45:14 +00:00
13 changed files with 450 additions and 82 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -1 +1 @@
11f4761c3a84e2cc9df62f117a003af8c57f3d226eec5a40d6241b121e78d002 a7dcf6a79f7e1c5884baee2909a4bf3174ae06d561dae87b390856e573f81b49

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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*);

View File

@ -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
** **

View File

@ -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{

View File

@ -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
View 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