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 |
Timelines: | family | ancestors | descendants | both | read-only-shadow |
Files: | files | file ages | folders |
SHA3-256: |
f79b47c9859de597d5924870752dd7ca |
User & Date: | drh 2018-11-06 13:37:20.946 |
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: d890c65825 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: f79b47c985 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: 31942b3dd3 user: drh tags: read-only-shadow) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
1900 1901 1902 1903 1904 1905 1906 | ** ** 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 */ | | | | < | < < | | | | 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). **************************************************************************/ |
︙ | ︙ |