]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Allow "ALTER TABLE ... DROP CONSTRAINT" to drop foreign key constraints. drop-constraint-fk
authordan <Dan Kennedy>
Wed, 8 Jul 2026 17:40:04 +0000 (17:40 +0000)
committerdan <Dan Kennedy>
Wed, 8 Jul 2026 17:40:04 +0000 (17:40 +0000)
FossilOrigin-Name: 17c08963812d6458783720c511806727aeae263a243a11d49b463d2c7867cd54

manifest
manifest.tags
manifest.uuid
src/alter.c
test/altercons2.test
test/altercons3.test [new file with mode: 0644]

index 4fa0339a151bdec854f0fdffb4a67b60f8c08f28..3fc0eb9bec6b5d7e9e140bfaff6f4dc22bba9fc8 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C For\sdisplay\smodes\sin\sthe\sCLI\sfor\swhich\scolumn\sheaders\sare\senabled,\nmake\sthe\smode\s"always"\sinstead\sof\s"on.\s\sImproved\scomments\sand\stest\ncases.
-D 2026-07-08T15:43:42.959
+C Allow\s"ALTER\sTABLE\s...\sDROP\sCONSTRAINT"\sto\sdrop\sforeign\skey\sconstraints.
+D 2026-07-08T17:40:04.496
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -675,7 +675,7 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
 F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
 F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
-F src/alter.c da59ac700b52ba5d0e4dd099fb1818975cf8a79a546594da586b4e1eba3ae405
+F src/alter.c 0c6e7f9d2ddd1ee55e5e9dd903ea00a13ba728b7be2fbbaa2e83725dafdadbd9
 F src/analyze.c 73162482c656187823217f4c00758c9ee13a420c8745bc542129e0279b792287
 F src/attach.c c58278c7d2d954785591c4fde81669ec3e4d52f348c453b028a19ae8adf4f338
 F src/auth.c b5ece4e1edccad082c0332fa0087df225473bae0feea9269f824312201377185
@@ -846,7 +846,8 @@ F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256b
 F test/alterauth2.test 4b74fa8f184f4736497317feb587b65759eb87d87acfe3a8ef433d4d18bb002b
 F test/altercol.test 3661c432aacb42bc2198dd4611bbb9c3b09fc73251b59edda046109103b8ac00
 F test/altercons.test 9b036a956268eccd64761a6af3ab6f7b313c738392c7460b747d8aacd32589a2
-F test/altercons2.test 4933eadb035fc0ccfc34ed879f69a09051c53907f9dae9c3d36d25f93519ccc7
+F test/altercons2.test 264c1cc31c16b319de423af9565eb7129d7e9f55b21bb4eda6fdae02841265ae
+F test/altercons3.test d0bd7dde66a4a4f0b432b3ae3520e989b52b9bdfadddb9bd80be94554fecf803
 F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12
 F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e
 F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
@@ -2213,9 +2214,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 4edba31af4ef18350cb415079fb92cae0c53767fc0e74d63d404296974e75e5c f94259fc07cd7856e9c6f81a46689f4f96bbf464fda7f1d11b51a308c296aca0
-R 688db872c29fb684e76bc6c6acf8cc9b
-T +closed f94259fc07cd7856e9c6f81a46689f4f96bbf464fda7f1d11b51a308c296aca0
-U drh
-Z aa42c4c981256f3d4f6c42fc99d72364
+P c8aa208bf5b00f3ab93c5edd510dfd0d7edd271c064f159616ee409b308f7eb9
+R 4bd3a46fbadb8b3a12b89cadb35de70a
+T *branch * drop-constraint-fk
+T *sym-drop-constraint-fk *
+T -sym-trunk *
+U dan
+Z 7b2661190251d9be0a0996978db71a70
 # Remove this line to create a well-formed Fossil manifest.
index bec971799ff1b8ee641c166c7aeb22d12c785393..d37ec80d4772026b0e852fdfe7fb07cbefd2fc5d 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch drop-constraint-fk
+tag drop-constraint-fk
index 9eba18e4276fdf8d58898182046a44b3af97b829..767d1600e9dfdea5a7d445ffea6a92d63b525ee0 100644 (file)
@@ -1 +1 @@
-c8aa208bf5b00f3ab93c5edd510dfd0d7edd271c064f159616ee409b308f7eb9
+17c08963812d6458783720c511806727aeae263a243a11d49b463d2c7867cd54
index 7d3c85b5aed6eb03467d384951b7e6c273571df7..5d39087e6fb65f250c686ecff9119ba2b30890cd 100644 (file)
@@ -2409,16 +2409,38 @@ static int getWhitespace(const u8 *z){
 /*
 ** Argument z points into the body of a constraint - specifically the 
 ** second token of the constraint definition.  For a named constraint,
-** z points to the first token past the CONSTRAINT keyword.  For an
-** unnamed NOT NULL constraint, z points to the first byte past the NOT
+** z points to the second token of the constraint definition. For an 
+** unnamed NOT NULL constraint, z points to the first byte past the NOT 
 ** keyword.
 **
+** Argument eTok may be the token value of the first token of the constraint
+** (e.g. TK_CHECK or TK_REFERENCES) or zero. If it is either TK_REFERENCES
+** or TK_FOREIGN, special parsing is enabled to find the end of the foreign-key
+** constraint definition.
+**
 ** Return the number of bytes until the end of the constraint. 
 */
-static int getConstraint(const u8 *z){
+static int getConstraint(const u8 *z, int eTok){
   int iOff = 0;
   int t = 0;
 
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+  if( eTok==TK_FOREIGN ){
+    /* For a FOREIGN KEY constraint, use getConstraint() to parse everything
+    ** up to the REFERENCES keyword. Then getConstraintToken() to consume
+    ** the TK_REFERENCES token itself. Then fall through to the special
+    ** handling for TK_REFERENCES below.  */
+    iOff = getConstraint(z, 0);
+    iOff += getConstraintToken(&z[iOff], &eTok);
+  }
+
+  if( eTok==TK_REFERENCES ){
+    /* REFERENCES is followed by a table name. Gobble this up here in
+    ** case the table name is a fallback token like TK_GENERATED. */
+    iOff += getConstraintToken(&z[iOff], &t);
+  }
+#endif
+
   /* Now, the current constraint proceeds until the next occurence of one 
   ** of the following tokens: 
   **
@@ -2590,11 +2612,11 @@ static void dropConstraintFunc(
           t = TK_CHECK;
         }else{
           iOff += nTok;
-          iOff += getConstraint(&zSql[iOff]);
+          iOff += getConstraint(&zSql[iOff], t);
         }
 
         if( cmp==0 || (iNotNull>=0 && t==TK_NOT) ){
-          if( t!=TK_NOT && t!=TK_CHECK ){
+          if( t!=TK_NOT && t!=TK_CHECK && t!=TK_REFERENCES && t!=TK_FOREIGN ){
             errorMPrintf(ctx, "constraint may not be dropped: %s", zCons);
             return;
           }
@@ -2603,7 +2625,7 @@ static void dropConstraintFunc(
         }
 
       }else if( t==TK_NOT && iNotNull==ii ){
-        iEnd = iOff + getConstraint(&zSql[iOff]);
+        iEnd = iOff + getConstraint(&zSql[iOff], 0);
         break;
       }else if( t==TK_RP || t==TK_ILLEGAL ){
         iEnd = -1;
index 1e6aa1acc3af54c21417d932622a9977228a4f00..916ae27077bfe9b261beb4939413a8cbaf7f7b96 100644 (file)
@@ -172,7 +172,10 @@ do_execsql_test 8.0 {
 }
 do_catchsql_test 8.1 {
   ALTER TABLE abc DROP CONSTRAINT one
-} {1 {constraint may not be dropped: one}}
+} {0 {}}
+do_execsql_test 8.2 {
+  SELECT sql FROM sqlite_schema
+} {{CREATE TABLE abc(a, b, c)}}
 
 #-------------------------------------------------------------------------
 reset_db
diff --git a/test/altercons3.test b/test/altercons3.test
new file mode 100644 (file)
index 0000000..5fe8a86
--- /dev/null
@@ -0,0 +1,101 @@
+# 2026 July 8
+#
+# 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.
+#
+#*************************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix altercons3
+
+# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
+ifcapable !altertable {
+  finish_test
+  return
+}
+
+#-------------------------------------------------------------------------
+do_execsql_test 1.0 {
+  CREATE TABLE p1(a PRIMARY KEY);
+  CREATE TABLE c1(b CONSTRAINT fk REFERENCES p1(a));
+}
+do_execsql_test 1.1 {
+  ALTER TABLE c1 DROP CONSTRAINT fk;
+  SELECT sql FROM sqlite_schema WHERE name='c1';
+} {{CREATE TABLE c1(b)}}
+
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 2.0 {
+  CREATE TABLE p1(a PRIMARY KEY);
+  CREATE TABLE c1(b, CONSTRAINT fk FOREIGN KEY (b) REFERENCES p1(a));
+}
+do_execsql_test 2.1 {
+  ALTER TABLE c1 DROP CONSTRAINT fk;
+  SELECT sql FROM sqlite_schema WHERE name='c1';
+} {{CREATE TABLE c1(b)}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 3.0 {
+  CREATE TABLE generated(a PRIMARY KEY);
+  CREATE TABLE c1(b CONSTRAINT fk REFERENCES generated(a));
+}
+do_execsql_test 3.1 {
+  ALTER TABLE c1 DROP CONSTRAINT fk;
+  SELECT sql FROM sqlite_schema WHERE name='c1';
+} {{CREATE TABLE c1(b)}}
+
+#--------------------------------------------------------------------------
+reset_db
+
+foreach {tn before after} {
+  1 "CREATE TABLE c1(b CONSTRAINT fk REFERENCES p1(a))"
+    "CREATE TABLE c1(b)"
+
+  2 "CREATE TABLE c1(b, c, CONSTRAINT fk FOREIGN key (c, b) REFERENCES p1(o,t))"
+    "CREATE TABLE c1(b, c)"
+
+  3 "CREATE TABLE c1(b, generated, 
+       CONSTRAINT fk FOREIGN key (generated) REFERENCES p1(o))"
+    "CREATE TABLE c1(b, generated)"
+
+  4 "CREATE TABLE c1(b, generated CONSTRAINT fk REFERENCES p1(o) NOT NULL)"
+    "CREATE TABLE c1(b, generated NOT NULL)"
+
+  5 "CREATE TABLE c1(b, generated CONSTRAINT fk REFERENCES x1)"
+    "CREATE TABLE c1(b, generated)"
+} {
+  do_execsql_test 4.$tn.1 { DROP TABLE IF EXISTS c1 }
+  do_execsql_test 4.$tn.2 $before
+  do_execsql_test 4.$tn.3 { ALTER TABLE c1 DROP CONSTRAINT fk }
+  do_execsql_test 4.$tn.4 { 
+    SELECT sql FROM sqlite_schema WHERE name='c1' 
+  } [list $after]
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 5.0 {
+  CREATE TABLE x1(a, b CONSTRAINT ott REFERENCES x2);
+  PRAGMA writable_schema = 1;
+  UPDATE sqlite_schema SET sql='CREATE TABLE x1(a, b CONSTRAINT ott REFERENCES';
+}
+
+do_execsql_test 5.1 {
+  ALTER TABLE x1 DROP CONSTRAINT ott;
+}
+
+do_execsql_test 5.2 {
+  SELECT sql FROM sqlite_schema
+} {{CREATE TABLE x1(a, b }}
+
+finish_test
+