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: |
7453790c3b21c94b1f6d419598b120b7 |
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
Changes to src/build.c.
︙ | ︙ | |||
178 179 180 181 182 183 184 | sqlite3VdbeAddOp4Int(v, OP_Transaction, /* Opcode */ iDb, /* P1 */ DbMaskTest(pParse->writeMask,iDb), /* P2 */ pParse->cookieValue[iDb], /* P3 */ db->aDb[iDb].pSchema->iGeneration /* P4 */ ); | | | 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 | break; } default: { static const struct { int op; /* The opcode */ u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ } aFlagOp[] = { | | | > | 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 | ** 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. | < < | > > > > > > > > > > > > > > > > > | | | > | 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 | #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 | | > | 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 | ** 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. ** | | | | | > > > > > | > | | > > > > > | 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 | ** 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; } | | | < | | 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 |