/ Check-in [055f173a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:A partial fix for ticket #3292. This fixes the original problem but there are other similar problems lurking in the code still. (CVS 5561)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 055f173ab1b6fb657bf817faa3a37335d8fa60d5
User & Date: drh 2008-08-13 14:07:40
Context
2008-08-13
19:11
Additional changes toward fixing ticket #3292. (CVS 5562) check-in: 0b92cbf5 user: drh tags: trunk
14:07
A partial fix for ticket #3292. This fixes the original problem but there are other similar problems lurking in the code still. (CVS 5561) check-in: 055f173a user: drh tags: trunk
2008-08-12
15:48
Make sure the lookaside test script saturates the lookaside buffer even when SQLITE_DEBUG is off. Ticket #3289 (CVS 5560) check-in: d6aacc5d user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.495 2008/08/02 17:36:46 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

................................................................................
          c = +1;
        }
      }else{
        int available;
        pCellKey = (void *)fetchPayload(pCur, &available, 0);
        nCellKey = pCur->info.nKey;
        if( available>=nCellKey ){
          c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pUnKey);
        }else{
          pCellKey = sqlite3Malloc( nCellKey );
          if( pCellKey==0 ){
            rc = SQLITE_NOMEM;
            goto moveto_finish;
          }
          rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
          c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pUnKey);
          sqlite3_free(pCellKey);
          if( rc ) goto moveto_finish;
        }
      }
      if( c==0 ){
        pCur->info.nKey = nCellKey;
        if( pPage->intKey && !pPage->leaf ){







|







 







|







|







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.496 2008/08/13 14:07:40 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

................................................................................
          c = +1;
        }
      }else{
        int available;
        pCellKey = (void *)fetchPayload(pCur, &available, 0);
        nCellKey = pCur->info.nKey;
        if( available>=nCellKey ){
          c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey);
        }else{
          pCellKey = sqlite3Malloc( nCellKey );
          if( pCellKey==0 ){
            rc = SQLITE_NOMEM;
            goto moveto_finish;
          }
          rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
          c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey);
          sqlite3_free(pCellKey);
          if( rc ) goto moveto_finish;
        }
      }
      if( c==0 ){
        pCur->info.nKey = nCellKey;
        if( pPage->intKey && !pPage->leaf ){

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.753 2008/08/12 15:21:12 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
** otherwise be equal, then return a result as if the second key
** were larger.
*/
struct KeyInfo {
  sqlite3 *db;        /* The database connection */
  u8 enc;             /* Text encoding - one of the TEXT_Utf* values */
  u8 incrKey;         /* Increase 2nd key by epsilon before comparison */
  u8 prefixIsEqual;   /* Treat a prefix as equal */
  int nField;         /* Number of entries in aColl[] */
  u8 *aSortOrder;     /* If defined an aSortOrder[i] is true, sort DESC */
  CollSeq *aColl[1];  /* Collating sequence for each term of the key */
};

/*
** Each SQL index is represented in memory by an







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.754 2008/08/13 14:07:40 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
** otherwise be equal, then return a result as if the second key
** were larger.
*/
struct KeyInfo {
  sqlite3 *db;        /* The database connection */
  u8 enc;             /* Text encoding - one of the TEXT_Utf* values */
  u8 incrKey;         /* Increase 2nd key by epsilon before comparison */
  u8 ckPrefixOnly;    /* Records are equal if shorter is a prefix of longer */
  int nField;         /* Number of entries in aColl[] */
  u8 *aSortOrder;     /* If defined an aSortOrder[i] is true, sort DESC */
  CollSeq *aColl[1];  /* Collating sequence for each term of the key */
};

/*
** Each SQL index is represented in memory by an

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.773 2008/08/11 18:44:58 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
................................................................................
  assert( i>=0 && i<p->nCursor );
  assert( p->apCsr[i]!=0 );
  if( (pC = p->apCsr[i])->pCursor!=0 ){
    int res;
    assert( pC->isTable==0 );
    assert( pIn3->flags & MEM_Blob );
    if( pOp->opcode==OP_Found ){
      pC->pKeyInfo->prefixIsEqual = 1;
    }
    rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res);
    pC->pKeyInfo->prefixIsEqual = 0;
    if( rc!=SQLITE_OK ){
      break;
    }
    alreadyExists = (res==0);
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }







|







 







|


|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.774 2008/08/13 14:07:40 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
................................................................................
  assert( i>=0 && i<p->nCursor );
  assert( p->apCsr[i]!=0 );
  if( (pC = p->apCsr[i])->pCursor!=0 ){
    int res;
    assert( pC->isTable==0 );
    assert( pIn3->flags & MEM_Blob );
    if( pOp->opcode==OP_Found ){
      pC->pKeyInfo->ckPrefixOnly = 1;
    }
    rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res);
    pC->pKeyInfo->ckPrefixOnly = 0;
    if( rc!=SQLITE_OK ){
      break;
    }
    alreadyExists = (res==0);
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }

Changes to src/vdbe.h.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.135 2008/08/01 20:10:08 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
void sqlite3VdbeSwap(Vdbe*,Vdbe*);

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3VdbeReleaseMemory(int);
#endif
UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int);
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);


#ifndef NDEBUG
  void sqlite3VdbeComment(Vdbe*, const char*, ...);
# define VdbeComment(X)  sqlite3VdbeComment X
  void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
# define VdbeNoopComment(X)  sqlite3VdbeNoopComment X
#else
# define VdbeComment(X)
# define VdbeNoopComment(X)
#endif

#endif







|







 







|













11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.136 2008/08/13 14:07:41 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
void sqlite3VdbeSwap(Vdbe*,Vdbe*);

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3VdbeReleaseMemory(int);
#endif
UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int);
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,int,UnpackedRecord*);


#ifndef NDEBUG
  void sqlite3VdbeComment(Vdbe*, const char*, ...);
# define VdbeComment(X)  sqlite3VdbeComment X
  void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
# define VdbeNoopComment(X)  sqlite3VdbeNoopComment X
#else
# define VdbeComment(X)
# define VdbeNoopComment(X)
#endif

#endif

Changes to src/vdbeaux.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
2270
2271
2272
2273
2274
2275
2276
2277













2278
2279
2280
2281
2282
2283
2284
2285
2286
2287

2288
2289
2290
2291
2292
2293
2294
2295
....
2301
2302
2303
2304
2305
2306
2307

2308
2309
2310
2311
2312
2313
2314
....
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341




2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
....
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
....
2405
2406
2407
2408
2409
2410
2411
2412




2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.405 2008/08/02 03:50:39 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"



................................................................................
** or positive integer if {nKey1, pKey1} is less than, equal to or 
** greater than pPKey2.  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.
** But if the lengths differ, Key2 must be the shorter of the two.













**
** Historical note: In earlier versions of this routine both Key1
** and Key2 were blobs obtained from OP_MakeRecord.  But we found
** that in typical use the same Key2 would be submitted multiple times
** in a row.  So an optimization was added to parse the Key2 key
** separately and submit the parsed version.  In this way, we avoid
** parsing the same Key2 multiple times in a row.
*/
int sqlite3VdbeRecordCompare(
  int nKey1, const void *pKey1, 

  UnpackedRecord *pPKey2
){
  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 nField;
  int rc = 0;
................................................................................
  mem1.enc = pKeyInfo->enc;
  mem1.db = pKeyInfo->db;
  mem1.flags = 0;
  mem1.zMalloc = 0;
  
  idx1 = getVarint32(aKey1, szHdr1);
  d1 = szHdr1;

  nField = pKeyInfo->nField;
  while( idx1<szHdr1 && i<pPKey2->nField ){
    u32 serial_type1;

    /* Read the serial types for the next element in each key. */
    idx1 += getVarint32( aKey1+idx1, serial_type1 );
    if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
................................................................................
    if( rc!=0 ){
      break;
    }
    i++;
  }
  if( mem1.zMalloc ) sqlite3VdbeMemRelease(&mem1);

  /* One of the keys ran out of fields, but all the fields up to that point
  ** were equal. If the incrKey flag is true, then the second key is
  ** treated as larger.
  */
  if( rc==0 ){
    if( pKeyInfo->incrKey ){
      rc = -1;
    }else if( !pKeyInfo->prefixIsEqual ){
      if( d1<nKey1 ){
        rc = 1;
      }




    }
  }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
               && pKeyInfo->aSortOrder[i] ){
    rc = -rc;
  }

  return rc;
}

/*
** The argument is an index entry composed using the OP_MakeRecord opcode.
** The last entry in this record should be an integer (specifically
** an integer rowid).  This routine returns the number of bytes in
** that integer.
*/
int sqlite3VdbeIdxRowidLen(const u8 *aKey, int nKey, int *pRowidLen){
................................................................................
  if( szHdr>nKey ){
    return SQLITE_CORRUPT_BKPT;
  }
  (void)getVarint32(&aKey[szHdr-1], typeRowid);
  *pRowidLen = sqlite3VdbeSerialTypeLen(typeRowid);
  return SQLITE_OK;
}
  

/*
** 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.
** Return SQLITE_OK if everything works, or an error code otherwise.
*/
int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
................................................................................
** Compare the key of the index entry that cursor pC is point to against
** the key string in pKey (of length nKey).  Write into *pRes a number
** that is negative, zero, or positive if pC is less than, equal to,
** or greater than pKey.  Return SQLITE_OK on success.
**
** pKey is either created without a rowid or is truncated so that it
** omits the rowid at the end.  The rowid at the end of the index entry
** is ignored as well.




*/
int sqlite3VdbeIdxKeyCompare(
  Cursor *pC,                 /* The cursor to compare against */
  UnpackedRecord *pUnpacked,
  int nKey, const u8 *pKey,   /* The key to compare */
  int *res                    /* Write the comparison result here */
){
  i64 nCellKey = 0;
  int rc;
  BtCursor *pCur = pC->pCursor;
  int lenRowid;
  Mem m;
  UnpackedRecord *pRec;
  char zSpace[200];

  sqlite3BtreeKeySize(pCur, &nCellKey);
  if( nCellKey<=0 ){
    *res = 0;
    return SQLITE_OK;
  }
  m.db = 0;
  m.flags = 0;
  m.zMalloc = 0;
  if( (rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m))
   || (rc = sqlite3VdbeIdxRowidLen((u8*)m.z, m.n, &lenRowid))
  ){
    return rc;
  }
  if( !pUnpacked ){
    pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey,
                                zSpace, sizeof(zSpace));
  }else{
    pRec = pUnpacked;
  }
  if( pRec==0 ){
    return SQLITE_NOMEM;
  }
  *res = sqlite3VdbeRecordCompare(m.n-lenRowid, m.z, pRec);
  if( !pUnpacked ){
    sqlite3VdbeDeleteUnpackedRecord(pRec);
  }
  sqlite3VdbeMemRelease(&m);
  return SQLITE_OK;
}








|







 







|
>
>
>
>
>
>
>
>
>
>
>
>
>






|


|
>
|







 







>







 







|
|
|
|
|
|
|
|
|
|
|
>
>
>
>








|







 







|







 







|
>
>
>
>



|






<












|
<
|











|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
....
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
....
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
....
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
....
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445

2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458

2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.406 2008/08/13 14:07:41 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"



................................................................................
** or positive integer if {nKey1, pKey1} is less than, equal to or 
** greater than pPKey2.  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 considered lessor than the 
** longer.  However if pPKey2->pKeyInfo->incrKey is set and
** the common prefixes are equal, then key1 is less than key2.
** Or if pPKey2->pKeyInfo->ckPrefixOnly 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.
**
** The last nHdrIgnore1 bytes of the header of pKey1 are ignored,
** as if they do not exist.  Usually nHdrIgnore1 is 0 which means
** that we look at the entire key.  But sometimes nHdrIgnore1 is 1.
** When nHdrIgnore1 is 1, the keys are index records and so the last
** column is a rowid.  The type code is always one byte in length.
** Hence, setting nHdrIgnore1 to 1 means that the final rowid at the
** end of the record should be treated as if it does not exist.
**
** Historical note: In earlier versions of this routine both Key1
** and Key2 were blobs obtained from OP_MakeRecord.  But we found
** that in typical use the same Key2 would be submitted multiple times
** in a row.  So an optimization was added to parse the Key2 key
** separately and submit the parsed version.  In this way, we avoid
** parsing the same Key2 multiple times.
*/
int sqlite3VdbeRecordCompare(
  int nKey1, const void *pKey1, /* Left key */
  int nHdrIgnore1,              /* Omit this much from end of key1 header */
  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 nField;
  int rc = 0;
................................................................................
  mem1.enc = pKeyInfo->enc;
  mem1.db = pKeyInfo->db;
  mem1.flags = 0;
  mem1.zMalloc = 0;
  
  idx1 = getVarint32(aKey1, szHdr1);
  d1 = szHdr1;
  szHdr1 -= nHdrIgnore1;
  nField = pKeyInfo->nField;
  while( idx1<szHdr1 && i<pPKey2->nField ){
    u32 serial_type1;

    /* Read the serial types for the next element in each key. */
    idx1 += getVarint32( aKey1+idx1, serial_type1 );
    if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
................................................................................
    if( rc!=0 ){
      break;
    }
    i++;
  }
  if( mem1.zMalloc ) sqlite3VdbeMemRelease(&mem1);

  if( rc==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 incrKey 
    ** flag is true, then break the tie by treating the second key 
    ** as larger.  If ckPrefixOnly is true, 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.
    */
    if( pKeyInfo->incrKey ){
      rc = -1;
    }else if( pKeyInfo->ckPrefixOnly ){
      /* Leave rc==0 */
    }else if( idx1<szHdr1 ){
      rc = 1;
    }
  }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
               && pKeyInfo->aSortOrder[i] ){
    rc = -rc;
  }

  return rc;
}
  
/*
** The argument is an index entry composed using the OP_MakeRecord opcode.
** The last entry in this record should be an integer (specifically
** an integer rowid).  This routine returns the number of bytes in
** that integer.
*/
int sqlite3VdbeIdxRowidLen(const u8 *aKey, int nKey, int *pRowidLen){
................................................................................
  if( szHdr>nKey ){
    return SQLITE_CORRUPT_BKPT;
  }
  (void)getVarint32(&aKey[szHdr-1], typeRowid);
  *pRowidLen = sqlite3VdbeSerialTypeLen(typeRowid);
  return SQLITE_OK;
}
 

/*
** 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.
** Return SQLITE_OK if everything works, or an error code otherwise.
*/
int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
................................................................................
** Compare the key of the index entry that cursor pC is point to against
** the key string in pKey (of length nKey).  Write into *pRes a number
** that is negative, zero, or positive if pC is less than, equal to,
** or greater than pKey.  Return SQLITE_OK on success.
**
** pKey is either created without a rowid or is truncated so that it
** omits the rowid at the end.  The rowid at the end of the index entry
** is ignored as well.  Hence, this routine only compares the prefixes 
** of the keys prior to the final rowid, not the entire key.
**
** pUnpacked may be an unpacked version of pKey,nKey.  If pUnpacked is
** supplied it is used in place of pKey,nKey.
*/
int sqlite3VdbeIdxKeyCompare(
  Cursor *pC,                 /* The cursor to compare against */
  UnpackedRecord *pUnpacked,  /* Unpacked version of pKey and nKey */
  int nKey, const u8 *pKey,   /* The key to compare */
  int *res                    /* Write the comparison result here */
){
  i64 nCellKey = 0;
  int rc;
  BtCursor *pCur = pC->pCursor;

  Mem m;
  UnpackedRecord *pRec;
  char zSpace[200];

  sqlite3BtreeKeySize(pCur, &nCellKey);
  if( nCellKey<=0 ){
    *res = 0;
    return SQLITE_OK;
  }
  m.db = 0;
  m.flags = 0;
  m.zMalloc = 0;
  rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m);

  if( rc ){
    return rc;
  }
  if( !pUnpacked ){
    pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey,
                                zSpace, sizeof(zSpace));
  }else{
    pRec = pUnpacked;
  }
  if( pRec==0 ){
    return SQLITE_NOMEM;
  }
  *res = sqlite3VdbeRecordCompare(m.n, m.z, 1, pRec);
  if( !pUnpacked ){
    sqlite3VdbeDeleteUnpackedRecord(pRec);
  }
  sqlite3VdbeMemRelease(&m);
  return SQLITE_OK;
}

Changes to test/corrupt7.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
68
69
70
71
72
73
74



75
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

100
101
102
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.  It specifically focuses
# on corrupt cell offsets in a btree page.
#
# $Id: corrupt7.test,v 1.4 2008/07/26 18:26:10 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# We must have the page_size pragma for these tests to work.
#
ifcapable !pager_pragmas {
................................................................................
  db close
  hexio_write test.db 1062 04
  sqlite3 db test.db
  db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Corruption detected in cell 15 on page 2}}




do_test corrupt7-3.1 {
  execsql {
    DROP TABLE t1;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 'one');
    INSERT INTO t1 VALUES(100, 'one hundred');
    INSERT INTO t1 VALUES(100000, 'one hundred thousand');
    CREATE INDEX i1 ON t1(b);
  }

  db close

  # Locate the 3rd cell in the index.
  set cell_offset [hexio_get_int [hexio_read test.db [expr 1024*2 + 12] 2]]
  incr cell_offset [expr 1024*2]
  incr cell_offset 1

  # This write corrupts the "header-size" field of the database record
  # stored in the index cell. At one point this was causing sqlite to 
  # reference invalid memory.
  hexio_write test.db $cell_offset FFFF7F
  
  sqlite3 db test.db
  catchsql {
    SELECT b FROM t1 WHERE b > 'o' AND b < 'p';
  }

} {1 {database disk image is malformed}}

finish_test







|







 







>
>
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

102
103
104
105
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.  It specifically focuses
# on corrupt cell offsets in a btree page.
#
# $Id: corrupt7.test,v 1.5 2008/08/13 14:07:41 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# We must have the page_size pragma for these tests to work.
#
ifcapable !pager_pragmas {
................................................................................
  db close
  hexio_write test.db 1062 04
  sqlite3 db test.db
  db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Corruption detected in cell 15 on page 2}}

# The code path that was causing the buffer overrun that this test
# case was checking for was removed.
#
#do_test corrupt7-3.1 {
#  execsql {
#    DROP TABLE t1;
#    CREATE TABLE t1(a, b);
#    INSERT INTO t1 VALUES(1, 'one');
#    INSERT INTO t1 VALUES(100, 'one hundred');
#    INSERT INTO t1 VALUES(100000, 'one hundred thousand');
#    CREATE INDEX i1 ON t1(b);

#  }
#  db close
#
#  # Locate the 3rd cell in the index.
#  set cell_offset [hexio_get_int [hexio_read test.db [expr 1024*2 + 12] 2]]
#  incr cell_offset [expr 1024*2]
#  incr cell_offset 1
#
#  # This write corrupts the "header-size" field of the database record
#  # stored in the index cell. At one point this was causing sqlite to 
#  # reference invalid memory.
#  hexio_write test.db $cell_offset FFFF7F
#  
#  sqlite3 db test.db
#  catchsql {
#    SELECT b FROM t1 WHERE b > 'o' AND b < 'p';

#  }
#} {1 {database disk image is malformed}}

finish_test

Added test/tkt3292.test.



























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 2008 August 12
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library. 
# Specifically, it tests the behavior of the sqlite3VdbeRecordCompare()
# routine in cases where the rowid is 0 or 1 in file format 4
# (meaning that the rowid has type code 8 or 9 with zero bytes of
# data).  Ticket #3292.
#
# $Id: tkt3292.test,v 1.1 2008/08/13 14:07:41 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test tkt3292-1.1 {
  execsql {
    PRAGMA legacy_file_format=OFF;
    CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT);
    INSERT INTO t1 VALUES(0, 1);
    INSERT INTO t1 VALUES(1, 1);
    INSERT INTO t1 VALUES(2, 1);
    CREATE INDEX i1 ON t1(b);
    SELECT * FROM t1 WHERE b>=1;
  }
} {0 1 1 1 2 1}
do_test tkt3292-1.2 {
  execsql {
    INSERT INTO t1 VALUES(3, 0);
    INSERT INTO t1 VALUES(4, 2);
    SELECT * FROM t1 WHERE b>=1;
  }
} {0 1 1 1 2 1 4 2}


do_test tkt3292-2.1 {
  execsql {
    CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c, d);
    INSERT INTO t2 VALUES(0, 1, 'hello', x'012345');
    INSERT INTO t2 VALUES(1, 1, 'hello', x'012345');
    INSERT INTO t2 VALUES(2, 1, 'hello', x'012345');
    CREATE INDEX i2 ON t2(b,c,d);
    SELECT a FROM t2 WHERE b=1 AND c='hello' AND d>=x'012345';
  }
} {0 1 2}
do_test tkt3292-2.2 {
  execsql {
    INSERT INTO t2 VALUES(3, 1, 'hello', x'012344');
    INSERT INTO t2 VALUES(4, 1, 'hello', x'012346');
    SELECT a FROM t2 WHERE b=1 AND c='hello' AND d>=x'012345';
  }
} {0 1 2 4}


finish_test