Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b693d63e4 | |||
| e6912fd819 | |||
| c497441406 | |||
| 419b03c1bb | |||
| b324cf756e | |||
| 3480bfdae9 | |||
| 6b92288119 | |||
| c14566aff3 | |||
| 6c0e41b951 | |||
| debaa86c1c | |||
| edc4024b9d | |||
| 4d249e6128 | |||
| 8dc570b6af | |||
| b9f3f6b672 |
@@ -2507,9 +2507,9 @@ static void rbuFileSuffix3(const char *zBase, char *z){
|
||||
#endif
|
||||
{
|
||||
int i, sz;
|
||||
sz = sqlite3Strlen30(z);
|
||||
sz = (int)strlen(z)&0xffffff;
|
||||
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
|
||||
if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
|
||||
if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Fix\san\sundersized\sbuffer\sin\sthe\sSHA1\simplementation.
|
||||
D 2016-06-08T13:59:35.817
|
||||
C Allow\sLIKE\soperators\sthat\sappear\sin\sa\sWHERE\sclause\sto\sbe\sincluded\sin\sthe\scursor-hint\sfor\sa\scursor\son\sthe\srhs\sof\sa\sLEFT\sJOIN.
|
||||
D 2016-06-20T17:22:06.973
|
||||
F Makefile.in f3f7d2060ce03af4584e711ef3a626ef0b1d6340
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 50149765ef72f4e652b9a0f1f6462c4784bb9423
|
||||
@@ -252,7 +252,7 @@ F ext/rbu/rbuprogress.test 2023a7df2c523e3df1cb532eff811cda385a789a
|
||||
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
|
||||
F ext/rbu/rbuvacuum.test 4a977447c15c2581ab668781d9ef4294382530e0
|
||||
F ext/rbu/rbuvacuum2.test 45009e127c3fb385e5c0fd5a8a63fb922a79d0ab
|
||||
F ext/rbu/sqlite3rbu.c a37a7dfb225c497171aa60120e81b884954361c7
|
||||
F ext/rbu/sqlite3rbu.c 3d35b1dc46f5ca0f0f59db8e6163fe7627ea107c
|
||||
F ext/rbu/sqlite3rbu.h 2acd0a6344a6079de15c8dc9d84d3df83a665930
|
||||
F ext/rbu/test_rbu.c 9bbdf6bd8efd58fbc4f192698df50569598fbb9e
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
@@ -326,17 +326,17 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c 6df65fdd569c901a418887a1a76f82ec35044556
|
||||
F src/bitvec.c 3ee4c8b2c94ed3a7377256e18199e6ff5cf33f63
|
||||
F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 2781fb1db1e46390a9c27a2162395f371577ac66
|
||||
F src/btree.c 0621247619df15790f7ed5f14926cfb3925c10b1
|
||||
F src/btree.h 2107a2630e02c8cba58bb12ce14e731e734ea29c
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c e827e57e4a29c00e8429c5fd4d9d4572cb1b32a4
|
||||
F src/build.c d1fdfd7ab8f5447e494ef15825973bf0719527c6
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 999a828425b35b8092a8cde25690e71c20906344
|
||||
F src/ctime.c 61949e83c4c36e37195a8398ebc752780b534d95
|
||||
F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39
|
||||
F src/dbstat.c c845548d4346e606e2f2b7d2e714ace2b8a7dd1b
|
||||
F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0
|
||||
F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f
|
||||
F src/expr.c 798146ea4c87d723e8a157d88450ac9c43256998
|
||||
F src/expr.c 523a5b1db2b6d88c6eefb224877bf635a3bcfc92
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413
|
||||
F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045
|
||||
@@ -375,7 +375,7 @@ F src/parse.y 01b9f37c4c7009ab56fda98bc7db4c42643cecfe
|
||||
F src/pcache.c 5583c8ade4b05075a60ba953ef471d1c1a9c05df
|
||||
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
|
||||
F src/pcache1.c 7f51d2b541aab57596adf62db2c4bb025d34f04d
|
||||
F src/pragma.c d98039af2deb5a4990f6635462b3f61f325a6c75
|
||||
F src/pragma.c c8b499756658cb8b82cfdbb5845c22cf11f297aa
|
||||
F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
|
||||
F src/prepare.c 22df6171aec1d86904ed2ad30c2348a5748aa04e
|
||||
F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1
|
||||
@@ -387,11 +387,11 @@ F src/shell.c 14ff7f660530a52b117d110ba3390b7b2eb719b6
|
||||
F src/sqlite.h.in 5f8113dbec74c6c093ead9930afb8c9fbd9f643d
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2
|
||||
F src/sqliteInt.h 801e2a569ea79b09b87d045cd6f00ec88205f1f6
|
||||
F src/sqliteInt.h 2ac73e9fdd138f4607139d9bd6a1e6dcd01837dc
|
||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
|
||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||
F src/tclsqlite.c 9c4c4589d078de37813ded708d8838b338ffb060
|
||||
F src/tclsqlite.c 25fbbbb97f76dbfd113153fb63f52d7ecfac5dd0
|
||||
F src/test1.c 43b37ab2b7338fd3313e74902f0d6c821eae843b
|
||||
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
|
||||
F src/test3.c c75c8af0eadb335236c9e61b51044c58a8f7dd59
|
||||
@@ -462,9 +462,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a
|
||||
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c b9f5b0ddb14c3827e70b5379e659cf4cfd524c4d
|
||||
F src/where.c 74f0798525b6306682d7234f230ea93f86959b9b
|
||||
F src/whereInt.h e5b939701a7ceffc5a3a8188a37f9746416ebcd0
|
||||
F src/wherecode.c ba71a4e4bada29aa9842200e6299714bf18c812c
|
||||
F src/wherecode.c e20cb381ff621e56a4684c71e31999aca2547ca6
|
||||
F src/whereexpr.c c32d47085dbaca0b8fd013210f56693c7d220d48
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@@ -617,6 +617,7 @@ F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/csv01.test 0929a9ce47021519512be92861f29e32d2538e5f
|
||||
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
|
||||
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 2b45341d32d1aae9991a00ef31ebca339b274255
|
||||
F test/date.test 984ac1e3e5e031386866f034006148d3972b4a65
|
||||
F test/dbstatus.test 8de104bb5606f19537d23cd553b41349b5ab1204
|
||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||
@@ -840,7 +841,7 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
|
||||
F test/index3.test 81bc47890b8abfb181bc35f8d10b56c069803386
|
||||
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
|
||||
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
|
||||
F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a
|
||||
F test/index6.test 43b4e29258b978fcdab84fc61df4f5212119dd09
|
||||
F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c
|
||||
F test/indexedby.test 9c4cd331224e57f79fbf411ae245e6272d415985
|
||||
F test/indexexpr1.test cb71b6586177b840e28110dd952178bb2bdfedc2
|
||||
@@ -1100,7 +1101,7 @@ F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
|
||||
F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e
|
||||
F test/sqllimits1.test a74ee2a3740b9f9c2437c246d8fb77354862a142
|
||||
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/stat.test 66e95f97b9f724f9ab921d054ee0db3c2689f1ee
|
||||
F test/stat.test ab95d28503d0f6d98ffd8ce204643c9da090ebf1
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f
|
||||
F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
|
||||
@@ -1117,7 +1118,7 @@ F test/tabfunc01.test f977868fa8bb7beb4b2072883190411653473906
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test e1306001a0ca92250b691ea6d3cecaca5b6342aa
|
||||
F test/tclsqlite.test cf0d0a3fd03d64892cec2d48aae9fb2f148680a5
|
||||
F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6
|
||||
F test/tempdb2.test 4fc92055f2a3f7626c0f2eabbb637dc021b311d5
|
||||
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
@@ -1375,7 +1376,7 @@ F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test f0c325563acde44f2c4ea6ba348e9e29f7121757
|
||||
F test/where2.test 478d2170637b9211f593120648858593bf2445a1
|
||||
F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e
|
||||
F test/where3.test 54cdeb02157acc979de41530b804ae7b09552bf1
|
||||
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
@@ -1501,7 +1502,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 44f157e0f0d5a76ef9002b2592164c4fdae89e34
|
||||
R 654981991ade95156b7aa25e1b0590de
|
||||
U drh
|
||||
Z 0f8b86024c43c03c854a2dd32c154497
|
||||
P 998095aba01b75f685ed981b377e1dfe650d9bbf
|
||||
R 6b36cf1cbd5dc0e94253a2a90e40c230
|
||||
U dan
|
||||
Z 7f5e55d96c0f8c6a30345a5c923b92ab
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
fb2768154c513881886e89801e906bea959197b3
|
||||
7455d932f5079ffe40462a8c119fc22b8a9bcbcc
|
||||
+1
-1
@@ -5070,7 +5070,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( pRes );
|
||||
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
|
||||
assert( (pIdxKey==0)==(pCur->curIntKey!=0) || pCur->eState!=CURSOR_VALID );
|
||||
assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
|
||||
|
||||
/* If the cursor is already positioned at the point we are trying
|
||||
** to move to, then just return without doing any work */
|
||||
|
||||
+16
-12
@@ -338,7 +338,7 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
*/
|
||||
Table *sqlite3LocateTable(
|
||||
Parse *pParse, /* context in which to report errors */
|
||||
int isView, /* True if looking for a VIEW rather than a TABLE */
|
||||
u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */
|
||||
const char *zName, /* Name of the table we are looking for */
|
||||
const char *zDbase /* Name of the database. Might be NULL */
|
||||
){
|
||||
@@ -352,7 +352,7 @@ Table *sqlite3LocateTable(
|
||||
|
||||
p = sqlite3FindTable(pParse->db, zName, zDbase);
|
||||
if( p==0 ){
|
||||
const char *zMsg = isView ? "no such view" : "no such table";
|
||||
const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
|
||||
/* If zName is the not the name of a table in the schema created using
|
||||
@@ -364,12 +364,14 @@ Table *sqlite3LocateTable(
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( zDbase ){
|
||||
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
||||
if( (flags & LOCATE_NOERR)==0 ){
|
||||
if( zDbase ){
|
||||
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
}
|
||||
|
||||
return p;
|
||||
@@ -386,7 +388,7 @@ Table *sqlite3LocateTable(
|
||||
*/
|
||||
Table *sqlite3LocateTableItem(
|
||||
Parse *pParse,
|
||||
int isView,
|
||||
u32 flags,
|
||||
struct SrcList_item *p
|
||||
){
|
||||
const char *zDb;
|
||||
@@ -397,7 +399,7 @@ Table *sqlite3LocateTableItem(
|
||||
}else{
|
||||
zDb = p->zDatabase;
|
||||
}
|
||||
return sqlite3LocateTable(pParse, isView, p->zName, zDb);
|
||||
return sqlite3LocateTable(pParse, flags, p->zName, zDb);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2504,6 +2506,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
assert( pName->nSrc==1 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
if( noErr ) db->suppressErr++;
|
||||
assert( isView==0 || isView==LOCATE_VIEW );
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
|
||||
@@ -3434,10 +3437,11 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
int i;
|
||||
|
||||
/* Set the first entry (number of rows in the index) to the estimated
|
||||
** number of rows in the table. Or 10, if the estimated number of rows
|
||||
** in the table is less than that. */
|
||||
** number of rows in the table, or half the number of rows in the table
|
||||
** for a partial index. But do not let the estimate drop below 10. */
|
||||
a[0] = pIdx->pTable->nRowLogEst;
|
||||
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
||||
if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
|
||||
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
||||
|
||||
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
||||
** 6 and each subsequent value (if any) is 5. */
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ static const char * const azCompileOpt[] = {
|
||||
"DISABLE_LFS",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_8_3_NAMES
|
||||
"ENABLE_8_3_NAMES",
|
||||
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
|
||||
#endif
|
||||
#if SQLITE_ENABLE_API_ARMOR
|
||||
"ENABLE_API_ARMOR",
|
||||
|
||||
+3
-3
@@ -58,10 +58,10 @@
|
||||
*/
|
||||
#define VTAB_SCHEMA \
|
||||
"CREATE TABLE xx( " \
|
||||
" name STRING, /* Name of table or index */" \
|
||||
" path INTEGER, /* Path to page from root */" \
|
||||
" name TEXT, /* Name of table or index */" \
|
||||
" path TEXT, /* Path to page from root */" \
|
||||
" pageno INTEGER, /* Page number */" \
|
||||
" pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \
|
||||
" pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
|
||||
" ncell INTEGER, /* Cells on page (0 for overflow) */" \
|
||||
" payload INTEGER, /* Bytes of payload on this page */" \
|
||||
" unused INTEGER, /* Bytes of unused space on this page */" \
|
||||
|
||||
@@ -1818,6 +1818,11 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
||||
|
||||
if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
|
||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||
const i64 sOne = 1;
|
||||
sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
|
||||
iTab, 0, 0, (u8*)&sOne, P4_INT64);
|
||||
#endif
|
||||
*prRhsHasNull = ++pParse->nMem;
|
||||
sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1052,7 +1052,7 @@ void sqlite3Pragma(
|
||||
*/
|
||||
case PragTyp_TABLE_INFO: if( zRight ){
|
||||
Table *pTab;
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
|
||||
if( pTab ){
|
||||
static const char *azCol[] = {
|
||||
"cid", "name", "type", "notnull", "dflt_value", "pk"
|
||||
|
||||
+5
-3
@@ -2485,7 +2485,7 @@ struct SrcList {
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
struct {
|
||||
u8 jointype; /* Type of join between this able and the previous */
|
||||
u8 jointype; /* Type of join between this table and the previous */
|
||||
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
||||
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
|
||||
unsigned isTabFunc :1; /* True if table-valued-function syntax */
|
||||
@@ -3671,8 +3671,10 @@ void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
|
||||
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
||||
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
|
||||
Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
|
||||
#define LOCATE_VIEW 0x01
|
||||
#define LOCATE_NOERR 0x02
|
||||
Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
|
||||
Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
|
||||
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
||||
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
|
||||
+4
-2
@@ -2325,6 +2325,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
*/
|
||||
case DB_EXISTS:
|
||||
case DB_ONECOLUMN: {
|
||||
Tcl_Obj *pResult = 0;
|
||||
DbEvalContext sEval;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
|
||||
@@ -2335,14 +2336,15 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
rc = dbEvalStep(&sEval);
|
||||
if( choice==DB_ONECOLUMN ){
|
||||
if( rc==TCL_OK ){
|
||||
Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0));
|
||||
pResult = dbEvalColumnValue(&sEval, 0);
|
||||
}else if( rc==TCL_BREAK ){
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
}else if( rc==TCL_BREAK || rc==TCL_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc==TCL_OK));
|
||||
pResult = Tcl_NewBooleanObj(rc==TCL_OK);
|
||||
}
|
||||
dbEvalFinalize(&sEval);
|
||||
if( pResult ) Tcl_SetObjResult(interp, pResult);
|
||||
|
||||
if( rc==TCL_BREAK ){
|
||||
rc = TCL_OK;
|
||||
|
||||
@@ -2761,6 +2761,7 @@ static int whereLoopAddBtree(
|
||||
/* Full scan via index */
|
||||
if( b
|
||||
|| !HasRowid(pTab)
|
||||
|| pProbe->pPartIdxWhere!=0
|
||||
|| ( m==0
|
||||
&& pProbe->bUnordered==0
|
||||
&& (pProbe->szIdxRow<pTab->szTabRow)
|
||||
|
||||
+73
-5
@@ -626,6 +626,38 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Test whether or not expression pExpr, which was part of a WHERE clause,
|
||||
** should be included in the cursor-hint for a table that is on the rhs
|
||||
** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the
|
||||
** expression is not suitable.
|
||||
**
|
||||
** An expression is unsuitable if it might evaluate to non NULL even if
|
||||
** a TK_COLUMN node that does affect the value of the expression is set
|
||||
** to NULL. For example:
|
||||
**
|
||||
** col IS NULL
|
||||
** col IS NOT NULL
|
||||
** coalesce(col, 1)
|
||||
** CASE WHEN col THEN 0 ELSE 1 END
|
||||
*/
|
||||
static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_IS
|
||||
|| pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
|
||||
|| pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
|
||||
){
|
||||
pWalker->eCode = 1;
|
||||
}else if( pExpr->op==TK_FUNCTION ){
|
||||
int d1;
|
||||
char d2[3];
|
||||
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
|
||||
pWalker->eCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called on every node of an expression tree used as an
|
||||
@@ -678,6 +710,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
||||
** Insert an OP_CursorHint instruction if it is appropriate to do so.
|
||||
*/
|
||||
static void codeCursorHint(
|
||||
struct SrcList_item *pTabItem, /* FROM clause item */
|
||||
WhereInfo *pWInfo, /* The where clause */
|
||||
WhereLevel *pLevel, /* Which loop to provide hints for */
|
||||
WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */
|
||||
@@ -708,7 +741,42 @@ static void codeCursorHint(
|
||||
pTerm = &pWC->a[i];
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( pTerm->prereqAll & pLevel->notReady ) continue;
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
|
||||
|
||||
/* Any terms specified as part of the ON(...) clause for any LEFT
|
||||
** JOIN for which the current table is not the rhs are omitted
|
||||
** from the cursor-hint.
|
||||
**
|
||||
** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms
|
||||
** that were specified as part of the WHERE clause must be excluded.
|
||||
** This is to address the following:
|
||||
**
|
||||
** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL;
|
||||
**
|
||||
** Say there is a single row in t2 that matches (t1.a=t2.b), but its
|
||||
** t2.c values is not NULL. If the (t2.c IS NULL) constraint is
|
||||
** pushed down to the cursor, this row is filtered out, causing
|
||||
** SQLite to synthesize a row of NULL values. Which does match the
|
||||
** WHERE clause, and so the query returns a row. Which is incorrect.
|
||||
**
|
||||
** For the same reason, WHERE terms such as:
|
||||
**
|
||||
** WHERE 1 = (t2.c IS NULL)
|
||||
**
|
||||
** are also excluded. See codeCursorHintIsOrFunction() for details.
|
||||
*/
|
||||
if( pTabItem->fg.jointype & JT_LEFT ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
|| pExpr->iRightJoinTable!=pTabItem->iCursor
|
||||
){
|
||||
sWalker.eCode = 0;
|
||||
sWalker.xExprCallback = codeCursorHintIsOrFunction;
|
||||
sqlite3WalkExpr(&sWalker, pTerm->pExpr);
|
||||
if( sWalker.eCode ) continue;
|
||||
}
|
||||
}else{
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
|
||||
}
|
||||
|
||||
/* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
|
||||
** the cursor. These terms are not needed as hints for a pure range
|
||||
@@ -742,7 +810,7 @@ static void codeCursorHint(
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define codeCursorHint(A,B,C) /* No-op */
|
||||
# define codeCursorHint(A,B,C,D) /* No-op */
|
||||
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
|
||||
|
||||
/*
|
||||
@@ -998,7 +1066,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
pStart = pEnd;
|
||||
pEnd = pTerm;
|
||||
}
|
||||
codeCursorHint(pWInfo, pLevel, pEnd);
|
||||
codeCursorHint(pTabItem, pWInfo, pLevel, pEnd);
|
||||
if( pStart ){
|
||||
Expr *pX; /* The expression that defines the start bound */
|
||||
int r1, rTemp; /* Registers for holding the start boundary */
|
||||
@@ -1212,7 +1280,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** and store the values of those terms in an array of registers
|
||||
** starting at regBase.
|
||||
*/
|
||||
codeCursorHint(pWInfo, pLevel, pRangeEnd);
|
||||
codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd);
|
||||
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
|
||||
assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
|
||||
if( zStartAff ) cEndAff = zStartAff[nEq];
|
||||
@@ -1660,7 +1728,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** a pseudo-cursor. No need to Rewind or Next such cursors. */
|
||||
pLevel->op = OP_Noop;
|
||||
}else{
|
||||
codeCursorHint(pWInfo, pLevel, 0);
|
||||
codeCursorHint(pTabItem, pWInfo, pLevel, 0);
|
||||
pLevel->op = aStep[bRev];
|
||||
pLevel->p1 = iCur;
|
||||
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# 2016 June 17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus is on testing that cursor-hints are correct for queries
|
||||
# involving LEFT JOIN.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix cursorhint2
|
||||
|
||||
ifcapable !cursorhints {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc extract_hints {sql} {
|
||||
|
||||
db eval "SELECT tbl_name, rootpage FROM sqlite_master where rootpage" {
|
||||
set lookup($rootpage) $tbl_name
|
||||
}
|
||||
|
||||
set ret [list]
|
||||
db eval "EXPLAIN $sql" a {
|
||||
switch -- $a(opcode) {
|
||||
OpenRead {
|
||||
set csr($a(p1)) $lookup($a(p2))
|
||||
}
|
||||
CursorHint {
|
||||
lappend ret $csr($a(p1)) $a(p4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set ret
|
||||
}
|
||||
|
||||
proc do_extract_hints_test {tn sql ret} {
|
||||
uplevel [list do_test $tn [list extract_hints $sql] [list {*}$ret]]
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA automatic_index = 0;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE TABLE t3(e, f);
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.1 {
|
||||
SELECT * FROM t1 WHERE a=1;
|
||||
} {
|
||||
t1 EQ(c0,1)
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.2 {
|
||||
SELECT * FROM t1 CROSS JOIN t2 ON (a=c) WHERE d IS NULL;
|
||||
} {
|
||||
t2 {AND(ISNULL(c1),EQ(r[1],c0))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.3 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c) WHERE d IS NULL;
|
||||
} {
|
||||
t2 {EQ(r[2],c0)}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.4 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c AND a=10) WHERE d IS NULL;
|
||||
} {
|
||||
t2 {AND(EQ(r[2],c0),EQ(r[3],10))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.5 {
|
||||
SELECT * FROM t1 CROSS JOIN t2 ON (a=c AND a=10) WHERE d IS NULL;
|
||||
} {
|
||||
t1 EQ(c0,10) t2 {AND(ISNULL(c1),EQ(r[3],c0))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.6 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c) LEFT JOIN t3 ON (d=f);
|
||||
} {
|
||||
t2 {EQ(r[2],c0)} t3 {EQ(r[6],c1)}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.7 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c AND d=e) LEFT JOIN t3 ON (d=f);
|
||||
} {
|
||||
t2 {EQ(r[2],c0)} t3 {AND(EQ(r[6],c0),EQ(r[7],c1))}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE x1(x, y);
|
||||
CREATE TABLE x2(a, b);
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.1 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NULL;
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.2 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS +NULL;
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.3 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = (b IS NULL)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.4 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = coalesce(b, 1)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.5 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = coalesce(b, 1)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.6 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT NULL)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.7 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT +NULL)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.8 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NOT +NULL
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.9 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE CASE b WHEN 0 THEN 0 ELSE 1 END;
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.10 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b = 32+32
|
||||
} {
|
||||
x2 {AND(EQ(c1,ADD(32,32)),EQ(c0,r[2]))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.11 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b LIKE 'abc%'
|
||||
} {
|
||||
x2 {AND(expr,EQ(c0,r[2]))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.11 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE coalesce(x2.b, 1)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -376,4 +376,15 @@ do_execsql_test index6-10.3eqp {
|
||||
SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC;
|
||||
} {~/USING INDEX t10x/}
|
||||
|
||||
# A partial index will be used for a full table scan, where possible
|
||||
do_execsql_test index6-11.1 {
|
||||
CREATE TABLE t11(a,b,c);
|
||||
CREATE INDEX t11x ON t11(a) WHERE b<>99;
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99;
|
||||
} {/USING INDEX t11x/}
|
||||
do_execsql_test index6-11.2 {
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99 AND c<>98;
|
||||
} {/USING INDEX t11x/}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -32,6 +32,9 @@ db func a_string a_string
|
||||
|
||||
register_dbstat_vtab db
|
||||
do_execsql_test stat-0.0 {
|
||||
PRAGMA table_info(dbstat);
|
||||
} {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/}
|
||||
do_execsql_test stat-0.1 {
|
||||
PRAGMA auto_vacuum = OFF;
|
||||
CREATE VIRTUAL TABLE temp.stat USING dbstat;
|
||||
SELECT * FROM stat;
|
||||
|
||||
@@ -635,6 +635,39 @@ do_test tcl-14.2 {
|
||||
db one {SELECT x FROM t6 WHERE xCall()!='value'}
|
||||
} {}
|
||||
|
||||
# Verify that the "exists" and "onecolumn" methods work when
|
||||
# a "profile" is registered.
|
||||
#
|
||||
catch {db close}
|
||||
sqlite3 db :memory:
|
||||
proc noop-profile {args} {
|
||||
return
|
||||
}
|
||||
do_test tcl-15.0 {
|
||||
db eval {CREATE TABLE t1(a); INSERT INTO t1 VALUES(1),(2),(3);}
|
||||
db onecolumn {SELECT a FROM t1 WHERE a>2}
|
||||
} {3}
|
||||
do_test tcl-15.1 {
|
||||
db exists {SELECT a FROM t1 WHERE a>2}
|
||||
} {1}
|
||||
do_test tcl-15.2 {
|
||||
db exists {SELECT a FROM t1 WHERE a>3}
|
||||
} {0}
|
||||
db profile noop-profile
|
||||
do_test tcl-15.3 {
|
||||
db onecolumn {SELECT a FROM t1 WHERE a>2}
|
||||
} {3}
|
||||
do_test tcl-15.4 {
|
||||
db exists {SELECT a FROM t1 WHERE a>2}
|
||||
} {1}
|
||||
do_test tcl-15.5 {
|
||||
db exists {SELECT a FROM t1 WHERE a>3}
|
||||
} {0}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ do_test where3-1.1 {
|
||||
}
|
||||
} {222 two 2 222 {} {}}
|
||||
|
||||
ifcapable explain {
|
||||
ifcapable explain&&!cursorhints {
|
||||
do_test where3-1.1.1 {
|
||||
explain_no_trace {SELECT * FROM t1, t2 LEFT JOIN t3 ON q=x
|
||||
WHERE p=2 AND a=q}
|
||||
@@ -86,7 +86,7 @@ do_test where3-1.2 {
|
||||
}
|
||||
} {1 {Value for C1.1} {Value for C2.1} 2 {} {Value for C2.2} 3 {Value for C1.3} {Value for C2.3}}
|
||||
|
||||
ifcapable explain {
|
||||
ifcapable explain&&!cursorhints {
|
||||
do_test where3-1.2.1 {
|
||||
explain_no_trace {
|
||||
SELECT parent1.parent1key, child1.value, child2.value
|
||||
|
||||
Reference in New Issue
Block a user