]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Improvements to imposter tables: (1) They are read-only unless writable-schema imposter-tables
authordrh <>
Fri, 19 Sep 2025 17:24:12 +0000 (17:24 +0000)
committerdrh <>
Fri, 19 Sep 2025 17:24:12 +0000 (17:24 +0000)
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

ext/intck/intck1.test
ext/intck/intck2.test
manifest
manifest.tags
manifest.uuid
src/build.c
src/pragma.c
src/shell.c.in
src/sqliteInt.h
test/imposter1.test

index 187132f766c67e88f706ca7a2421fa59a22a0163..ef29c2c54c2b618210da250bc2bc729fc47e7fa3 100644 (file)
@@ -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 {
index 23b241b5a92058b056b68138f5ea964d2c1a667b..a35bbc70c9012398cbe1d296eea159607dca9a51 100644 (file)
@@ -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
index d11a18e8cb205fa3c9b4c6685a39b85cf003ad7a..2c18c1155444eb62225be7f3640012321742763a 100644 (file)
--- 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.
index bec971799ff1b8ee641c166c7aeb22d12c785393..a8c248c3e12650c0fee39cf49eda34dfa35b26ad 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch imposter-tables
+tag imposter-tables
index 5f03ba8a91583029f21c90ddd5c3ae124e1fc348..7e0eca6a5aebe5d7968cd24ace72a4299b7308cc 100644 (file)
@@ -1 +1 @@
-468a11fd415710042b23880772f6c2c7771008208823fe3b554227a9244dbf92
+ad152ddc4bcf6cfe840b9a36ab76a5ec36afdb1dd96eb7697e4b3df1bf63b00d
index 6b1d3993f0e2800857029ec1b1f2a625381ae119..276c131977c8d508c1e49020901225ab30e13ad5 100644 (file)
@@ -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. */
index a0f24c15c007eb5b822b45ac2403b17876c89507..791508ea4aafe165c7454646d9e3da74a2217b44 100644 (file)
@@ -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 ){
index 57ca5cf2f1ab9db220ebfa239f85eeb21c426078..5bcec5bd60935148cce8d5a7de19501e6a6a57df 100644 (file)
@@ -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);
index f012650088d9e765c8bf2d77b0a51668a1a4337a..0b6de670fe1095e9314d8917859aa4f4533fe215 100644 (file)
@@ -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
index 196767be15e45b8ed0e7a6c5cb70514c1448570b..da58266be2b2a48da6cbdfa8cc642956149b2943 100644 (file)
@@ -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;