From: drh <> Date: Thu, 19 Aug 2021 02:58:15 +0000 (+0000) Subject: Enhance PRAGMA integrity_check so that it verifies the datatype of X-Git-Tag: version-3.37.0~276^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9e1209d111aab64242aec299b347e60492556761;p=thirdparty%2Fsqlite.git Enhance PRAGMA integrity_check so that it verifies the datatype of all columns in STRICT tables. FossilOrigin-Name: 97c9248b3b81facce569bfa3fb405d44a1d1041e87132e8f649458c95620ccb2 --- diff --git a/manifest b/manifest index 8fec01b5ec..961317c00d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C STRICT\stables\srequire\sall\sfields\sof\sthe\sPRIMARY\sKEY\sto\sbe\sNOT\sNULL. -D 2021-08-19T00:24:43.029 +C Enhance\sPRAGMA\sintegrity_check\sso\sthat\sit\sverifies\sthe\sdatatype\sof\nall\scolumns\sin\sSTRICT\stables. +D 2021-08-19T02:58:15.725 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -500,7 +500,7 @@ F src/expr.c e98375fc63552cc8cdd36a41bdca3039cb603d9fe67abd9c9f40adae8405fbc5 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 1905af1821b88321e1bb9d6a69e704495b6844a9b6c29398d40117cc251e893c F src/func.c c224240cbc97fa5e9c4fe9acb128716cb835ca045532bca6951b7c45b020c56c -F src/global.c 5eba017ebbd887e2365e6e6e815e1619e41406b8946d17594e94116174787df5 +F src/global.c 436d4819e48d0272ef1ed72bd5fe44fed06ff5f83f54eebe8c74123771f7ad0b F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 @@ -537,7 +537,7 @@ F src/parse.y 86aa016b281f61d7664dd8cb7808cab8114d14cfaf362a9b9fc9ead8f33546b7 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 -F src/pragma.c af0f43789545622fd5377d71f6d4c0e7c9b9295a3f5d5b1242e4032d38ca12b5 +F src/pragma.c b6ba4aa11ad3e21a07cfb7be5dad4bdae7e733dd4f91e3f586dfc0ea703c0178 F src/pragma.h a11b4798f9c49f156f130e1f7041a9fcc9d316a64f3501b6013acdd2e4c6f549 F src/prepare.c 0d53d20532aada295c1690792a125adbd6435f5ce703ff0adf1b9b3605238b67 F src/printf.c 78fabb49b9ac9a12dd1c89d744abdc9b67fd3205e62967e158f78b965a29ec4b @@ -549,7 +549,7 @@ F src/shell.c.in f795a4ae3c35631f5edcfa754c7824ff1d8a75b23a07e22e664b50f82e82634 F src/sqlite.h.in 4e977a5e2ed1a9e8987ff65a2cab5f99a4298ebf040ea5ff636e1753339ff45a F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510 -F src/sqliteInt.h 732ef4ade4ea3e95ddc0a6be657c5f9eb1e4b8ede3105395fe0161c15fab9214 +F src/sqliteInt.h a0e00a52b90f236c77fd0c0b839cc091d9926aca7627eb6ad8cf3f55a9847a71 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -616,7 +616,7 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c eafc8cfeb66fdbf8839922d13019b7882f242ac31b383e3451aab7744c54df3e F src/vacuum.c 454973a59fb20bb982efc2df568a098616db6328a0491b6e84e2e07f7333db45 -F src/vdbe.c 0e70bef8e65fc217beb7909235502ce132d231fb656554205e0c13927b4140d1 +F src/vdbe.c db2033468624757c7560456d0935d7bac6732c626b193ed865da93a4ee6bd3e2 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe F src/vdbeInt.h 38206c8dd6b60ff03d9fd4f626b1b4fd0eef7cdc44f2fc2c1973b0f932a3f26b F src/vdbeapi.c aa5aaf2c37676b83af5724c6cd8207a3064ed46a217fd180957f75ac84f7a2a5 @@ -1426,6 +1426,7 @@ F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75 F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5 F test/strict1.test dab7a84f5445e696beb3e2eedda9b3a28fb16bf3092be1917b3f1a6163916197 +F test/strict2.test fe1928b3768f51b39774d753ac7e71727718d1c3305eead0e5ea60f75e9e6b4c F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49 F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f F test/subquery2.test 90cf944b9de8204569cf656028391e4af1ccc8c0cc02d4ef38ee3be8de1ffb12 @@ -1921,7 +1922,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7ee01ee47da247a80bcf16f88eb187b8c0928024536435ed20797a1a90495511 -R 9431b5ba9e76c466e3043738fddec247 +P 5efdf9acad9d54783f5134b7e9338f44336862d87dc324d315b8d55e44df1923 +R b81ba137d5fbe2c27e5bf73bf8e1c01f U drh -Z 0e5e6ca613f5601fc51663462528d032 +Z cb07934ea9a1c0a07dfc699c730ff260 diff --git a/manifest.uuid b/manifest.uuid index c53f8de72d..7844f9394f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5efdf9acad9d54783f5134b7e9338f44336862d87dc324d315b8d55e44df1923 \ No newline at end of file +97c9248b3b81facce569bfa3fb405d44a1d1041e87132e8f649458c95620ccb2 \ No newline at end of file diff --git a/src/global.c b/src/global.c index a1398fef5d..98793fbd3f 100644 --- a/src/global.c +++ b/src/global.c @@ -360,6 +360,13 @@ const char sqlite3StdTypeAffinity[] = { SQLITE_AFF_REAL, SQLITE_AFF_TEXT }; +const char sqlite3StdTypeMap[] = { + SQLITE_BLOB, + SQLITE_INTEGER, + SQLITE_INTEGER, + SQLITE_FLOAT, + SQLITE_TEXT +}; const char *sqlite3StdType[] = { "BLOB", "INT", diff --git a/src/pragma.c b/src/pragma.c index c931dd2acb..39095d82d7 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1653,6 +1653,7 @@ void sqlite3Pragma( int loopTop; int iDataCur, iIdxCur; int r1 = -1; + int bStrict; if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ if( pObjTab && pObjTab!=pTab ) continue; @@ -1675,22 +1676,44 @@ void sqlite3Pragma( sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } - /* Verify that all NOT NULL columns really are NOT NULL */ + /* Verify that all NOT NULL columns really are NOT NULL. At the + ** same time verify the type of the content of STRICT tables */ + bStrict = (pTab->tabFlags & TF_Strict)!=0; for(j=0; jnCol; j++){ char *zErr; - int jmp2; + Column *pCol = pTab->aCol + j; + int endLabel; if( j==pTab->iPKey ) continue; - if( pTab->aCol[j].notNull==0 ) continue; + if( pCol->notNull==0 && !bStrict ) continue; + endLabel = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } - jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); - zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, - pTab->aCol[j].zCnName); - sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, jmp2); + if( pCol->notNull ){ + int jmp2; + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, + pCol->zCnName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + integrityCheckResultRow(v); + if( bStrict ) sqlite3VdbeGoto(v, endLabel); + sqlite3VdbeJumpHere(v, jmp2); + } + if( pTab->tabFlags & TF_Strict ){ + if( pCol->notNull==0 ){ + sqlite3VdbeAddOp2(v, OP_IsNull, 3, endLabel); VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, OP_IfType, 3, endLabel, + sqlite3StdTypeMap[pCol->eCType-1]); + VdbeCoverage(v); + zErr = sqlite3MPrintf(db, "non-%s value in %s.%s", + sqlite3StdType[pCol->eCType-1], + pTab->zName, pTab->aCol[j].zCnName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + integrityCheckResultRow(v); + sqlite3VdbeResolveLabel(v, endLabel); + } } /* Verify CHECK constraints */ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0a01179090..348a41393d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4841,6 +4841,7 @@ extern const unsigned char sqlite3OpcodeProperty[]; extern const char sqlite3StrBINARY[]; extern const unsigned char sqlite3StdTypeLen[]; extern const char sqlite3StdTypeAffinity[]; +extern const char sqlite3StdTypeMap[]; extern const char *sqlite3StdType[]; extern const unsigned char sqlite3UpperToLower[]; extern const unsigned char *sqlite3aLTb; diff --git a/src/vdbe.c b/src/vdbe.c index d7def8a79f..01da0a9568 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2534,6 +2534,22 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ break; } +/* Opcode: IfType P1 P2 P3 * * +** Synopsis: if typeof(r[P1])!=P3 goto P2 +** +** Jump to P2 if the value in register has a datatype given by P3. +** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT, +** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT. +*/ +case OP_IfType: { /* jump, in1 */ + int doTheJump; + pIn1 = &aMem[pOp->p1]; + doTheJump = sqlite3_value_type(pIn1)==pOp->p3; + VdbeBranchTaken( doTheJump, 2); + if( doTheJump ) goto jump_to_p2; + break; +} + /* Opcode: IfNullRow P1 P2 P3 * * ** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 ** diff --git a/test/strict2.test b/test/strict2.test new file mode 100644 index 0000000000..854d1c59fd --- /dev/null +++ b/test/strict2.test @@ -0,0 +1,143 @@ +# 2021-08-19 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements regression tests for SQLite library. The +# focus of this file is testing STRICT tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix strict2 + +# PRAGMA integrity_check on a STRICT table should verify that +# all of the values are of the correct type. +# +do_execsql_test strict2-1.1 { + CREATE TABLE t1( + a INT, + b INTEGER, + c TEXT, + d REAL, + e BLOB + ) STRICT; + CREATE TABLE t1nn( + a INT NOT NULL, + b INTEGER NOT NULL, + c TEXT NOT NULL, + d REAL NOT NULL, + e BLOB NOT NULL + ) STRICT; + CREATE TABLE t2(a,b,c,d,e); + INSERT INTO t1(a,b,c,d,e) VALUES(1,1,'one',1.0,x'b1'),(2,2,'two',2.25,x'b2b2b2'); + PRAGMA writable_schema=on; + UPDATE sqlite_schema SET rootpage=(SELECT rootpage FROM sqlite_schema WHERE name='t1'); +} {} +db close +sqlite3 db test.db +do_execsql_test strict2-1.2 { + PRAGMA quick_check('t1'); +} {ok} +do_execsql_test strict2-1.3 { + UPDATE t2 SET a=2.5 WHERE b=2; + PRAGMA quick_check('t1'); +} {{non-INT value in t1.a}} +do_execsql_test strict2-1.4 { + UPDATE t2 SET a='xyz' WHERE b=2; + PRAGMA quick_check('t1'); +} {{non-INT value in t1.a}} +do_execsql_test strict2-1.5 { + UPDATE t2 SET a=x'445566' WHERE b=2; + PRAGMA quick_check('t1'); +} {{non-INT value in t1.a}} +do_execsql_test strict2-1.6 { + UPDATE t2 SET a=2.5 WHERE b=2; + PRAGMA quick_check('t1nn'); +} {{non-INT value in t1nn.a}} +do_execsql_test strict2-1.7 { + UPDATE t2 SET a='xyz' WHERE b=2; + PRAGMA quick_check('t1nn'); +} {{non-INT value in t1nn.a}} +do_execsql_test strict2-1.8 { + UPDATE t2 SET a=x'445566' WHERE b=2; + PRAGMA quick_check('t1nn'); +} {{non-INT value in t1nn.a}} + +do_execsql_test strict2-1.13 { + UPDATE t2 SET a=2 WHERE b=2; + UPDATE t2 SET b=2.5 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-INTEGER value in t1.b}} +do_execsql_test strict2-1.14 { + UPDATE t2 SET b='two' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-INTEGER value in t1.b}} +do_execsql_test strict2-1.15 { + UPDATE t2 SET b=x'b0b1b2b3b4' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-INTEGER value in t1.b}} +do_execsql_test strict2-1.16 { + UPDATE t2 SET b=NULL WHERE a=2; + PRAGMA quick_check('t1'); +} {ok} +do_execsql_test strict2-1.17 { + UPDATE t2 SET b=2.5 WHERE a=2; + PRAGMA quick_check('t1nn'); +} {{non-INTEGER value in t1nn.b}} +do_execsql_test strict2-1.18 { + UPDATE t2 SET b=NULL WHERE a=2; + PRAGMA quick_check('t1nn'); +} {{NULL value in t1nn.b}} + +do_execsql_test strict2-1.23 { + UPDATE t2 SET b=2 WHERE a=2; + UPDATE t2 SET c=9 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-TEXT value in t1.c}} +do_execsql_test strict2-1.24 { + UPDATE t2 SET c=9.5 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-TEXT value in t1.c}} +do_execsql_test strict2-1.25 { + UPDATE t2 SET c=x'b0b1b2b3b4' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-TEXT value in t1.c}} + +do_execsql_test strict2-1.33 { + UPDATE t2 SET c='two' WHERE a=2; + UPDATE t2 SET d=9 WHERE a=2; + PRAGMA quick_check('t1'); +} {ok} +do_execsql_test strict2-1.34 { + UPDATE t2 SET d='nine' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-REAL value in t1.d}} +do_execsql_test strict2-1.35 { + UPDATE t2 SET d=x'b0b1b2b3b4' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-REAL value in t1.d}} + +do_execsql_test strict2-1.43 { + UPDATE t2 SET d=2.5 WHERE a=2; + UPDATE t2 SET e=9 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-BLOB value in t1.e}} +do_execsql_test strict2-1.44 { + UPDATE t2 SET e=9.5 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-BLOB value in t1.e}} +do_execsql_test strict2-1.45 { + UPDATE t2 SET e='hello' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-BLOB value in t1.e}} + + + +finish_test