/ Check-in [f79b47c9]
Login

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

Overview
Comment:Add enforcement of read-only on shadow tables. This does not currently work since some virtual tables are attempting to update shadow tables using sqlite3_exec().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | read-only-shadow
Files: files | file ages | folders
SHA3-256:f79b47c9859de597d5924870752dd7cab89c8f0608e5cceb2281f6ffb2e91930
User & Date: drh 2018-11-06 13:37:20
Context
2018-11-06
14:03
Only allow shadow table to be written from within a recursive SQL call. Omit the SQLITE_PREPARE_SHADOW flag. Some tests are failing because the tests depend on being able to write to shadow tables. check-in: d890c658 user: drh tags: read-only-shadow
13:37
Add enforcement of read-only on shadow tables. This does not currently work since some virtual tables are attempting to update shadow tables using sqlite3_exec(). check-in: f79b47c9 user: drh tags: read-only-shadow
2018-11-05
23:01
Initial code to make shadow tables read-only to ordinary SQL. The now xShadowName method is added to the sqlite3_module object and is used to identify potential shadow tables. The SQLITE_PREPARE_SHADOW argument to sqlite3_prepare_v3() is defined. It is designed to permit writing to shadow tables, but is currently an unused placeholder. check-in: 31942b3d user: drh tags: read-only-shadow
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

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
**
** zName is temporarily modified while this routine is running, but is
** restored to its original value prior to this routine returning.
*/
static int isShadowTableName(sqlite3 *db, char *zName){
  char *zTail;                  /* Pointer to the last "_" in zName */
  Table *pTab;                  /* Table that zName is a shadow of */
  VTable *pVTab;                /* Virtual table corresponding to pTab */
  const sqlite3_module *pMod;   /* module methods for pVTab */

  zTail = strrchr(zName, '_');
  if( zTail==0 ) return 0;
  *zTail = 0;
  pTab = sqlite3FindTable(db, zName, 0);
  *zTail = '_';
  if( pTab==0 ) return 0;
  if( !IsVirtual(pTab) ) return 0;
  pVTab = sqlite3GetVTable(db, pTab);
  if( pVTab==0 ) return 0;
  if( pVTab->pMod==0 ) return 0;
  pMod = pVTab->pMod->pModule;
  assert( pMod!=0 );
  if( pMod->iVersion<3 ) return 0;
  if( pMod->xShadowName==0 ) return 0;
  return pMod->xShadowName(zTail+1);
}

/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
**
** The table structure that other action routines have been building







|
<
>







|
<
|
<
<
|
|
|







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
**
** zName is temporarily modified while this routine is running, but is
** restored to its original value prior to this routine returning.
*/
static int isShadowTableName(sqlite3 *db, char *zName){
  char *zTail;                  /* Pointer to the last "_" in zName */
  Table *pTab;                  /* Table that zName is a shadow of */
  Module *pMod;                 /* Module for the virtual table */


  zTail = strrchr(zName, '_');
  if( zTail==0 ) return 0;
  *zTail = 0;
  pTab = sqlite3FindTable(db, zName, 0);
  *zTail = '_';
  if( pTab==0 ) return 0;
  if( !IsVirtual(pTab) ) return 0;
  pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);

  if( pMod==0 ) return 0;


  if( pMod->pModule->iVersion<3 ) return 0;
  if( pMod->pModule->xShadowName==0 ) return 0;
  return pMod->pModule->xShadowName(zTail+1);
}

/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
**
** The table structure that other action routines have been building

Changes to src/delete.c.

53
54
55
56
57
58
59


60
61
62
63
64
65
66
67


68
69
70
71
72
73
74
  /* A table is not writable under the following circumstances:
  **
  **   1) It is a virtual table and no implementation of the xUpdate method
  **      has been provided, or
  **   2) It is a system table (i.e. sqlite_master), this call is not
  **      part of a nested parse and writable_schema pragma has not 
  **      been specified.


  **
  ** In either case leave an error message in pParse and return non-zero.
  */
  if( ( IsVirtual(pTab) 
     && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 )
   || ( (pTab->tabFlags & TF_Readonly)!=0
     && sqlite3WritableSchema(pParse->db)==0
     && pParse->nested==0)


  ){
    sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
    return 1;
  }

#ifndef SQLITE_OMIT_VIEW
  if( !viewOk && pTab->pSelect ){







>
>








>
>







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
  /* A table is not writable under the following circumstances:
  **
  **   1) It is a virtual table and no implementation of the xUpdate method
  **      has been provided, or
  **   2) It is a system table (i.e. sqlite_master), this call is not
  **      part of a nested parse and writable_schema pragma has not 
  **      been specified.
  **   3) The table is a shadow table and the SQLITE_PREPARE_SHADOW flag
  **      is omitted.
  **
  ** In either case leave an error message in pParse and return non-zero.
  */
  if( ( IsVirtual(pTab) 
     && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 )
   || ( (pTab->tabFlags & TF_Readonly)!=0
     && sqlite3WritableSchema(pParse->db)==0
     && pParse->nested==0)
   || ( (pTab->tabFlags & TF_Shadow)!=0
     && pParse->writeShadow==0)
  ){
    sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
    return 1;
  }

#ifndef SQLITE_OMIT_VIEW
  if( !viewOk && pTab->pSelect ){

Changes to src/prepare.c.

540
541
542
543
544
545
546



547
548
549
550
551
552
553

  /* For a long-term use prepared statement avoid the use of
  ** lookaside memory.
  */
  if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
    sParse.disableLookaside++;
    db->lookaside.bDisable++;



  }

  /* Check to verify that it is possible to get a read lock on all
  ** database schemas.  The inability to get a read lock indicates that
  ** some other database connection is holding a write-lock, which in
  ** turn means that the other connection has made uncommitted changes
  ** to the schema.







>
>
>







540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556

  /* For a long-term use prepared statement avoid the use of
  ** lookaside memory.
  */
  if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
    sParse.disableLookaside++;
    db->lookaside.bDisable++;
  }
  if( prepFlags & SQLITE_PREPARE_SHADOW ){
    sParse.writeShadow = 1;
  }

  /* Check to verify that it is possible to get a read lock on all
  ** database schemas.  The inability to get a read lock indicates that
  ** some other database connection is holding a write-lock, which in
  ** turn means that the other connection has made uncommitted changes
  ** to the schema.

Changes to src/sqliteInt.h.

3082
3083
3084
3085
3086
3087
3088

3089
3090
3091
3092
3093
3094
3095
  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
  u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
  u32 oldmask;         /* Mask of old.* columns referenced */
  u32 newmask;         /* Mask of new.* columns referenced */
  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
  u8 disableTriggers;  /* True to disable triggers */


  /**************************************************************************
  ** Fields above must be initialized to zero.  The fields that follow,
  ** down to the beginning of the recursive section, do not need to be
  ** initialized as they will be set before being used.  The boundary is
  ** determined by offsetof(Parse,aTempReg).
  **************************************************************************/







>







3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
  u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
  u32 oldmask;         /* Mask of old.* columns referenced */
  u32 newmask;         /* Mask of new.* columns referenced */
  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
  u8 disableTriggers;  /* True to disable triggers */
  u8 writeShadow;      /* True if shadow tables are writable */

  /**************************************************************************
  ** Fields above must be initialized to zero.  The fields that follow,
  ** down to the beginning of the recursive section, do not need to be
  ** initialized as they will be set before being used.  The boundary is
  ** determined by offsetof(Parse,aTempReg).
  **************************************************************************/