SQLite

Check-in [7453790c3b]
Login

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

Overview
Comment:Add the SQLITE_DBCONFIG_REQUIRE_WRITE_TXN connection setting, which if enabled requires all write operations to be enclosed within BEGIN ... COMMIT.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | require-write-txn
Files: files | file ages | folders
SHA1: 7453790c3b21c94b1f6d419598b120b7be9d3711
User & Date: drh 2016-02-02 00:59:51.351
Context
2016-02-02
00:59
Add the SQLITE_DBCONFIG_REQUIRE_WRITE_TXN connection setting, which if enabled requires all write operations to be enclosed within BEGIN ... COMMIT. (Leaf check-in: 7453790c3b user: drh tags: require-write-txn)
2016-02-01
21:48
Change the OP_SetCookie instruction to write the literal P3 value, not the value in register P3. (check-in: 6d7d4703eb user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
        sqlite3VdbeAddOp4Int(v,
          OP_Transaction,                    /* Opcode */
          iDb,                               /* P1 */
          DbMaskTest(pParse->writeMask,iDb), /* P2 */
          pParse->cookieValue[iDb],          /* P3 */
          db->aDb[iDb].pSchema->iGeneration  /* P4 */
        );
        if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
        VdbeComment((v,
              "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
      }
#ifndef SQLITE_OMIT_VIRTUALTABLE
      for(i=0; i<pParse->nVtabLock; i++){
        char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
        sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);







|







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
        sqlite3VdbeAddOp4Int(v,
          OP_Transaction,                    /* Opcode */
          iDb,                               /* P1 */
          DbMaskTest(pParse->writeMask,iDb), /* P2 */
          pParse->cookieValue[iDb],          /* P3 */
          db->aDb[iDb].pSchema->iGeneration  /* P4 */
        );
        if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, OPFLAG_TXNCK);
        VdbeComment((v,
              "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
      }
#ifndef SQLITE_OMIT_VIRTUALTABLE
      for(i=0; i<pParse->nVtabLock; i++){
        char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
        sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
3902
3903
3904
3905
3906
3907
3908

3909
3910
3911
3912
3913
3914
3915
    return;
  }
  v = sqlite3GetVdbe(pParse);
  if( !v ) return;
  if( type!=TK_DEFERRED ){
    for(i=0; i<db->nDb; i++){
      sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);

      sqlite3VdbeUsesBtree(v, i);
    }
  }
  sqlite3VdbeAddOp0(v, OP_AutoCommit);
}

/*







>







3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
    return;
  }
  v = sqlite3GetVdbe(pParse);
  if( !v ) return;
  if( type!=TK_DEFERRED ){
    for(i=0; i<db->nDb; i++){
      sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
      sqlite3VdbeChangeP5(v, OPFLAG_TXNBEGIN);
      sqlite3VdbeUsesBtree(v, i);
    }
  }
  sqlite3VdbeAddOp0(v, OP_AutoCommit);
}

/*
Changes to src/main.c.
793
794
795
796
797
798
799
800
801

802
803
804
805
806
807
808
      break;
    }
    default: {
      static const struct {
        int op;      /* The opcode */
        u32 mask;    /* Mask of the bit in sqlite3.flags to set/clear */
      } aFlagOp[] = {
        { SQLITE_DBCONFIG_ENABLE_FKEY,    SQLITE_ForeignKeys    },
        { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger  },

      };
      unsigned int i;
      rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
      for(i=0; i<ArraySize(aFlagOp); i++){
        if( aFlagOp[i].op==op ){
          int onoff = va_arg(ap, int);
          int *pRes = va_arg(ap, int*);







|
|
>







793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
      break;
    }
    default: {
      static const struct {
        int op;      /* The opcode */
        u32 mask;    /* Mask of the bit in sqlite3.flags to set/clear */
      } aFlagOp[] = {
        { SQLITE_DBCONFIG_ENABLE_FKEY,         SQLITE_ForeignKeys    },
        { SQLITE_DBCONFIG_ENABLE_TRIGGER,      SQLITE_EnableTrigger  },
        { SQLITE_DBCONFIG_REQUIRE_WRITE_TXN,   SQLITE_RequireWrTxn   },
      };
      unsigned int i;
      rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
      for(i=0; i<ArraySize(aFlagOp); i++){
        if( aFlagOp[i].op==op ){
          int onoff = va_arg(ap, int);
          int *pRes = va_arg(ap, int*);
Changes to src/sqlite.h.in.
487
488
489
490
491
492
493

494
495
496
497
498
499
500
#define SQLITE_CANTOPEN_FULLPATH       (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH       (SQLITE_CANTOPEN | (4<<8))
#define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))

#define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK        (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK   (SQLITE_CONSTRAINT | (2<<8))
#define SQLITE_CONSTRAINT_FOREIGNKEY   (SQLITE_CONSTRAINT | (3<<8))
#define SQLITE_CONSTRAINT_FUNCTION     (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))







>







487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
#define SQLITE_CANTOPEN_FULLPATH       (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH       (SQLITE_CANTOPEN | (4<<8))
#define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
#define SQLITE_READONLY_NOTXN          (SQLITE_READONLY | (5<<8))
#define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK        (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK   (SQLITE_CONSTRAINT | (2<<8))
#define SQLITE_CONSTRAINT_FOREIGNKEY   (SQLITE_CONSTRAINT | (3<<8))
#define SQLITE_CONSTRAINT_FUNCTION     (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906

















1907
1908
1909
1910
1911

1912
1913
1914
1915
1916
1917
1918
** which case the FK enforcement setting is not reported back. </dd>
**
** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
** There should be two additional arguments.
** The first argument is an integer which is 0 to disable triggers,
** positive to enable triggers or negative to leave the setting unchanged.
** The second parameter is a pointer to an integer into which
** is written 0 or 1 to indicate whether triggers are disabled or enabled
** following this call.  The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**

















** </dl>
*/
#define SQLITE_DBCONFIG_LOOKASIDE       1001  /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY     1002  /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER  1003  /* int int* */



/*
** CAPI3REF: Enable Or Disable Extended Result Codes
** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the







<
<
|


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


|
|
|
>







1896
1897
1898
1899
1900
1901
1902


1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
** which case the FK enforcement setting is not reported back. </dd>
**
** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
** There should be two additional arguments.
** The first argument is an integer which is 0 to disable triggers,
** positive to enable triggers or negative to leave the setting unchanged.


  The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
** <dt>SQLITE_DBCONFIG_REQUIRE_WRITE_TXN</dt>
** <dd> ^This option is used to enable or disable automatic write
** transactions. There should be two additional arguments.
** The first argument is an integer which is nonzero to disable
** automatic write transactions and zero to enable automatic write
** transactions. ^The second parameter is a pointer to an integer which if
** is not a NULL pointer is written 0 or 1 to indicate, respectively,
** whether or automatic writes transactions are enabled or disabled
** following this call. ^Automatic write transactions are enabled by default.
** ^(When automatic write transactions are enabled, any write operation
** that is not inside an explicit BEGIN ... COMMIT creates an automatic
** transaction that latests for the duration of that one write operation
** and commits or rolls back when the statement finishes.  ^(When
** automatic write transactions are disabled, attempts to write
** to the database outside of an explicit BEGIN ... COMMIT will result
** in an [SQLITE_READONLY_TXN] error.)^</dd>
**
** </dl>
*/
#define SQLITE_DBCONFIG_LOOKASIDE          1001  /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY        1002  /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER     1003  /* int int* */
#define SQLITE_DBCONFIG_REQUIRE_WRITE_TXN  1004  /* int int* */


/*
** CAPI3REF: Enable Or Disable Extended Result Codes
** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the
Changes to src/sqliteInt.h.
1312
1313
1314
1315
1316
1317
1318

1319
1320
1321
1322
1323
1324
1325
#define SQLITE_LoadExtension  0x00400000  /* Enable load_extension */
#define SQLITE_EnableTrigger  0x00800000  /* True to enable triggers */
#define SQLITE_DeferFKs       0x01000000  /* Defer all FK constraints */
#define SQLITE_QueryOnly      0x02000000  /* Disable database changes */
#define SQLITE_VdbeEQP        0x04000000  /* Debug EXPLAIN QUERY PLAN */
#define SQLITE_Vacuum         0x08000000  /* Currently in a VACUUM */
#define SQLITE_CellSizeCk     0x10000000  /* Check btree cell sizes on load */



/*
** Bits of the sqlite3.dbOptFlags field that are used by the
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
** selectively disable various optimizations.
*/







>







1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
#define SQLITE_LoadExtension  0x00400000  /* Enable load_extension */
#define SQLITE_EnableTrigger  0x00800000  /* True to enable triggers */
#define SQLITE_DeferFKs       0x01000000  /* Defer all FK constraints */
#define SQLITE_QueryOnly      0x02000000  /* Disable database changes */
#define SQLITE_VdbeEQP        0x04000000  /* Debug EXPLAIN QUERY PLAN */
#define SQLITE_Vacuum         0x08000000  /* Currently in a VACUUM */
#define SQLITE_CellSizeCk     0x10000000  /* Check btree cell sizes on load */
#define SQLITE_RequireWrTxn   0x20000000  /* BEGIN required to write */


/*
** Bits of the sqlite3.dbOptFlags field that are used by the
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
** selectively disable various optimizations.
*/
2859
2860
2861
2862
2863
2864
2865


2866
2867
2868
2869
2870
2871
2872
#define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ        0x02    /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE     0x08    /* OP_Open should use BTREE_FORDELETE */
#define OPFLAG_P2ISREG       0x10    /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */
#define OPFLAG_SAVEPOSITION  0x02    /* OP_Delete: keep cursor position */
#define OPFLAG_AUXDELETE     0x04    /* OP_Delete: index in a DELETE op */



/*
 * Each trigger present in the database schema is stored as an instance of
 * struct Trigger. 
 *
 * Pointers to instances of struct Trigger are stored in two ways.
 * 1. In the "trigHash" hash table (part of the sqlite3* that represents the 







>
>







2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
#define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ        0x02    /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE     0x08    /* OP_Open should use BTREE_FORDELETE */
#define OPFLAG_P2ISREG       0x10    /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */
#define OPFLAG_SAVEPOSITION  0x02    /* OP_Delete: keep cursor position */
#define OPFLAG_AUXDELETE     0x04    /* OP_Delete: index in a DELETE op */
#define OPFLAG_TXNCK         0x01    /* OP_Transaction: check cookie */
#define OPFLAG_TXNBEGIN      0x02    /* OP_Transaction: part of BEGIN */

/*
 * Each trigger present in the database schema is stored as an instance of
 * struct Trigger. 
 *
 * Pointers to instances of struct Trigger are stored in two ways.
 * 1. In the "trigHash" hash table (part of the sqlite3* that represents the 
Changes to src/test1.c.
2242
2243
2244
2245
2246
2247
2248









































2249
2250
2251
2252
2253
2254
2255
    Tcl_WrongNumArgs(interp, 1, objv, "");
    return TCL_ERROR;
  }
  sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0);
  return TCL_OK;
}
#endif










































/*
** Usage: vfs_current_time_int64
**
** Return the value returned by the default VFS's xCurrentTimeInt64 method.
*/
static int vfsCurrentTimeInt64(







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







2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
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
    Tcl_WrongNumArgs(interp, 1, objv, "");
    return TCL_ERROR;
  }
  sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0);
  return TCL_OK;
}
#endif

/*
** Usage:  sqlite3_db_config_flag db FLAG-VALUE ON/OFF
**
** Run one of the sqlite3_db_config(db, <flag>, int, int) interfaces.
**
** If FLAG-VALUE is negative, then make the last argument to sqlite3_db_config()
** be NULL rather than a pointer to an integer.
*/
static int test_db_config_flag(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;
  int iFlag;
  int iNewValue;
  int iResult;
  int *piResult = &iResult;
  int rc;
  if( objc!=4 ){ 
    Tcl_WrongNumArgs(interp, 1, objv, "");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  if( Tcl_GetIntFromObj(interp, objv[2], &iFlag) ) return TCL_ERROR;
  if( Tcl_GetIntFromObj(interp, objv[3], &iNewValue) ) return TCL_ERROR;
  if( iFlag<0 ){
    iFlag = -iFlag;
    piResult = 0;
  }
  iResult = -99;
  rc = sqlite3_db_config(db, iFlag, iNewValue, piResult);
  if( rc ){
    Tcl_AppendResult(interp, "sqlite3_dbconfig() returned non-zero", (char*)0);
    return TCL_ERROR;
  }
  Tcl_SetObjResult(interp, Tcl_NewIntObj(iResult));
  return TCL_OK;
}

/*
** Usage: vfs_current_time_int64
**
** Return the value returned by the default VFS's xCurrentTimeInt64 method.
*/
static int vfsCurrentTimeInt64(
7166
7167
7168
7169
7170
7171
7172
7173

7174
7175
7176
7177
7178
7179
7180
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
     { "sqlite3_stmt_scanstatus",       test_stmt_scanstatus,   0 },
     { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset,   0 },
#endif
#ifdef SQLITE_ENABLE_SQLLOG
     { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
#endif
     { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },

#ifdef SQLITE_ENABLE_SNAPSHOT
     { "sqlite3_snapshot_get", test_snapshot_get, 0 },
     { "sqlite3_snapshot_open", test_snapshot_open, 0 },
     { "sqlite3_snapshot_free", test_snapshot_free, 0 },
#endif
  };
  static int bitmask_size = sizeof(Bitmask)*8;







|
>







7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
     { "sqlite3_stmt_scanstatus",       test_stmt_scanstatus,   0 },
     { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset,   0 },
#endif
#ifdef SQLITE_ENABLE_SQLLOG
     { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
#endif
     { "vfs_current_time_int64",        vfsCurrentTimeInt64,  0 },
     { "sqlite3_db_config_flag",        test_db_config_flag,  0 }, 
#ifdef SQLITE_ENABLE_SNAPSHOT
     { "sqlite3_snapshot_get", test_snapshot_get, 0 },
     { "sqlite3_snapshot_open", test_snapshot_open, 0 },
     { "sqlite3_snapshot_free", test_snapshot_free, 0 },
#endif
  };
  static int bitmask_size = sizeof(Bitmask)*8;
Changes to src/vdbe.c.
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094





3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105

3106
3107





3108
3109
3110
3111
3112
3113
3114
** More specifically, a statement transaction is opened iff the database
** connection is currently not in autocommit mode, or if there are other
** active statements. A statement transaction allows the changes made by this
** VDBE to be rolled back after an error without having to roll back the
** entire transaction. If no error is encountered, the statement transaction
** will automatically commit when the VDBE halts.
**
** If P5!=0 then this opcode also checks the schema cookie against P3
** and the schema generation counter against P4.
** The cookie changes its value whenever the database schema changes.
** This operation is used to detect when that the cookie has changed
** and that the current process needs to reread the schema.  If the schema
** cookie in P3 differs from the schema cookie in the database header or
** if the schema generation counter in P4 differs from the current
** generation counter, then an SQLITE_SCHEMA error is raised and execution
** halts.  The sqlite3_step() wrapper function might then reprepare the
** statement and rerun it from the beginning.





*/
case OP_Transaction: {
  Btree *pBt;
  int iMeta;
  int iGen;

  assert( p->bIsReader );
  assert( p->readOnly==0 || pOp->p2==0 );
  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  assert( DbMaskTest(p->btreeMask, pOp->p1) );
  if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){

    rc = SQLITE_READONLY;
    goto abort_due_to_error;





  }
  pBt = db->aDb[pOp->p1].pBt;

  if( pBt ){
    rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
    testcase( rc==SQLITE_BUSY_SNAPSHOT );
    testcase( rc==SQLITE_BUSY_RECOVERY );







|
|
|
|






>
>
>
>
>










|
>
|
|
>
>
>
>
>







3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
** More specifically, a statement transaction is opened iff the database
** connection is currently not in autocommit mode, or if there are other
** active statements. A statement transaction allows the changes made by this
** VDBE to be rolled back after an error without having to roll back the
** entire transaction. If no error is encountered, the statement transaction
** will automatically commit when the VDBE halts.
**
** If the OPFLAG_TXNCK bit (0x01) of P5 is set then this opcode also
** checks the schema cookie against P3 and the schema generation counter
** against P4.  The cookie changes its value whenever the database schema
** changes.  This operation is used to detect when that the cookie has changed
** and that the current process needs to reread the schema.  If the schema
** cookie in P3 differs from the schema cookie in the database header or
** if the schema generation counter in P4 differs from the current
** generation counter, then an SQLITE_SCHEMA error is raised and execution
** halts.  The sqlite3_step() wrapper function might then reprepare the
** statement and rerun it from the beginning.
**
** The OPFLAG_TXNBEGIN bit (0x02) of P5 is set if this opcode is part of
** the implementation of a BEGIN statement.  The OPFLAG_TXNBEGIN bit allows
** a write transaction to proceed even if the SQLITE_RequireWrTxn bit is
** set on the database connection.
*/
case OP_Transaction: {
  Btree *pBt;
  int iMeta;
  int iGen;

  assert( p->bIsReader );
  assert( p->readOnly==0 || pOp->p2==0 );
  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  assert( DbMaskTest(p->btreeMask, pOp->p1) );
  if( pOp->p2 && (db->flags & (SQLITE_QueryOnly|SQLITE_RequireWrTxn))!=0 ){
    if( db->flags & SQLITE_QueryOnly ){
      rc = SQLITE_READONLY;
      goto abort_due_to_error;
    }
    if( db->autoCommit && (pOp->p5 & OPFLAG_TXNBEGIN)==0 ){
      rc = SQLITE_READONLY_NOTXN;
      goto abort_due_to_error;
    }
  }
  pBt = db->aDb[pOp->p1].pBt;

  if( pBt ){
    rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
    testcase( rc==SQLITE_BUSY_SNAPSHOT );
    testcase( rc==SQLITE_BUSY_RECOVERY );
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
    ** database against which the compiled query is actually executed.
    */
    sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
    iGen = db->aDb[pOp->p1].pSchema->iGeneration;
  }else{
    iGen = iMeta = 0;
  }
  assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
  if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){
    sqlite3DbFree(db, p->zErrMsg);
    p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
    /* If the schema-cookie from the database file matches the cookie 
    ** stored with the in-memory representation of the schema, do
    ** not reload the schema from the database file.
    **
    ** If virtual-tables are in use, this is not just an optimization.
    ** Often, v-tables store their data in other SQLite tables, which
    ** are queried from within xNext() and other v-table methods using







|
|
<
|







3161
3162
3163
3164
3165
3166
3167
3168
3169

3170
3171
3172
3173
3174
3175
3176
3177
    ** database against which the compiled query is actually executed.
    */
    sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
    iGen = db->aDb[pOp->p1].pSchema->iGeneration;
  }else{
    iGen = iMeta = 0;
  }
  assert( (pOp->p5 & OPFLAG_TXNCK)==0 || pOp->p4type==P4_INT32 );
  if( (pOp->p5 & OPFLAG_TXNCK)!=0 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){

    sqlite3VdbeError(p, "database schema has changed");
    /* If the schema-cookie from the database file matches the cookie 
    ** stored with the in-memory representation of the schema, do
    ** not reload the schema from the database file.
    **
    ** If virtual-tables are in use, this is not just an optimization.
    ** Often, v-tables store their data in other SQLite tables, which
    ** are queried from within xNext() and other v-table methods using
Added test/dbconfig1.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
62
63
64
65
66
67
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
106
# 2016-02-01
#
# 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.  The
# focus of this file is testing the sqlite3_db_config() interface
#

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

do_test 100 {
  db eval {PRAGMA foreign_keys=ON;}
  sqlite3_db_config_flag db 1002 0
} {0}
do_test 101 {
  db eval {PRAGMA foreign_keys;}
} {0}
do_test 102 {
  sqlite3_db_config_flag db 1002 1
} {1}
do_test 103 {
  db eval {PRAGMA foreign_keys;}
} {1}
do_test 104 {
  sqlite3_db_config_flag db -1002 0
} {-99}

# Require explicit BEGIN...COMMIT in order to modify the database
#
sqlite3_db_config_flag db 1004 1
do_catchsql_test 200 {
  CREATE TABLE t1(x);
} {1 {attempt to write a readonly database}}
do_execsql_test 201 {
  BEGIN;
  CREATE TABLE t1(x);
  COMMIT;
  SELECT name FROM sqlite_master ORDER BY name;
} {t1}
do_execsql_test 202 {
  BEGIN IMMEDIATE;
  CREATE TABLE t2(x);
  COMMIT;
  SELECT name FROM sqlite_master ORDER BY name;
} {t1 t2}
do_execsql_test 203 {
  BEGIN EXCLUSIVE;
  CREATE TABLE t3(x);
  COMMIT;
  SELECT name FROM sqlite_master ORDER BY name;
} {t1 t2 t3}
do_execsql_test 204 {
  BEGIN;
  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
  INSERT INTO t1(x) SELECT randomblob(500) FROM c;
  COMMIT;
  BEGIN;
  DELETE FROM t1 WHERE rowid%4!=0;
  COMMIT;
  VACUUM;
  PRAGMA integrity_check;
} {ok}

do_execsql_test 210 {
  PRAGMA journal_mode=WAL;
} {wal}
do_execsql_test 211 {
  BEGIN;
  CREATE TABLE t4(x);
  COMMIT;
  SELECT name FROM sqlite_master ORDER BY name;
} {t1 t2 t3 t4}
do_execsql_test 212 {
  BEGIN IMMEDIATE;
  CREATE TABLE t5(x);
  COMMIT;
  SELECT name FROM sqlite_master ORDER BY name;
} {t1 t2 t3 t4 t5}
do_execsql_test 213 {
  BEGIN EXCLUSIVE;
  CREATE TABLE t6(x);
  COMMIT;
  SELECT name FROM sqlite_master ORDER BY name;
} {t1 t2 t3 t4 t5 t6}
do_execsql_test 214 {
  BEGIN;
  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
  INSERT INTO t6(x) SELECT randomblob(500) FROM c;
  COMMIT;
  BEGIN;
  DELETE FROM t6 WHERE rowid%4!=0;
  COMMIT;
  VACUUM;
  PRAGMA integrity_check;
} {ok}


finish_test