From 1fed5dab0dedceca104c51670cf74114587b536f Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 25 Feb 2014 21:01:25 +0000 Subject: [PATCH 01/10] Attempt to speed up sqlite3VdbeRecordCompare() by various means. This code is in an interim state. FossilOrigin-Name: 85206e0bbac29adab52bef795f6d1479f2ae2c0e --- manifest | 31 ++-- manifest.uuid | 2 +- src/btree.c | 12 +- src/sqliteInt.h | 7 +- src/vdbe.c | 23 ++- src/vdbe.h | 3 + src/vdbeaux.c | 413 ++++++++++++++++++++++++++++++++++++++++++++--- src/vdbemem.c | 113 ------------- src/vdbesort.c | 2 +- test/pragma.test | 3 + 10 files changed, 440 insertions(+), 169 deletions(-) diff --git a/manifest b/manifest index f25d3185ff..2d70d7d908 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Also\sadjust\sthe\sorder\sof\sfiles\sin\sthe\samalgamation\sto\sensure\sthat\n_FILE_OFFSET_BITS\sis\sdefined\sbefore\sany\s#include,\sfor\sQNX. -D 2014-02-25T18:12:58.878 +C Attempt\sto\sspeed\sup\ssqlite3VdbeRecordCompare()\sby\svarious\smeans.\sThis\scode\sis\sin\san\sinterim\sstate. +D 2014-02-25T21:01:25.824 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -163,7 +163,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c b945df4f0114b4cc71006acc2fbb1333fb33a200 +F src/btree.c f4d85c3e2e189a219965d6d4525330333735fd1d F src/btree.h 9e0f97c01b972f779eb7655cfb4f8727fd6dc26f F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4 F src/build.c 00ce613bc2256e525c9195cb10d0df7bcc48d1f0 @@ -221,7 +221,7 @@ F src/shell.c 3dd86bf73ccd079f0e32ef5069600586085e8239 F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 6725dc99b3985a97bad315910e59c3f7f5058916 +F src/sqliteInt.h 6d868994f476b616ddb1795a51aa83c331ef5a62 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -277,14 +277,14 @@ F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c 6c8f28911e702151c8ef03c568db5a066d3a85d4 -F src/vdbe.h 147027d6e8e667a63e87177a38e2b42c71fdacf8 +F src/vdbe.c ab910206dd8c9c5c1455f82953934bdbfe0bcc2a +F src/vdbe.h 0758eff7f1bf939bcafa377b2fafba4f5be63007 F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c 8b8eeb3cd89e4b3d4f40186344915b49b7c1c0f7 +F src/vdbeaux.c 988269c675ebb75a3610479840b65bcb8ea92647 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 -F src/vdbemem.c 06603e8e9d2f3247b68c6bbe4bd37fb6721b5bda -F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147 +F src/vdbemem.c 25cc487244bf6ad647105c5adbc3052403dfd143 +F src/vdbesort.c 5144d84bd7d0d2545af1c6322edbbf07f97e3892 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 @@ -735,7 +735,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04 -F test/pragma.test e882183ecd21d064cec5c7aaea174fbd36293429 +F test/pragma.test c1bc3a29f664b57d0ae40b498ad31f370de8daa6 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1 @@ -1151,7 +1151,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 953cdd6adadfd46b51ad61d7939cecca154a02cb -R d169e5164f16cb0355a3972eba04326c -U drh -Z 6c6f89e1dd41d2a146386cfa06ae53d9 +P 23001a85cd334090cf6c70d4d7e722a01f4f6899 +R 04ade79c9b23add6f2d6adf0c34db1e4 +T *branch * experimental +T *sym-experimental * +T -sym-trunk * +U dan +Z d3f147085a7b8a8eca4578239439871b diff --git a/manifest.uuid b/manifest.uuid index a069c374c5..dd611d410f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -23001a85cd334090cf6c70d4d7e722a01f4f6899 \ No newline at end of file +85206e0bbac29adab52bef795f6d1479f2ae2c0e \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 4fd8e27bf4..6c5f02403e 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4547,6 +4547,7 @@ int sqlite3BtreeMovetoUnpacked( int *pRes /* Write search results here */ ){ int rc; + int (*xRecordCompare)(int, const void*, UnpackedRecord*); assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); @@ -4568,6 +4569,11 @@ int sqlite3BtreeMovetoUnpacked( } } + if( pIdxKey ){ + xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); + assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1); + } + rc = moveToRoot(pCur); if( rc ){ return rc; @@ -4652,14 +4658,14 @@ int sqlite3BtreeMovetoUnpacked( ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); - c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); - c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated @@ -4680,7 +4686,7 @@ int sqlite3BtreeMovetoUnpacked( sqlite3_free(pCellKey); goto moveto_finish; } - c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); + c = xRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } if( c<0 ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 72fe47be5a..76dea413e0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1590,15 +1590,10 @@ struct KeyInfo { struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ - u8 flags; /* Boolean settings. UNPACKED_... below */ + char default_rc; /* Comparison result if keys are equal */ Mem *aMem; /* Values */ }; -/* -** Allowed values of UnpackedRecord.flags -*/ -#define UNPACKED_INCRKEY 0x01 /* Make this key an epsilon larger */ -#define UNPACKED_PREFIX_MATCH 0x02 /* A prefix match is considered OK */ /* ** Each SQL index is represented in memory by an diff --git a/src/vdbe.c b/src/vdbe.c index 5ab0127658..097f182a23 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3555,16 +3555,16 @@ case OP_SeekGT: { /* jump, in3 */ /* The next line of code computes as follows, only faster: ** if( oc==OP_SeekGT || oc==OP_SeekLE ){ - ** r.flags = UNPACKED_INCRKEY; + ** r.default_rc = -1; ** }else{ - ** r.flags = 0; + ** r.default_rc = +1; ** } */ - r.flags = (u8)(UNPACKED_INCRKEY * (1 & (oc - OP_SeekLT))); - assert( oc!=OP_SeekGT || r.flags==UNPACKED_INCRKEY ); - assert( oc!=OP_SeekLE || r.flags==UNPACKED_INCRKEY ); - assert( oc!=OP_SeekGE || r.flags==0 ); - assert( oc!=OP_SeekLT || r.flags==0 ); + r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1); + assert( oc!=OP_SeekGT || r.default_rc==-1 ); + assert( oc!=OP_SeekLE || r.default_rc==-1 ); + assert( oc!=OP_SeekGE || r.default_rc==+1 ); + assert( oc!=OP_SeekLT || r.default_rc==+1 ); r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG @@ -3722,7 +3722,6 @@ case OP_Found: { /* jump, in3 */ if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]); #endif } - r.flags = UNPACKED_PREFIX_MATCH; pIdxKey = &r; }else{ pIdxKey = sqlite3VdbeAllocUnpackedRecord( @@ -3732,8 +3731,8 @@ case OP_Found: { /* jump, in3 */ assert( pIn3->flags & MEM_Blob ); assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); - pIdxKey->flags |= UNPACKED_PREFIX_MATCH; } + pIdxKey->default_rc = 0; if( pOp->opcode==OP_NoConflict ){ /* For the OP_NoConflict opcode, take the jump if any of the ** input fields are NULL, since any key with a NULL will not @@ -4622,7 +4621,7 @@ case OP_IdxDelete: { assert( pOp->p5==0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p3; - r.flags = UNPACKED_PREFIX_MATCH; + r.default_rc = 0; r.aMem = &aMem[pOp->p2]; #ifdef SQLITE_DEBUG { int i; for(i=0; ip4.i; if( pOp->opcodeopcode==OP_IdxLE || pOp->opcode==OP_IdxGT ); - r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH; + r.default_rc = -1; }else{ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); - r.flags = UNPACKED_PREFIX_MATCH; + r.default_rc = 0; } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG diff --git a/src/vdbe.h b/src/vdbe.h index 66c69eec23..af07831faa 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -214,6 +214,9 @@ void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); +typedef int (*RecordCompare)(int,const void*, UnpackedRecord*); +RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *); + #ifndef SQLITE_OMIT_TRIGGER void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif diff --git a/src/vdbeaux.c b/src/vdbeaux.c index ef70f8ae3f..e817ccb23f 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3102,7 +3102,7 @@ void sqlite3VdbeRecordUnpack( u32 szHdr; Mem *pMem = p->aMem; - p->flags = 0; + p->default_rc = 0; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); idx = getVarint32(aKey, szHdr); d = szHdr; @@ -3123,6 +3123,215 @@ void sqlite3VdbeRecordUnpack( p->nField = u; } +static int vdbeRecordCompareString( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + const u8 *aKey1 = (const u8*)pKey1; + int szHdr; + int serial_type; + int res; + + szHdr = aKey1[0]; + getVarint32(&aKey1[1], serial_type); + + if( serial_type<12 ){ + res = -1; /* (pKey1/nKey1) is a number or a null */ + }else if( !(serial_type & 0x01) ){ + res = +1; /* (pKey1/nKey1) is a blob */ + }else{ + int nCmp; + int nStr; + aKey1 = &aKey1[szHdr]; + + nStr = (serial_type-12) / 2; + if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */ + nCmp = MIN( pPKey2->aMem[0].n, nStr ); + res = memcmp(aKey1, pPKey2->aMem[0].z, nCmp); + + if( res==0 ){ + res = nStr - pPKey2->aMem[0].n; + if( res==0 ) res = pPKey2->default_rc; + } + } + + assert( (res==0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)==0) + || (res<0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)<0) + || (res>0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)>0) + ); + return res; +} + +static int vdbeRecordCompareInt( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + const u8 *aKey1 = (const u8*)pKey1; + int szHdr; + int serial_type; + int res; + + szHdr = aKey1[0]; + getVarint32(&aKey1[1], serial_type); + + if( serial_type==0 ){ + res = -1; /* NULL values are smaller than integers */ + }else if( serial_type>=12 ){ + res = +1; /* text/blob values are greater */ + }else{ + Mem mem; + sqlite3VdbeSerialGet(&aKey1[szHdr], serial_type, &mem); + if( mem.flags & MEM_Int ){ + i64 v = pPKey2->aMem[0].u.i; + if( v>mem.u.i ){ + res = -1; + }else if( vdefault_rc; + } + }else{ + double v = (double)pPKey2->aMem[0].u.i; + if( v>mem.r ){ + res = -1; + }else if( vdefault_rc; + } + } + } + + assert( (res==0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)==0) + || (res<0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)<0) + || (res>0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)>0) + ); + return res; +} + +static int vdbeCompareMemString( + const Mem *pMem1, + const Mem *pMem2, + const CollSeq *pColl +){ + if( pMem1->enc==pColl->enc ){ + /* The strings are already in the correct encoding. Call the + ** comparison function directly */ + return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); + }else{ + int rc; + const void *v1, *v2; + int n1, n2; + Mem c1; + Mem c2; + memset(&c1, 0, sizeof(c1)); + memset(&c2, 0, sizeof(c2)); + sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); + sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); + v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); + n1 = v1==0 ? 0 : c1.n; + v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); + n2 = v2==0 ? 0 : c2.n; + rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); + sqlite3VdbeMemRelease(&c1); + sqlite3VdbeMemRelease(&c2); + return rc; + } +} + +/* +** Compare the values contained by the two memory cells, returning +** negative, zero or positive if pMem1 is less than, equal to, or greater +** than pMem2. Sorting order is NULL's first, followed by numbers (integers +** and reals) sorted numerically, followed by text ordered by the collating +** sequence pColl and finally blob's ordered by memcmp(). +** +** Two NULL values are considered equal by this function. +*/ +int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ + int rc; + int f1, f2; + int combined_flags; + + f1 = pMem1->flags; + f2 = pMem2->flags; + combined_flags = f1|f2; + assert( (combined_flags & MEM_RowSet)==0 ); + + /* If one value is NULL, it is less than the other. If both values + ** are NULL, return 0. + */ + if( combined_flags&MEM_Null ){ + return (f2&MEM_Null) - (f1&MEM_Null); + } + + /* If one value is a number and the other is not, the number is less. + ** If both are numbers, compare as reals if one is a real, or as integers + ** if both values are integers. + */ + if( combined_flags&(MEM_Int|MEM_Real) ){ + double r1, r2; + if( (f1 & f2 & MEM_Int)!=0 ){ + if( pMem1->u.i < pMem2->u.i ) return -1; + if( pMem1->u.i > pMem2->u.i ) return 1; + return 0; + } + if( (f1&MEM_Real)!=0 ){ + r1 = pMem1->r; + }else if( (f1&MEM_Int)!=0 ){ + r1 = (double)pMem1->u.i; + }else{ + return 1; + } + if( (f2&MEM_Real)!=0 ){ + r2 = pMem2->r; + }else if( (f2&MEM_Int)!=0 ){ + r2 = (double)pMem2->u.i; + }else{ + return -1; + } + if( r1r2 ) return 1; + return 0; + } + + /* If one value is a string and the other is a blob, the string is less. + ** If both are strings, compare using the collating functions. + */ + if( combined_flags&MEM_Str ){ + if( (f1 & MEM_Str)==0 ){ + return 1; + } + if( (f2 & MEM_Str)==0 ){ + return -1; + } + + assert( pMem1->enc==pMem2->enc ); + assert( pMem1->enc==SQLITE_UTF8 || + pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); + + /* The collation sequence must be defined at this point, even if + ** the user deletes the collation sequence after the vdbe program is + ** compiled (this was not always the case). + */ + assert( !pColl || pColl->xCmp ); + + if( pColl ){ + return vdbeCompareMemString(pMem1, pMem2, pColl); + } + /* If a NULL pointer was passed as the collate function, fall through + ** to the blob case and use memcmp(). */ + } + + /* Both values must be blobs. Compare using memcmp(). */ + rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); + if( rc==0 ){ + rc = pMem1->n - pMem2->n; + } + return rc; +} + + /* ** This function compares the two table rows or index records ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero @@ -3140,7 +3349,7 @@ void sqlite3VdbeRecordUnpack( ** equal, then the keys are considered to be equal and ** the parts beyond the common prefix are ignored. */ -int sqlite3VdbeRecordCompare( +static int vdbeRecordComparePrev( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ @@ -3216,25 +3425,192 @@ int sqlite3VdbeRecordCompare( assert( mem1.zMalloc==0 ); /* rc==0 here means that one of the keys ran out of fields and - ** all the fields up to that point were equal. If the UNPACKED_INCRKEY - ** flag is set, then break the tie by treating key2 as larger. - ** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes - ** are considered to be equal. Otherwise, the longer key is the - ** larger. As it happens, the pPKey2 will always be the longer - ** if there is a difference. - */ - assert( rc==0 ); - if( pPKey2->flags & UNPACKED_INCRKEY ){ - rc = -1; - }else if( pPKey2->flags & UNPACKED_PREFIX_MATCH ){ - /* Leave rc==0 */ - }else if( idx1default_rc; } +int sqlite3VdbeRecordCompare( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + u32 d1; /* Offset into aKey[] of next data element */ + u32 idx1; /* Offset into aKey[] of next header element */ + u32 szHdr1; /* Number of bytes in header */ + int i = 0; + int rc = 0; + KeyInfo *pKeyInfo = pPKey2->pKeyInfo; + const unsigned char *aKey1 = (const unsigned char *)pKey1; + Mem mem1; + +#ifdef SQLITE_DEBUG + int expected = vdbeRecordComparePrev(nKey1, pKey1, pPKey2); + static int nCall = 0; + nCall++; +#endif + + VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ + + idx1 = getVarint32(aKey1, szHdr1); + d1 = szHdr1; + assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField + || CORRUPT_DB ); + assert( pPKey2->pKeyInfo->aSortOrder!=0 ); + assert( pPKey2->pKeyInfo->nField>0 ); + assert( idx1<=szHdr1 || CORRUPT_DB ); + do{ + Mem *pRhs = &pPKey2->aMem[i]; + u32 serial_type; + + /* RHS is an integer */ + if( pRhs->flags & MEM_Int ){ + serial_type = aKey1[idx1]; + if( serial_type>=12 ){ + rc = +1; + }else if( serial_type==0 ){ + rc = -1; + }else{ + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); + if( serial_type==7 ){ + double rhs = (double)pRhs->u.i; + if( mem1.rrhs ){ + rc = +1; + } + }else{ + i64 rhs = pRhs->u.i; + if( mem1.u.irhs ){ + rc = +1; + } + } + } + } + + /* RHS is real */ + else if( pRhs->flags & MEM_Real ){ + serial_type = aKey1[idx1]; + if( serial_type>=12 ){ + rc = +1; + }else if( serial_type==0 ){ + rc = -1; + }else{ + double rhs = pRhs->r; + double lhs; + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); + if( serial_type==7 ){ + lhs = mem1.r; + }else{ + lhs = mem1.u.i; + } + if( lhsrhs ){ + rc = +1; + } + } + } + + /* RHS is a string */ + else if( pRhs->flags & MEM_Str ){ + getVarint32(&aKey1[idx1], serial_type); + if( serial_type<12 ){ + rc = -1; + }else if( !(serial_type & 0x01) ){ + rc = +1; + }else{ + mem1.n = (serial_type - 12) / 2; + if( (d1+mem1.n) > nKey1 ){ + rc = 1; /* Corruption */ + }else if( pKeyInfo->aColl[i] ){ + mem1.enc = pKeyInfo->enc; + mem1.db = pKeyInfo->db; + mem1.flags = MEM_Str; + mem1.z = &aKey1[d1]; + rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]); + }else{ + int nCmp = MIN(mem1.n, pRhs->n); + rc = memcmp(&aKey1[d1], pRhs->z, nCmp); + if( rc==0 ) rc = mem1.n - pRhs->n; + } + } + } + + /* RHS is a blob */ + else if( pRhs->flags & MEM_Blob ){ + getVarint32(&aKey1[idx1], serial_type); + if( serial_type<12 || (serial_type & 0x01) ){ + rc = -1; + }else{ + int nStr = (serial_type - 12) / 2; + if( (d1+nStr) > nKey1 ){ + rc = 1; /* Corruption */ + }else{ + int nCmp = MIN(nStr, pRhs->n); + rc = memcmp(&aKey1[d1], pRhs->z, nCmp); + if( rc==0 ) rc = nStr - pRhs->n; + } + } + } + + /* RHS is null */ + else{ + serial_type = aKey1[idx1]; + rc = (serial_type!=0); + } + + if( rc!=0 ){ + assert( mem1.zMalloc==0 ); /* See comment below */ + if( pKeyInfo->aSortOrder[i] ){ + rc = -rc; +#if 0 + assert( (rc>0 && (rc^(int)0x80000000)<0) + || (rc<0 && (rc^(int)0x80000000)>0) ); + assert( sizeof(int)==4 ); + rc ^= (int)0x80000000; /* similar in spirit to: "rc = -rc;" */ + assert( rc!=0 ); +#endif + } + assert( (rc<0 && expected<0) || (rc>0 && expected>0) || CORRUPT_DB ); + return rc; + } + + i++; + d1 += sqlite3VdbeSerialTypeLen(serial_type); + idx1 += sqlite3VarintLen(serial_type); + }while( idx1nField && d1<=nKey1 ); + + /* No memory allocation is ever used on mem1. Prove this using + ** the following assert(). If the assert() fails, it indicates a + ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). + */ + assert( mem1.zMalloc==0 ); + + /* rc==0 here means that one or both of the keys ran out of fields and + ** all the fields up to that point were equal. Return the the default_rc + ** value. */ + assert( pPKey2->default_rc==expected ); + return pPKey2->default_rc; +} + +RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ + if( p->nField==1 && p->pKeyInfo->aSortOrder[0]==0 ){ + int flags = p->aMem[0].flags; + if( (flags & MEM_Int) ){ + return vdbeRecordCompareInt; + }else if( (p->aMem[0].flags&(MEM_Int|MEM_Real|MEM_Null|MEM_Blob))==0 + && p->pKeyInfo->aColl[0]==0 + ){ + return vdbeRecordCompareString; + } + } + return sqlite3VdbeRecordCompare; +} + + /* ** pCur points at an index entry created using the OP_MakeRecord opcode. ** Read the rowid (the last field in the record) and store it in *rowid. @@ -3347,7 +3723,6 @@ int sqlite3VdbeIdxKeyCompare( if( rc ){ return rc; } - assert( pUnpacked->flags & UNPACKED_PREFIX_MATCH ); *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); sqlite3VdbeMemRelease(&m); return SQLITE_OK; diff --git a/src/vdbemem.c b/src/vdbemem.c index bcf9586b3f..4936f40016 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -754,119 +754,6 @@ int sqlite3VdbeMemSetStr( return SQLITE_OK; } -/* -** Compare the values contained by the two memory cells, returning -** negative, zero or positive if pMem1 is less than, equal to, or greater -** than pMem2. Sorting order is NULL's first, followed by numbers (integers -** and reals) sorted numerically, followed by text ordered by the collating -** sequence pColl and finally blob's ordered by memcmp(). -** -** Two NULL values are considered equal by this function. -*/ -int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ - int rc; - int f1, f2; - int combined_flags; - - f1 = pMem1->flags; - f2 = pMem2->flags; - combined_flags = f1|f2; - assert( (combined_flags & MEM_RowSet)==0 ); - - /* If one value is NULL, it is less than the other. If both values - ** are NULL, return 0. - */ - if( combined_flags&MEM_Null ){ - return (f2&MEM_Null) - (f1&MEM_Null); - } - - /* If one value is a number and the other is not, the number is less. - ** If both are numbers, compare as reals if one is a real, or as integers - ** if both values are integers. - */ - if( combined_flags&(MEM_Int|MEM_Real) ){ - double r1, r2; - if( (f1 & f2 & MEM_Int)!=0 ){ - if( pMem1->u.i < pMem2->u.i ) return -1; - if( pMem1->u.i > pMem2->u.i ) return 1; - return 0; - } - if( (f1&MEM_Real)!=0 ){ - r1 = pMem1->r; - }else if( (f1&MEM_Int)!=0 ){ - r1 = (double)pMem1->u.i; - }else{ - return 1; - } - if( (f2&MEM_Real)!=0 ){ - r2 = pMem2->r; - }else if( (f2&MEM_Int)!=0 ){ - r2 = (double)pMem2->u.i; - }else{ - return -1; - } - if( r1r2 ) return 1; - return 0; - } - - /* If one value is a string and the other is a blob, the string is less. - ** If both are strings, compare using the collating functions. - */ - if( combined_flags&MEM_Str ){ - if( (f1 & MEM_Str)==0 ){ - return 1; - } - if( (f2 & MEM_Str)==0 ){ - return -1; - } - - assert( pMem1->enc==pMem2->enc ); - assert( pMem1->enc==SQLITE_UTF8 || - pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); - - /* The collation sequence must be defined at this point, even if - ** the user deletes the collation sequence after the vdbe program is - ** compiled (this was not always the case). - */ - assert( !pColl || pColl->xCmp ); - - if( pColl ){ - if( pMem1->enc==pColl->enc ){ - /* The strings are already in the correct encoding. Call the - ** comparison function directly */ - return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); - }else{ - const void *v1, *v2; - int n1, n2; - Mem c1; - Mem c2; - memset(&c1, 0, sizeof(c1)); - memset(&c2, 0, sizeof(c2)); - sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); - sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); - v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); - n1 = v1==0 ? 0 : c1.n; - v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); - n2 = v2==0 ? 0 : c2.n; - rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); - sqlite3VdbeMemRelease(&c1); - sqlite3VdbeMemRelease(&c2); - return rc; - } - } - /* If a NULL pointer was passed as the collate function, fall through - ** to the blob case and use memcmp(). */ - } - - /* Both values must be blobs. Compare using memcmp(). */ - rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); - if( rc==0 ){ - rc = pMem1->n - pMem2->n; - } - return rc; -} - /* ** Move data out of a btree key or data field and into a Mem structure. ** The data or key is taken from the entry that pCur is currently pointing diff --git a/src/vdbesort.c b/src/vdbesort.c index 3e4cad5b4a..c4d15d6872 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -409,7 +409,7 @@ static void vdbeSorterCompare( return; } } - r2->flags |= UNPACKED_PREFIX_MATCH; + assert( r2->default_rc==0 ); } *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2); diff --git a/test/pragma.test b/test/pragma.test index 1043170378..fcbb1808fa 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -1575,6 +1575,8 @@ do_test pragma-20.8 { forcedelete data_dir } ;# endif windows +database_may_be_corrupt + do_test 21.1 { # Create a corrupt database in testerr.db. And a non-corrupt at test.db. # @@ -1680,4 +1682,5 @@ do_test 23.5 { } } {0 0 t1 y {} {NO ACTION} {NO ACTION} NONE} +database_never_corrupt finish_test From 3b9330f83ce327bd34acb6e48a910fcc41f2dd92 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 27 Feb 2014 20:44:18 +0000 Subject: [PATCH 02/10] Further changes to sqlite3VdbeRecordCompare(). FossilOrigin-Name: 570893740067a7caa952f259fa078cdf67017d71 --- manifest | 23 +-- manifest.uuid | 2 +- src/btree.c | 13 +- src/sqliteInt.h | 2 + src/vdbe.h | 5 +- src/vdbeaux.c | 495 +++++++++++++++++++++++++++++------------------- src/vdbesort.c | 5 + 7 files changed, 333 insertions(+), 212 deletions(-) diff --git a/manifest b/manifest index 2d70d7d908..e7df2f4996 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Attempt\sto\sspeed\sup\ssqlite3VdbeRecordCompare()\sby\svarious\smeans.\sThis\scode\sis\sin\san\sinterim\sstate. -D 2014-02-25T21:01:25.824 +C Further\schanges\sto\ssqlite3VdbeRecordCompare(). +D 2014-02-27T20:44:18.479 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -163,7 +163,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c f4d85c3e2e189a219965d6d4525330333735fd1d +F src/btree.c 77f175987c80ebec063f8653cb7d300776411413 F src/btree.h 9e0f97c01b972f779eb7655cfb4f8727fd6dc26f F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4 F src/build.c 00ce613bc2256e525c9195cb10d0df7bcc48d1f0 @@ -221,7 +221,7 @@ F src/shell.c 3dd86bf73ccd079f0e32ef5069600586085e8239 F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 6d868994f476b616ddb1795a51aa83c331ef5a62 +F src/sqliteInt.h 7b42e02c1ca4599b5420d44cb549460b2348139a F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -278,13 +278,13 @@ F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 F src/vdbe.c ab910206dd8c9c5c1455f82953934bdbfe0bcc2a -F src/vdbe.h 0758eff7f1bf939bcafa377b2fafba4f5be63007 +F src/vdbe.h 6833579fc0fbdc1c933e34519064841abda5b9b3 F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c 988269c675ebb75a3610479840b65bcb8ea92647 +F src/vdbeaux.c 80e5315957377554c9011858f5afde61afedc181 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 25cc487244bf6ad647105c5adbc3052403dfd143 -F src/vdbesort.c 5144d84bd7d0d2545af1c6322edbbf07f97e3892 +F src/vdbesort.c 72290f12428973c2c6b9d4f95ad0a7c8181e1280 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 @@ -1151,10 +1151,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 23001a85cd334090cf6c70d4d7e722a01f4f6899 -R 04ade79c9b23add6f2d6adf0c34db1e4 -T *branch * experimental -T *sym-experimental * -T -sym-trunk * +P 85206e0bbac29adab52bef795f6d1479f2ae2c0e +R eb22cd7a0c8c7d3bc8c75c472c26dd6a U dan -Z d3f147085a7b8a8eca4578239439871b +Z 91158d7f280c804b2fe508b4511e22e9 diff --git a/manifest.uuid b/manifest.uuid index dd611d410f..927ab5603a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -85206e0bbac29adab52bef795f6d1479f2ae2c0e \ No newline at end of file +570893740067a7caa952f259fa078cdf67017d71 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 6c5f02403e..c0b04cc08c 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4547,7 +4547,7 @@ int sqlite3BtreeMovetoUnpacked( int *pRes /* Write search results here */ ){ int rc; - int (*xRecordCompare)(int, const void*, UnpackedRecord*); + RecordCompare xRecordCompare; assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); @@ -4571,7 +4571,10 @@ int sqlite3BtreeMovetoUnpacked( if( pIdxKey ){ xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); - assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1); + assert( pIdxKey->default_rc==1 + || pIdxKey->default_rc==0 + || pIdxKey->default_rc==-1 + ); } rc = moveToRoot(pCur); @@ -4658,14 +4661,14 @@ int sqlite3BtreeMovetoUnpacked( ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + c = xRecordCompare(nCell, (void*)&pCell[1], pCell[1], 1, pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + c = xRecordCompare(nCell, (void*)&pCell[2], pCell[2], 1, pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated @@ -4686,7 +4689,7 @@ int sqlite3BtreeMovetoUnpacked( sqlite3_free(pCellKey); goto moveto_finish; } - c = xRecordCompare(nCell, pCellKey, pIdxKey); + c = xRecordCompare(nCell, pCellKey, ((u8*)pCellKey)[0], 1, pIdxKey); sqlite3_free(pCellKey); } if( c<0 ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 76dea413e0..b19a0bd453 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1592,6 +1592,8 @@ struct UnpackedRecord { u16 nField; /* Number of entries in apMem[] */ char default_rc; /* Comparison result if keys are equal */ Mem *aMem; /* Values */ + int r1; + int r2; }; diff --git a/src/vdbe.h b/src/vdbe.h index af07831faa..c08512e7aa 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -214,8 +214,9 @@ void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*, UnpackedRecord*); -RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *); +typedef int (*RecordCompare)(int,const void*,int,u32,UnpackedRecord*); +RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); +RecordCompare sqlite3VdbeFindSorterCompare(KeyInfo*); #ifndef SQLITE_OMIT_TRIGGER void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index e817ccb23f..8ca605ebe6 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3123,90 +3123,102 @@ void sqlite3VdbeRecordUnpack( p->nField = u; } -static int vdbeRecordCompareString( +/* +** This function compares the two table rows or index records +** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero +** or positive integer if key1 is less than, equal to or +** greater than key2. The {nKey1, pKey1} key must be a blob +** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 +** key must be a parsed key such as obtained from +** sqlite3VdbeParseRecord. +** +** Key1 and Key2 do not have to contain the same number of fields. +** The key with fewer fields is usually compares less than the +** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set +** and the common prefixes are equal, then key1 is less than key2. +** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are +** equal, then the keys are considered to be equal and +** the parts beyond the common prefix are ignored. +*/ +static int vdbeRecordComparePrev( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ - const u8 *aKey1 = (const u8*)pKey1; - int szHdr; - int serial_type; - int res; + u32 d1; /* Offset into aKey[] of next data element */ + u32 idx1; /* Offset into aKey[] of next header element */ + u32 szHdr1; /* Number of bytes in header */ + int i = 0; + int rc = 0; + const unsigned char *aKey1 = (const unsigned char *)pKey1; + KeyInfo *pKeyInfo; + Mem mem1; - szHdr = aKey1[0]; - getVarint32(&aKey1[1], serial_type); + pKeyInfo = pPKey2->pKeyInfo; + mem1.enc = pKeyInfo->enc; + mem1.db = pKeyInfo->db; + /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ + VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ - if( serial_type<12 ){ - res = -1; /* (pKey1/nKey1) is a number or a null */ - }else if( !(serial_type & 0x01) ){ - res = +1; /* (pKey1/nKey1) is a blob */ - }else{ - int nCmp; - int nStr; - aKey1 = &aKey1[szHdr]; + /* Compilers may complain that mem1.u.i is potentially uninitialized. + ** We could initialize it, as shown here, to silence those complaints. + ** But in fact, mem1.u.i will never actually be used uninitialized, and doing + ** the unnecessary initialization has a measurable negative performance + ** impact, since this routine is a very high runner. And so, we choose + ** to ignore the compiler warnings and leave this variable uninitialized. + */ + /* mem1.u.i = 0; // not needed, here to silence compiler warning */ + + idx1 = getVarint32(aKey1, szHdr1); + d1 = szHdr1; + assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); + assert( pKeyInfo->aSortOrder!=0 ); + assert( pKeyInfo->nField>0 ); + assert( idx1<=szHdr1 || CORRUPT_DB ); + do{ + u32 serial_type1; - nStr = (serial_type-12) / 2; - if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */ - nCmp = MIN( pPKey2->aMem[0].n, nStr ); - res = memcmp(aKey1, pPKey2->aMem[0].z, nCmp); + /* Read the serial types for the next element in each key. */ + idx1 += getVarint32( aKey1+idx1, serial_type1 ); - if( res==0 ){ - res = nStr - pPKey2->aMem[0].n; - if( res==0 ) res = pPKey2->default_rc; + /* Verify that there is enough key space remaining to avoid + ** a buffer overread. The "d1+serial_type1+2" subexpression will + ** always be greater than or equal to the amount of required key space. + ** Use that approximation to avoid the more expensive call to + ** sqlite3VdbeSerialTypeLen() in the common case. + */ + if( d1+serial_type1+2>(u32)nKey1 + && d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 + ){ + break; } - } - assert( (res==0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)==0) - || (res<0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)<0) - || (res>0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)>0) - ); - return res; -} + /* Extract the values to be compared. + */ + d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); -static int vdbeRecordCompareInt( - int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2 /* Right key */ -){ - const u8 *aKey1 = (const u8*)pKey1; - int szHdr; - int serial_type; - int res; - - szHdr = aKey1[0]; - getVarint32(&aKey1[1], serial_type); - - if( serial_type==0 ){ - res = -1; /* NULL values are smaller than integers */ - }else if( serial_type>=12 ){ - res = +1; /* text/blob values are greater */ - }else{ - Mem mem; - sqlite3VdbeSerialGet(&aKey1[szHdr], serial_type, &mem); - if( mem.flags & MEM_Int ){ - i64 v = pPKey2->aMem[0].u.i; - if( v>mem.u.i ){ - res = -1; - }else if( vdefault_rc; - } - }else{ - double v = (double)pPKey2->aMem[0].u.i; - if( v>mem.r ){ - res = -1; - }else if( vdefault_rc; + /* Do the comparison + */ + rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); + if( rc!=0 ){ + assert( mem1.zMalloc==0 ); /* See comment below */ + if( pKeyInfo->aSortOrder[i] ){ + rc = -rc; /* Invert the result for DESC sort order. */ } + return rc; } - } + i++; + }while( idx1nField ); - assert( (res==0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)==0) - || (res<0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)<0) - || (res>0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)>0) - ); - return res; + /* No memory allocation is ever used on mem1. Prove this using + ** the following assert(). If the assert() fails, it indicates a + ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). + */ + assert( mem1.zMalloc==0 ); + + /* rc==0 here means that one of the keys ran out of fields and + ** all the fields up to that point were equal. Return the the default_rc + ** value. */ + return pPKey2->default_rc; } static int vdbeCompareMemString( @@ -3332,114 +3344,43 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ } -/* -** This function compares the two table rows or index records -** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero -** or positive integer if key1 is less than, equal to or -** greater than key2. The {nKey1, pKey1} key must be a blob -** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 -** key must be a parsed key such as obtained from -** sqlite3VdbeParseRecord. -** -** Key1 and Key2 do not have to contain the same number of fields. -** The key with fewer fields is usually compares less than the -** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set -** and the common prefixes are equal, then key1 is less than key2. -** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are -** equal, then the keys are considered to be equal and -** the parts beyond the common prefix are ignored. -*/ -static int vdbeRecordComparePrev( - int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2 /* Right key */ -){ - u32 d1; /* Offset into aKey[] of next data element */ - u32 idx1; /* Offset into aKey[] of next header element */ - u32 szHdr1; /* Number of bytes in header */ - int i = 0; - int rc = 0; - const unsigned char *aKey1 = (const unsigned char *)pKey1; - KeyInfo *pKeyInfo; - Mem mem1; +static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ + switch( serial_type ){ + case 1: + return (char)aKey[0]; + case 2: + return ((char)aKey[0] << 8) | aKey[1]; + case 3: + return ((char)aKey[0] << 16) | (aKey[1] << 8) | aKey[2]; + case 4: + return ((char)aKey[0]<<24) | (aKey[1]<<16) | (aKey[2]<<8)| aKey[3]; - pKeyInfo = pPKey2->pKeyInfo; - mem1.enc = pKeyInfo->enc; - mem1.db = pKeyInfo->db; - /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ - VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ - - /* Compilers may complain that mem1.u.i is potentially uninitialized. - ** We could initialize it, as shown here, to silence those complaints. - ** But in fact, mem1.u.i will never actually be used uninitialized, and doing - ** the unnecessary initialization has a measurable negative performance - ** impact, since this routine is a very high runner. And so, we choose - ** to ignore the compiler warnings and leave this variable uninitialized. - */ - /* mem1.u.i = 0; // not needed, here to silence compiler warning */ - - idx1 = getVarint32(aKey1, szHdr1); - d1 = szHdr1; - assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); - assert( pKeyInfo->aSortOrder!=0 ); - assert( pKeyInfo->nField>0 ); - assert( idx1<=szHdr1 || CORRUPT_DB ); - do{ - u32 serial_type1; - - /* Read the serial types for the next element in each key. */ - idx1 += getVarint32( aKey1+idx1, serial_type1 ); - - /* Verify that there is enough key space remaining to avoid - ** a buffer overread. The "d1+serial_type1+2" subexpression will - ** always be greater than or equal to the amount of required key space. - ** Use that approximation to avoid the more expensive call to - ** sqlite3VdbeSerialTypeLen() in the common case. - */ - if( d1+serial_type1+2>(u32)nKey1 - && d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 - ){ - break; + case 5: { + i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; + u32 lsw = (aKey[4] << 8) | aKey[5]; + return (i64)( msw << 16 | (u64)lsw ); } - /* Extract the values to be compared. - */ - d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); - - /* Do the comparison - */ - rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); - if( rc!=0 ){ - assert( mem1.zMalloc==0 ); /* See comment below */ - if( pKeyInfo->aSortOrder[i] ){ - rc = -rc; /* Invert the result for DESC sort order. */ - } - return rc; + case 6: { + i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; + u32 lsw = ((unsigned)aKey[4]<<24)|(aKey[5]<<16)|(aKey[6]<<8)|aKey[7]; + return (i64)( msw << 32 | (u64)lsw ); } - i++; - }while( idx1nField ); + } - /* No memory allocation is ever used on mem1. Prove this using - ** the following assert(). If the assert() fails, it indicates a - ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). - */ - assert( mem1.zMalloc==0 ); - - /* rc==0 here means that one of the keys ran out of fields and - ** all the fields up to that point were equal. Return the the default_rc - ** value. */ - return pPKey2->default_rc; + return (serial_type - 8); } - -int sqlite3VdbeRecordCompare( +static int vdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2 /* Right key */ + int szHdr1, /* Size of record header in bytes */ + u32 idx1, /* Offset of first type in header */ + UnpackedRecord *const pPKey2 /* Right key */ ){ - u32 d1; /* Offset into aKey[] of next data element */ - u32 idx1; /* Offset into aKey[] of next header element */ - u32 szHdr1; /* Number of bytes in header */ + u32 d1 = szHdr1; /* Offset into aKey[] of next data element */ int i = 0; int rc = 0; + Mem *pRhs = pPKey2->aMem; KeyInfo *pKeyInfo = pPKey2->pKeyInfo; const unsigned char *aKey1 = (const unsigned char *)pKey1; Mem mem1; @@ -3450,17 +3391,25 @@ int sqlite3VdbeRecordCompare( nCall++; #endif + /* If idx==0, then the caller has already determined that the first two + ** elements in the keys are equal. Fix the various stack variables so + ** that this routine begins comparing at the second field. */ + if( idx1==0 ){ + u32 s1; + assert( sqlite3VarintLen(szHdr1)==1 ); + idx1 = 1 + getVarint32(&aKey1[1], s1); + d1 += sqlite3VdbeSerialTypeLen(s1); + i = 1; + pRhs++; + } + VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ - - idx1 = getVarint32(aKey1, szHdr1); - d1 = szHdr1; assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); assert( pPKey2->pKeyInfo->aSortOrder!=0 ); assert( pPKey2->pKeyInfo->nField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ - Mem *pRhs = &pPKey2->aMem[i]; u32 serial_type; /* RHS is an integer */ @@ -3470,22 +3419,21 @@ int sqlite3VdbeRecordCompare( rc = +1; }else if( serial_type==0 ){ rc = -1; - }else{ + }else if( serial_type==7 ){ + double rhs = (double)pRhs->u.i; sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); - if( serial_type==7 ){ - double rhs = (double)pRhs->u.i; - if( mem1.rrhs ){ - rc = +1; - } - }else{ - i64 rhs = pRhs->u.i; - if( mem1.u.irhs ){ - rc = +1; - } + if( mem1.rrhs ){ + rc = +1; + } + }else{ + i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); + i64 rhs = pRhs->u.i; + if( lhsrhs ){ + rc = +1; } } } @@ -3579,6 +3527,7 @@ int sqlite3VdbeRecordCompare( } i++; + pRhs++; d1 += sqlite3VdbeSerialTypeLen(serial_type); idx1 += sqlite3VarintLen(serial_type); }while( idx1nField && d1<=nKey1 ); @@ -3596,20 +3545,184 @@ int sqlite3VdbeRecordCompare( return pPKey2->default_rc; } +static int vdbeRecordCompareInt( + int nKey1, const void *pKey1, /* Left key */ + int szHdr, + u32 idx1, + UnpackedRecord *pPKey2 /* Right key */ +){ + const u8 *aKey = &((const u8*)pKey1)[szHdr]; + int serial_type = ((const u8*)pKey1)[1]; + int res; + i64 v = pPKey2->aMem[0].u.i; + i64 lhs; + + switch( serial_type ){ + case 1: + lhs = (char)(aKey[0]); + break; + case 2: + lhs = 256*(signed char)aKey[0] + aKey[1]; + break; + case 3: + lhs = 65536*(char)aKey[0] | (aKey[1]<<8) | aKey[2]; + break; + case 4: + lhs = (int)(((u32)aKey[0]<<24) | (aKey[1]<<16) | (aKey[2]<<8)| aKey[3]); + break; + + case 5: { + i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; + u32 lsw = (aKey[4] << 8) | aKey[5]; + lhs = (i64)( msw << 16 | (u64)lsw ); + break; + } + + case 6: { + i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; + u32 lsw = ((unsigned)aKey[4]<<24)|(aKey[5]<<16)|(aKey[6]<<8)|aKey[7]; + lhs = (i64)( msw << 32 | (u64)lsw ); + break; + } + + case 8: + lhs = 0; + break; + + case 9: + lhs = 1; + break; + + default: + return vdbeRecordCompare(nKey1, pKey1, szHdr, 1, pPKey2); + } + + if( v>lhs ){ + res = pPKey2->r1; + }else if( vr2; + }else if( pPKey2->nField>1 ){ + res = vdbeRecordCompare(nKey1, pKey1, szHdr, 0, pPKey2); + }else{ + res = pPKey2->default_rc; + } + + assert( (res==0 && vdbeRecordComparePrev(nKey1, pKey1, pPKey2)==0) + || (res<0 && vdbeRecordComparePrev(nKey1, pKey1, pPKey2)<0) + || (res>0 && vdbeRecordComparePrev(nKey1, pKey1, pPKey2)>0) + || CORRUPT_DB + ); + return res; +} + +static int vdbeRecordCompareString( + int nKey1, const void *pKey1, /* Left key */ + int szHdr, + u32 idx1, + UnpackedRecord *pPKey2 /* Right key */ +){ + const u8 *aKey1 = (const u8*)pKey1; + int serial_type; + int res; + + getVarint32(&aKey1[1], serial_type); + + if( serial_type<12 ){ + res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ + }else if( !(serial_type & 0x01) ){ + res = pPKey2->r2; /* (pKey1/nKey1) is a blob */ + }else{ + int nCmp; + int nStr; + aKey1 = &aKey1[szHdr]; + + nStr = (serial_type-12) / 2; + if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */ + nCmp = MIN( pPKey2->aMem[0].n, nStr ); + res = memcmp(aKey1, pPKey2->aMem[0].z, nCmp); + + if( res==0 ){ + res = nStr - pPKey2->aMem[0].n; + if( res==0 ){ + if( pPKey2->nField>1 ){ + res = vdbeRecordCompare(nKey1, pKey1, szHdr, 0, pPKey2); + }else{ + res = pPKey2->default_rc; + } + }else if( res>0 ){ + res = pPKey2->r2; + }else{ + res = pPKey2->r1; + } + }else if( res>0 ){ + res = pPKey2->r2; + }else{ + res = pPKey2->r1; + } + } + + assert( (res==0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)==0) + || (res<0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)<0) + || (res>0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)>0) + || CORRUPT_DB + ); + return res; +} + + +int vdbeRecordCompareLargeHeader( + int nKey1, const void *pKey1, /* Left key */ + int dummy1, u32 dummy2, /* Unused arguments */ + UnpackedRecord *pPKey2 /* Right key */ +){ + int szHdr; + u32 idx1; + idx1 = getVarint32(((u8*)pKey1), szHdr); + return vdbeRecordCompare(nKey1, pKey1, szHdr, idx1, pPKey2); +} + RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ - if( p->nField==1 && p->pKeyInfo->aSortOrder[0]==0 ){ + if( (p->pKeyInfo->nField + p->pKeyInfo->nXField) > 10 ){ + return vdbeRecordCompareLargeHeader; + }else{ int flags = p->aMem[0].flags; + if( p->pKeyInfo->aSortOrder[0] ){ + p->r1 = 1; + p->r2 = -1; + }else{ + p->r1 = -1; + p->r2 = 1; + } if( (flags & MEM_Int) ){ return vdbeRecordCompareInt; - }else if( (p->aMem[0].flags&(MEM_Int|MEM_Real|MEM_Null|MEM_Blob))==0 - && p->pKeyInfo->aColl[0]==0 + } + if( (flags & (MEM_Int|MEM_Real|MEM_Null|MEM_Blob))==0 + && p->pKeyInfo->aColl[0]==0 ){ return vdbeRecordCompareString; } } - return sqlite3VdbeRecordCompare; + + return vdbeRecordCompare; } +RecordCompare sqlite3VdbeFindSorterCompare(KeyInfo *pKeyInfo){ + if( (pKeyInfo->nField + pKeyInfo->nXField) > 10 ){ + return vdbeRecordCompareLargeHeader; + } + return vdbeRecordCompare; +} + +int sqlite3VdbeRecordCompare( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + int szHdr; + u32 idx1; + + idx1 = getVarint32(((u8*)pKey1), szHdr); + return vdbeRecordCompare(nKey1, pKey1, szHdr, idx1, pPKey2); +} /* ** pCur points at an index entry created using the OP_MakeRecord opcode. diff --git a/src/vdbesort.c b/src/vdbesort.c index c4d15d6872..be5a6064c2 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -105,6 +105,7 @@ struct VdbeSorter { sqlite3_file *pTemp1; /* PMA file 1 */ SorterRecord *pRecord; /* Head of in-memory record list */ UnpackedRecord *pUnpacked; /* Used to unpack keys */ + RecordCompare xRecordCompare; /* Record compare function */ }; /* @@ -412,7 +413,10 @@ static void vdbeSorterCompare( assert( r2->default_rc==0 ); } +#if 0 *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2); +#endif + *pRes = pSorter->xRecordCompare(nKey1, pKey1, *((u8*)pKey1), 1, r2); } /* @@ -488,6 +492,7 @@ int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){ if( mxCachemxPmaSize = mxCache * pgsz; } + pSorter->xRecordCompare = sqlite3VdbeFindSorterCompare(pCsr->pKeyInfo); return SQLITE_OK; } From 063d4a041a5f1bf8938c7a01c2c4c656bf9384ce Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 28 Feb 2014 09:48:30 +0000 Subject: [PATCH 03/10] Minor tweak to vdbeRecordCompareInt(). FossilOrigin-Name: 284bde0ee20261737446eb8f5b6b36ad9bc3f355 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeaux.c | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index ab9697fb73..3b948c33cf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sin\slatest\strunk\schanges. -D 2014-02-27T20:52:26.303 +C Minor\stweak\sto\svdbeRecordCompareInt(). +D 2014-02-28T09:48:30.694 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -281,7 +281,7 @@ F src/vdbe.c ab910206dd8c9c5c1455f82953934bdbfe0bcc2a F src/vdbe.h 6833579fc0fbdc1c933e34519064841abda5b9b3 F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c 80e5315957377554c9011858f5afde61afedc181 +F src/vdbeaux.c fc95358566a454fadcf17858d582ff38c2e55c54 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 25cc487244bf6ad647105c5adbc3052403dfd143 F src/vdbesort.c 72290f12428973c2c6b9d4f95ad0a7c8181e1280 @@ -1152,7 +1152,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 570893740067a7caa952f259fa078cdf67017d71 51ce713c6ee91bdf0126155334dcc800b3daa509 -R f4fa5a4e2d9c34dae5f26cd35d7bbdb3 +P 8f30b09518d23c3f6cecd244a66ef918fdb55323 +R c980d8afe2372c0277fee962182b32ac U dan -Z 489718005e4064c97910e87ca8ac5405 +Z 7196a891773623dba164b983a9b4c516 diff --git a/manifest.uuid b/manifest.uuid index ab94dbb62a..52a4739a0c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f30b09518d23c3f6cecd244a66ef918fdb55323 \ No newline at end of file +284bde0ee20261737446eb8f5b6b36ad9bc3f355 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 8ca605ebe6..8468d13b96 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3558,6 +3558,7 @@ static int vdbeRecordCompareInt( i64 lhs; switch( serial_type ){ + case 1: lhs = (char)(aKey[0]); break; @@ -3593,6 +3594,15 @@ static int vdbeRecordCompareInt( lhs = 1; break; + /* This case could be removed without changing the results of running + ** this code. Including it causes gcc to generate a faster switch + ** statement (since the range of switch targets now starts at zero and + ** is contiguous)) but does not cause any duplicate code to be generated + ** (as gcc is clever enough to combine the two like cases). Other + ** compilers might be similar. */ + case 0: case 7: + return vdbeRecordCompare(nKey1, pKey1, szHdr, 1, pPKey2); + default: return vdbeRecordCompare(nKey1, pKey1, szHdr, 1, pPKey2); } @@ -3602,8 +3612,12 @@ static int vdbeRecordCompareInt( }else if( vr2; }else if( pPKey2->nField>1 ){ + /* The first fields of the two keys are equal. Compare the trailing + ** fields. */ res = vdbeRecordCompare(nKey1, pKey1, szHdr, 0, pPKey2); }else{ + /* The first fields of the two keys are equal and there are no trailing + ** fields. Return pPKey2->default_rc in this case. */ res = pPKey2->default_rc; } From 597515d70c009a74c54dd8a82acb2bfc66cb2664 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 28 Feb 2014 18:39:51 +0000 Subject: [PATCH 04/10] Update some test cases that deal with corrupt databases. FossilOrigin-Name: 3a09f5605ac7c6e503eb10acfdc607010414d917 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/vdbeaux.c | 2 +- src/vdbemem.c | 1 - test/analyze9.test | 3 +++ test/corruptG.test | 2 +- test/pragma.test | 15 ++++++++++----- 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 3b948c33cf..f20f7a0353 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\stweak\sto\svdbeRecordCompareInt(). -D 2014-02-28T09:48:30.694 +C Update\ssome\stest\scases\sthat\sdeal\swith\scorrupt\sdatabases. +D 2014-02-28T18:39:51.462 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -281,9 +281,9 @@ F src/vdbe.c ab910206dd8c9c5c1455f82953934bdbfe0bcc2a F src/vdbe.h 6833579fc0fbdc1c933e34519064841abda5b9b3 F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c fc95358566a454fadcf17858d582ff38c2e55c54 +F src/vdbeaux.c aad5345869c110f45074e2c1ca230e623b1ba182 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 -F src/vdbemem.c 25cc487244bf6ad647105c5adbc3052403dfd143 +F src/vdbemem.c 93fc3f13ebe6809ebaac8d0a17c812ec053ba233 F src/vdbesort.c 72290f12428973c2c6b9d4f95ad0a7c8181e1280 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd @@ -310,7 +310,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88 -F test/analyze9.test 339e87723cd4dc158dc5e9095acd8df9e87faf79 +F test/analyze9.test e072a5172d55afcba98d6ca6a219ce8878c2f5c9 F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944 F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b @@ -402,7 +402,7 @@ F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040 F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 -F test/corruptG.test c150f156dace653c00a121ad0f5772a0568c41ba +F test/corruptG.test 58ec333a01997fe655e34e5bea52b7a2a6b9704d F test/corruptH.test 9d8186f6f8751efdfd445d8546fd98f073499039 F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62 @@ -735,7 +735,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04 -F test/pragma.test c1bc3a29f664b57d0ae40b498ad31f370de8daa6 +F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1 @@ -1152,7 +1152,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 8f30b09518d23c3f6cecd244a66ef918fdb55323 -R c980d8afe2372c0277fee962182b32ac +P 284bde0ee20261737446eb8f5b6b36ad9bc3f355 +R 75b55639e7bdd048d8263d0acfa3cf8a U dan -Z 7196a891773623dba164b983a9b4c516 +Z d116a418c5c97c83b8ebfe7a3e655c3c diff --git a/manifest.uuid b/manifest.uuid index 52a4739a0c..9cb218f1b4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -284bde0ee20261737446eb8f5b6b36ad9bc3f355 \ No newline at end of file +3a09f5605ac7c6e503eb10acfdc607010414d917 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 8468d13b96..007f4e650d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3597,7 +3597,7 @@ static int vdbeRecordCompareInt( /* This case could be removed without changing the results of running ** this code. Including it causes gcc to generate a faster switch ** statement (since the range of switch targets now starts at zero and - ** is contiguous)) but does not cause any duplicate code to be generated + ** is contiguous) but does not cause any duplicate code to be generated ** (as gcc is clever enough to combine the two like cases). Other ** compilers might be similar. */ case 0: case 7: diff --git a/src/vdbemem.c b/src/vdbemem.c index 4936f40016..bc703e8eeb 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -913,7 +913,6 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ if( pRec->pKeyInfo ){ assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol ); assert( pRec->pKeyInfo->enc==ENC(db) ); - pRec->flags = UNPACKED_PREFIX_MATCH; pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord))); for(i=0; iaMem[i].flags = MEM_Null; diff --git a/test/analyze9.test b/test/analyze9.test index 0fce55ac4b..820bcdb0e7 100644 --- a/test/analyze9.test +++ b/test/analyze9.test @@ -326,6 +326,7 @@ do_execsql_test 6.2 { reset_db sqlite3_db_config_lookaside db 0 0 0 +database_may_be_corrupt do_execsql_test 7.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); @@ -366,6 +367,8 @@ do_execsql_test 7.5 { SELECT * FROM t1 WHERE a = 5; } {5 5} +database_never_corrupt + #------------------------------------------------------------------------- # reset_db diff --git a/test/corruptG.test b/test/corruptG.test index 11253fd12c..1ec5d6f6a9 100644 --- a/test/corruptG.test +++ b/test/corruptG.test @@ -76,6 +76,6 @@ do_test 2.1 { # incorrect answer from a corrupt database file, that is OK. If the # result below changes, that just means that "undefined behavior" has # changed. -} {0 52} +} {/0 .*/} finish_test diff --git a/test/pragma.test b/test/pragma.test index fcbb1808fa..8f54e695d7 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -1602,11 +1602,16 @@ Multiple uses for byte 672 of page 15} set auxerr {*** in database aux *** Multiple uses for byte 672 of page 15} +set mainerr {/{\*\*\* in database main \*\*\* +Multiple uses for byte 672 of page 15}.*/} +set auxerr {/{\*\*\* in database aux \*\*\* +Multiple uses for byte 672 of page 15}.*/} + do_test 22.2 { catch { db close } sqlite3 db testerr.db execsql { PRAGMA integrity_check } -} [list $mainerr] +} $mainerr do_test 22.3.1 { catch { db close } @@ -1615,13 +1620,13 @@ do_test 22.3.1 { ATTACH 'testerr.db' AS 'aux'; PRAGMA integrity_check; } -} [list $auxerr] +} $auxerr do_test 22.3.2 { execsql { PRAGMA main.integrity_check; } } {ok} do_test 22.3.3 { execsql { PRAGMA aux.integrity_check; } -} [list $auxerr] +} $auxerr do_test 22.4.1 { catch { db close } @@ -1630,10 +1635,10 @@ do_test 22.4.1 { ATTACH 'test.db' AS 'aux'; PRAGMA integrity_check; } -} [list $mainerr] +} $mainerr do_test 22.4.2 { execsql { PRAGMA main.integrity_check; } -} [list $mainerr] +} $mainerr do_test 22.4.3 { execsql { PRAGMA aux.integrity_check; } } {ok} From 3833e934d3b219dfb05d9a38333d1c8d7bfe4f82 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 1 Mar 2014 19:44:56 +0000 Subject: [PATCH 05/10] Remove the vdbeRecordCompareLargeHeader function. Fix some other details. FossilOrigin-Name: 3861e853105cb8da344c7eebd2e455622b26395e --- manifest | 22 ++--- manifest.uuid | 2 +- src/btree.c | 6 +- src/sqliteInt.h | 7 +- src/vdbe.h | 5 +- src/vdbeaux.c | 226 ++++++++++++++++++++++++------------------------ src/vdbesort.c | 7 +- src/where.c | 8 +- 8 files changed, 142 insertions(+), 141 deletions(-) diff --git a/manifest b/manifest index f20f7a0353..08b453f312 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\ssome\stest\scases\sthat\sdeal\swith\scorrupt\sdatabases. -D 2014-02-28T18:39:51.462 +C Remove\sthe\svdbeRecordCompareLargeHeader\sfunction.\sFix\ssome\sother\sdetails. +D 2014-03-01T19:44:56.574 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -163,7 +163,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 77f175987c80ebec063f8653cb7d300776411413 +F src/btree.c d288e668614449571ec269535dc4aaf216a23db2 F src/btree.h 9e0f97c01b972f779eb7655cfb4f8727fd6dc26f F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4 F src/build.c 00ce613bc2256e525c9195cb10d0df7bcc48d1f0 @@ -221,7 +221,7 @@ F src/shell.c bf75ce6bea4c8f56c1b46bee201c25acddffb675 F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 843e23d43ee2ab9369e68eb778815ba02835da59 +F src/sqliteInt.h b06500d391d4b7bf4c69fc110e37dd45719b760c F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -278,19 +278,19 @@ F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 F src/vdbe.c ab910206dd8c9c5c1455f82953934bdbfe0bcc2a -F src/vdbe.h 6833579fc0fbdc1c933e34519064841abda5b9b3 +F src/vdbe.h c6dc01f85cf3bdcc992d244aeff952c033fd5ad0 F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c aad5345869c110f45074e2c1ca230e623b1ba182 +F src/vdbeaux.c da0979ce81ecdf3d018be9ee1e8998110181fb12 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 93fc3f13ebe6809ebaac8d0a17c812ec053ba233 -F src/vdbesort.c 72290f12428973c2c6b9d4f95ad0a7c8181e1280 +F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 -F src/where.c 6042e1a377cf7dc72c10493269ed75e276275cd8 +F src/where.c 36ef94b653a10944b39e34938ee4c758f3f42879 F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1152,7 +1152,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 284bde0ee20261737446eb8f5b6b36ad9bc3f355 -R 75b55639e7bdd048d8263d0acfa3cf8a +P 3a09f5605ac7c6e503eb10acfdc607010414d917 +R b23b5e438c1d698174ad52d7cfba370e U dan -Z d116a418c5c97c83b8ebfe7a3e655c3c +Z 35d9cecacf0cc917a2c2ed9a75b36eab diff --git a/manifest.uuid b/manifest.uuid index 9cb218f1b4..54a81caa10 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3a09f5605ac7c6e503eb10acfdc607010414d917 \ No newline at end of file +3861e853105cb8da344c7eebd2e455622b26395e \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index c0b04cc08c..4d42969be8 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4661,14 +4661,14 @@ int sqlite3BtreeMovetoUnpacked( ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pCell[1], 1, pIdxKey); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey, 0); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pCell[2], 1, pIdxKey); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey, 0); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated @@ -4689,7 +4689,7 @@ int sqlite3BtreeMovetoUnpacked( sqlite3_free(pCellKey); goto moveto_finish; } - c = xRecordCompare(nCell, pCellKey, ((u8*)pCellKey)[0], 1, pIdxKey); + c = xRecordCompare(nCell, pCellKey, pIdxKey, 0); sqlite3_free(pCellKey); } if( c<0 ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index eece50f7a1..a368b96c63 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1586,14 +1586,17 @@ struct KeyInfo { ** ** This structure holds a record that has already been disassembled ** into its constituent fields. +** +** The r1 and r2 member variables are only used by the optimized comparison +** functions vdbeRecordCompareInt() and vdbeRecordCompareString(). */ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ char default_rc; /* Comparison result if keys are equal */ Mem *aMem; /* Values */ - int r1; - int r2; + int r1; /* Value to return if (lhs > rhs) */ + int r2; /* Value to return if (rhs < lhs) */ }; diff --git a/src/vdbe.h b/src/vdbe.h index c08512e7aa..389c1d5ffb 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -211,12 +211,11 @@ void sqlite3VdbeSetVarmask(Vdbe*, int); #endif void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); -int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); +int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*,int,u32,UnpackedRecord*); +typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); -RecordCompare sqlite3VdbeFindSorterCompare(KeyInfo*); #ifndef SQLITE_OMIT_TRIGGER void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 007f4e650d..f15f5e95be 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3123,24 +3123,16 @@ void sqlite3VdbeRecordUnpack( p->nField = u; } +#if SQLITE_DEBUG /* -** This function compares the two table rows or index records -** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero -** or positive integer if key1 is less than, equal to or -** greater than key2. The {nKey1, pKey1} key must be a blob -** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 -** key must be a parsed key such as obtained from -** sqlite3VdbeParseRecord. -** -** Key1 and Key2 do not have to contain the same number of fields. -** The key with fewer fields is usually compares less than the -** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set -** and the common prefixes are equal, then key1 is less than key2. -** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are -** equal, then the keys are considered to be equal and -** the parts beyond the common prefix are ignored. +** This function compares two index or table record keys in the same way +** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(), +** this function deserializes and compares values using the +** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used +** in assert() statements to ensure that the optimized code in +** sqlite3VdbeRecordCompare() returns results with these two primitives. */ -static int vdbeRecordComparePrev( +static int vdbeRecordCompareDebug( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ @@ -3220,10 +3212,17 @@ static int vdbeRecordComparePrev( ** value. */ return pPKey2->default_rc; } +#endif +/* +** Both *pMem1 and *pMem2 contain string values. Compare the two values +** using the collation sequence pColl. As usual, return a negative , zero +** or positive value if *pMem1 is less than, equal to or greater than +** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);". +*/ static int vdbeCompareMemString( - const Mem *pMem1, - const Mem *pMem2, + const Mem *pMem1, + const Mem *pMem2, const CollSeq *pColl ){ if( pMem1->enc==pColl->enc ){ @@ -3344,8 +3343,17 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ } +/* +** The first argument passed to this function is a serial-type that +** corresponds to an integer - all values between 1 and 9 inclusive +** except 7. The second points to a buffer containing an integer value +** serialized according to serial_type. This function deserializes +** and returns the value. +*/ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ + assert( CORRUPT_DB || (serial_type>=1 && serial_type<=9 && serial_type!=7) ); switch( serial_type ){ + case 0: case 1: return (char)aKey[0]; case 2: @@ -3354,13 +3362,11 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ return ((char)aKey[0] << 16) | (aKey[1] << 8) | aKey[2]; case 4: return ((char)aKey[0]<<24) | (aKey[1]<<16) | (aKey[2]<<8)| aKey[3]; - case 5: { i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; u32 lsw = (aKey[4] << 8) | aKey[5]; return (i64)( msw << 16 | (u64)lsw ); } - case 6: { i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; u32 lsw = ((unsigned)aKey[4]<<24)|(aKey[5]<<16)|(aKey[6]<<8)|aKey[7]; @@ -3371,36 +3377,51 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ return (serial_type - 8); } -static int vdbeRecordCompare( - int nKey1, const void *pKey1, /* Left key */ - int szHdr1, /* Size of record header in bytes */ - u32 idx1, /* Offset of first type in header */ - UnpackedRecord *const pPKey2 /* Right key */ +/* +** This function compares the two table rows or index records +** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero +** or positive integer if key1 is less than, equal to or +** greater than key2. The {nKey1, pKey1} key must be a blob +** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 +** key must be a parsed key such as obtained from +** sqlite3VdbeParseRecord. +** +** If argument bSkip is non-zero, it is assumed that the caller has already +** determined that the first fields of the keys are equal. +** +** 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. +*/ +int sqlite3VdbeRecordCompare( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *const pPKey2, /* Right key */ + int bSkip /* If true, skip the first field */ ){ - u32 d1 = szHdr1; /* Offset into aKey[] of next data element */ - int i = 0; - int rc = 0; - Mem *pRhs = pPKey2->aMem; + u32 d1; /* Offset into aKey[] of next data element */ + int i; /* Index of next field to compare */ + int szHdr1; /* Size of record header in bytes */ + u32 idx1; /* Offset of first type in header */ + int rc = 0; /* Return value */ + Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */ KeyInfo *pKeyInfo = pPKey2->pKeyInfo; const unsigned char *aKey1 = (const unsigned char *)pKey1; Mem mem1; -#ifdef SQLITE_DEBUG - int expected = vdbeRecordComparePrev(nKey1, pKey1, pPKey2); - static int nCall = 0; - nCall++; -#endif - - /* If idx==0, then the caller has already determined that the first two - ** elements in the keys are equal. Fix the various stack variables so + /* If bSkip is true, then the caller has already determined that the first + ** two elements in the keys are equal. Fix the various stack variables so ** that this routine begins comparing at the second field. */ - if( idx1==0 ){ + if( bSkip ){ u32 s1; - assert( sqlite3VarintLen(szHdr1)==1 ); idx1 = 1 + getVarint32(&aKey1[1], s1); - d1 += sqlite3VdbeSerialTypeLen(s1); + szHdr1 = aKey1[0]; + d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1); i = 1; pRhs++; + }else{ + idx1 = getVarint32(aKey1, szHdr1); + d1 = szHdr1; + i = 0; } VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ @@ -3511,18 +3532,14 @@ static int vdbeRecordCompare( } if( rc!=0 ){ - assert( mem1.zMalloc==0 ); /* See comment below */ if( pKeyInfo->aSortOrder[i] ){ rc = -rc; -#if 0 - assert( (rc>0 && (rc^(int)0x80000000)<0) - || (rc<0 && (rc^(int)0x80000000)>0) ); - assert( sizeof(int)==4 ); - rc ^= (int)0x80000000; /* similar in spirit to: "rc = -rc;" */ - assert( rc!=0 ); -#endif } - assert( (rc<0 && expected<0) || (rc>0 && expected>0) || CORRUPT_DB ); + assert( CORRUPT_DB + || (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) + || (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) + ); + assert( mem1.zMalloc==0 ); /* See comment below */ return rc; } @@ -3534,31 +3551,38 @@ static int vdbeRecordCompare( /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a - ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). - */ + ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ assert( mem1.zMalloc==0 ); /* rc==0 here means that one or both of the keys ran out of fields and ** all the fields up to that point were equal. Return the the default_rc ** value. */ - assert( pPKey2->default_rc==expected ); + assert( CORRUPT_DB + || pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2) + ); return pPKey2->default_rc; } +/* +** This function is an optimized version of sqlite3VdbeRecordCompare() +** that (a) the first field of pPKey2 is an integer, and (b) the +** size-of-header varint at the start of (pKey1/nKey1) fits in a single +** byte (i.e. is less than 128). +*/ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ - int szHdr, - u32 idx1, - UnpackedRecord *pPKey2 /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ + int bSkip /* Ignored */ ){ - const u8 *aKey = &((const u8*)pKey1)[szHdr]; + const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1]; int serial_type = ((const u8*)pKey1)[1]; int res; i64 v = pPKey2->aMem[0].u.i; i64 lhs; - switch( serial_type ){ + assert( bSkip==0 ); + switch( serial_type ){ case 1: lhs = (char)(aKey[0]); break; @@ -3571,25 +3595,21 @@ static int vdbeRecordCompareInt( case 4: lhs = (int)(((u32)aKey[0]<<24) | (aKey[1]<<16) | (aKey[2]<<8)| aKey[3]); break; - case 5: { i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; u32 lsw = (aKey[4] << 8) | aKey[5]; lhs = (i64)( msw << 16 | (u64)lsw ); break; } - case 6: { i64 msw = ((char)aKey[0]<<24)|(aKey[1]<<16)|(aKey[2]<<8)|aKey[3]; u32 lsw = ((unsigned)aKey[4]<<24)|(aKey[5]<<16)|(aKey[6]<<8)|aKey[7]; lhs = (i64)( msw << 32 | (u64)lsw ); break; } - case 8: lhs = 0; break; - case 9: lhs = 1; break; @@ -3601,10 +3621,10 @@ static int vdbeRecordCompareInt( ** (as gcc is clever enough to combine the two like cases). Other ** compilers might be similar. */ case 0: case 7: - return vdbeRecordCompare(nKey1, pKey1, szHdr, 1, pPKey2); + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); default: - return vdbeRecordCompare(nKey1, pKey1, szHdr, 1, pPKey2); + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); } if( v>lhs ){ @@ -3614,31 +3634,37 @@ static int vdbeRecordCompareInt( }else if( pPKey2->nField>1 ){ /* The first fields of the two keys are equal. Compare the trailing ** fields. */ - res = vdbeRecordCompare(nKey1, pKey1, szHdr, 0, pPKey2); + res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); }else{ /* The first fields of the two keys are equal and there are no trailing ** fields. Return pPKey2->default_rc in this case. */ res = pPKey2->default_rc; } - assert( (res==0 && vdbeRecordComparePrev(nKey1, pKey1, pPKey2)==0) - || (res<0 && vdbeRecordComparePrev(nKey1, pKey1, pPKey2)<0) - || (res>0 && vdbeRecordComparePrev(nKey1, pKey1, pPKey2)>0) + assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) + || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) + || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) || CORRUPT_DB ); return res; } +/* +** This function is an optimized version of sqlite3VdbeRecordCompare() +** that (a) the first field of pPKey2 is a string, that (b) the first field +** uses the collation sequence BINARY and (c) that the size-of-header varint +** at the start of (pKey1/nKey1) fits in a single byte. +*/ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ - int szHdr, - u32 idx1, - UnpackedRecord *pPKey2 /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ + int bSkip ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; + assert( bSkip==0 ); getVarint32(&aKey1[1], serial_type); if( serial_type<12 ){ @@ -3648,18 +3674,18 @@ static int vdbeRecordCompareString( }else{ int nCmp; int nStr; - aKey1 = &aKey1[szHdr]; + int szHdr = aKey1[0]; nStr = (serial_type-12) / 2; if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */ nCmp = MIN( pPKey2->aMem[0].n, nStr ); - res = memcmp(aKey1, pPKey2->aMem[0].z, nCmp); + res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); if( res==0 ){ res = nStr - pPKey2->aMem[0].n; if( res==0 ){ if( pPKey2->nField>1 ){ - res = vdbeRecordCompare(nKey1, pKey1, szHdr, 0, pPKey2); + res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); }else{ res = pPKey2->default_rc; } @@ -3675,30 +3701,26 @@ static int vdbeRecordCompareString( } } - assert( (res==0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)==0) - || (res<0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)<0) - || (res>0 && sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2)>0) + assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) + || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) + || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) || CORRUPT_DB ); return res; } - -int vdbeRecordCompareLargeHeader( - int nKey1, const void *pKey1, /* Left key */ - int dummy1, u32 dummy2, /* Unused arguments */ - UnpackedRecord *pPKey2 /* Right key */ -){ - int szHdr; - u32 idx1; - idx1 = getVarint32(((u8*)pKey1), szHdr); - return vdbeRecordCompare(nKey1, pKey1, szHdr, idx1, pPKey2); -} - +/* +** Return a pointer to an sqlite3VdbeRecordCompare() compatible function +** suitable for comparing serialized records to the unpacked record passed +** as the only argument. +*/ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ - if( (p->pKeyInfo->nField + p->pKeyInfo->nXField) > 10 ){ - return vdbeRecordCompareLargeHeader; - }else{ + /* As the varints that make up a record header are all 5 bytes in size + ** or less, if the binary keys being compared have 25 or fewer fields + ** then it is guaranteed that the varint at the start of every record + ** (the record-header size in bytes) fits in a single byte. If this + ** is not the case, then sqlite3VdbeRecordCompare() must be used. */ + if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=25 ){ int flags = p->aMem[0].flags; if( p->pKeyInfo->aSortOrder[0] ){ p->r1 = 1; @@ -3717,25 +3739,7 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ } } - return vdbeRecordCompare; -} - -RecordCompare sqlite3VdbeFindSorterCompare(KeyInfo *pKeyInfo){ - if( (pKeyInfo->nField + pKeyInfo->nXField) > 10 ){ - return vdbeRecordCompareLargeHeader; - } - return vdbeRecordCompare; -} - -int sqlite3VdbeRecordCompare( - int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2 /* Right key */ -){ - int szHdr; - u32 idx1; - - idx1 = getVarint32(((u8*)pKey1), szHdr); - return vdbeRecordCompare(nKey1, pKey1, szHdr, idx1, pPKey2); + return sqlite3VdbeRecordCompare; } /* @@ -3850,7 +3854,7 @@ int sqlite3VdbeIdxKeyCompare( if( rc ){ return rc; } - *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); + *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked, 0); sqlite3VdbeMemRelease(&m); return SQLITE_OK; } diff --git a/src/vdbesort.c b/src/vdbesort.c index be5a6064c2..b9ed97e8b3 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -105,7 +105,6 @@ struct VdbeSorter { sqlite3_file *pTemp1; /* PMA file 1 */ SorterRecord *pRecord; /* Head of in-memory record list */ UnpackedRecord *pUnpacked; /* Used to unpack keys */ - RecordCompare xRecordCompare; /* Record compare function */ }; /* @@ -413,10 +412,7 @@ static void vdbeSorterCompare( assert( r2->default_rc==0 ); } -#if 0 - *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2); -#endif - *pRes = pSorter->xRecordCompare(nKey1, pKey1, *((u8*)pKey1), 1, r2); + *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2, 0); } /* @@ -492,7 +488,6 @@ int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){ if( mxCachemxPmaSize = mxCache * pgsz; } - pSorter->xRecordCompare = sqlite3VdbeFindSorterCompare(pCsr->pKeyInfo); return SQLITE_OK; } diff --git a/src/where.c b/src/where.c index a5dd7b59e7..4ce0cb7ded 100644 --- a/src/where.c +++ b/src/where.c @@ -1913,7 +1913,7 @@ static void whereKeyStats( assert( pRec->nField>0 && iColnSampleCol ); do{ iTest = (iMin+i)/2; - res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec); + res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec, 0); if( res<0 ){ iMin = iTest+1; }else{ @@ -1928,16 +1928,16 @@ static void whereKeyStats( if( res==0 ){ /* If (res==0) is true, then sample $i must be equal to pRec */ assert( inSample ); - assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) + assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0) || pParse->db->mallocFailed ); }else{ /* Otherwise, pRec must be smaller than sample $i and larger than ** sample ($i-1). */ assert( i==pIdx->nSample - || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 + || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)>0 || pParse->db->mallocFailed ); assert( i==0 - || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 + || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec, 0)<0 || pParse->db->mallocFailed ); } #endif /* ifdef SQLITE_DEBUG */ From fcb44a89f226010a40265101128cc13c4fae5dfa Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Mar 2014 15:13:27 +0000 Subject: [PATCH 06/10] Fix a harmless compiler warning. FossilOrigin-Name: d7f6837e6997a4d5c0fd2d08b52887d691dd6f97 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbeaux.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 2b023bb25c..956052609f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\slatest\strunk\schanges. -D 2014-03-03T14:45:06.920 +C Fix\sa\sharmless\scompiler\swarning. +D 2014-03-03T15:13:27.429 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -281,7 +281,7 @@ F src/vdbe.c 75c3f5d27ab79af214646cf37d7551bc8cec09c2 F src/vdbe.h c6dc01f85cf3bdcc992d244aeff952c033fd5ad0 F src/vdbeInt.h d55cab859abb2c6656911497ae74eba9dcf34e28 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c f0532f7ce4fc3f4d9811d0bc29c6ce56d448596e +F src/vdbeaux.c e4a0f89d15097debae8117ba17e4a640a0d3116f F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 2d7918e4c80546d943414668b1485b2581f58a28 F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59 @@ -1152,7 +1152,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 9c1747b5ded995e77fdab2fa9d334ec3c17c7c14 7fdd378d54754a3ffdc01c6c0a66cf6d5899a495 -R 4cede51faff0bb760b6f55494711c674 -U dan -Z 2c68a923f498f2b3622ae1d55f13bc1f +P e00ed717fbe456010ec6c746490d7c3e9d94ec5a +R 8e3a8f60ae350e66db9c9ecb1f09657d +U drh +Z 6dbc33a5cff12ba0585c075afb66f191 diff --git a/manifest.uuid b/manifest.uuid index b161fe627f..206d58eaa6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e00ed717fbe456010ec6c746490d7c3e9d94ec5a \ No newline at end of file +d7f6837e6997a4d5c0fd2d08b52887d691dd6f97 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index d13049a1a9..10623ecbc0 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3499,7 +3499,7 @@ int sqlite3VdbeRecordCompare( mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = MEM_Str; - mem1.z = &aKey1[d1]; + mem1.z = (char*)&aKey1[d1]; rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]); }else{ int nCmp = MIN(mem1.n, pRhs->n); From 295aedf097e947c5975cc1a79e16f779e7992f31 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Mar 2014 18:25:24 +0000 Subject: [PATCH 07/10] Fix compiler warnings. FossilOrigin-Name: ba8993727e5752cbc92c7d78437e9e0510c899f7 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/vdbe.h | 4 ++-- src/vdbeInt.h | 2 +- src/vdbeaux.c | 24 +++++++++++++----------- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 15339f6098..d6d61e95b6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\slatest\strunk\schanges. -D 2014-03-03T17:48:03.279 +C Fix\scompiler\swarnings. +D 2014-03-03T18:25:24.475 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -278,10 +278,10 @@ F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 F src/vdbe.c 75c3f5d27ab79af214646cf37d7551bc8cec09c2 -F src/vdbe.h c6dc01f85cf3bdcc992d244aeff952c033fd5ad0 -F src/vdbeInt.h d55cab859abb2c6656911497ae74eba9dcf34e28 +F src/vdbe.h d189f92468a17a6f04daeec9df3b767f50557b21 +F src/vdbeInt.h 9ccca0bc7646c918d065943e44bead4bf5de213d F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c e4a0f89d15097debae8117ba17e4a640a0d3116f +F src/vdbeaux.c f6d49b824fb9b4025098d73ba63a579bceab46c1 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 2d7918e4c80546d943414668b1485b2581f58a28 F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59 @@ -1153,7 +1153,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P d7f6837e6997a4d5c0fd2d08b52887d691dd6f97 c0fa0c0e2de50d7eda19ab8862496b18eff93538 -R 9a9d986bbf5df1b40c16a7d9f71c4a7c -U dan -Z 5c6a6f0f42fa42f03fa0c54709a35c4c +P 1d60356462f111ed147aa865dd17a13511db6ab7 +R 21f5b7d1de45908a8d9a08e2efe5ba51 +U drh +Z bf94921d4ecf2467a56de90bb29e8bf1 diff --git a/manifest.uuid b/manifest.uuid index a61bcd33e6..19e8b9d202 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1d60356462f111ed147aa865dd17a13511db6ab7 \ No newline at end of file +ba8993727e5752cbc92c7d78437e9e0510c899f7 \ No newline at end of file diff --git a/src/vdbe.h b/src/vdbe.h index 389c1d5ffb..66ca602ab7 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -211,10 +211,10 @@ void sqlite3VdbeSetVarmask(Vdbe*, int); #endif void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); -int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); +int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); +typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int); RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); #ifndef SQLITE_OMIT_TRIGGER diff --git a/src/vdbeInt.h b/src/vdbeInt.h index c16baff685..33c06142f6 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -391,7 +391,7 @@ u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); -int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); +int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const 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 10623ecbc0..0a2f11ab2b 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3135,7 +3135,7 @@ void sqlite3VdbeRecordUnpack( */ static int vdbeRecordCompareDebug( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2 /* Right key */ + const UnpackedRecord *pPKey2 /* Right key */ ){ u32 d1; /* Offset into aKey[] of next data element */ u32 idx1; /* Offset into aKey[] of next header element */ @@ -3396,7 +3396,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ */ int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *const pPKey2, /* Right key */ + const UnpackedRecord *pPKey2, /* Right key */ int bSkip /* If true, skip the first field */ ){ u32 d1; /* Offset into aKey[] of next data element */ @@ -3474,7 +3474,7 @@ int sqlite3VdbeRecordCompare( if( serial_type==7 ){ lhs = mem1.r; }else{ - lhs = mem1.u.i; + lhs = (double)mem1.u.i; } if( lhs nKey1 ){ + if( (d1+mem1.n) > (unsigned)nKey1 ){ rc = 1; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; @@ -3516,7 +3516,7 @@ int sqlite3VdbeRecordCompare( rc = -1; }else{ int nStr = (serial_type - 12) / 2; - if( (d1+nStr) > nKey1 ){ + if( (d1+nStr) > (unsigned)nKey1 ){ rc = 1; /* Corruption */ }else{ int nCmp = MIN(nStr, pRhs->n); @@ -3548,7 +3548,7 @@ int sqlite3VdbeRecordCompare( pRhs++; d1 += sqlite3VdbeSerialTypeLen(serial_type); idx1 += sqlite3VarintLen(serial_type); - }while( idx1nField && d1<=nKey1 ); + }while( idx1<(unsigned)szHdr1 && inField && d1<=(unsigned)nKey1 ); /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a @@ -3572,7 +3572,7 @@ int sqlite3VdbeRecordCompare( */ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ + const UnpackedRecord *pPKey2, /* Right key */ int bSkip /* Ignored */ ){ const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1]; @@ -3580,6 +3580,7 @@ static int vdbeRecordCompareInt( int res; i64 v = pPKey2->aMem[0].u.i; i64 lhs; + UNUSED_PARAMETER(bSkip); assert( bSkip==0 ); @@ -3658,12 +3659,13 @@ static int vdbeRecordCompareInt( */ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ + const UnpackedRecord *pPKey2, /* Right key */ int bSkip ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; + UNUSED_PARAMETER(bSkip); assert( bSkip==0 ); getVarint32(&aKey1[1], serial_type); @@ -3832,9 +3834,9 @@ idx_rowid_corruption: ** of the keys prior to the final rowid, not the entire key. */ int sqlite3VdbeIdxKeyCompare( - VdbeCursor *pC, /* The cursor to compare against */ - UnpackedRecord *pUnpacked, /* Unpacked version of key to compare against */ - int *res /* Write the comparison result here */ + VdbeCursor *pC, /* The cursor to compare against */ + const UnpackedRecord *pUnpacked, /* Unpacked version of key */ + int *res /* Write the comparison result here */ ){ i64 nCellKey = 0; int rc; From 5668969a69c34859d6c670218c9cebb52f6d7f55 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Mar 2014 19:29:28 +0000 Subject: [PATCH 08/10] Fix a typo in a comment. No changes to code. FossilOrigin-Name: 1f4991ab1676bf85599fc32068ceeddeb05f648c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeaux.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d6d61e95b6..4302dac32e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scompiler\swarnings. -D 2014-03-03T18:25:24.475 +C Fix\sa\stypo\sin\sa\scomment.\s\sNo\schanges\sto\scode. +D 2014-03-03T19:29:28.807 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -281,7 +281,7 @@ F src/vdbe.c 75c3f5d27ab79af214646cf37d7551bc8cec09c2 F src/vdbe.h d189f92468a17a6f04daeec9df3b767f50557b21 F src/vdbeInt.h 9ccca0bc7646c918d065943e44bead4bf5de213d F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c f6d49b824fb9b4025098d73ba63a579bceab46c1 +F src/vdbeaux.c b817480055ea37f04cbda6524cbcda56d8620c78 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 2d7918e4c80546d943414668b1485b2581f58a28 F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59 @@ -1153,7 +1153,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 1d60356462f111ed147aa865dd17a13511db6ab7 -R 21f5b7d1de45908a8d9a08e2efe5ba51 +P ba8993727e5752cbc92c7d78437e9e0510c899f7 +R 84a57b7d3530d77238186688acf2fb15 U drh -Z bf94921d4ecf2467a56de90bb29e8bf1 +Z 743719e98998c2037f212aec24c916c8 diff --git a/manifest.uuid b/manifest.uuid index 19e8b9d202..2f5a48fd68 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba8993727e5752cbc92c7d78437e9e0510c899f7 \ No newline at end of file +1f4991ab1676bf85599fc32068ceeddeb05f648c \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 0a2f11ab2b..47a3f0899b 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3846,7 +3846,7 @@ int sqlite3VdbeIdxKeyCompare( assert( sqlite3BtreeCursorIsValid(pCur) ); VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ - /* nCellKey will always be between 0 and 0xffffffff because of the say + /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; From 9b8afef260c0ed02cc0d1a195fa697844eb1c02e Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 3 Mar 2014 20:48:50 +0000 Subject: [PATCH 09/10] Avoid a buffer overread in vdbeCompareRecordInt() that might occur if the database is corrupt. FossilOrigin-Name: 7c0b4381f0e6f33cb13299a915851d9431bf3850 --- manifest | 15 ++++++++------- manifest.uuid | 2 +- src/vdbeaux.c | 24 +++++++++++++++-------- test/corruptI.test | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 test/corruptI.test diff --git a/manifest b/manifest index 4302dac32e..1f36291c28 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sa\scomment.\s\sNo\schanges\sto\scode. -D 2014-03-03T19:29:28.807 +C Avoid\sa\sbuffer\soverread\sin\svdbeCompareRecordInt()\sthat\smight\soccur\sif\sthe\sdatabase\sis\scorrupt. +D 2014-03-03T20:48:50.982 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -281,7 +281,7 @@ F src/vdbe.c 75c3f5d27ab79af214646cf37d7551bc8cec09c2 F src/vdbe.h d189f92468a17a6f04daeec9df3b767f50557b21 F src/vdbeInt.h 9ccca0bc7646c918d065943e44bead4bf5de213d F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c b817480055ea37f04cbda6524cbcda56d8620c78 +F src/vdbeaux.c 687165bd405b33553c9aaf5da74c249cea083d24 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 2d7918e4c80546d943414668b1485b2581f58a28 F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59 @@ -404,6 +404,7 @@ F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 F test/corruptG.test 58ec333a01997fe655e34e5bea52b7a2a6b9704d F test/corruptH.test 9d8186f6f8751efdfd445d8546fd98f073499039 +F test/corruptI.test d9eca60cb373215d97e0994bf104f9a37e1ac0fc F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62 F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f @@ -1153,7 +1154,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P ba8993727e5752cbc92c7d78437e9e0510c899f7 -R 84a57b7d3530d77238186688acf2fb15 -U drh -Z 743719e98998c2037f212aec24c916c8 +P 1f4991ab1676bf85599fc32068ceeddeb05f648c +R 112194c4c042293d2f5fc41663c08a7a +U dan +Z e0c8dc8360525071b6a4931f6b50a318 diff --git a/manifest.uuid b/manifest.uuid index 2f5a48fd68..f96d8cdcc1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1f4991ab1676bf85599fc32068ceeddeb05f648c \ No newline at end of file +7c0b4381f0e6f33cb13299a915851d9431bf3850 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 47a3f0899b..dd724cc39e 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3575,7 +3575,8 @@ static int vdbeRecordCompareInt( const UnpackedRecord *pPKey2, /* Right key */ int bSkip /* Ignored */ ){ - const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1]; + int szHdr = *(const u8*)pKey1; + const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; int serial_type = ((const u8*)pKey1)[1]; int res; i64 v = pPKey2->aMem[0].u.i; @@ -3583,7 +3584,6 @@ static int vdbeRecordCompareInt( UNUSED_PARAMETER(bSkip); assert( bSkip==0 ); - switch( serial_type ){ case 1: lhs = (char)(aKey[0]); @@ -3718,12 +3718,20 @@ static int vdbeRecordCompareString( ** as the only argument. */ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ - /* As the varints that make up a record header are all 5 bytes in size - ** or less, if the binary keys being compared have 25 or fewer fields - ** then it is guaranteed that the varint at the start of every record - ** (the record-header size in bytes) fits in a single byte. If this - ** is not the case, then sqlite3VdbeRecordCompare() must be used. */ - if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=25 ){ + /* varintRecordCompareInt() and varintRecordCompareString() both assume + ** that the size-of-header varint that occurs at the start of each record + ** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt() + ** also assumes that it is safe to overread a buffer by at least the + ** maximum possible legal header size plus 8 bytes. Because there is + ** guaranteed to be at least 74 (but not 136) bytes of padding following each + ** buffer passed to varintRecordCompareInt() this makes it convenient to + ** limit the size of the header to 64 bytes in cases where the first field + ** is an integer. + ** + ** The easiest way to enforce this limit is to consider only records with + ** 13 fields or less. If the first field is an integer, the maximum legal + ** header size is (12*5 + 1 + 1) bytes. */ + if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){ int flags = p->aMem[0].flags; if( p->pKeyInfo->aSortOrder[0] ){ p->r1 = 1; diff --git a/test/corruptI.test b/test/corruptI.test new file mode 100644 index 0000000000..9c9a19310b --- /dev/null +++ b/test/corruptI.test @@ -0,0 +1,47 @@ +# 2014-01-20 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix corruptI + +# Do not use a codec for tests in this file, as the database file is +# manipulated directly using tcl scripts (using the [hexio_write] command). +# +do_not_use_codec +database_may_be_corrupt + +# Initialize the database. +# +do_execsql_test 1.1 { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=0; + CREATE TABLE t1(a); + CREATE INDEX i1 ON t1(a); + INSERT INTO t1 VALUES('a'); +} {} +db close + +do_test 1.2 { + set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]] + set off [expr 2*1024 + $offset + 1] + hexio_write test.db $off FF06 + + breakpoint + + sqlite3 db test.db + catchsql { SELECT * FROM t1 WHERE a = 10 } +} {1 {database disk image is malformed}} + + +finish_test + From 13a747e5e4ef5a8ab69169ad9d2dec2653d3490b Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Mar 2014 21:46:55 +0000 Subject: [PATCH 10/10] Fix a couple of harmless compiler warnings. FossilOrigin-Name: fcf480cc630976b619aabd5f7fb7b09601a178fb --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/btree.c | 2 ++ src/vdbeaux.c | 1 - 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 1f36291c28..52a206ae83 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\sa\sbuffer\soverread\sin\svdbeCompareRecordInt()\sthat\smight\soccur\sif\sthe\sdatabase\sis\scorrupt. -D 2014-03-03T20:48:50.982 +C Fix\sa\scouple\sof\sharmless\scompiler\swarnings. +D 2014-03-03T21:46:55.799 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -163,7 +163,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c d288e668614449571ec269535dc4aaf216a23db2 +F src/btree.c 7a81c2c6b5c0bf6334b4247e709c639c573fbcc1 F src/btree.h 9e0f97c01b972f779eb7655cfb4f8727fd6dc26f F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4 F src/build.c 00ce613bc2256e525c9195cb10d0df7bcc48d1f0 @@ -281,7 +281,7 @@ F src/vdbe.c 75c3f5d27ab79af214646cf37d7551bc8cec09c2 F src/vdbe.h d189f92468a17a6f04daeec9df3b767f50557b21 F src/vdbeInt.h 9ccca0bc7646c918d065943e44bead4bf5de213d F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c 687165bd405b33553c9aaf5da74c249cea083d24 +F src/vdbeaux.c 5adf67ef9cdaa57b393c0a8bf0a29eadbd6f9158 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 F src/vdbemem.c 2d7918e4c80546d943414668b1485b2581f58a28 F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59 @@ -1154,7 +1154,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 1f4991ab1676bf85599fc32068ceeddeb05f648c -R 112194c4c042293d2f5fc41663c08a7a -U dan -Z e0c8dc8360525071b6a4931f6b50a318 +P 7c0b4381f0e6f33cb13299a915851d9431bf3850 +R 4042a62ac4c0618104f381105ba13add +U drh +Z 0037dd9417989b6d6f935caf436e0a2a diff --git a/manifest.uuid b/manifest.uuid index f96d8cdcc1..aaa189ba4b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c0b4381f0e6f33cb13299a915851d9431bf3850 \ No newline at end of file +fcf480cc630976b619aabd5f7fb7b09601a178fb \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 4d42969be8..ce35afbd58 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4575,6 +4575,8 @@ int sqlite3BtreeMovetoUnpacked( || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 ); + }else{ + xRecordCompare = 0; /* Not actually used. Avoids a compiler warning. */ } rc = moveToRoot(pCur); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index dd724cc39e..2526d6fc50 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3575,7 +3575,6 @@ static int vdbeRecordCompareInt( const UnpackedRecord *pPKey2, /* Right key */ int bSkip /* Ignored */ ){ - int szHdr = *(const u8*)pKey1; const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; int serial_type = ((const u8*)pKey1)[1]; int res;