aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/btree.c3
-rw-r--r--src/mem5.c2
-rw-r--r--src/shell.c2
-rw-r--r--src/sqliteInt.h1
-rw-r--r--src/vdbe.c2
-rw-r--r--src/vdbe.h4
-rw-r--r--src/vdbeInt.h2
-rw-r--r--src/vdbeaux.c27
-rw-r--r--src/where.c48
9 files changed, 66 insertions, 25 deletions
diff --git a/src/btree.c b/src/btree.c
index 43d41d67e..c3055836c 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -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;
diff --git a/src/mem5.c b/src/mem5.c
index 5d75611a3..67615bb96 100644
--- a/src/mem5.c
+++ b/src/mem5.c
@@ -248,7 +248,7 @@ static void *memsys5MallocUnsafe(int nByte){
** block. If not, then split a block of the next larger power of
** two in order to create a new free block of size iLogsize.
*/
- for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
+ for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){}
if( iBin>LOGMAX ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
diff --git a/src/shell.c b/src/shell.c
index 131311270..f380962a8 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -2130,10 +2130,12 @@ static void tryToClone(struct callback_data *p, const char *zNewDb){
fprintf(stderr, "Cannot create output database: %s\n",
sqlite3_errmsg(newDb));
}else{
+ sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
tryToCloneSchema(p, newDb, "type!='table'", 0);
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
+ sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
}
sqlite3_close(newDb);
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 683df99ac..cbbdc2b60 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1635,6 +1635,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) */
diff --git a/src/vdbe.c b/src/vdbe.c
index 7a1d42dc1..e16639690 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -5990,7 +5990,7 @@ case OP_VOpen: {
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 P3 P4 *
-** Synopsis: iPlan=r[P3] zPlan='P4'
+** Synopsis: iplan=r[P3] zplan='P4'
**
** P1 is a cursor opened using VOpen. P2 is an address to jump to if
** the filtered result set is empty.
diff --git a/src/vdbe.h b/src/vdbe.h
index 5892c5def..53b0749f8 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -213,10 +213,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
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index a276b1ecb..7be25e56a 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -411,7 +411,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*);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 806739a35..e98707f7f 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -3407,10 +3407,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 */
@@ -3436,7 +3439,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;
}
@@ -3513,7 +3519,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;
@@ -3539,7 +3546,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);
@@ -3598,7 +3606,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];
@@ -3696,7 +3704,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;
@@ -3717,7 +3725,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);
@@ -3882,7 +3893,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;
diff --git a/src/where.c b/src/where.c
index 15084f099..dd6893f69 100644
--- a/src/where.c
+++ b/src/where.c
@@ -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. */
@@ -5900,7 +5924,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
- pOp->opcode = OP_SCopy;
+ pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + pTabItem->regResult;
pOp->p2 = pOp->p3;
pOp->p3 = 0;