-C Add\sexperimental\simplementations\sof\sALTER\sTABLE\scommands\sto\sadd\sand\sdrop\sCHECK\sand\sNOT\sNULL\sconstraints.
-D 2025-09-27T14:59:21.750
+C Fix\sauthorization\scallbacks\sfor\sthe\snew\scommands\son\sthis\sbranch.
+D 2025-09-27T16:13:56.339
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
-F src/alter.c 8eeaacd19f6b5948600c7d567c1e22a906d60777c1de8be0d2caa6b68a058a3a
+F src/alter.c b126042887cccd2c6476685f634cbcfa7b7f2812ca4dc96bbb6d606fa9ba56e6
F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d
F src/attach.c 9af61b63b10ee702b1594ecd24fb8cea0839cfdb6addee52fba26fa879f5db9d
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
F src/pager.c 113f9149092ccff6cf90e97c2611200e5a237f13d26c394bc9fd933377852764
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
-F src/parse.y 853bfe037292ab3731b0753a92291d248161e721dd6893affb9d181d65f43702
+F src/parse.y 834ba749a6a9f34ef49ad4dd30531252739f6f796f1589d0c4ba548385276535
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
F src/sqlite.h.in 5732519a2acb09066032ceac21f25996eb3f28f807a4468e30633c7c70faae1c
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 3f0c4ed6934e7309a61c6f3c30f70a30a5b869f785bb3d9f721a36c5e4359126
-F src/sqliteInt.h 9e65623e73c1c6d45e8bba3bad2d86d90cc289b2923ca35a26db5328d9f1ed60
+F src/sqliteInt.h d555ae8089e7032ae47823a58150f424e2f8715eaadc0eb3071a5c3de028a8a7
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
F test/alterauth2.test 48967abae0494d9a300d1c92473d99fcb66edfcc23579c89322f033f49410adc
F test/altercol.test b43fb5725332f4cf8cff0280605202c1672e808281accea60a066d2ccc5129e5
-F test/altercons.test 2e05836679a139317b8ac18c48c86d814b38011a7f225cbd52880fc8bc22c2f5
+F test/altercons.test 33fb8117e669b14536a7cf5df694a6027e5773c2e5d12dd2a240c7b2046c9cc5
F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12
F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P b44650f907e9cb4ec908bb7525488e309946fac9d84cdac4cdde730527a440a9
-R 62bf02b8a31c34d045e943408d7ca34a
-T *branch * alter-table-constraints
-T *sym-alter-table-constraints *
-T -sym-trunk *
+P d939b25d76fe70a3255cfe38097d4489323028cd05e5512a98dce06b48eee445
+R df87aa2ddd3ec2e579d06904451a2687
U dan
-Z df1bd70c76c4689d412ec3f686f545c6
+Z afa946c19eec2db0cf6e37984f361e84
# Remove this line to create a well-formed Fossil manifest.
** Or, if pTab is not a view or virtual table, zero is returned.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
-static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
+static int isRealTable(Parse *pParse, Table *pTab, int iOp){
const char *zType = 0;
#ifndef SQLITE_OMIT_VIEW
if( IsView(pTab) ){
}
#endif
if( zType ){
+ const char *azMsg[] = {
+ "rename columns of", "drop column from", "edit constraints of"
+ };
+ assert( iOp>=0 && iOp<ArraySize(azMsg) );
sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"",
- (bDrop ? "drop column from" : "rename columns of"),
- zType, pTab->zName
+ azMsg[iOp], zType, pTab->zName
);
return 1;
}
}
}
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ if( rc==SQLITE_OK ){
+ const char *zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
+ const char *zCol = pTab->aCol[iCol].zCnName;
+ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){
+ pTab = 0;
+ }
+ }
+#endif
+
sqlite3DbFree(db, zName);
*piCol = iCol;
return rc;
}
+
+/*
+** Find the table named by the first entry in source list pSrc. If successful,
+** return a pointer to the Table structure and set output variable (*pzDb)
+** to point to the name of the database containin the table (i.e. "main",
+** "temp" or the name of an attached database).
+**
+** If the table cannot be located, return NULL. The value of the two output
+** parameters is undefined in this case.
+*/
+static Table *alterFindTable(
+ Parse *pParse,
+ SrcList *pSrc,
+ int *piDb,
+ const char **pzDb,
+ int bAuth
+){
+ sqlite3 *db = pParse->db;
+ Table *pTab = 0;
+ assert( sqlite3BtreeHoldsAllMutexes(db) );
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
+ if( pTab ){
+ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ *pzDb = db->aDb[iDb].zDbSName;
+ *piDb = iDb;
+
+ if( SQLITE_OK!=isRealTable(pParse, pTab, 2)
+ || SQLITE_OK!=isAlterableTable(pParse, pTab)
+ ){
+ pTab = 0;
+ }
+ }
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ if( pTab && bAuth ){
+ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, *pzDb, pTab->zName, 0) ){
+ pTab = 0;
+ }
+ }
+#endif
+ sqlite3SrcListDelete(db, pSrc);
+ return pTab;
+}
+
void alterDropConstraint(
Parse *pParse,
SrcList *pSrc,
const char *zDb = 0;
char *zArg = 0;
- /* Look up the table being altered. */
- assert( sqlite3BtreeHoldsAllMutexes(db) );
- pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
- if( !pTab ) goto exit_drop_cons;
-
- /* Make sure this is not an attempt to ALTER a view, virtual table or
- ** system table. */
- if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_cons;
- if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_cons;
-
- /* Edit the sqlite_schema table */
- iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- assert( iDb>=0 );
- zDb = db->aDb[iDb].zDbSName;
+ pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, pCons!=0);
+ if( !pTab ) return;
if( pCons ){
zArg = sqlite3MPrintf(db, "%.*Q", pCons->n, pCons->z);
}else{
int iCol;
- if( alterFindCol(pParse, pTab, pCol, &iCol) ) goto exit_drop_cons;
+ if( alterFindCol(pParse, pTab, pCol, &iCol) ) return;
zArg = sqlite3MPrintf(db, "%d", iCol);
}
/* Finally, reload the database schema. */
renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons);
-
- exit_drop_cons:
- sqlite3SrcListDelete(db, pSrc);
}
sqlite3_result_error_code(ctx, err);
}
-/*
-** Find the table named by the first entry in source list pSrc. If successful,
-** return a pointer to the Table structure and set output variable (*pzDb)
-** to point to the name of the database containin the table (i.e. "main",
-** "temp" or the name of an attached database).
-**
-** If the table cannot be located, return NULL. The value of the two output
-** parameters is undefined in this case.
-*/
-static Table *alterFindTable(
- Parse *pParse,
- SrcList *pSrc,
- int *piDb,
- const char **pzDb
-){
- sqlite3 *db = pParse->db;
- Table *pTab = 0;
- assert( sqlite3BtreeHoldsAllMutexes(db) );
- pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
- sqlite3SrcListDelete(db, pSrc);
- if( pTab ){
- int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- *pzDb = db->aDb[iDb].zDbSName;
- *piDb = iDb;
- }
- return pTab;
-}
-
/*
** Prepare a statement of the form:
**
void sqlite3AlterSetNotNull(
Parse *pParse,
SrcList *pSrc,
- Token *pCol
+ Token *pCol,
+ Token *pFirst
){
Table *pTab = 0;
int iCol = 0;
int t = 0;
/* Look up the table being altered. */
- pTab = alterFindTable(pParse, pSrc, &iDb, &zDb);
+ pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 0);
if( !pTab ) return;
/* Find the column being altered. */
return;
}
- /* Find the start of the constraint definition */
- pCons = &pCol->z[pCol->n];
- pCons += getConstraintToken((const u8*)pCons, &t);
- pCons += getWhitespace((const u8*)pCons);
-
/* Find the length in bytes of the constraint definition */
+ pCons = pFirst->z;
nCons = pParse->sLastToken.z - pCons;
if( pCons[nCons-1]==';' ) nCons--;
while( sqlite3Isspace(pCons[nCons-1]) ) nCons--;
int nCons;
/* Look up the table being altered. */
- pTab = alterFindTable(pParse, pSrc, &iDb, &zDb);
+ pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 1);
if( !pTab ) return;
/* If this new constraint has a name, check that it is not a duplicate of
SELECT sql FROM sqlite_schema WHERE tbl_name='b1'
} {{CREATE TABLE b1(a, b, CONSTRAINT abc CHECK (a!=2))}}
+#-------------------------------------------------------------------------
+# Try attaching a NOT NULL to a generated column.
+#
+reset_db
+do_execsql_test 7.0 {
+ CREATE TABLE x1(a, b AS (a+1));
+ INSERT INTO x1 VALUES(1), (2), (3), (NULL);
+}
+
+do_catchsql_test 7.1 {
+ ALTER TABLE x1 ALTER b SET NOT NULL;
+} {1 {constraint failed}}
+
+do_catchsql_test 7.2 {
+ DELETE FROM x1 WHERE b IS NULL;
+ ALTER TABLE x1 ALTER b SET NOT NULL;
+} {0 {}}
+
+do_execsql_test 7.3 {
+ SELECT b FROM x1
+} {2 3 4}
+
+do_catchsql_test 7.4 {
+ ALTER TABLE x1 ALTER rowid SET NOT NULL;
+} {1 {no such column: rowid}}
+
+do_execsql_test 7.5 {
+ CREATE VIEW v1 AS SELECT a, b FROM x1;
+}
+do_catchsql_test 7.6 {
+ ALTER TABLE v1 RENAME a TO c;
+} {1 {cannot rename columns of view "v1"}}
+do_catchsql_test 7.7 {
+ ALTER TABLE v1 ALTER a SET NOT NULL;
+} {1 {cannot edit constraints of view "v1"}}
+do_catchsql_test 7.8 {
+ ALTER TABLE sqlite_schema ALTER sql SET NOT NULL;
+} {1 {table sqlite_master may not be altered}}
+do_catchsql_test 7.9 {
+ ALTER TABLE v1 ALTER a DROP NOT NULL
+} {1 {cannot edit constraints of view "v1"}}
+
finish_test