Merge the latest changes from trunk.
FossilOrigin-Name: 3047a25f1c41e83f0b4772f7c36fbfec0f12dc7e
This commit is contained in:
@@ -4588,6 +4588,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
|
||||
if( pIdxKey ){
|
||||
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
|
||||
pIdxKey->isCorrupt = 0;
|
||||
assert( pIdxKey->default_rc==1
|
||||
|| pIdxKey->default_rc==0
|
||||
|| pIdxKey->default_rc==-1
|
||||
@@ -4711,6 +4712,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
|
||||
sqlite3_free(pCellKey);
|
||||
}
|
||||
assert( pIdxKey->isCorrupt==0 || c==0 );
|
||||
if( c<0 ){
|
||||
lwr = idx+1;
|
||||
}else if( c>0 ){
|
||||
@@ -4720,6 +4722,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
if( lwr>upr ) break;
|
||||
|
||||
@@ -1627,6 +1627,7 @@ struct UnpackedRecord {
|
||||
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
||||
u16 nField; /* Number of entries in apMem[] */
|
||||
i8 default_rc; /* Comparison result if keys are equal */
|
||||
u8 isCorrupt; /* Corruption detected by xRecordCompare() */
|
||||
Mem *aMem; /* Values */
|
||||
int r1; /* Value to return if (lhs > rhs) */
|
||||
int r2; /* Value to return if (rhs < lhs) */
|
||||
|
||||
+2
-2
@@ -211,10 +211,10 @@ void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
#endif
|
||||
|
||||
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
|
||||
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
|
||||
|
||||
typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int);
|
||||
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
|
||||
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
||||
+1
-1
@@ -392,7 +392,7 @@ u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
|
||||
|
||||
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const UnpackedRecord*,int*);
|
||||
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
|
||||
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
|
||||
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
int sqlite3VdbeExec(Vdbe*);
|
||||
|
||||
+19
-8
@@ -3405,10 +3405,13 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
||||
** Key1 and Key2 do not have to contain the same number of fields. If all
|
||||
** fields that appear in both keys are equal, then pPKey2->default_rc is
|
||||
** returned.
|
||||
**
|
||||
** If database corruption is discovered, set pPKey2->isCorrupt to non-zero
|
||||
** and return 0.
|
||||
*/
|
||||
int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
const UnpackedRecord *pPKey2, /* Right key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* If true, skip the first field */
|
||||
){
|
||||
u32 d1; /* Offset into aKey[] of next data element */
|
||||
@@ -3434,7 +3437,10 @@ int sqlite3VdbeRecordCompare(
|
||||
}else{
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
d1 = szHdr1;
|
||||
if( d1>(unsigned)nKey1 ) return 1; /* Corruption */
|
||||
if( d1>(unsigned)nKey1 ){
|
||||
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
|
||||
@@ -3511,7 +3517,8 @@ int sqlite3VdbeRecordCompare(
|
||||
testcase( (d1+mem1.n)==(unsigned)nKey1 );
|
||||
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
|
||||
if( (d1+mem1.n) > (unsigned)nKey1 ){
|
||||
rc = 1; /* Corruption */
|
||||
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}else if( pKeyInfo->aColl[i] ){
|
||||
mem1.enc = pKeyInfo->enc;
|
||||
mem1.db = pKeyInfo->db;
|
||||
@@ -3537,7 +3544,8 @@ int sqlite3VdbeRecordCompare(
|
||||
testcase( (d1+nStr)==(unsigned)nKey1 );
|
||||
testcase( (d1+nStr+1)==(unsigned)nKey1 );
|
||||
if( (d1+nStr) > (unsigned)nKey1 ){
|
||||
rc = 1; /* Corruption */
|
||||
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}else{
|
||||
int nCmp = MIN(nStr, pRhs->n);
|
||||
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
|
||||
@@ -3596,7 +3604,7 @@ int sqlite3VdbeRecordCompare(
|
||||
*/
|
||||
static int vdbeRecordCompareInt(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
const UnpackedRecord *pPKey2, /* Right key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* Ignored */
|
||||
){
|
||||
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
|
||||
@@ -3694,7 +3702,7 @@ static int vdbeRecordCompareInt(
|
||||
*/
|
||||
static int vdbeRecordCompareString(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
const UnpackedRecord *pPKey2, /* Right key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip
|
||||
){
|
||||
const u8 *aKey1 = (const u8*)pKey1;
|
||||
@@ -3715,7 +3723,10 @@ static int vdbeRecordCompareString(
|
||||
int szHdr = aKey1[0];
|
||||
|
||||
nStr = (serial_type-12) / 2;
|
||||
if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */
|
||||
if( (szHdr + nStr) > nKey1 ){
|
||||
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}
|
||||
nCmp = MIN( pPKey2->aMem[0].n, nStr );
|
||||
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
|
||||
|
||||
@@ -3880,7 +3891,7 @@ idx_rowid_corruption:
|
||||
*/
|
||||
int sqlite3VdbeIdxKeyCompare(
|
||||
VdbeCursor *pC, /* The cursor to compare against */
|
||||
const UnpackedRecord *pUnpacked, /* Unpacked version of key */
|
||||
UnpackedRecord *pUnpacked, /* Unpacked version of key */
|
||||
int *res /* Write the comparison result here */
|
||||
){
|
||||
i64 nCellKey = 0;
|
||||
|
||||
+35
-11
@@ -4328,18 +4328,34 @@ static int whereLoopAddBtree(
|
||||
)
|
||||
){
|
||||
pNew->iSortIdx = b ? iSortIdx : 0;
|
||||
/* TUNING: The base cost of an index scan is N + log2(N).
|
||||
** The log2(N) is for the initial seek to the beginning and the N
|
||||
** is for the scan itself. */
|
||||
pNew->rRun = sqlite3LogEstAdd(rSize, rLogSize);
|
||||
if( m==0 ){
|
||||
/* TUNING: Cost of a covering index scan is K*(N + log2(N)).
|
||||
** + The extra factor K of between 1.1 and 3.0 that depends
|
||||
** on the relative sizes of the table and the index. K
|
||||
** is smaller for smaller indices, thus favoring them.
|
||||
** The upper bound on K (3.0) matches the penalty factor
|
||||
** on a full table scan that tries to encourage the use of
|
||||
** indexed lookups over full scans.
|
||||
*/
|
||||
pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 +
|
||||
(15*pProbe->szIdxRow)/pTab->szTabRow;
|
||||
pNew->rRun += 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
|
||||
}else{
|
||||
/* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
|
||||
** which we will simplify to just N*log2(N) */
|
||||
pNew->rRun = rSize + rLogSize;
|
||||
/* TUNING: The cost of scanning a non-covering index is multiplied
|
||||
** by log2(N) to account for the binary search of the main table
|
||||
** that must happen for each row of the index.
|
||||
** TODO: Should there be a multiplier here, analogous to the 3x
|
||||
** multiplier for a fulltable scan or covering index scan, to
|
||||
** further discourage the use of an index scan? Or is the log2(N)
|
||||
** term sufficient discouragement?
|
||||
** TODO: What if some or all of the WHERE clause terms can be
|
||||
** computed without reference to the original table. Then the
|
||||
** penality should reduce to logK where K is the number of output
|
||||
** rows.
|
||||
*/
|
||||
pNew->rRun += rLogSize;
|
||||
}
|
||||
whereLoopOutputAdjust(pWC, pNew);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
@@ -4920,7 +4936,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
}
|
||||
}
|
||||
} /* End the loop over all WhereLoops from outer-most down to inner-most */
|
||||
if( obSat==obDone ) return nOrderBy;
|
||||
if( obSat==obDone ) return (i8)nOrderBy;
|
||||
if( !isOrderDistinct ){
|
||||
for(i=nOrderBy-1; i>0; i--){
|
||||
Bitmask m = MASKBIT(i) - 1;
|
||||
@@ -5041,11 +5057,19 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
|
||||
iLoop, pWLoop, &revMask);
|
||||
if( isOrdered>=0 && isOrdered<nOrderBy ){
|
||||
/* TUNING: Estimated cost of sorting cost as roughly N*log(N).
|
||||
** If some but not all of the columns are in sorted order, then
|
||||
** scale down the log(N) term. */
|
||||
LogEst rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy);
|
||||
LogEst rSortCost = nRowEst + estLog(nRowEst) + rScale - 66;
|
||||
/* TUNING: Estimated cost of sorting is N*log(N).
|
||||
** If the order-by clause has X terms but only the last Y terms
|
||||
** are out of order, then block-sorting will reduce the sorting
|
||||
** cost to N*log(N)*log(Y/X). The log(Y/X) term is computed
|
||||
** by rScale.
|
||||
** TODO: Should the sorting cost get a small multiplier to help
|
||||
** discourage the use of sorting and encourage the use of index
|
||||
** scans instead?
|
||||
*/
|
||||
LogEst rScale, rSortCost;
|
||||
assert( nOrderBy>0 );
|
||||
rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66;
|
||||
rSortCost = nRowEst + estLog(nRowEst) + rScale;
|
||||
/* TUNING: The cost of implementing DISTINCT using a B-TREE is
|
||||
** also N*log(N) but it has a larger constant of proportionality.
|
||||
** Multiply by 3.0. */
|
||||
|
||||
Reference in New Issue
Block a user