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
This commit is contained in:
drh
2025-09-19 17:24:12 +00:00
parent e7fe1d3b3e
commit 49a37f333a
10 changed files with 46 additions and 29 deletions
+2
View 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 {
+1
View 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
+15 -12
View File
@@ -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.
+2 -2
View File
@@ -1,2 +1,2 @@
branch trunk
tag trunk
branch imposter-tables
tag imposter-tables
+1 -1
View File
@@ -1 +1 @@
468a11fd415710042b23880772f6c2c7771008208823fe3b554227a9244dbf92
ad152ddc4bcf6cfe840b9a36ab76a5ec36afdb1dd96eb7697e4b3df1bf63b00d
+2
View 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. */
+21 -5
View 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 ){
-9
View 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);
+1
View 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
+1
View 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;