SQLite

Check-in [aef6698c73]
Login

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

Overview
Comment:Merge trunk changes into experimental branch.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: aef6698c732f3f9e46986f53e63ca2bdf5f7d208
User & Date: dan 2010-08-06 13:53:10.000
Context
2010-08-06
14:37
Fix some problems with running test scripts with the inmemory_journal permutation. (check-in: 7bd8ba084e user: dan tags: experimental)
13:53
Merge trunk changes into experimental branch. (check-in: aef6698c73 user: dan tags: experimental)
13:50
Do not run some tests in notify3.test with the inmemory_journal permutation. They do not pass as the tests assume that the database schema is not loaded until the first invocation of [db eval]. This is not true with the inmemory_journal permutation. (check-in: 698fba826e user: dan tags: trunk)
12:00
Further updates to comments in pager.c. (check-in: 5f4c17a33f user: dan tags: experimental)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
  int noSync                      /* True to omit the xSync on the db file */
){
  int rc = SQLITE_OK;             /* Return code */

  assert( pPager->eState==PAGER_WRITER_LOCKED
       || pPager->eState==PAGER_WRITER_CACHEMOD
       || pPager->eState==PAGER_WRITER_DBMOD
       || pPager->eState==PAGER_WRITER_ERROR
  );
  assert( assert_pager_state(pPager) );

  /* If a prior error occurred, report that error again. */
  if( pPager->errCode ) return pPager->errCode;

  PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", 







|







5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
  int noSync                      /* True to omit the xSync on the db file */
){
  int rc = SQLITE_OK;             /* Return code */

  assert( pPager->eState==PAGER_WRITER_LOCKED
       || pPager->eState==PAGER_WRITER_CACHEMOD
       || pPager->eState==PAGER_WRITER_DBMOD
       || pPager->eState==PAGER_ERROR
  );
  assert( assert_pager_state(pPager) );

  /* If a prior error occurred, report that error again. */
  if( pPager->errCode ) return pPager->errCode;

  PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", 
Changes to src/sqliteInt.h.
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
** argument to sqlite3VdbeKeyCompare and is used to control the 
** comparison of the two index keys.
*/
struct KeyInfo {
  sqlite3 *db;        /* The database connection */
  u8 enc;             /* Text encoding - one of the TEXT_Utf* values */
  u16 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 */
};

/*
** An instance of the following structure holds information about a
** single index record that has already been parsed out into individual
** values.







|







1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
** argument to sqlite3VdbeKeyCompare and is used to control the 
** comparison of the two index keys.
*/
struct KeyInfo {
  sqlite3 *db;        /* The database connection */
  u8 enc;             /* Text encoding - one of the TEXT_Utf* values */
  u16 nField;         /* Number of entries in aColl[] */
  u8 *aSortOrder;     /* Sort order for each column.  May be NULL */
  CollSeq *aColl[1];  /* Collating sequence for each term of the key */
};

/*
** An instance of the following structure holds information about a
** single index record that has already been parsed out into individual
** values.
Changes to src/vdbe.c.
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
** then jump to P2.  Otherwise fall through to the next instruction.
**
** If P5 is non-zero then the key value is increased by an epsilon 
** prior to the comparison.  This make the opcode work like IdxGT except
** that if the key from register P3 is a prefix of the key in the cursor,
** the result is false whereas it would be true with IdxGT.
*/
/* Opcode: IdxLT P1 P2 P3 * P5
**
** The P4 register values beginning with P3 form an unpacked index 
** key that omits the ROWID.  Compare this key value against the index 
** that P1 is currently pointing to, ignoring the ROWID on the P1 index.
**
** If the P1 index entry is less than the key value then jump to P2.
** Otherwise fall through to the next instruction.







|







4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
** then jump to P2.  Otherwise fall through to the next instruction.
**
** If P5 is non-zero then the key value is increased by an epsilon 
** prior to the comparison.  This make the opcode work like IdxGT except
** that if the key from register P3 is a prefix of the key in the cursor,
** the result is false whereas it would be true with IdxGT.
*/
/* Opcode: IdxLT P1 P2 P3 P4 P5
**
** The P4 register values beginning with P3 form an unpacked index 
** key that omits the ROWID.  Compare this key value against the index 
** that P1 is currently pointing to, ignoring the ROWID on the P1 index.
**
** If the P1 index entry is less than the key value then jump to P2.
** Otherwise fall through to the next instruction.
Changes to src/where.c.
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
    **         If there are no inequality constraints, then N is at
    **         least one.
    **
    **         This case is also used when there are no WHERE clause
    **         constraints but an index is selected anyway, in order
    **         to force the output order to conform to an ORDER BY.
    */  
    int aStartOp[] = {
      0,
      0,
      OP_Rewind,           /* 2: (!start_constraints && startEq &&  !bRev) */
      OP_Last,             /* 3: (!start_constraints && startEq &&   bRev) */
      OP_SeekGt,           /* 4: (start_constraints  && !startEq && !bRev) */
      OP_SeekLt,           /* 5: (start_constraints  && !startEq &&  bRev) */
      OP_SeekGe,           /* 6: (start_constraints  &&  startEq && !bRev) */
      OP_SeekLe            /* 7: (start_constraints  &&  startEq &&  bRev) */
    };
    int aEndOp[] = {
      OP_Noop,             /* 0: (!end_constraints) */
      OP_IdxGE,            /* 1: (end_constraints && !bRev) */
      OP_IdxLT             /* 2: (end_constraints && bRev) */
    };
    int nEq = pLevel->plan.nEq;
    int isMinQuery = 0;          /* If this is an optimized SELECT min(x).. */
    int regBase;                 /* Base register holding constraint values */
    int r1;                      /* Temp register */
    WhereTerm *pRangeStart = 0;  /* Inequality constraint at range start */
    WhereTerm *pRangeEnd = 0;    /* Inequality constraint at range end */
    int startEq;                 /* True if range start uses ==, >= or <= */
    int endEq;                   /* True if range end uses ==, >= or <= */
    int start_constraints;       /* Start of range is constrained */
    int nConstraint;             /* Number of constraint terms */
    Index *pIdx;         /* The index we will be using */
    int iIdxCur;         /* The VDBE cursor for the index */
    int nExtraReg = 0;   /* Number of extra registers needed */
    int op;              /* Instruction opcode */
    char *zStartAff;             /* Affinity for start of range constraint */
    char *zEndAff;               /* Affinity for end of range constraint */

    pIdx = pLevel->plan.u.pIdx;
    iIdxCur = pLevel->iIdxCur;
    k = pIdx->aiColumn[nEq];     /* Column for inequality constraints */








|









|




|









|
|
|
|







3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
    **         If there are no inequality constraints, then N is at
    **         least one.
    **
    **         This case is also used when there are no WHERE clause
    **         constraints but an index is selected anyway, in order
    **         to force the output order to conform to an ORDER BY.
    */  
    static const u8 aStartOp[] = {
      0,
      0,
      OP_Rewind,           /* 2: (!start_constraints && startEq &&  !bRev) */
      OP_Last,             /* 3: (!start_constraints && startEq &&   bRev) */
      OP_SeekGt,           /* 4: (start_constraints  && !startEq && !bRev) */
      OP_SeekLt,           /* 5: (start_constraints  && !startEq &&  bRev) */
      OP_SeekGe,           /* 6: (start_constraints  &&  startEq && !bRev) */
      OP_SeekLe            /* 7: (start_constraints  &&  startEq &&  bRev) */
    };
    static const u8 aEndOp[] = {
      OP_Noop,             /* 0: (!end_constraints) */
      OP_IdxGE,            /* 1: (end_constraints && !bRev) */
      OP_IdxLT             /* 2: (end_constraints && bRev) */
    };
    int nEq = pLevel->plan.nEq;  /* Number of == or IN terms */
    int isMinQuery = 0;          /* If this is an optimized SELECT min(x).. */
    int regBase;                 /* Base register holding constraint values */
    int r1;                      /* Temp register */
    WhereTerm *pRangeStart = 0;  /* Inequality constraint at range start */
    WhereTerm *pRangeEnd = 0;    /* Inequality constraint at range end */
    int startEq;                 /* True if range start uses ==, >= or <= */
    int endEq;                   /* True if range end uses ==, >= or <= */
    int start_constraints;       /* Start of range is constrained */
    int nConstraint;             /* Number of constraint terms */
    Index *pIdx;                 /* The index we will be using */
    int iIdxCur;                 /* The VDBE cursor for the index */
    int nExtraReg = 0;           /* Number of extra registers needed */
    int op;                      /* Instruction opcode */
    char *zStartAff;             /* Affinity for start of range constraint */
    char *zEndAff;               /* Affinity for end of range constraint */

    pIdx = pLevel->plan.u.pIdx;
    iIdxCur = pLevel->iIdxCur;
    k = pIdx->aiColumn[nEq];     /* Column for inequality constraints */

Changes to test/notify3.test.
88
89
90
91
92
93
94






95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
#
# This block tests that if the loading of schemas as a result of an
# ATTACH fails due to locks on the schema table held by other shared-cache
# connections the extended error code is SQLITE_LOCKED_SHAREDCACHE and
# it is possible to use the unlock-notify mechanism to determine when
# the ATTACH might succeed.
#






foreach {
  tn
  db1_loaded
  db2_loaded
  enable_extended_errors
  result
  error1 error2
} "
  0   0 0 0   $err     SQLITE_LOCKED               SQLITE_LOCKED_SHAREDCACHE
  1   0 0 1   $err     SQLITE_LOCKED_SHAREDCACHE   SQLITE_LOCKED_SHAREDCACHE
  2   0 1 0   $err     SQLITE_LOCKED               SQLITE_LOCKED_SHAREDCACHE
  3   0 1 1   $err     SQLITE_LOCKED_SHAREDCACHE   SQLITE_LOCKED_SHAREDCACHE
  4   1 0 0   $err     SQLITE_LOCKED               SQLITE_LOCKED_SHAREDCACHE
  5   1 0 1   $err     SQLITE_LOCKED_SHAREDCACHE   SQLITE_LOCKED_SHAREDCACHE
  6   1 1 0   $noerr   SQLITE_OK                   SQLITE_OK
  7   1 1 1   $noerr   SQLITE_OK                   SQLITE_OK
" {

  do_test notify3-2.$tn.1 {
    catch { db1 close }
    catch { db2 close }
    sqlite3 db1 test.db
    sqlite3 db2 test.db2

    sqlite3_extended_result_codes db1 $enable_extended_errors
    sqlite3_extended_result_codes db2 $enable_extended_errors

    if { $db1_loaded } { db1 eval "SELECT * FROM sqlite_master" }
    if { $db2_loaded } { db2 eval "SELECT * FROM sqlite_master" }

    db2 eval "BEGIN EXCLUSIVE"
    catchsql "ATTACH 'test.db2' AS two" db1
  } $result

  do_test notify3-2.$tn.2 {
    list [sqlite3_errcode db1] [sqlite3_extended_errcode db1]
  } [list $error1 $error2]

  do_test notify3-2.$tn.3 {
    db1 unlock_notify {set invoked 1}
    set invoked 0
    db2 eval commit
    set invoked
  } [lindex $result 0]

}
catch { db1 close }
catch { db2 close }


sqlite3_enable_shared_cache $esc
finish_test







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







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#
# This block tests that if the loading of schemas as a result of an
# ATTACH fails due to locks on the schema table held by other shared-cache
# connections the extended error code is SQLITE_LOCKED_SHAREDCACHE and
# it is possible to use the unlock-notify mechanism to determine when
# the ATTACH might succeed.
#
# This test does not work for test-permutations that specify SQL to
# be executed as part of the [sqlite3] command that opens the database.
# Executing such SQL causes SQLite to load the database schema into memory 
# earlier than expected, causing test cases to fail.
#
if {[presql] == ""} {
  foreach {
    tn
    db1_loaded
    db2_loaded
    enable_extended_errors
    result
    error1 error2
  } "
    0   0 0 0   $err     SQLITE_LOCKED               SQLITE_LOCKED_SHAREDCACHE
    1   0 0 1   $err     SQLITE_LOCKED_SHAREDCACHE   SQLITE_LOCKED_SHAREDCACHE
    2   0 1 0   $err     SQLITE_LOCKED               SQLITE_LOCKED_SHAREDCACHE
    3   0 1 1   $err     SQLITE_LOCKED_SHAREDCACHE   SQLITE_LOCKED_SHAREDCACHE
    4   1 0 0   $err     SQLITE_LOCKED               SQLITE_LOCKED_SHAREDCACHE
    5   1 0 1   $err     SQLITE_LOCKED_SHAREDCACHE   SQLITE_LOCKED_SHAREDCACHE
    6   1 1 0   $noerr   SQLITE_OK                   SQLITE_OK
    7   1 1 1   $noerr   SQLITE_OK                   SQLITE_OK
  " {
  
    do_test notify3-2.$tn.1 {
      catch { db1 close }
      catch { db2 close }
      sqlite3 db1 test.db
      sqlite3 db2 test.db2
  
      sqlite3_extended_result_codes db1 $enable_extended_errors
      sqlite3_extended_result_codes db2 $enable_extended_errors
  
      if { $db1_loaded } { db1 eval "SELECT * FROM sqlite_master" }
      if { $db2_loaded } { db2 eval "SELECT * FROM sqlite_master" }
  
      db2 eval "BEGIN EXCLUSIVE"
      catchsql "ATTACH 'test.db2' AS two" db1
    } $result
  
    do_test notify3-2.$tn.2 {
      list [sqlite3_errcode db1] [sqlite3_extended_errcode db1]
    } [list $error1 $error2]
  
    do_test notify3-2.$tn.3 {
      db1 unlock_notify {set invoked 1}
      set invoked 0
      db2 eval commit
      set invoked
    } [lindex $result 0]
  }
}
catch { db1 close }
catch { db2 close }


sqlite3_enable_shared_cache $esc
finish_test
Changes to test/tester.tcl.
66
67
68
69
70
71
72

73
74
75
76
77
78
79
# Commands to help create test files that run with the "WAL" and other
# permutations (see file permutations.test):
#
#      wal_is_wal_mode
#      wal_set_journal_mode   ?DB?
#      wal_check_journal_mode TESTNAME?DB?
#      permutation

#

# Set the precision of FP arithmatic used by the interpreter. And 
# configure SQLite to take database file locks on the page that begins
# 64KB into the database file instead of the one 1GB in. This means
# the code that handles that special case can be tested without creating
# very large database files.







>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# Commands to help create test files that run with the "WAL" and other
# permutations (see file permutations.test):
#
#      wal_is_wal_mode
#      wal_set_journal_mode   ?DB?
#      wal_check_journal_mode TESTNAME?DB?
#      permutation
#      presql
#

# Set the precision of FP arithmatic used by the interpreter. And 
# configure SQLite to take database file locks on the page that begins
# 64KB into the database file instead of the one 1GB in. This means
# the code that handles that special case can be tested without creating
# very large database files.
1145
1146
1147
1148
1149
1150
1151





1152
1153
1154
1155
1156
1157
1158
  }
}

proc permutation {} {
  set perm ""
  catch {set perm $::G(perm:name)}
  set perm





}

#-------------------------------------------------------------------------
#
proc slave_test_script {script} {

  # Create the interpreter used to run the test script.







>
>
>
>
>







1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
  }
}

proc permutation {} {
  set perm ""
  catch {set perm $::G(perm:name)}
  set perm
}
proc presql {} {
  set presql ""
  catch {set presql $::G(perm:presql)}
  set presql
}

#-------------------------------------------------------------------------
#
proc slave_test_script {script} {

  # Create the interpreter used to run the test script.