Merge recent trunk changes with this branch.

FossilOrigin-Name: c71f23590c25b4cecd27722e6c0fc8e3bf320d399c7d9398b7016dd5cf5b05eb
This commit is contained in:
dan 2018-06-09 18:09:44 +00:00
commit 96f55d0fa5
11 changed files with 210 additions and 144 deletions

View File

@ -1,5 +1,5 @@
C Update\sthe\samalgamation\sbuild\sscript\sto\sinclude\swindow.c.
D 2018-06-09T17:58:51.834
C Merge\srecent\strunk\schanges\swith\sthis\sbranch.
D 2018-06-09T18:09:44.345
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 498b77b89a8cb42f2ee20fcd6317f279a45c0d6ff40d27825f94b69884c09bbe
@ -436,10 +436,10 @@ F src/auth.c a38f3c63c974787ecf75e3213f8cac6568b9a7af7591fb0372ec0517dd16dca8
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c c38cd920641bf05c932caf657524927115c721489f14cc109efc4da5c43205b2
F src/btree.c 671207d68ac2fb32c782f9b65cd6f8a861757044b1448098cb08fab4fcf02947
F src/btree.h 7b557914561f60a0eb76c2e22c23ab5b82f87b734a91c1b9385654b6474fdf7f
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
F src/build.c 5fc41458505331bfb0c175f40b9a13cb335f826bed3ae311aaae000c132d7b16
F src/build.c 3b3bfa88800739e1f11313dcecfba5ef8e4757b6c929cdf7de9fcfc01002b81f
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 849d4cebe008cfc6e4799b034a172b4eaf8856b100739632a852732ba66eee48
@ -500,7 +500,7 @@ F src/shell.c.in 4d0ddf10c403710d241bf920163dcf032c21119aebb61e70840942c0eafecdf
F src/sqlite.h.in 63b07f76731f2b1e55c48fdb9f0508dcc6fbe3971010b8612ffd847c3c56d9a1
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
F src/sqliteInt.h 8cdd2f8c920cc7de683c27322d2f146079bc36ad267b63eaf9ee186ee58e287f
F src/sqliteInt.h 04c732e9e770d35c12f5e649b7288510f3a2abb238e32eadaf506678717ddb25
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@ -576,13 +576,13 @@ F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 10ea07dec111de6fb0a4fc87a7ffa4c65fdc088a19dbfaf7d6f2b128f2e8eb7b
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c aa9cffc7a2bad6b826a86c8562dd4978398720ed41cb8ee7aa9d054eb8b456a0
F src/wal.c d44a0811afd2155b1157c38b33141d4ac028fda6232485bed664015bb05819ca
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
F src/where.c 7dcb13bbcfd8c926546946556014c8f5aa0829eb8b65a6c18f8d187d265200a5
F src/whereInt.h b09753e74bf92a8b17cf0e41ca94c44432c454544be6699b5311dcc57bf229c6
F src/where.c fe1a6f97c12cc9472ccce86166ba3f827cf61d6ae770c036a6396b63863baac4
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
F src/whereexpr.c 6f022d6cc9daf56495f191b199352f783aff5cf268ba136b4d8cea3fb62d8c7d
F src/window.c 72c08229b59a447db5ffb8e87680105549465df502092e0e24f9451e6b082031
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
@ -968,7 +968,7 @@ F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
F test/in5.test 7ae37fcd4a5e198291c6ab5f31a5bb3d15397efe8b75a6736d7a95a7b8dd9e08
F test/in6.test 77c3e1d356d8aeb0864051f0677d3c0a032cf97b7f33a0ba8fa2b04a663f6b7b
F test/in6.test 62d943a02f722948f4410ee0b53c3cb39acd7c41afb083df8d7004238fe90a20
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
F test/incrblob2.test a494c9e848560039a23974b9119cfc2cf3ad3bd15cc2694ee6367ae537ef8f1f
F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4
@ -1187,7 +1187,7 @@ F test/rowid.test 5b7509f384f4f6fae1af3c8c104c8ca299fea18d
F test/rowvalue.test ef851a80f7e6de93b51caca9e4b6b7d2dcd540bbcca7d51860e80435b8b4c0de
F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b
F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256
F test/rowvalue4.test cbd1cead27a797d11ec93301fd801c89e97eb1809b3d984b7f16a3876e362eac
F test/rowvalue4.test 2b20468da3775aba971caf3158e9696a4d99c69a7623fb495f332a596daebbee
F test/rowvalue5.test c81c7d8cf36711ab37675ad7376084ae2a359cb6
F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087
F test/rowvalue7.test 5d06ff19d9e6969e574a2e662a531dd0c67801a8
@ -1740,7 +1740,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 ceaf798ea09184bc0e7d3dcf3ad4d909d2e4e7018754a8417a813f33010140a7
R 25d876301d00e59b71583c6b55d6c00d
P 21d2f4a62eceab0de0b4669bf3e81eb71512211ed710ce0eb525695fb7309d6b 538a365b7a32ab7fa84f59d7556242cfb59b76d287b6417eb3a823197a354e8e
R 6acfedbb724c9a0a79fb2548396e647b
U dan
Z 68e027e36121929eecffb8d7c085a490
Z fb63cabb1c512a4c919ea08381d46601

View File

@ -1 +1 @@
21d2f4a62eceab0de0b4669bf3e81eb71512211ed710ce0eb525695fb7309d6b
c71f23590c25b4cecd27722e6c0fc8e3bf320d399c7d9398b7016dd5cf5b05eb

View File

@ -5596,7 +5596,16 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
assert( pPage->isInit );
if( !pPage->isInit ){
/* The only known way for this to happen is for there to be a
** recursive SQL function that does a DELETE operation as part of a
** SELECT which deletes content out from under an active cursor
** in a corrupt database file where the table being DELETE-ed from
** has pages in common with the table being queried. See TH3
** module cov1/btree78.test testcase 220 (2018-06-08) for an
** example. */
return SQLITE_CORRUPT_BKPT;
}
/* If the database file is corrupt, it is possible for the value of idx
** to be invalid here. This can only occur if a second cursor modifies

View File

@ -1695,6 +1695,31 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
return 0;
}
/* Recompute the colNotIdxed field of the Index.
**
** colNotIdxed is a bitmask that has a 0 bit representing each indexed
** columns that are within the first 63 columns of the table. The
** high-order bit of colNotIdxed is always 1. All unindexed columns
** of the table have a 1.
**
** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask
** to determine if the index is covering index.
*/
static void recomputeColumnsNotIndexed(Index *pIdx){
Bitmask m = 0;
int j;
for(j=pIdx->nColumn-1; j>=0; j--){
int x = pIdx->aiColumn[j];
if( x>=0 ){
testcase( x==BMS-1 );
testcase( x==BMS-2 );
if( x<BMS-1 ) m |= MASKBIT(x);
}
}
pIdx->colNotIdxed = ~m;
assert( (pIdx->colNotIdxed>>63)==1 );
}
/*
** This routine runs at the end of parsing a CREATE TABLE statement that
** has a WITHOUT ROWID clause. The job of this routine is to convert both
@ -1843,6 +1868,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
}else{
pPk->nColumn = pTab->nCol;
}
recomputeColumnsNotIndexed(pPk);
}
/*
@ -3276,6 +3302,7 @@ void sqlite3CreateIndex(
** it as a covering index */
assert( HasRowid(pTab)
|| pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
recomputeColumnsNotIndexed(pIndex);
if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
pIndex->isCovering = 1;
for(j=0; j<pTab->nCol; j++){

View File

@ -1110,6 +1110,32 @@ typedef struct WhereInfo WhereInfo;
typedef struct Window Window;
typedef struct With With;
/*
** The bitmask datatype defined below is used for various optimizations.
**
** Changing this from a 64-bit to a 32-bit type limits the number of
** tables in a join to 32 instead of 64. But it also reduces the size
** of the library by 738 bytes on ix86.
*/
#ifdef SQLITE_BITMASK_TYPE
typedef SQLITE_BITMASK_TYPE Bitmask;
#else
typedef u64 Bitmask;
#endif
/*
** The number of bits in a Bitmask. "BMS" means "BitMask Size".
*/
#define BMS ((int)(sizeof(Bitmask)*8))
/*
** A bit in a Bitmask
*/
#define MASKBIT(n) (((Bitmask)1)<<(n))
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define ALLBITS ((Bitmask)-1)
/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
** variable number associated with that parameter. See the format description
@ -2213,6 +2239,7 @@ struct Index {
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */
};
/*
@ -2559,31 +2586,6 @@ struct IdList {
int nId; /* Number of identifiers on the list */
};
/*
** The bitmask datatype defined below is used for various optimizations.
**
** Changing this from a 64-bit to a 32-bit type limits the number of
** tables in a join to 32 instead of 64. But it also reduces the size
** of the library by 738 bytes on ix86.
*/
#ifdef SQLITE_BITMASK_TYPE
typedef SQLITE_BITMASK_TYPE Bitmask;
#else
typedef u64 Bitmask;
#endif
/*
** The number of bits in a Bitmask. "BMS" means "BitMask Size".
*/
#define BMS ((int)(sizeof(Bitmask)*8))
/*
** A bit in a Bitmask
*/
#define MASKBIT(n) (((Bitmask)1)<<(n))
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define ALLBITS ((Bitmask)-1)
/*
** The following structure describes the FROM clause of a SELECT statement.
** Each table or subquery in the FROM clause is a separate element of

143
src/wal.c
View File

@ -880,48 +880,51 @@ static int walNextHash(int iPriorHash){
return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
}
/*
** An instance of the WalHashLoc object is used to describe the location
** of a page hash table in the wal-index. This becomes the return value
** from walHashGet().
*/
typedef struct WalHashLoc WalHashLoc;
struct WalHashLoc {
volatile ht_slot *aHash; /* Start of the wal-index hash table */
volatile u32 *aPgno; /* aPgno[1] is the page of first frame indexed */
u32 iZero; /* One less than the frame number of first indexed*/
};
/*
** Return pointers to the hash table and page number array stored on
** page iHash of the wal-index. The wal-index is broken into 32KB pages
** numbered starting from 0.
**
** Set output variable *paHash to point to the start of the hash table
** in the wal-index file. Set *piZero to one less than the frame
** Set output variable pLoc->aHash to point to the start of the hash table
** in the wal-index file. Set pLoc->iZero to one less than the frame
** number of the first frame indexed by this hash table. If a
** slot in the hash table is set to N, it refers to frame number
** (*piZero+N) in the log.
** (pLoc->iZero+N) in the log.
**
** Finally, set *paPgno so that *paPgno[1] is the page number of the
** first frame indexed by the hash table, frame (*piZero+1).
** Finally, set pLoc->aPgno so that pLoc->aPgno[1] is the page number of the
** first frame indexed by the hash table, frame (pLoc->iZero+1).
*/
static int walHashGet(
Wal *pWal, /* WAL handle */
int iHash, /* Find the iHash'th table */
volatile ht_slot **paHash, /* OUT: Pointer to hash index */
volatile u32 **paPgno, /* OUT: Pointer to page number array */
u32 *piZero /* OUT: Frame associated with *paPgno[0] */
WalHashLoc *pLoc /* OUT: Hash table location */
){
int rc; /* Return code */
volatile u32 *aPgno;
rc = walIndexPage(pWal, iHash, &aPgno);
rc = walIndexPage(pWal, iHash, &pLoc->aPgno);
assert( rc==SQLITE_OK || iHash>0 );
if( rc==SQLITE_OK ){
u32 iZero;
volatile ht_slot *aHash;
aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE];
if( iHash==0 ){
aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
iZero = 0;
pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
pLoc->iZero = 0;
}else{
iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
}
*paPgno = &aPgno[-1];
*paHash = aHash;
*piZero = iZero;
pLoc->aPgno = &pLoc->aPgno[-1];
}
return rc;
}
@ -967,9 +970,7 @@ static u32 walFramePgno(Wal *pWal, u32 iFrame){
** actually needed.
*/
static void walCleanupHash(Wal *pWal){
volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
volatile u32 *aPgno = 0; /* Page number array for hash table */
u32 iZero = 0; /* frame == (aHash[x]+iZero) */
WalHashLoc sLoc; /* Hash table location */
int iLimit = 0; /* Zero values greater than this */
int nByte; /* Number of bytes to zero in aPgno[] */
int i; /* Used to iterate through aHash[] */
@ -987,24 +988,24 @@ static void walCleanupHash(Wal *pWal){
*/
assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
/* Zero all hash-table entries that correspond to frame numbers greater
** than pWal->hdr.mxFrame.
*/
iLimit = pWal->hdr.mxFrame - iZero;
iLimit = pWal->hdr.mxFrame - sLoc.iZero;
assert( iLimit>0 );
for(i=0; i<HASHTABLE_NSLOT; i++){
if( aHash[i]>iLimit ){
aHash[i] = 0;
if( sLoc.aHash[i]>iLimit ){
sLoc.aHash[i] = 0;
}
}
/* Zero the entries in the aPgno array that correspond to frames with
** frame numbers greater than pWal->hdr.mxFrame.
*/
nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
memset((void *)&aPgno[iLimit+1], 0, nByte);
nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]);
memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte);
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* Verify that the every entry in the mapping region is still reachable
@ -1014,10 +1015,10 @@ static void walCleanupHash(Wal *pWal){
int j; /* Loop counter */
int iKey; /* Hash key */
for(j=1; j<=iLimit; j++){
for(iKey=walHash(aPgno[j]); aHash[iKey]; iKey=walNextHash(iKey)){
if( aHash[iKey]==j ) break;
for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){
if( sLoc.aHash[iKey]==j ) break;
}
assert( aHash[iKey]==j );
assert( sLoc.aHash[iKey]==j );
}
}
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
@ -1030,11 +1031,9 @@ static void walCleanupHash(Wal *pWal){
*/
static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
int rc; /* Return code */
u32 iZero = 0; /* One less than frame number of aPgno[1] */
volatile u32 *aPgno = 0; /* Page number array */
volatile ht_slot *aHash = 0; /* Hash table */
WalHashLoc sLoc; /* Wal-index hash table location */
rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
rc = walHashGet(pWal, walFramePage(iFrame), &sLoc);
/* Assuming the wal-index file was successfully mapped, populate the
** page number array and hash table entry.
@ -1044,15 +1043,16 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
int idx; /* Value to write to hash-table slot */
int nCollide; /* Number of hash collisions */
idx = iFrame - iZero;
idx = iFrame - sLoc.iZero;
assert( idx <= HASHTABLE_NSLOT/2 + 1 );
/* If this is the first entry to be added to this hash-table, zero the
** entire hash table and aPgno[] array before proceeding.
*/
if( idx==1 ){
int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
memset((void*)&aPgno[1], 0, nByte);
int nByte = (int)((u8 *)&sLoc.aHash[HASHTABLE_NSLOT]
- (u8 *)&sLoc.aPgno[1]);
memset((void*)&sLoc.aPgno[1], 0, nByte);
}
/* If the entry in aPgno[] is already set, then the previous writer
@ -1061,18 +1061,18 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
** Remove the remnants of that writers uncommitted transaction from
** the hash-table before writing any new entries.
*/
if( aPgno[idx] ){
if( sLoc.aPgno[idx] ){
walCleanupHash(pWal);
assert( !aPgno[idx] );
assert( !sLoc.aPgno[idx] );
}
/* Write the aPgno[] array entry and the hash-table slot. */
nCollide = idx;
for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
}
aPgno[idx] = iPage;
aHash[iKey] = (ht_slot)idx;
sLoc.aPgno[idx] = iPage;
sLoc.aHash[iKey] = (ht_slot)idx;
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* Verify that the number of entries in the hash table exactly equals
@ -1081,7 +1081,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
{
int i; /* Loop counter */
int nEntry = 0; /* Number of entries in the hash table */
for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
for(i=0; i<HASHTABLE_NSLOT; i++){ if( sLoc.aHash[i] ) nEntry++; }
assert( nEntry==idx );
}
@ -1093,10 +1093,12 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
if( (idx&0x3ff)==0 ){
int i; /* Loop counter */
for(i=1; i<=idx; i++){
for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
if( aHash[iKey]==i ) break;
for(iKey=walHash(sLoc.aPgno[i]);
sLoc.aHash[iKey];
iKey=walNextHash(iKey)){
if( sLoc.aHash[iKey]==i ) break;
}
assert( aHash[iKey]==i );
assert( sLoc.aHash[iKey]==i );
}
}
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
@ -1634,33 +1636,31 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
}
for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
volatile ht_slot *aHash;
u32 iZero;
volatile u32 *aPgno;
WalHashLoc sLoc;
rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
rc = walHashGet(pWal, i, &sLoc);
if( rc==SQLITE_OK ){
int j; /* Counter variable */
int nEntry; /* Number of entries in this segment */
ht_slot *aIndex; /* Sorted index for this segment */
aPgno++;
sLoc.aPgno++;
if( (i+1)==nSegment ){
nEntry = (int)(iLast - iZero);
nEntry = (int)(iLast - sLoc.iZero);
}else{
nEntry = (int)((u32*)aHash - (u32*)aPgno);
nEntry = (int)((u32*)sLoc.aHash - (u32*)sLoc.aPgno);
}
aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
iZero++;
aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero];
sLoc.iZero++;
for(j=0; j<nEntry; j++){
aIndex[j] = (ht_slot)j;
}
walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
p->aSegment[i].iZero = iZero;
walMergesort((u32 *)sLoc.aPgno, aTmp, aIndex, &nEntry);
p->aSegment[i].iZero = sLoc.iZero;
p->aSegment[i].nEntry = nEntry;
p->aSegment[i].aIndex = aIndex;
p->aSegment[i].aPgno = (u32 *)aPgno;
p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
}
}
sqlite3_free(aTmp);
@ -2673,16 +2673,14 @@ int sqlite3WalSnapshotRecover(Wal *pWal){
}else{
u32 i = pInfo->nBackfillAttempted;
for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
volatile ht_slot *dummy;
volatile u32 *aPgno; /* Array of page numbers */
u32 iZero; /* Frame corresponding to aPgno[0] */
WalHashLoc sLoc; /* Hash table location */
u32 pgno; /* Page number in db file */
i64 iDbOff; /* Offset of db file entry */
i64 iWalOff; /* Offset of wal file entry */
rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero);
rc = walHashGet(pWal, walFramePage(i), &sLoc);
if( rc!=SQLITE_OK ) break;
pgno = aPgno[i-iZero];
pgno = sLoc.aPgno[i-sLoc.iZero];
iDbOff = (i64)(pgno-1) * szPage;
if( iDbOff+szPage<=szDb ){
@ -2883,21 +2881,20 @@ int sqlite3WalFindFrame(
*/
iMinHash = walFramePage(pWal->minFrame);
for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){
volatile ht_slot *aHash; /* Pointer to hash table */
volatile u32 *aPgno; /* Pointer to array of page numbers */
u32 iZero; /* Frame number corresponding to aPgno[0] */
WalHashLoc sLoc; /* Hash table location */
int iKey; /* Hash slot index */
int nCollide; /* Number of hash collisions remaining */
int rc; /* Error code */
rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
rc = walHashGet(pWal, iHash, &sLoc);
if( rc!=SQLITE_OK ){
return rc;
}
nCollide = HASHTABLE_NSLOT;
for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
u32 iFrame = aHash[iKey] + iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){
for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame
&& sLoc.aPgno[sLoc.aHash[iKey]]==pgno ){
assert( iFrame>iRead || CORRUPT_DB );
iRead = iFrame;
}

View File

@ -2451,7 +2451,6 @@ static int whereLoopAddBtreeIndex(
if( eOp & WO_IN ){
Expr *pExpr = pTerm->pExpr;
pNew->wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
int i;
@ -2471,6 +2470,42 @@ static int whereLoopAddBtreeIndex(
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
** changes "x IN (?)" into "x=?". */
}
if( pProbe->hasStat1 ){
LogEst M, logK, safetyMargin;
/* Let:
** N = the total number of rows in the table
** K = the number of entries on the RHS of the IN operator
** M = the number of rows in the table that match terms to the
** to the left in the same index. If the IN operator is on
** the left-most index column, M==N.
**
** Given the definitions above, it is better to omit the IN operator
** from the index lookup and instead do a scan of the M elements,
** testing each scanned row against the IN operator separately, if:
**
** M*log(K) < K*log(N)
**
** Our estimates for M, K, and N might be inaccurate, so we build in
** a safety margin of 2 (LogEst: 10) that favors using the IN operator
** with the index, as using an index has better worst-case behavior.
** If we do not have real sqlite_stat1 data, always prefer to use
** the index.
*/
M = pProbe->aiRowLogEst[saved_nEq];
logK = estLog(nIn);
safetyMargin = 10; /* TUNING: extra weight for indexed IN */
if( M + logK + safetyMargin < nIn + rLogSize ){
WHERETRACE(0x40,
("Scan preferred over IN operator on column %d of \"%s\" (%d<%d)\n",
saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
continue;
}else{
WHERETRACE(0x40,
("IN operator preferred on column %d of \"%s\" (%d>=%d)\n",
saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
}
}
pNew->wsFlags |= WHERE_COLUMN_IN;
}else if( eOp & (WO_EQ|WO_IS) ){
int iCol = pProbe->aiColumn[saved_nEq];
pNew->wsFlags |= WHERE_COLUMN_EQ;
@ -2700,24 +2735,6 @@ static int indexMightHelpWithOrderBy(
return 0;
}
/*
** Return a bitmask where 1s indicate that the corresponding column of
** the table is used by an index. Only the first 63 columns are considered.
*/
static Bitmask columnsInIndex(Index *pIdx){
Bitmask m = 0;
int j;
for(j=pIdx->nColumn-1; j>=0; j--){
int x = pIdx->aiColumn[j];
if( x>=0 ){
testcase( x==BMS-1 );
testcase( x==BMS-2 );
if( x<BMS-1 ) m |= MASKBIT(x);
}
}
return m;
}
/* Check to see if a partial index with pPartIndexWhere can be used
** in the current query. Return true if it can be and false if not.
*/
@ -2933,7 +2950,7 @@ static int whereLoopAddBtree(
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
m = 0;
}else{
m = pSrc->colUsed & ~columnsInIndex(pProbe);
m = pSrc->colUsed & pProbe->colNotIdxed;
pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
}
@ -3500,7 +3517,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
{
rc = whereLoopAddBtree(pBuilder, mPrereq);
}
if( rc==SQLITE_OK ){
if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){
rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
}
mPrior |= pNew->maskSelf;
@ -4336,7 +4353,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
}
if( j!=pIdx->nKeyCol ) continue;
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED;
if( pIdx->isCovering || (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){
if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){
pLoop->wsFlags |= WHERE_IDX_ONLY;
}
pLoop->nLTerm = j;

View File

@ -322,6 +322,7 @@ struct WhereClause {
WhereInfo *pWInfo; /* WHERE clause processing context */
WhereClause *pOuter; /* Outer conjunction */
u8 op; /* Split operator. TK_AND or TK_OR */
u8 hasOr; /* True if any a[].eOperator is WO_OR */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
@ -495,6 +496,7 @@ void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
void sqlite3WhereClauseClear(WhereClause*);
void sqlite3WhereSplit(WhereClause*,Expr*,u8);
Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);

View File

@ -672,7 +672,12 @@ static void exprAnalyzeOrTerm(
** empty.
*/
pOrInfo->indexable = indexable;
pTerm->eOperator = indexable==0 ? 0 : WO_OR;
if( indexable ){
pTerm->eOperator = WO_OR;
pWC->hasOr = 1;
}else{
pTerm->eOperator = WO_OR;
}
/* For a two-way OR, attempt to implementation case 2.
*/
@ -1011,7 +1016,7 @@ static void exprAnalyze(
pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
}
pMaskSet->bVarSelect = 0;
prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr);
prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
if( ExprHasProperty(pExpr, EP_FromJoin) ){
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
@ -1440,17 +1445,18 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
** a bitmask indicating which tables are used in that expression
** tree.
*/
Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
Bitmask mask;
if( p==0 ) return 0;
if( p->op==TK_COLUMN ){
return sqlite3WhereGetMask(pMaskSet, p->iTable);
}else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
assert( p->op!=TK_IF_NULL_ROW );
return 0;
}
mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
assert( !ExprHasProperty(p, EP_TokenOnly) );
if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft);
if( p->pRight ){
mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight);
mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight);
assert( p->x.pList==0 );
}else if( ExprHasProperty(p, EP_xIsSelect) ){
if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
@ -1460,6 +1466,9 @@ Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
}
return mask;
}
Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
}
Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){
int i;
Bitmask mask = 0;

View File

@ -28,6 +28,9 @@ do_test in6-1.1 {
INSERT INTO t1(a,b,c,d)
SELECT 100, 200+x/2, 300+x/5, x FROM c;
CREATE INDEX t1abc ON t1(a,b,c);
ANALYZE;
UPDATE sqlite_stat1 SET stat='1000000 500000 500 50';
ANALYZE sqlite_master;
}
set ::sqlite_search_count 0
db eval {

View File

@ -224,7 +224,7 @@ do_execsql_test 5.0 {
WITH i(i) AS (
VALUES(1) UNION ALL SELECT i+1 FROM i WHERE i<1000
)
INSERT INTO d2 SELECT i/3, i%3, i/3 FROM i;
INSERT INTO d2 SELECT i/100, i%100, i/100 FROM i;
ANALYZE;
}