/ Check-in [0d99229a]
Login

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

Overview
Comment:Merge in the latest changes from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schema-parse-refactor
Files: files | file ages | folders
SHA1: 0d99229a7a58da07748072326f6261c533c1958f
User & Date: drh 2011-04-02 20:08:10
Context
2011-04-04
13:07
Merge in the latest changes from trunk. check-in: 47b79c40 user: drh tags: schema-parse-refactor
2011-04-02
20:08
Merge in the latest changes from trunk. check-in: 0d99229a user: drh tags: schema-parse-refactor
20:01
Change the name of the "tAttachMask" datatype to "yDbMask". check-in: 3d6f2e82 user: drh tags: trunk
16:50
When resetting any non-TEMP schema, also reset the TEMP schema since it might be holding references to the non-TEMP schema that just got reset. check-in: 211d5dde user: drh tags: schema-parse-refactor
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
....
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
....
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
    /* The cookie mask contains one bit for each database file open.
    ** (Bit 0 is for main, bit 1 is for temp, and so forth.)  Bits are
    ** set for each database that is used.  Generate code to start a
    ** transaction on each used database and to verify the schema cookie
    ** on each used database.
    */
    if( pParse->cookieGoto>0 ){
      tAttachMask mask;
      int iDb;
      sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
      for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
        if( (mask & pParse->cookieMask)==0 ) continue;
        sqlite3VdbeUsesBtree(v, iDb);
        sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
        if( db->init.busy==0 ){
................................................................................
  if( pToplevel->cookieGoto==0 ){
    Vdbe *v = sqlite3GetVdbe(pToplevel);
    if( v==0 ) return;  /* This only happens if there was a prior error */
    pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
  }
  if( iDb>=0 ){
    sqlite3 *db = pToplevel->db;
    tAttachMask mask;

    assert( iDb<db->nDb );
    assert( db->aDb[iDb].pBt!=0 || iDb==1 );
    assert( iDb<SQLITE_MAX_ATTACHED+2 );
    mask = ((tAttachMask)1)<<iDb;
    if( (pToplevel->cookieMask & mask)==0 ){
      pToplevel->cookieMask |= mask;
      pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
      if( !OMIT_TEMPDB && iDb==1 ){
        sqlite3OpenTempDatabase(pToplevel);
      }
    }
................................................................................
** rollback the whole transaction.  For operations where all constraints
** can be checked before any changes are made to the database, it is never
** necessary to undo a write and the checkpoint should not be set.
*/
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
  Parse *pToplevel = sqlite3ParseToplevel(pParse);
  sqlite3CodeVerifySchema(pParse, iDb);
  pToplevel->writeMask |= ((tAttachMask)1)<<iDb;
  pToplevel->isMultiWrite |= setStatement;
}

/*
** Indicate that the statement currently under construction might write
** more than one entry (example: deleting one row then inserting another,
** inserting multiple rows in a table, or inserting a row and index entries.)







|







 







|




|







 







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
....
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
....
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
    /* The cookie mask contains one bit for each database file open.
    ** (Bit 0 is for main, bit 1 is for temp, and so forth.)  Bits are
    ** set for each database that is used.  Generate code to start a
    ** transaction on each used database and to verify the schema cookie
    ** on each used database.
    */
    if( pParse->cookieGoto>0 ){
      yDbMask mask;
      int iDb;
      sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
      for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
        if( (mask & pParse->cookieMask)==0 ) continue;
        sqlite3VdbeUsesBtree(v, iDb);
        sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
        if( db->init.busy==0 ){
................................................................................
  if( pToplevel->cookieGoto==0 ){
    Vdbe *v = sqlite3GetVdbe(pToplevel);
    if( v==0 ) return;  /* This only happens if there was a prior error */
    pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
  }
  if( iDb>=0 ){
    sqlite3 *db = pToplevel->db;
    yDbMask mask;

    assert( iDb<db->nDb );
    assert( db->aDb[iDb].pBt!=0 || iDb==1 );
    assert( iDb<SQLITE_MAX_ATTACHED+2 );
    mask = ((yDbMask)1)<<iDb;
    if( (pToplevel->cookieMask & mask)==0 ){
      pToplevel->cookieMask |= mask;
      pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
      if( !OMIT_TEMPDB && iDb==1 ){
        sqlite3OpenTempDatabase(pToplevel);
      }
    }
................................................................................
** rollback the whole transaction.  For operations where all constraints
** can be checked before any changes are made to the database, it is never
** necessary to undo a write and the checkpoint should not be set.
*/
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
  Parse *pToplevel = sqlite3ParseToplevel(pParse);
  sqlite3CodeVerifySchema(pParse, iDb);
  pToplevel->writeMask |= ((yDbMask)1)<<iDb;
  pToplevel->isMultiWrite |= setStatement;
}

/*
** Indicate that the statement currently under construction might write
** more than one entry (example: deleting one row then inserting another,
** inserting multiple rows in a table, or inserting a row and index entries.)

Changes to src/os_unix.c.

390
391
392
393
394
395
396

397
398
399
400
401
402
403
404
405
406
407
  int rc = SQLITE_NOTFOUND;

  UNUSED_PARAMETER(pNotUsed);
  if( zName==0 ){
    /* If no zName is given, restore all system calls to their default
    ** settings and return NULL
    */

    for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
      if( aSyscall[i].pDefault ){
        aSyscall[i].pCurrent = aSyscall[i].pDefault;
        rc = SQLITE_OK;
      }
    }
  }else{
    /* If zName is specified, operate on only the one system call
    ** specified.
    */
    for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){







>



<







390
391
392
393
394
395
396
397
398
399
400

401
402
403
404
405
406
407
  int rc = SQLITE_NOTFOUND;

  UNUSED_PARAMETER(pNotUsed);
  if( zName==0 ){
    /* If no zName is given, restore all system calls to their default
    ** settings and return NULL
    */
    rc = SQLITE_OK;
    for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
      if( aSyscall[i].pDefault ){
        aSyscall[i].pCurrent = aSyscall[i].pDefault;

      }
    }
  }else{
    /* If zName is specified, operate on only the one system call
    ** specified.
    */
    for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){

Changes to src/sqliteInt.h.

2121
2122
2123
2124
2125
2126
2127

2128

2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
....
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
  Trigger *pTrigger;      /* Trigger this program was coded from */
  int orconf;             /* Default ON CONFLICT policy */
  SubProgram *pProgram;   /* Program implementing pTrigger/orconf */
  u32 aColmask[2];        /* Masks of old.*, new.* columns accessed */
  TriggerPrg *pNext;      /* Next entry in Parse.pTriggerPrg list */
};


/* Datatype for the bitmask of all attached databases */

#if SQLITE_MAX_ATTACHED>30
  typedef sqlite3_uint64 tAttachMask;
#else
  typedef unsigned int tAttachMask;
#endif

/*
** An SQL parser context.  A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
** carry around information that is global to the entire parse.
**
................................................................................
    int iTable;           /* Table cursor number */
    int iColumn;          /* Table column number */
    u8 tempReg;           /* iReg is a temp register that needs to be freed */
    int iLevel;           /* Nesting level */
    int iReg;             /* Reg with value of this column. 0 means none. */
    int lru;              /* Least recently used entry has the smallest value */
  } aColCache[SQLITE_N_COLCACHE];  /* One for each column cache entry */
  tAttachMask writeMask;  /* Start a write transaction on these databases */
  tAttachMask cookieMask; /* Bitmask of schema verified databases */
  u8 isMultiWrite;     /* True if statement may affect/insert multiple rows */
  u8 mayAbort;         /* True if statement may throw an ABORT exception */
  int cookieGoto;      /* Address of OP_Goto to cookie verifier subroutine */
  int cookieValue[SQLITE_MAX_ATTACHED+2];  /* Values of cookies to verify */
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nTableLock;        /* Number of locks in aTableLock */
  TableLock *aTableLock; /* Required table locks for shared-cache mode */







>
|
>

|

|







 







|
|







2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
....
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
  Trigger *pTrigger;      /* Trigger this program was coded from */
  int orconf;             /* Default ON CONFLICT policy */
  SubProgram *pProgram;   /* Program implementing pTrigger/orconf */
  u32 aColmask[2];        /* Masks of old.*, new.* columns accessed */
  TriggerPrg *pNext;      /* Next entry in Parse.pTriggerPrg list */
};

/*
** The yDbMask datatype for the bitmask of all attached databases.
*/
#if SQLITE_MAX_ATTACHED>30
  typedef sqlite3_uint64 yDbMask;
#else
  typedef unsigned int yDbMask;
#endif

/*
** An SQL parser context.  A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
** carry around information that is global to the entire parse.
**
................................................................................
    int iTable;           /* Table cursor number */
    int iColumn;          /* Table column number */
    u8 tempReg;           /* iReg is a temp register that needs to be freed */
    int iLevel;           /* Nesting level */
    int iReg;             /* Reg with value of this column. 0 means none. */
    int lru;              /* Least recently used entry has the smallest value */
  } aColCache[SQLITE_N_COLCACHE];  /* One for each column cache entry */
  yDbMask writeMask;   /* Start a write transaction on these databases */
  yDbMask cookieMask;  /* Bitmask of schema verified databases */
  u8 isMultiWrite;     /* True if statement may affect/insert multiple rows */
  u8 mayAbort;         /* True if statement may throw an ABORT exception */
  int cookieGoto;      /* Address of OP_Goto to cookie verifier subroutine */
  int cookieValue[SQLITE_MAX_ATTACHED+2];  /* Values of cookies to verify */
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nTableLock;        /* Number of locks in aTableLock */
  TableLock *aTableLock; /* Required table locks for shared-cache mode */

Changes to src/test_syscall.c.

594
595
596
597
598
599
600


















601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618

619
620
621
622
623
624
625
    Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(zSys, -1));
  }

  Tcl_SetObjResult(interp, pList);
  Tcl_DecrRefCount(pList);
  return TCL_OK;
}



















static int test_syscall(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  struct SyscallCmd {
    const char *zName;
    Tcl_ObjCmdProc *xCmd;
  } aCmd[] = {
    { "fault",     test_syscall_fault },
    { "install",   test_syscall_install },
    { "uninstall", test_syscall_uninstall },
    { "reset",     test_syscall_reset },
    { "errno",     test_syscall_errno },
    { "exists",    test_syscall_exists },
    { "list",      test_syscall_list },

    { 0, 0 }
  };
  int iCmd;
  int rc;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











|
|
|
|
|
|
|
>







594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
    Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(zSys, -1));
  }

  Tcl_SetObjResult(interp, pList);
  Tcl_DecrRefCount(pList);
  return TCL_OK;
}

static int test_syscall_defaultvfs(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_vfs *pVfs; 

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 2, objv, "");
    return TCL_ERROR;
  }

  pVfs = sqlite3_vfs_find(0);
  Tcl_SetObjResult(interp, Tcl_NewStringObj(pVfs->zName, -1));
  return TCL_OK;
}

static int test_syscall(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  struct SyscallCmd {
    const char *zName;
    Tcl_ObjCmdProc *xCmd;
  } aCmd[] = {
    { "fault",      test_syscall_fault },
    { "install",    test_syscall_install },
    { "uninstall",  test_syscall_uninstall },
    { "reset",      test_syscall_reset },
    { "errno",      test_syscall_errno },
    { "exists",     test_syscall_exists },
    { "list",       test_syscall_list },
    { "defaultvfs", test_syscall_defaultvfs },
    { 0, 0 }
  };
  int iCmd;
  int rc;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");

Changes to src/vdbeInt.h.

298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  u8 runOnlyOnce;         /* Automatically expire on reset */
  u8 minWriteFileFormat;  /* Minimum file format for writable database files */
  u8 inVtabMethod;        /* See comments above */
  u8 usesStmtJournal;     /* True if uses a statement journal */
  u8 readOnly;            /* True for read-only statements */
  u8 isPrepareV2;         /* True if prepared with prepare_v2() */
  int nChange;            /* Number of db changes made since last reset */
  tAttachMask btreeMask;  /* Bitmask of db->aDb[] entries referenced */
  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
  int aCounter[3];        /* Counters used by sqlite3_stmt_status() */
  BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
#ifndef SQLITE_OMIT_TRACE
  i64 startTime;          /* Time when query started - used for profiling */
#endif
  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */







|







298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  u8 runOnlyOnce;         /* Automatically expire on reset */
  u8 minWriteFileFormat;  /* Minimum file format for writable database files */
  u8 inVtabMethod;        /* See comments above */
  u8 usesStmtJournal;     /* True if uses a statement journal */
  u8 readOnly;            /* True for read-only statements */
  u8 isPrepareV2;         /* True if prepared with prepare_v2() */
  int nChange;            /* Number of db changes made since last reset */
  yDbMask btreeMask;      /* Bitmask of db->aDb[] entries referenced */
  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
  int aCounter[3];        /* Counters used by sqlite3_stmt_status() */
  BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
#ifndef SQLITE_OMIT_TRACE
  i64 startTime;          /* Time when query started - used for profiling */
#endif
  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */

Changes to src/vdbeaux.c.

947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
**
** The prepared statement has to know in advance which Btree objects
** will be used so that it can acquire mutexes on them all in sorted
** order (via sqlite3VdbeMutexArrayEnter().  Mutexes are acquired
** in order (and released in reverse order) to avoid deadlocks.
*/
void sqlite3VdbeUsesBtree(Vdbe *p, int i){
  tAttachMask mask;
  assert( i>=0 && i<p->db->nDb && i<sizeof(tAttachMask)*8 );
  assert( i<(int)sizeof(p->btreeMask)*8 );
  mask = ((u32)1)<<i;
  if( (p->btreeMask & mask)==0 ){
    p->btreeMask |= mask;
    sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
  }
}







|
|







947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
**
** The prepared statement has to know in advance which Btree objects
** will be used so that it can acquire mutexes on them all in sorted
** order (via sqlite3VdbeMutexArrayEnter().  Mutexes are acquired
** in order (and released in reverse order) to avoid deadlocks.
*/
void sqlite3VdbeUsesBtree(Vdbe *p, int i){
  yDbMask mask;
  assert( i>=0 && i<p->db->nDb && i<sizeof(yDbMask)*8 );
  assert( i<(int)sizeof(p->btreeMask)*8 );
  mask = ((u32)1)<<i;
  if( (p->btreeMask & mask)==0 ){
    p->btreeMask |= mask;
    sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
  }
}

Changes to test/oserror.test.

107
108
109
110
111
112
113

114
115
116
117
do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c:\d+: \(\d+\) unlink\(.*test.db-wal\) - }
do_test 2.1.3 { 
  dbh close
  forcedelete test.db-wal
} {}
  


sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test







>




107
108
109
110
111
112
113
114
115
116
117
118
do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c:\d+: \(\d+\) unlink\(.*test.db-wal\) - }
do_test 2.1.3 { 
  dbh close
  forcedelete test.db-wal
} {}
  

test_syscall reset
sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test

Changes to test/syscall.test.

15
16
17
18
19
20
21
22
23





24
25
26
27
28
29
30
..
48
49
50
51
52
53
54
55
56
57
58


59
60


61
62
63
64
65
66
67
...
241
242
243
244
245
246
247
248
249

250
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl

if {[llength [info commands test_syscall]]==0} {
  finish_test
  return
} 
set testprefix syscall







#-------------------------------------------------------------------------
# Tests for the xSetSystemCall method.
#
do_test 1.1.1 {
  list [catch { test_syscall reset open } msg] $msg
} {0 {}}
................................................................................
#
do_test 2.1.1 { test_syscall exists open } 1
do_test 2.1.2 { test_syscall exists nosuchcall } 0

#-------------------------------------------------------------------------
# Tests for the xNextSystemCall method.
#
set syscall_list [list                                \
    open close access getcwd stat fstat ftruncate     \
    fcntl read pread write pwrite fchmod              \
]


if {[test_syscall exists fallocate]} {lappend syscall_list fallocate}
do_test 3.1 { test_syscall list } $syscall_list



#-------------------------------------------------------------------------
# This test verifies that if a call to open() fails and errno is set to
# EINTR, the call is retried. If it succeeds, execution continues as if
# nothing happened. 
#
test_syscall reset
................................................................................
} {
  do_test 8.2.$tn {
    file_control_sizehint_test db main $hint
    file size test.db
  } $size
}




finish_test







<

>
>
>
>
>







 







|
|
|
<
>
>
|
<
>
>







 







<
<
>

15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30
31
32
33
34
..
52
53
54
55
56
57
58
59
60
61

62
63
64

65
66
67
68
69
70
71
72
73
...
247
248
249
250
251
252
253


254
255
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl

if {[llength [info commands test_syscall]]==0} {
  finish_test
  return
} 


if {[test_syscall defaultvfs] != "unix"} {
  finish_test
  return
}
set testprefix syscall

#-------------------------------------------------------------------------
# Tests for the xSetSystemCall method.
#
do_test 1.1.1 {
  list [catch { test_syscall reset open } msg] $msg
} {0 {}}
................................................................................
#
do_test 2.1.1 { test_syscall exists open } 1
do_test 2.1.2 { test_syscall exists nosuchcall } 0

#-------------------------------------------------------------------------
# Tests for the xNextSystemCall method.
#
foreach s {
    open close access getcwd stat fstat ftruncate
    fcntl read pread write pwrite fchmod fallocate

    pread64 pwrite64
} {
  if {[test_syscall exists $s]} {lappend syscall_list $s}

}
do_test 3.1 { lsort [test_syscall list] } [lsort $syscall_list]

#-------------------------------------------------------------------------
# This test verifies that if a call to open() fails and errno is set to
# EINTR, the call is retried. If it succeeds, execution continues as if
# nothing happened. 
#
test_syscall reset
................................................................................
} {
  do_test 8.2.$tn {
    file_control_sizehint_test db main $hint
    file size test.db
  } $size
}



test_syscall reset
finish_test