]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance PRAGMA integrity_check so that it verifies the datatype of
authordrh <>
Thu, 19 Aug 2021 02:58:15 +0000 (02:58 +0000)
committerdrh <>
Thu, 19 Aug 2021 02:58:15 +0000 (02:58 +0000)
all columns in STRICT tables.

FossilOrigin-Name: 97c9248b3b81facce569bfa3fb405d44a1d1041e87132e8f649458c95620ccb2

manifest
manifest.uuid
src/global.c
src/pragma.c
src/sqliteInt.h
src/vdbe.c
test/strict2.test [new file with mode: 0644]

index 8fec01b5ec57cd3a7992212902515de7fd59e0e1..961317c00d0d5e705564fd13337c1bcf56e2742c 100644 (file)
--- 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
index c53f8de72d04f3ef5636651b8628135ff8e5e90c..7844f9394f1ebd82d58985fe1f25486051f6d84d 100644 (file)
@@ -1 +1 @@
-5efdf9acad9d54783f5134b7e9338f44336862d87dc324d315b8d55e44df1923
\ No newline at end of file
+97c9248b3b81facce569bfa3fb405d44a1d1041e87132e8f649458c95620ccb2
\ No newline at end of file
index a1398fef5dc95efede8765ab84ad3d29c8add54f..98793fbd3fcb040ff3a2bb635f7a4510cba6b729 100644 (file)
@@ -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",
index c931dd2acbc024431c0780d71b03ad1598b876c7..39095d82d75b604b97f77688a6a4d207162b0573 100644 (file)
@@ -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; j<pTab->nCol; 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 ){
index 0a01179090ad34d95f18fb8659a9db43cc14b9dd..348a41393d619cc50171ded5a2af2e67679ebc8d 100644 (file)
@@ -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;
index d7def8a79f121652fc0a61bcfea272e2946226ea..01da0a956836c8ef064d0de503903ee580a84475 100644 (file)
@@ -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 (file)
index 0000000..854d1c5
--- /dev/null
@@ -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