/ Check-in [23054110]
Login

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

Overview
Comment:Experimental sqlite_db_config() setting to disable writing to all btrees except for one btree with a particular root page.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | one-writable-btree
Files: files | file ages | folders
SHA1:2305411097c4985b61c5faf4361c4da8414101f2
User & Date: drh 2015-01-29 02:26:40
Context
2015-01-29
14:48
Avoid overlength command lines in Makefile.msc when using TOP= with a large directory name. check-in: 0cdd59bf user: drh tags: one-writable-btree
02:26
Experimental sqlite_db_config() setting to disable writing to all btrees except for one btree with a particular root page. check-in: 23054110 user: drh tags: one-writable-btree
2015-01-27
21:24
Fix harmless compiler warnings. check-in: e7d2ec04 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/delete.c.

   670    670     }
   671    671   
   672    672     /* Delete the index and table entries. Skip this step if pTab is really
   673    673     ** a view (in which case the only effect of the DELETE statement is to
   674    674     ** fire the INSTEAD OF triggers).  */ 
   675    675     if( pTab->pSelect==0 ){
   676    676       sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
   677         -    sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
   678         -    if( count ){
   679         -      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
          677  +    if( !WRITE_RESTRICT(pParse->db, pTab->tnum) ){
          678  +      sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
          679  +      if( count ){
          680  +        sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
          681  +      }
   680    682       }
   681    683     }
   682    684   
   683    685     /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
   684    686     ** handle rows (possibly in other tables) that refer via a foreign key
   685    687     ** to the row just deleted. */ 
   686    688     sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
................................................................................
   732    734   
   733    735     v = pParse->pVdbe;
   734    736     pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
   735    737     for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
   736    738       assert( iIdxCur+i!=iDataCur || pPk==pIdx );
   737    739       if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
   738    740       if( pIdx==pPk ) continue;
          741  +    if( WRITE_RESTRICT(pParse->db, pIdx->tnum) ) continue;
   739    742       VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
   740    743       r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
   741    744                                    &iPartIdxLabel, pPrior, r1);
   742    745       sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
   743    746                         pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
   744    747       sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
   745    748       pPrior = pIdx;

Changes to src/insert.c.

  1362   1362     for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
  1363   1363       int regIdx;          /* Range of registers hold conent for pIdx */
  1364   1364       int regR;            /* Range of registers holding conflicting PK */
  1365   1365       int iThisCur;        /* Cursor for this UNIQUE index */
  1366   1366       int addrUniqueOk;    /* Jump here if the UNIQUE constraint is satisfied */
  1367   1367   
  1368   1368       if( aRegIdx[ix]==0 ) continue;  /* Skip indices that do not change */
         1369  +    if( WRITE_RESTRICT(db, pIdx->tnum) ) continue;
  1369   1370       if( bAffinityDone==0 ){
  1370   1371         sqlite3TableAffinity(v, pTab, regNewData+1);
  1371   1372         bAffinityDone = 1;
  1372   1373       }
  1373   1374       iThisCur = iIdxCur+ix;
  1374   1375       addrUniqueOk = sqlite3VdbeMakeLabel(v);
  1375   1376   
................................................................................
  1541   1542     int *aRegIdx,       /* Register used by each index.  0 for unused indices */
  1542   1543     int isUpdate,       /* True for UPDATE, False for INSERT */
  1543   1544     int appendBias,     /* True if this is likely to be an append */
  1544   1545     int useSeekResult   /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
  1545   1546   ){
  1546   1547     Vdbe *v;            /* Prepared statements under construction */
  1547   1548     Index *pIdx;        /* An index being inserted or updated */
         1549  +  sqlite3 *db;
  1548   1550     u8 pik_flags;       /* flag values passed to the btree insert */
  1549   1551     int regData;        /* Content registers (after the rowid) */
  1550   1552     int regRec;         /* Register holding assembled record for the table */
  1551   1553     int i;              /* Loop counter */
  1552   1554     u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
  1553   1555   
  1554   1556     v = sqlite3GetVdbe(pParse);
  1555   1557     assert( v!=0 );
  1556   1558     assert( pTab->pSelect==0 );  /* This table is not a VIEW */
         1559  +  db = pParse->db;
  1557   1560     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
  1558   1561       if( aRegIdx[i]==0 ) continue;
         1562  +    if( WRITE_RESTRICT(db, pIdx->tnum) ) continue;
  1559   1563       bAffinityDone = 1;
  1560   1564       if( pIdx->pPartIdxWhere ){
  1561   1565         sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
  1562   1566         VdbeCoverage(v);
  1563   1567       }
  1564   1568       sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
  1565   1569       pik_flags = 0;
................................................................................
  1567   1571       if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
  1568   1572         assert( pParse->nested==0 );
  1569   1573         pik_flags |= OPFLAG_NCHANGE;
  1570   1574       }
  1571   1575       if( pik_flags )  sqlite3VdbeChangeP5(v, pik_flags);
  1572   1576     }
  1573   1577     if( !HasRowid(pTab) ) return;
         1578  +  if( WRITE_RESTRICT(db, pTab->tnum) ) return;
  1574   1579     regData = regNewData + 1;
  1575   1580     regRec = sqlite3GetTempReg(pParse);
  1576   1581     sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
  1577   1582     if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
  1578   1583     sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
  1579   1584     if( pParse->nested ){
  1580   1585       pik_flags = 0;

Changes to src/main.c.

   720    720     switch( op ){
   721    721       case SQLITE_DBCONFIG_LOOKASIDE: {
   722    722         void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */
   723    723         int sz = va_arg(ap, int);       /* IMP: R-47871-25994 */
   724    724         int cnt = va_arg(ap, int);      /* IMP: R-04460-53386 */
   725    725         rc = setupLookaside(db, pBuf, sz, cnt);
   726    726         break;
          727  +    }
          728  +    case SQLITE_DBCONFIG_WRITABLE_BTREE: {
          729  +      db->onlyWritableBtree = va_arg(ap,int);
          730  +      rc = SQLITE_OK;
          731  +      break;
   727    732       }
   728    733       default: {
   729    734         static const struct {
   730    735           int op;      /* The opcode */
   731    736           u32 mask;    /* Mask of the bit in sqlite3.flags to set/clear */
   732    737         } aFlagOp[] = {
   733    738           { SQLITE_DBCONFIG_ENABLE_FKEY,    SQLITE_ForeignKeys    },

Changes to src/shell.c.

  2563   2563       sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
  2564   2564       if( zErrMsg ){
  2565   2565         fprintf(stderr,"Error: %s\n", zErrMsg);
  2566   2566         sqlite3_free(zErrMsg);
  2567   2567         rc = 1;
  2568   2568       }
  2569   2569     }else
         2570  +
         2571  +  if( c=='d' && n>1 && strncmp(azArg[0], "dbconfig", n)==0 ){
         2572  +    int nHit = 0, x;
         2573  +    open_db(p, 0);
         2574  +    if( nArg>=2 ){
         2575  +      n = (int)strlen(azArg[1]);
         2576  +      if( strncmp(azArg[1], "writable_btree",n)==0 ){
         2577  +        if( nArg!=3 ){
         2578  +          fprintf(stderr, "Usage: .dbconfig writable_btree N\n");
         2579  +          rc = 1;
         2580  +        }else{
         2581  +          sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_BTREE,
         2582  +                            integerValue(azArg[2]));
         2583  +        }
         2584  +        nHit = 1;
         2585  +      }else
         2586  +      if( strncmp(azArg[1], "enable_fkey",n)==0 ){
         2587  +        if( nArg!=3 ){
         2588  +          fprintf(stderr, "Usage: .dbconfig enable_fkey (1|0|-1)\n");
         2589  +          rc = 1;
         2590  +        }else{
         2591  +          sqlite3_db_config(p->db, SQLITE_DBCONFIG_ENABLE_FKEY,
         2592  +                            integerValue(azArg[2]), &x);
         2593  +          printf("result: %d\n", x);
         2594  +        }
         2595  +        nHit = 1;
         2596  +      }else
         2597  +      if( strncmp(azArg[1], "enable_trigger",n)==0 ){
         2598  +        if( nArg!=3 ){
         2599  +          fprintf(stderr, "Usage: .dbconfig enable_trigger (1|0|-1)\n");
         2600  +          rc = 1;
         2601  +        }else{
         2602  +          sqlite3_db_config(p->db, SQLITE_DBCONFIG_ENABLE_TRIGGER,
         2603  +                            integerValue(azArg[2]), &x);
         2604  +          printf("result: %d\n", x);
         2605  +        }
         2606  +        nHit = 1;
         2607  +      }
         2608  +    }
         2609  +    if( nHit==0 ){
         2610  +      fprintf(stderr, "Usage: .dbconfig COMMAND ARGS...\n");
         2611  +      fprintf(stderr, 
         2612  +        "COMMAND is one of: writable_btree enable_fkey enable_trigger\n");
         2613  +      rc = 1;
         2614  +    }    
         2615  +  }else
  2570   2616   
  2571   2617     if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
  2572   2618       open_db(p, 0);
  2573   2619       /* When playing back a "dump", the content might appear in an order
  2574   2620       ** which causes immediate foreign key constraints to be violated.
  2575   2621       ** So disable foreign-key constraint enforcement to prevent problems. */
  2576   2622       if( nArg!=1 && nArg!=2 ){

Changes to src/sqlite.h.in.

  1836   1836   ** The first argument is an integer which is 0 to disable triggers,
  1837   1837   ** positive to enable triggers or negative to leave the setting unchanged.
  1838   1838   ** The second parameter is a pointer to an integer into which
  1839   1839   ** is written 0 or 1 to indicate whether triggers are disabled or enabled
  1840   1840   ** following this call.  The second parameter may be a NULL pointer, in
  1841   1841   ** which case the trigger setting is not reported back. </dd>
  1842   1842   **
         1843  +** <dt>SQLITE_DBCONFIG_WRITABLE_BTREE</dt>
         1844  +** <dd> ^This option is used to disable INSERT and DELETE operations
         1845  +** against all attached b-trees, except for b-trees that have a 
         1846  +** particular root page. 
         1847  +** There must be one additional integer argument which is the root page
         1848  +** that is allowed to be written.  If the argument is zero, then
         1849  +** writing is allowed to all b-trees, as is normally the case.
         1850  +**
  1843   1851   ** </dl>
  1844   1852   */
  1845   1853   #define SQLITE_DBCONFIG_LOOKASIDE       1001  /* void* int int */
  1846   1854   #define SQLITE_DBCONFIG_ENABLE_FKEY     1002  /* int int* */
  1847   1855   #define SQLITE_DBCONFIG_ENABLE_TRIGGER  1003  /* int int* */
         1856  +#define SQLITE_DBCONFIG_WRITABLE_BTREE  1004  /* int */
  1848   1857   
  1849   1858   
  1850   1859   /*
  1851   1860   ** CAPI3REF: Enable Or Disable Extended Result Codes
  1852   1861   **
  1853   1862   ** ^The sqlite3_extended_result_codes() routine enables or disables the
  1854   1863   ** [extended result codes] feature of SQLite. ^The extended result

Changes to src/sqliteInt.h.

  1073   1073     u8 mallocFailed;              /* True if we have seen a malloc failure */
  1074   1074     u8 dfltLockMode;              /* Default locking-mode for attached dbs */
  1075   1075     signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  1076   1076     u8 suppressErr;               /* Do not issue error messages if true */
  1077   1077     u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
  1078   1078     u8 isTransactionSavepoint;    /* True if the outermost savepoint is a TS */
  1079   1079     int nextPagesize;             /* Pagesize after VACUUM if >0 */
         1080  +  int onlyWritableBtree;        /* Do not write to any other b-tree */
  1080   1081     u32 magic;                    /* Magic number for detect library misuse */
  1081   1082     int nChange;                  /* Value returned by sqlite3_changes() */
  1082   1083     int nTotalChange;             /* Value returned by sqlite3_total_changes() */
  1083   1084     int aLimit[SQLITE_N_LIMIT];   /* Limits */
  1084   1085     int nMaxSorterMmap;           /* Maximum size of regions mapped by sorter */
  1085   1086     struct sqlite3InitInfo {      /* Information used during initialization */
  1086   1087       int newTnum;                /* Rootpage of table being initialized */
................................................................................
  1162   1163     sqlite3 *pNextBlocked;        /* Next in list of all blocked connections */
  1163   1164   #endif
  1164   1165   #ifdef SQLITE_USER_AUTHENTICATION
  1165   1166     sqlite3_userauth auth;        /* User authentication information */
  1166   1167   #endif
  1167   1168   };
  1168   1169   
         1170  +/*
         1171  +** This macro returns true if the only_writable_btree pragma is turned
         1172  +** on and is set to a btree root node other than N.
         1173  +*/
         1174  +#define WRITE_RESTRICT(db,N) ((db)->onlyWritableBtree>0 && \
         1175  +                              (db)->onlyWritableBtree!=(N))
         1176  +
  1169   1177   /*
  1170   1178   ** A macro to discover the encoding of a database.
  1171   1179   */
  1172   1180   #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
  1173   1181   #define ENC(db)        ((db)->enc)
  1174   1182   
  1175   1183   /*