From: dan Date: Tue, 2 Dec 2025 14:43:59 +0000 (+0000) Subject: Fix a problem with ALTER TABLE DROP COLUMN commands where the column being dropped... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d200379affa222bf3ae86f6da88d63830f3f980b;p=thirdparty%2Fsqlite.git Fix a problem with ALTER TABLE DROP COLUMN commands where the column being dropped is the rightmost in table and is immediately preceded by a comment containing a "," character. FossilOrigin-Name: c872bd1ee7b219e055f40e43766e4ed6bc2d2ca8cb92577cd3560f4173b1f257 --- diff --git a/manifest b/manifest index bc0447d376..c5099f5f3d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sdeveloper\snote\son\show\sto\smeasure\scoverage\sof\sQRF. -D 2025-12-02T12:23:24.524 +C Fix\sa\sproblem\swith\sALTER\sTABLE\sDROP\sCOLUMN\scommands\swhere\sthe\scolumn\sbeing\sdropped\sis\sthe\srightmost\sin\stable\sand\sis\simmediately\spreceded\sby\sa\scomment\scontaining\sa\s","\scharacter. +D 2025-12-02T14:43:59.730 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -669,7 +669,7 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366 F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398 -F src/alter.c fe6fa35700b968f8f9d2515939455e70f6b6ff2586a6e3ce9827bf44756354f2 +F src/alter.c 49274beed71d31591c8de17404f31e53ed8798507c8b3016d6f15b8ec478b1e2 F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d F src/attach.c 9af61b63b10ee702b1594ecd24fb8cea0839cfdb6addee52fba26fa879f5db9d F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc @@ -852,7 +852,7 @@ F test/altermalloc3.test 8040e486368403f2fdd6fc3998258b499bd4cc2f3ddbb5f8f874cd4 F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834ccba F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27 F test/altertab2.test 0889ba0700cc1cdb7bc7d25975aa61fece34f621de963d0886e2395716b38576 -F test/altertab3.test 471b8898d10bbc6488db9c23dc76811f405de6707d2d342b1b8b6fd1f13cd3c8 +F test/altertab3.test 575e771e2f02b13eb98798dc92eabacd187d6dbcf596e70f11d699b0b6b5d0b2 F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b @@ -2181,8 +2181,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7e99e93cddeba555836206a278c5dcfd8565cc2a486a83cffab64dad168e9464 -R de758b56921e31817918b1313754b07f -U drh -Z cc3cfdbf6b5a72385cbc0d52882a934a +P 0fdd453c03addb8f5c1e546f7513e3498bccd61266174ce99a61ceebf04e97cf +R a05db7d00d43861c033636a6b23ea3b7 +U dan +Z 7c7543e8fa4c87f35bf5869e2e4f8ba1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 519daae95e..fd5dff5037 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0fdd453c03addb8f5c1e546f7513e3498bccd61266174ce99a61ceebf04e97cf +c872bd1ee7b219e055f40e43766e4ed6bc2d2ca8cb92577cd3560f4173b1f257 diff --git a/src/alter.c b/src/alter.c index 21b90abdb5..2a23076753 100644 --- a/src/alter.c +++ b/src/alter.c @@ -2114,6 +2114,57 @@ static void renameTableTest( #endif } + +/* +** Return the number of bytes until the end of the next non-whitespace and +** non-comment token. For the purpose of this function, a "(" token includes +** all of the bytes through and including the matching ")", or until the +** first illegal token, whichever comes first. +** +** Write the token type into *piToken. +** +** The value returned is the number of bytes in the token itself plus +** the number of bytes of leading whitespace and comments skipped plus +** all bytes through the next matching ")" if the token is TK_LP. +** +** Example: (Note: '.' used in place of '*' in the example z[] text) +** +** ,--------- *piToken := TK_RP +** v +** z[] = " /.comment./ --comment\n (two three four) five" +** | | +** |<-------------------------------------->| +** | +** `--- return value +*/ +static int getConstraintToken(const u8 *z, int *piToken){ + int iOff = 0; + int t = 0; + do { + iOff += sqlite3GetToken(&z[iOff], &t); + }while( t==TK_SPACE || t==TK_COMMENT ); + + *piToken = t; + + if( t==TK_LP ){ + int nNest = 1; + while( nNest>0 ){ + iOff += sqlite3GetToken(&z[iOff], &t); + if( t==TK_LP ){ + nNest++; + }else if( t==TK_RP ){ + t = TK_LP; + nNest--; + }else if( t==TK_ILLEGAL ){ + break; + } + } + } + + *piToken = t; + return iOff; +} + /* ** The implementation of internal UDF sqlite_drop_column(). ** @@ -2158,15 +2209,24 @@ static void dropColumnFunc( goto drop_column_done; } - pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); if( iColnCol-1 ){ RenameToken *pEnd; + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName); zEnd = (const char*)pEnd->t.z; }else{ + int eTok; assert( IsOrdinaryTable(pTab) ); + assert( iCol!=0 ); + /* Point pCol->t.z at the "," immediately preceding the definition of + ** the column being dropped. To do this, start at the name of the + ** previous column, and tokenize until the next ",". */ + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol-1].zCnName); + do { + pCol->t.z += getConstraintToken(pCol->t.z, &eTok); + }while( eTok!=TK_COMMA ); + pCol->t.z--; zEnd = (const char*)&zSql[pTab->u.tab.addColOffset]; - while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--; } zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd); @@ -2350,56 +2410,6 @@ static int getWhitespace(const u8 *z){ } -/* -** Return the number of bytes until the end of the next non-whitespace and -** non-comment token. For the purpose of this function, a "(" token includes -** all of the bytes through and including the matching ")", or until the -** first illegal token, whichever comes first. -** -** Write the token type into *piToken. -** -** The value returned is the number of bytes in the token itself plus -** the number of bytes of leading whitespace and comments skipped plus -** all bytes through the next matching ")" if the token is TK_LP. -** -** Example: (Note: '.' used in place of '*' in the example z[] text) -** -** ,--------- *piToken := TK_RP -** v -** z[] = " /.comment./ --comment\n (two three four) five" -** | | -** |<-------------------------------------->| -** | -** `--- return value -*/ -static int getConstraintToken(const u8 *z, int *piToken){ - int iOff = 0; - int t = 0; - do { - iOff += sqlite3GetToken(&z[iOff], &t); - }while( t==TK_SPACE || t==TK_COMMENT ); - - *piToken = t; - - if( t==TK_LP ){ - int nNest = 1; - while( nNest>0 ){ - iOff += sqlite3GetToken(&z[iOff], &t); - if( t==TK_LP ){ - nNest++; - }else if( t==TK_RP ){ - t = TK_LP; - nNest--; - }else if( t==TK_ILLEGAL ){ - break; - } - } - } - - *piToken = t; - return iOff; -} - /* ** Argument z points into the body of a constraint - specifically the ** second token of the constraint definition. For a named constraint, diff --git a/test/altertab3.test b/test/altertab3.test index 92060fb41c..36e08c7694 100644 --- a/test/altertab3.test +++ b/test/altertab3.test @@ -778,4 +778,52 @@ do_execsql_test 31.2 { SELECT rr FROM t1 LIMIT 1 } {5.0} +#------------------------------------------------------------------------- +reset_db +do_execsql_test 32.1.0 { + CREATE TABLE t1( + a INT, + b INT, + -- comment with comma + c INT + ); +} +do_execsql_test 32.1.1 { + ALTER TABLE t1 DROP COLUMN c; +} +do_execsql_test 32.1.2 { + SELECT sql FROM sqlite_schema +} {{CREATE TABLE t1( + a INT, + b INT)}} + +reset_db +do_execsql_test 32.2.0 { + CREATE TABLE t1( + a INT, + b INT, + -- comment with, comma + c INT + ); +} +do_execsql_test 32.2.1 { + ALTER TABLE t1 DROP COLUMN c; +} +do_execsql_test 32.2.2 { + SELECT sql FROM sqlite_schema +} {{CREATE TABLE t1( + a INT, + b INT)}} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 33.1 { + CREATE TABLE x1(a TEXT, b INTEGER, c CHECK(c!=0)); +} + +do_execsql_test 33.2 { + ALTER TABLE x1 DROP COLUMN b; + SELECT sql FROM sqlite_schema; +} {{CREATE TABLE x1(a TEXT, c CHECK(c!=0))}} + finish_test