mirror of https://github.com/sqlite/sqlite
Merge recent trunk changes with this branch.
FossilOrigin-Name: c71f23590c25b4cecd27722e6c0fc8e3bf320d399c7d9398b7016dd5cf5b05eb
This commit is contained in:
commit
96f55d0fa5
28
manifest
28
manifest
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
21d2f4a62eceab0de0b4669bf3e81eb71512211ed710ce0eb525695fb7309d6b
|
||||
c71f23590c25b4cecd27722e6c0fc8e3bf320d399c7d9398b7016dd5cf5b05eb
|
11
src/btree.c
11
src/btree.c
|
@ -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
|
||||
|
|
27
src/build.c
27
src/build.c
|
@ -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++){
|
||||
|
|
|
@ -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
143
src/wal.c
|
@ -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;
|
||||
}
|
||||
|
|
61
src/where.c
61
src/where.c
|
@ -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;
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue