Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | After modifying and reparsing the schema as part of an ALTER TABLE RENAME COLUMN, check that no new schema errors have been introduced (e.g. ambiguous column names in views) before committing the operation. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | alter-table-rename-column |
Files: | files | file ages | folders |
SHA3-256: |
a0e06d2c5e3abb3f300491e7651bb177 |
User & Date: | dan 2018-08-24 17:55:49.159 |
Context
2018-08-24
| ||
20:10 | Fix a problem with renaming a column that occurs as an "excluded.colname" construction in an UPSERT that is part of a trigger program. (check-in: bb2f723496 user: dan tags: alter-table-rename-column) | |
17:55 | After modifying and reparsing the schema as part of an ALTER TABLE RENAME COLUMN, check that no new schema errors have been introduced (e.g. ambiguous column names in views) before committing the operation. (check-in: a0e06d2c5e user: dan tags: alter-table-rename-column) | |
16:04 | Avoid incorrectly replacing tokens that refer to a column being renamed via an alias. For example, do not overwrite "xyz" when "a" is renamed in "CREATE VIEW v1 AS SELECT a AS xyz FROM tbl WHERE xyz=1" (check-in: ad072a835f user: dan tags: alter-table-rename-column) | |
Changes
Changes to src/alter.c.
︙ | ︙ | |||
887 888 889 890 891 892 893 894 895 896 897 898 899 900 | ); /* Drop and reload the database schema. */ if( pParse->pVdbe ){ sqlite3ChangeCookie(pParse, iSchema); sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iSchema, 0); } exit_rename_column: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zOld); sqlite3DbFree(db, zNew); return; } | > > > > > > > > > > > | 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 | ); /* Drop and reload the database schema. */ if( pParse->pVdbe ){ sqlite3ChangeCookie(pParse, iSchema); sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iSchema, 0); } sqlite3NestedParse(pParse, "SELECT 1 " "FROM \"%w\".%s " "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, -1)=0 ", zDb, MASTER_NAME, pTab->zName, zDb, pTab->zName, iCol, zNew ); exit_rename_column: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zOld); sqlite3DbFree(db, zNew); return; } |
︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an ** ALTER TABLE RENAME COLUMN program. The error message emitted by the ** sub-routine is currently stored in pParse->zErrMsg. This function ** adds context to the error message and then stores it in pCtx. */ static void renameColumnParseError( sqlite3_context *pCtx, sqlite3_value *pType, sqlite3_value *pObject, Parse *pParse ){ const char *zT = (const char*)sqlite3_value_text(pType); const char *zN = (const char*)sqlite3_value_text(pObject); char *zErr; | > | > > > | 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 | ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an ** ALTER TABLE RENAME COLUMN program. The error message emitted by the ** sub-routine is currently stored in pParse->zErrMsg. This function ** adds context to the error message and then stores it in pCtx. */ static void renameColumnParseError( sqlite3_context *pCtx, int bPost, sqlite3_value *pType, sqlite3_value *pObject, Parse *pParse ){ const char *zT = (const char*)sqlite3_value_text(pType); const char *zN = (const char*)sqlite3_value_text(pObject); char *zErr; zErr = sqlite3_mprintf("error in %s %s%s: %s", zT, zN, (bPost ? " after rename" : ""), pParse->zErrMsg ); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); } /* ** For each name in the the expression-list pEList (i.e. each ** pEList->a[i].zName) that matches the string in zOld, extract the |
︙ | ︙ | |||
1136 1137 1138 1139 1140 1141 1142 | ** 0. zSql: SQL statement to rewrite ** 1. type: Type of object ("table", "view" etc.) ** 2. object: Name of object ** 3. Database: Database name (e.g. "main") ** 4. Table: Table name ** 5. iCol: Index of column to rename ** 6. zNew: New column name | | > > > | 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 | ** 0. zSql: SQL statement to rewrite ** 1. type: Type of object ("table", "view" etc.) ** 2. object: Name of object ** 3. Database: Database name (e.g. "main") ** 4. Table: Table name ** 5. iCol: Index of column to rename ** 6. zNew: New column name ** 7. bQuote: Non-zero if the new column name should be quoted. Negative ** if this function is being called to check that the schema ** can still be parsed and symbols resolved after the column ** has been renamed. ** ** Do a column rename operation on the CREATE statement given in zSql. ** The iCol-th column (left-most is 0) of table zTable is renamed from zCol ** into zNew. The name should be quoted if bQuote is true. ** ** This function is used internally by the ALTER TABLE RENAME COLUMN command. ** Though accessible to application code, it is not intended for use by |
︙ | ︙ | |||
1433 1434 1435 1436 1437 1438 1439 | }else{ rc = SQLITE_NOMEM; } renameColumnFunc_done: if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ | | | 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 | }else{ rc = SQLITE_NOMEM; } renameColumnFunc_done: if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ renameColumnParseError(context, (bQuote<0), argv[1], argv[2], &sParse); }else{ sqlite3_result_error_code(context, rc); } } if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 | #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ sqlite3SchemaClear(db->aDb[iDb].pSchema); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable); db->mDbFlags |= DBFLAG_SchemaChange; }else #endif { zMaster = MASTER_NAME; initData.db = db; initData.iDb = pOp->p1; initData.pzErrMsg = &p->zErrMsg; | > | 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 | #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ sqlite3SchemaClear(db->aDb[iDb].pSchema); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable); db->mDbFlags |= DBFLAG_SchemaChange; p->expired = 0; }else #endif { zMaster = MASTER_NAME; initData.db = db; initData.iDb = pOp->p1; initData.pzErrMsg = &p->zErrMsg; |
︙ | ︙ |
Changes to test/altercol.test.
︙ | ︙ | |||
337 338 339 340 341 342 343 | ALTER TABLE b2 RENAME x TO hello; SELECT sql FROM sqlite_master WHERE name='xxx'; } {{CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT hello FROM b2 ORDER BY 1 COLLATE nocase}} do_catchsql_test 8.4.5 { CREATE VIEW zzz AS SELECT george, ringo FROM b1; ALTER TABLE b1 RENAME a TO aaa; | | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | ALTER TABLE b2 RENAME x TO hello; SELECT sql FROM sqlite_master WHERE name='xxx'; } {{CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT hello FROM b2 ORDER BY 1 COLLATE nocase}} do_catchsql_test 8.4.5 { CREATE VIEW zzz AS SELECT george, ringo FROM b1; ALTER TABLE b1 RENAME a TO aaa; } {1 {error in view zzz: no such column: george}} #------------------------------------------------------------------------- # More triggers. # proc do_rename_column_test {tn old new lSchema} { for {set i 0} {$i < 2} {incr i} { drop_all_tables_and_views db |
︙ | ︙ | |||
468 469 470 471 472 473 474 | do_execsql_test 11.2 { CREATE VIEW v1 AS SELECT e1.*, x1.c FROM e1, x1; } do_catchsql_test 11.3 { ALTER TABLE x1 RENAME c TO ccc; | | | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | do_execsql_test 11.2 { CREATE VIEW v1 AS SELECT e1.*, x1.c FROM e1, x1; } do_catchsql_test 11.3 { ALTER TABLE x1 RENAME c TO ccc; } {1 {error in view v1: no such module: echo}} #------------------------------------------------------------------------- # Test some error conditions: # # 1. Renaming a column of a system table, # 2. Renaming a column of a VIEW, # 3. Renaming a column of a virtual table. |
︙ | ︙ | |||
537 538 539 540 541 542 543 | CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN SELECT * FROM nosuchtable; END; } do_catchsql_test 13.1.2 { ALTER TABLE x1 RENAME COLUMN t TO ttt; | | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN SELECT * FROM nosuchtable; END; } do_catchsql_test 13.1.2 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } {1 {error in trigger tr1: no such table: main.nosuchtable}} do_execsql_test 13.1.3 { DROP TRIGGER tr1; CREATE INDEX x1i ON x1(i); SELECT sql FROM sqlite_master WHERE name='x1i'; } {{CREATE INDEX x1i ON x1(i)}} do_execsql_test 13.1.4 { PRAGMA writable_schema = 1; UPDATE sqlite_master SET sql = 'CREATE INDEX x1i ON x1(j)' WHERE name='x1i'; } {} do_catchsql_test 13.1.5 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } {1 {error in index x1i: no such column: j}} do_execsql_test 13.1.6 { UPDATE sqlite_master SET sql = '' WHERE name='x1i'; } {} do_catchsql_test 13.1.7 { ALTER TABLE x1 RENAME COLUMN t TO ttt; |
︙ | ︙ | |||
603 604 605 606 607 608 609 | do_execsql_test 13.2.$tn.1 " DROP TRIGGER IF EXISTS tr1; $trigger " do_catchsql_test 13.2.$tn.2 { ALTER TABLE x1 RENAME COLUMN t TO ttt; | | | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | do_execsql_test 13.2.$tn.1 " DROP TRIGGER IF EXISTS tr1; $trigger " do_catchsql_test 13.2.$tn.2 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } "1 {error in trigger tr1: $error}" } #------------------------------------------------------------------------- # Passing invalid parameters directly to sqlite_rename_column(). # do_execsql_test 14.1 { CREATE TABLE ddd(sql, type, object, db, tbl, icol, znew, bquote); |
︙ | ︙ | |||
645 646 647 648 649 650 651 652 653 | CREATE VIEW vvv AS SELECT a AS d FROM xxx WHERE d=0; ALTER TABLE xxx RENAME a TO xyz; } do_execsql_test 15.2 { SELECT sql FROM sqlite_master WHERE type='view'; } {{CREATE VIEW vvv AS SELECT xyz AS d FROM xxx WHERE d=0}} finish_test | > > > > > > > > > > > > > > > > > > > > > | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 | CREATE VIEW vvv AS SELECT a AS d FROM xxx WHERE d=0; ALTER TABLE xxx RENAME a TO xyz; } do_execsql_test 15.2 { SELECT sql FROM sqlite_master WHERE type='view'; } {{CREATE VIEW vvv AS SELECT xyz AS d FROM xxx WHERE d=0}} #------------------------------------------------------------------------- # do_execsql_test 16.0 { CREATE TABLE t1(a,b,c); CREATE TABLE t2(d,e,f); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t2 VALUES(4,5,6); CREATE VIEW v4 AS SELECT a, d FROM t1, t2; SELECT * FROM v4; } {1 4} do_catchsql_test 16.1 { ALTER TABLE t2 RENAME d TO a; } {1 {error in view v4 after rename: ambiguous column name: a}} do_execsql_test 16.2 { SELECT * FROM v4; } {1 4} reset_db finish_test |