mirror of
https://github.com/sqlite/sqlite.git
synced 2025-10-22 22:13:04 +03:00
Fix some DROP CONSTRAINT and DROP NOT NULL cases involving SQL comments or multiple table constraints without separating commas.
FossilOrigin-Name: b0b02e58ac60e4371981938c904ccf831b2367e3fd7d22e0ec2b4782e4c6805b
This commit is contained in:
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Add\sfurther\stests\sfor\sthe\snew\sALTER\sTABLE\scommands\son\sthis\sbranch.
|
C Fix\ssome\sDROP\sCONSTRAINT\sand\sDROP\sNOT\sNULL\scases\sinvolving\sSQL\scomments\sor\smultiple\stable\sconstraints\swithout\sseparating\scommas.
|
||||||
D 2025-09-29T16:49:55.217
|
D 2025-09-30T17:13:12.931
|
||||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
@@ -670,7 +670,7 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
|
|||||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||||
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
|
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
|
||||||
F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
|
F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
|
||||||
F src/alter.c 875b85a0306968cfb811650d1c994bf65cf3112a521717d058e363705853a4a6
|
F src/alter.c a2d3e4d1afe75c98048400b316e01c73a3688548ddbd9a8b76bebbae3f91b883
|
||||||
F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d
|
F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d
|
||||||
F src/attach.c 9af61b63b10ee702b1594ecd24fb8cea0839cfdb6addee52fba26fa879f5db9d
|
F src/attach.c 9af61b63b10ee702b1594ecd24fb8cea0839cfdb6addee52fba26fa879f5db9d
|
||||||
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
|
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
|
||||||
@@ -839,8 +839,8 @@ F test/alter4.test 37cafe164067a6590a0ee4cec780bddbbaa33dc50b11542dcfbe0e6562649
|
|||||||
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
|
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
|
||||||
F test/alterauth2.test 4b74fa8f184f4736497317feb587b65759eb87d87acfe3a8ef433d4d18bb002b
|
F test/alterauth2.test 4b74fa8f184f4736497317feb587b65759eb87d87acfe3a8ef433d4d18bb002b
|
||||||
F test/altercol.test b43fb5725332f4cf8cff0280605202c1672e808281accea60a066d2ccc5129e5
|
F test/altercol.test b43fb5725332f4cf8cff0280605202c1672e808281accea60a066d2ccc5129e5
|
||||||
F test/altercons.test ac50608f34171021e67c5f2cbd9615a9fbf181804b84817d7a35e2cd89fbeb7d
|
F test/altercons.test 22f4882404a7ba114ec9cbcadc4d15cea4a9ff73079d26cb649357808d586521
|
||||||
F test/altercons2.test 9adc4e742655d2e55e38f507bd97dc1cd48bc91aa26b59bd3518fd2184a58114
|
F test/altercons2.test 6e8e384f394ac1b6657429a885bc50be27bb88fe7427d8e1d5a64bdf600c221c
|
||||||
F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12
|
F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12
|
||||||
F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e
|
F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e
|
||||||
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
|
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
|
||||||
@@ -2171,8 +2171,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
|
|||||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||||
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P 8f2e066e9a0a34fe7a41b153c0fb54b621128b2195141cc454a44180c969b4a9
|
P 17a6f4e69e54a5dc233e33501f16f0f69f77fff071142cefc309b5407f57f721
|
||||||
R 7160ac4e86f1b04a352a7675b4a73b19
|
R cad1fca46ac4b09e84f0a86ca159c2b9
|
||||||
U dan
|
U dan
|
||||||
Z 729e8deb8af33990459f24e581d10a3d
|
Z 5d912a204d4b04c238cd0328baa01045
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@@ -1 +1 @@
|
|||||||
17a6f4e69e54a5dc233e33501f16f0f69f77fff071142cefc309b5407f57f721
|
b0b02e58ac60e4371981938c904ccf831b2367e3fd7d22e0ec2b4782e4c6805b
|
||||||
|
45
src/alter.c
45
src/alter.c
@@ -2343,7 +2343,7 @@ static int getWhitespace(const u8 *z){
|
|||||||
while( 1 ){
|
while( 1 ){
|
||||||
int t = 0;
|
int t = 0;
|
||||||
int n = sqlite3GetToken(&z[nRet], &t);
|
int n = sqlite3GetToken(&z[nRet], &t);
|
||||||
if( t!=TK_SPACE ) break;
|
if( t!=TK_SPACE && t!=TK_COMMENT ) break;
|
||||||
nRet += n;
|
nRet += n;
|
||||||
}
|
}
|
||||||
return nRet;
|
return nRet;
|
||||||
@@ -2361,7 +2361,7 @@ static int getConstraintToken(const u8 *z, int *piToken){
|
|||||||
int t = 0;
|
int t = 0;
|
||||||
do {
|
do {
|
||||||
iOff += sqlite3GetToken(&z[iOff], &t);
|
iOff += sqlite3GetToken(&z[iOff], &t);
|
||||||
}while( t==TK_SPACE );
|
}while( t==TK_SPACE || t==TK_COMMENT );
|
||||||
|
|
||||||
*piToken = t;
|
*piToken = t;
|
||||||
|
|
||||||
@@ -2386,8 +2386,8 @@ static int getConstraintToken(const u8 *z, int *piToken){
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Argument z points into the body of a constraint - specifically the
|
** Argument z points into the body of a constraint - specifically the
|
||||||
** token following the first of the
|
** second token of the constraint definition. Return the number of bytes
|
||||||
** of bytes in string z to the end of the current constraint.
|
** until the end of the constraint.
|
||||||
*/
|
*/
|
||||||
static int getConstraint(const u8 *z){
|
static int getConstraint(const u8 *z){
|
||||||
int iOff = 0;
|
int iOff = 0;
|
||||||
@@ -2470,7 +2470,6 @@ static void dropConstraintFunc(
|
|||||||
int NotUsed,
|
int NotUsed,
|
||||||
sqlite3_value **argv
|
sqlite3_value **argv
|
||||||
){
|
){
|
||||||
const char *zSpace = " ";
|
|
||||||
const u8 *zSql = sqlite3_value_text(argv[0]);
|
const u8 *zSql = sqlite3_value_text(argv[0]);
|
||||||
const u8 *zCons = 0;
|
const u8 *zCons = 0;
|
||||||
int iNotNull = -1;
|
int iNotNull = -1;
|
||||||
@@ -2496,8 +2495,8 @@ static void dropConstraintFunc(
|
|||||||
/* Now parse the column or table constraint definition. Search
|
/* Now parse the column or table constraint definition. Search
|
||||||
** for the token CONSTRAINT if this is a DROP CONSTRAINT command, or
|
** for the token CONSTRAINT if this is a DROP CONSTRAINT command, or
|
||||||
** NOT in the right column if this is a DROP NOT NULL. */
|
** NOT in the right column if this is a DROP NOT NULL. */
|
||||||
iStart = iOff - 1;
|
|
||||||
while( 1 ){
|
while( 1 ){
|
||||||
|
iStart = iOff;
|
||||||
iOff += getConstraintToken(&zSql[iOff], &t);
|
iOff += getConstraintToken(&zSql[iOff], &t);
|
||||||
if( t==TK_CONSTRAINT && (zCons || iNotNull==ii) ){
|
if( t==TK_CONSTRAINT && (zCons || iNotNull==ii) ){
|
||||||
/* Check if this is the constraint we are searching for. */
|
/* Check if this is the constraint we are searching for. */
|
||||||
@@ -2515,9 +2514,26 @@ static void dropConstraintFunc(
|
|||||||
}
|
}
|
||||||
iOff += nTok;
|
iOff += nTok;
|
||||||
|
|
||||||
/* The first token of the constraint definition. */
|
/* The next token is usually the first token of the constraint
|
||||||
iOff += getConstraintToken(&zSql[iOff], &t);
|
** definition. This is enough to tell the type of the constraint -
|
||||||
iOff += getConstraint(&zSql[iOff]);
|
** TK_NOT means it is a NOT NULL, TK_CHECK a CHECK constraint etc.
|
||||||
|
**
|
||||||
|
** There is also the chance that the next token is TK_CONSTRAINT,
|
||||||
|
** for example if a table has been created as follows:
|
||||||
|
**
|
||||||
|
** CREATE TABLE t1(cols, CONSTRAINT one CONSTRAINT two NOT NULL);
|
||||||
|
**
|
||||||
|
** In this case, allow the "CONSTRAINT one" bit to be dropped by
|
||||||
|
** this command if that is what is requested, or to advance to
|
||||||
|
** the next iteration of the loop with &zSql[iOff] still pointing
|
||||||
|
** to the CONSTRAINT keyword. */
|
||||||
|
nTok = getConstraintToken(&zSql[iOff], &t);
|
||||||
|
if( t==TK_CONSTRAINT || t==TK_COMMA || t==TK_RP ){
|
||||||
|
t = TK_CHECK;
|
||||||
|
}else{
|
||||||
|
iOff += nTok;
|
||||||
|
iOff += getConstraint(&zSql[iOff]);
|
||||||
|
}
|
||||||
|
|
||||||
if( cmp==0 || (iNotNull>=0 && t==TK_NOT) ){
|
if( cmp==0 || (iNotNull>=0 && t==TK_NOT) ){
|
||||||
if( t!=TK_NOT && t!=TK_CHECK ){
|
if( t!=TK_NOT && t!=TK_CHECK ){
|
||||||
@@ -2537,7 +2553,6 @@ static void dropConstraintFunc(
|
|||||||
}else if( t==TK_COMMA ){
|
}else if( t==TK_COMMA ){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
iStart = iOff;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2551,10 +2566,16 @@ static void dropConstraintFunc(
|
|||||||
sqlite3_result_text(ctx, (const char*)zSql, -1, SQLITE_TRANSIENT);
|
sqlite3_result_text(ctx, (const char*)zSql, -1, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
/* Figure out if an extra space is required following the constraint. */
|
|
||||||
|
/* Figure out if an extra space should be inserted after the constraint
|
||||||
|
** is removed. And if an additional comma preceding the constraint
|
||||||
|
** should be removed. */
|
||||||
|
const char *zSpace = " ";
|
||||||
|
iEnd += getWhitespace(&zSql[iEnd]);
|
||||||
sqlite3GetToken(&zSql[iEnd], &t);
|
sqlite3GetToken(&zSql[iEnd], &t);
|
||||||
if( t==TK_RP || t==TK_SPACE || t==TK_COMMA ){
|
if( t==TK_RP || t==TK_COMMA ){
|
||||||
zSpace = "";
|
zSpace = "";
|
||||||
|
if( zSql[iStart-1]==',' ) iStart--;
|
||||||
}
|
}
|
||||||
|
|
||||||
zNew = sqlite3_mprintf("%.*s%s%s", iStart, zSql, zSpace, &zSql[iEnd]);
|
zNew = sqlite3_mprintf("%.*s%s%s", iStart, zSql, zSpace, &zSql[iEnd]);
|
||||||
|
@@ -57,6 +57,25 @@ foreach {tn before after} {
|
|||||||
11 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) REFERENCES t2) }
|
11 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) REFERENCES t2) }
|
||||||
{ CREATE TABLE t1(a, b REFERENCES t2) }
|
{ CREATE TABLE t1(a, b REFERENCES t2) }
|
||||||
|
|
||||||
|
12 { CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT abc CHECK(a!=b) CONSTRAINT three) }
|
||||||
|
{ CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT three) }
|
||||||
|
|
||||||
|
13 { CREATE TABLE t1(a, b, c, CONSTRAINT abc CONSTRAINT one CHECK(a!=b) CONSTRAINT three) }
|
||||||
|
{ CREATE TABLE t1(a, b, c, CONSTRAINT one CHECK(a!=b) CONSTRAINT three) }
|
||||||
|
|
||||||
|
14 { CREATE TABLE t1(a, b, c, CONSTRAINT abc) }
|
||||||
|
{ CREATE TABLE t1(a, b, c) }
|
||||||
|
|
||||||
|
15 { CREATE TABLE t1(a, b, c,
|
||||||
|
CONSTRAINT abc, CHECK( a!=b )) }
|
||||||
|
{ CREATE TABLE t1(a, b, c, CHECK( a!=b )) }
|
||||||
|
|
||||||
|
16 { CREATE TABLE t1(a, b, c, CONSTRAINT abc /* hello */ CHECK( a!=b )) }
|
||||||
|
{ CREATE TABLE t1(a, b, c) }
|
||||||
|
|
||||||
|
17 { CREATE TABLE t1(a, b, c, /* world */ CONSTRAINT abc CHECK( a!=b )) }
|
||||||
|
{ CREATE TABLE t1(a, b, c) }
|
||||||
|
|
||||||
} {
|
} {
|
||||||
reset_db
|
reset_db
|
||||||
|
|
||||||
|
@@ -102,11 +102,37 @@ reset_db
|
|||||||
do_execsql_test 3.0 {
|
do_execsql_test 3.0 {
|
||||||
CREATE TABLE t1(x);
|
CREATE TABLE t1(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
breakpoint
|
|
||||||
do_execsql_test 3.1 {
|
do_execsql_test 3.1 {
|
||||||
ALTER TABLE t1 ALTER x SET NOT NULL;
|
ALTER TABLE t1 ALTER x SET NOT NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
reset_db
|
||||||
|
do_execsql_test 4.0 {
|
||||||
|
CREATE TABLE abc(a, b, c, CONSTRAINT one CONSTRAINT two CHECK (b!=c));
|
||||||
|
}
|
||||||
|
do_execsql_test 4.1 {
|
||||||
|
ALTER TABLE abc DROP CONSTRAINT one
|
||||||
|
}
|
||||||
|
do_execsql_test 4.2 {
|
||||||
|
SELECT sql FROM sqlite_schema
|
||||||
|
} {
|
||||||
|
{CREATE TABLE abc(a, b, c, CONSTRAINT two CHECK (b!=c))}
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
reset_db
|
||||||
|
|
||||||
|
# The columns must come before the table constraints in a CREATE TABLE
|
||||||
|
# statement. This is useful, as it means the DROP CONSTRAINT code does
|
||||||
|
# not have to handle the constraint immediately following the '(' at
|
||||||
|
# the start of the column-list.
|
||||||
|
do_catchsql_test 5.0 {
|
||||||
|
CREATE TABLE abc(a, b, c, CONSTRAINT two CHECK (b!=c), d)
|
||||||
|
} {1 {near "d": syntax error}}
|
||||||
|
do_catchsql_test 5.1 {
|
||||||
|
CREATE TABLE def(CONSTRAINT abc CHECK( b!=c ), a, b, c);
|
||||||
|
} {1 {near "CONSTRAINT": syntax error}}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user