From: drh <> Date: Fri, 19 Sep 2025 17:24:12 +0000 (+0000) Subject: Improvements to imposter tables: (1) They are read-only unless writable-schema X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=49a37f333a36f7c595077ef8a2da545f5f270173;p=thirdparty%2Fsqlite.git Improvements to imposter tables: (1) They are read-only unless writable-schema is enabled. (2) Because they are now read-only, the ".imposter" command in the CLI no longer requires the --unsafe-testing command-line option. (3) Imposter tables do not participate in a PRAGMA integrity_check and hence do not cause false-positive errors. However, you can still do an integrity_check on the the imposter table itself by naming the imposter table as the argument to integrity_check. FossilOrigin-Name: ad152ddc4bcf6cfe840b9a36ab76a5ec36afdb1dd96eb7697e4b3df1bf63b00d --- diff --git a/ext/intck/intck1.test b/ext/intck/intck1.test index 187132f766..ef29c2c54c 100644 --- a/ext/intck/intck1.test +++ b/ext/intck/intck1.test @@ -139,6 +139,7 @@ do_test 2.3 { sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0 db eval { + PRAGMA writable_schema=on; DELETE FROM imp1 WHERE rowid=1; DELETE FROM imp2 WHERE rowid=2; } @@ -174,6 +175,7 @@ do_test 3.2 { sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0 db eval { + PRAGMA writable_schema=on; DELETE FROM imp1 WHERE a=5; } execsql_pp { diff --git a/ext/intck/intck2.test b/ext/intck/intck2.test index 23b241b5a9..a35bbc70c9 100644 --- a/ext/intck/intck2.test +++ b/ext/intck/intck2.test @@ -29,6 +29,7 @@ do_execsql_test 1.0 { proc imposter_edit {obj create sql} { sqlite3 xdb test.db set pgno [xdb one {SELECT rootpage FROM sqlite_schema WHERE name=$obj}] + xdb eval {PRAGMA Writable_schema=ON} sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 1 $pgno xdb eval $create diff --git a/manifest b/manifest index d11a18e8cb..2c18c11554 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypo\sin\sthe\sname\sof\sthe\sCursorHints\soptimization\sin\sthe\sCLI. -D 2025-09-19T09:18:22.076 +C Improvements\sto\simposter\stables:\s\s(1)\sThey\sare\sread-only\sunless\swritable-schema\nis\senabled.\s\s(2)\sBecause\sthey\sare\snow\sread-only,\sthe\s".imposter"\scommand\nin\sthe\sCLI\sno\slonger\srequires\sthe\s--unsafe-testing\scommand-line\soption.\n(3)\sImposter\stables\sdo\snot\sparticipate\sin\sa\sPRAGMA\sintegrity_check\sand\shence\ndo\snot\scause\sfalse-positive\serrors.\s\sHowever,\syou\scan\sstill\sdo\san\nintegrity_check\son\sthe\sthe\simposter\stable\sitself\sby\snaming\sthe\simposter\ntable\sas\sthe\sargument\sto\sintegrity_check. +D 2025-09-19T17:24:12.005 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -277,8 +277,8 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/icu/README.txt 1f8d76e10d2385fc77914a14ccd99acfbaf68111dfcf26a360ad9063787f57fb F ext/icu/icu.c 9837f4611915baad1edbe38222f3ee7d1b5e118ab16fec9ba603720f72c78b2a F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 -F ext/intck/intck1.test f3a3cba14b6aeff145ffa5515546dd22f7510dad91512e519f43b92b56514012 -F ext/intck/intck2.test d2457c7e5e5b688046d15ebe08a1e1427cc5e7a6dc8d6af215f42e8bcaf67304 +F ext/intck/intck1.test 53d885075abeb45aeb1eeffeaa8560b329060835ade4af5c44cf5fcb581c1e63 +F ext/intck/intck2.test a29343a8e65c5c3400e10747f394924f3df95a5b2de94f46e9b5c9b97f5e7339 F ext/intck/intck_common.tcl a61fd2697ae55b0a3d89847ca0b590c6e0d8ff64bebb70920d93724799894159 F ext/intck/intckbusy.test d5ed4ef85a4b1dc1dee2484bd14a4bb68529659cca743327df0c775f005fa387 F ext/intck/intckcorrupt.test f6c302792326fb3db9dcfc70b554c55369bc4b52882eaaf039cfe0b74c821029 @@ -686,7 +686,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea F src/btree.c cb5b8ceb9baa02a63a2f83dec09c4153e1cfbdf9c2adef5c62c26d2160eeb067 F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0 F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886 -F src/build.c 213a9d24c931ef4694564894cda8dac8dbeb1519d428fd2d7ae622ac357c05a5 +F src/build.c 9c95d5bd5969be8962bcbebe651a5b664f92fc5d6c9e8bf0d9e6e008ad3c99d3 F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/date.c b6f92001f4b1f73f21774927488661d28f4dac9cd9701ed96486d96b44f5b058 @@ -736,18 +736,18 @@ F src/parse.y 619c3e92a54686c5e47923688c4b9bf7ec534a4690db5677acc28b299c403250 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd -F src/pragma.c 20847ce727fa0efe64de13f54427d44d25df7a00c806f198463dc37041aeeed0 +F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f F src/prepare.c 2af0b5c1ec787c8eebd21baa9d79caf4a4dc3a18e76ce2edbf2027d706bca37a F src/printf.c 5f0c957af9699e849d786e8fbaa3baab648ca5612230dc17916434c14bc8698f F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c f8d1d011aba0964ff1bdccd049d4d2c2fec217efd90d202a4bb775e926b2c25d F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c b95181711d59c36d9789e67f76c4cfec64b99f9629a50be5e6566e117b87d957 -F src/shell.c.in 07e33255efbf18de49e7afa2ebc70ab3602aa7fb86bba35416c5a95a6574e94d +F src/shell.c.in 4fe89ea95c2ea05b1fc98ee8e27aa03dd080ae12dfe201334cc7f338f4ece7e2 F src/sqlite.h.in 5732519a2acb09066032ceac21f25996eb3f28f807a4468e30633c7c70faae1c F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 3f0c4ed6934e7309a61c6f3c30f70a30a5b869f785bb3d9f721a36c5e4359126 -F src/sqliteInt.h 27c73e48878d31ef230ba867d1f8c3af6aed357fd93ccc605d3f1aae007ea62b +F src/sqliteInt.h 5f6db0908f0e1d5cbae56955cc119bf85e92f3bdd1bcffe22190d6775efac7b4 F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364 F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1266,7 +1266,7 @@ F test/hook.test 2d89bf9480646feb8093be3a58ea502d6521906779ed960de31dd9c4502c054 F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8 F test/icu.test 8da7d52cd9722c82f33b0466ed915460cb03c23a38f18a9a2d3ff97da9a4a8c0 F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e -F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 +F test/imposter1.test 5a20b2cdeb53e65fc57cdb10a33750bd4ef6259909eaf1972253b9e79f7a3fb2 F test/in.test edf979bff3244b9e47849e2b43886631354c8213791f42da92216f08012141af F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 @@ -2175,8 +2175,11 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 42c225a2ed7fc95f9b01467c64ba2bf97bca216fdcd6ab1ba3fb49c068650de9 -R fec5e9cf9c4aa5198306438cd736e135 +P 468a11fd415710042b23880772f6c2c7771008208823fe3b554227a9244dbf92 +R f09c6f119013a99c86219264c1bd3d49 +T *branch * imposter-tables +T *sym-imposter-tables * +T -sym-trunk * U drh -Z 1e7399cfaf854450b90c6eb04c4097ba +Z a8fecea68551ccfe826c7588dedc6269 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..a8c248c3e1 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch imposter-tables +tag imposter-tables diff --git a/manifest.uuid b/manifest.uuid index 5f03ba8a91..7e0eca6a5a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -468a11fd415710042b23880772f6c2c7771008208823fe3b554227a9244dbf92 +ad152ddc4bcf6cfe840b9a36ab76a5ec36afdb1dd96eb7697e4b3df1bf63b00d diff --git a/src/build.c b/src/build.c index 6b1d3993f0..276c131977 100644 --- a/src/build.c +++ b/src/build.c @@ -1368,6 +1368,8 @@ void sqlite3StartTable( sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp0(v, OP_Close); + }else if( db->init.imposterTable ){ + pTable->tabFlags |= TF_Readonly | TF_Imposter; } /* Normal (non-error) return. */ diff --git a/src/pragma.c b/src/pragma.c index a0f24c15c0..791508ea4a 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -391,6 +391,22 @@ static int integrityCheckResultRow(Vdbe *v){ return addr; } +/* +** Should table pTab be skipped when doing an integrity_check? +** Return true or false. +** +** If pObjTab is not null, the return true if pTab matches pObjTab. +** +** If pObjTab is null, then return true only if pTab is an imposter table. +*/ +static int tableSkipIntegrityCheck(const Table *pTab, const Table *pObjTab){ + if( pObjTab ){ + return pTab!=pObjTab; + }else{ + return (pTab->tabFlags & TF_Imposter)!=0; + } +} + /* ** Process a pragma statement. ** @@ -1736,7 +1752,7 @@ void sqlite3Pragma( Table *pTab = sqliteHashData(x); /* Current table */ Index *pIdx; /* An index on pTab */ int nIdx; /* Number of indexes on pTab */ - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } } @@ -1749,7 +1765,7 @@ void sqlite3Pragma( for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ aRoot[++cnt] = pIdx->tnum; @@ -1780,7 +1796,7 @@ void sqlite3Pragma( int iTab = 0; Table *pTab = sqliteHashData(x); Index *pIdx; - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( HasRowid(pTab) ){ iTab = cnt++; }else{ @@ -1816,7 +1832,7 @@ void sqlite3Pragma( int r2; /* Previous key for WITHOUT ROWID tables */ int mxCol; /* Maximum non-virtual column number */ - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( !IsOrdinaryTable(pTab) ) continue; if( isQuick || HasRowid(pTab) ){ pPk = 0; @@ -2140,7 +2156,7 @@ void sqlite3Pragma( Table *pTab = sqliteHashData(x); sqlite3_vtab *pVTab; int a1; - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( IsOrdinaryTable(pTab) ) continue; if( !IsVirtual(pTab) ) continue; if( pTab->nCol<=0 ){ diff --git a/src/shell.c.in b/src/shell.c.in index 57ca5cf2f1..5bcec5bd60 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -9770,12 +9770,6 @@ static int do_meta_command(char *zLine, ShellState *p){ int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */ int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */ int i; - if( !ShellHasFlag(p,SHFLG_TestingMode) ){ - sqlite3_fprintf(stderr,".%s unavailable without --unsafe-testing\n", - "imposter"); - rc = 1; - goto meta_command_exit; - } if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){ eputz("Usage: .imposter INDEX IMPOSTER\n" " .imposter off\n"); @@ -9856,9 +9850,6 @@ static int do_meta_command(char *zLine, ShellState *p){ "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db)); }else{ sqlite3_fprintf(stdout, "%s;\n", zSql); - sqlite3_fprintf(stdout, - "WARNING: writing to an imposter table will corrupt" - " the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index"); } }else{ sqlite3_fprintf(stderr,"SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f012650088..0b6de670fe 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2494,6 +2494,7 @@ struct Table { #define TF_Ephemeral 0x00004000 /* An ephemeral table */ #define TF_Eponymous 0x00008000 /* An eponymous virtual table */ #define TF_Strict 0x00010000 /* STRICT mode */ +#define TF_Imposter 0x00020000 /* An imposter table */ /* ** Allowed values for Table.eTabType diff --git a/test/imposter1.test b/test/imposter1.test index 196767be15..da58266be2 100644 --- a/test/imposter1.test +++ b/test/imposter1.test @@ -85,6 +85,7 @@ do_execsql_test imposter-1.2 { # database. # do_execsql_test imposter-1.3 { + PRAGMA writable_schema=on; DELETE FROM xt1 WHERE rowid=5; INSERT INTO xt1(rowid,a,b,c,d) VALUES(99,'hello',1099,2022,NULL); SELECT * FROM chnglog ORDER BY rowid;