/ Check-in [6805b5900d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improve the error messages emitted by RENAME TABLE.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256: 6805b5900df5e6d3329cbad2660875ebe4069efe37b19575f527d153dc0882a1
User & Date: dan 2018-09-03 20:05:15
Context
2018-09-04
18:23
Merge latest trunk changes into this branch. check-in: ef9e088290 user: dan tags: alter-table-rename-column
2018-09-03
20:05
Improve the error messages emitted by RENAME TABLE. check-in: 6805b5900d user: dan tags: alter-table-rename-column
2018-09-01
20:38
Add another test case to altertab.test. check-in: 828e8849fa user: dan tags: alter-table-rename-column
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/alter.c.

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
....
1271
1272
1273
1274
1275
1276
1277


1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
....
1384
1385
1386
1387
1388
1389
1390



1391

1392
1393
1394
1395
1396
1397
1398
....
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  zTabName = pTab->zName;
  nTabName = sqlite3Utf8CharLen(zTabName, -1);

  /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
  ** the schema to use the new table name.  */
  sqlite3NestedParse(pParse, 
      "UPDATE \"%w\".%s SET "
      "sql = sqlite_rename_table(%Q, sql, %Q, %Q, %d) "
      "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
      "AND   name NOT LIKE 'sqlite_%%'"
      , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName
  );

  /* Update the tbl_name and name columns of the sqlite_master table
  ** as required.  */
................................................................................

  /* If the table being renamed is not itself part of the temp database,
  ** edit view and trigger definitions within the temp database 
  ** as required.  */
  if( iDb!=1 ){
    sqlite3NestedParse(pParse, 
        "UPDATE sqlite_temp_master SET "
            "sql = sqlite_rename_table(%Q, sql, %Q, %Q, 1), "
            "tbl_name = "
              "CASE WHEN tbl_name=%Q COLLATE nocase THEN %Q ELSE tbl_name END "
            "WHERE type IN ('view', 'trigger')"
        , zDb, zTabName, zName, zTabName, zTabName, zName);
  }

  renameReloadSchema(pParse, iDb);
................................................................................
/*
** This C function implements an SQL user function that is used by SQL code
** generated by the ALTER TABLE ... RENAME command to modify the definition
** of any foreign key constraints that use the table being renamed as the 
** parent table. It is passed three arguments:
**
**   0: The database containing the table being renamed.


**   1: The complete text of the schema statement being modified,
**   2: The old name of the table being renamed, and
**   3: The new name of the table being renamed.
**   4: True if the schema statement comes from the temp db.
**
** It returns the new schema statement. For example:
**
** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0)
**       -> 'CREATE TABLE t1(a REFERENCES t3)'
*/
static void renameTableFunc(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **argv
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  const char *zDb = (const char*)sqlite3_value_text(argv[0]);
  const char *zInput = (const char*)sqlite3_value_text(argv[1]);
  const char *zOld = (const char*)sqlite3_value_text(argv[2]);
  const char *zNew = (const char*)sqlite3_value_text(argv[3]);
  int bTemp = sqlite3_value_int(argv[4]);
  UNUSED_PARAMETER(NotUsed);

  if( zInput && zOld && zNew ){
    Parse sParse;
    int rc;
    int bQuote = 1;
    RenameCtx sCtx;
................................................................................
#endif
    }

    if( rc==SQLITE_OK ){
      rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote);
    }
    if( rc!=SQLITE_OK ){



      sqlite3_result_error_code(context, rc);

    }

    renameParseCleanup(&sParse);
    renameTokenFree(db, sCtx.pList);
    sqlite3BtreeLeaveAll(db);
#ifndef SQLITE_OMIT_AUTHORIZATION
    db->xAuth = xAuth;
................................................................................

/*
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(void){
  static FuncDef aAlterTableFuncs[] = {
    FUNCTION(sqlite_rename_column,  9, 0, 0, renameColumnFunc),
    FUNCTION(sqlite_rename_table,  5, 0, 0, renameTableFunc),
    FUNCTION(sqlite_rename_test,  5, 0, 0, renameTableTest),
  };
  sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
#endif  /* SQLITE_ALTER_TABLE */







|







 







|







 







>
>
|
|
|
|













|
|
|
|







 







>
>
>
|
>







 







|





187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
....
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
....
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
....
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
  zTabName = pTab->zName;
  nTabName = sqlite3Utf8CharLen(zTabName, -1);

  /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
  ** the schema to use the new table name.  */
  sqlite3NestedParse(pParse, 
      "UPDATE \"%w\".%s SET "
      "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) "
      "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
      "AND   name NOT LIKE 'sqlite_%%'"
      , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName
  );

  /* Update the tbl_name and name columns of the sqlite_master table
  ** as required.  */
................................................................................

  /* If the table being renamed is not itself part of the temp database,
  ** edit view and trigger definitions within the temp database 
  ** as required.  */
  if( iDb!=1 ){
    sqlite3NestedParse(pParse, 
        "UPDATE sqlite_temp_master SET "
            "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
            "tbl_name = "
              "CASE WHEN tbl_name=%Q COLLATE nocase THEN %Q ELSE tbl_name END "
            "WHERE type IN ('view', 'trigger')"
        , zDb, zTabName, zName, zTabName, zTabName, zName);
  }

  renameReloadSchema(pParse, iDb);
................................................................................
/*
** This C function implements an SQL user function that is used by SQL code
** generated by the ALTER TABLE ... RENAME command to modify the definition
** of any foreign key constraints that use the table being renamed as the 
** parent table. It is passed three arguments:
**
**   0: The database containing the table being renamed.
**   1. type:     Type of object ("table", "view" etc.)
**   2. object:   Name of object
**   3: The complete text of the schema statement being modified,
**   4: The old name of the table being renamed, and
**   5: The new name of the table being renamed.
**   6: True if the schema statement comes from the temp db.
**
** It returns the new schema statement. For example:
**
** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0)
**       -> 'CREATE TABLE t1(a REFERENCES t3)'
*/
static void renameTableFunc(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **argv
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  const char *zDb = (const char*)sqlite3_value_text(argv[0]);
  const char *zInput = (const char*)sqlite3_value_text(argv[3]);
  const char *zOld = (const char*)sqlite3_value_text(argv[4]);
  const char *zNew = (const char*)sqlite3_value_text(argv[5]);
  int bTemp = sqlite3_value_int(argv[6]);
  UNUSED_PARAMETER(NotUsed);

  if( zInput && zOld && zNew ){
    Parse sParse;
    int rc;
    int bQuote = 1;
    RenameCtx sCtx;
................................................................................
#endif
    }

    if( rc==SQLITE_OK ){
      rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote);
    }
    if( rc!=SQLITE_OK ){
      if( sParse.zErrMsg ){
        renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
      }else{
        sqlite3_result_error_code(context, rc);
      }
    }

    renameParseCleanup(&sParse);
    renameTokenFree(db, sCtx.pList);
    sqlite3BtreeLeaveAll(db);
#ifndef SQLITE_OMIT_AUTHORIZATION
    db->xAuth = xAuth;
................................................................................

/*
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(void){
  static FuncDef aAlterTableFuncs[] = {
    FUNCTION(sqlite_rename_column,  9, 0, 0, renameColumnFunc),
    FUNCTION(sqlite_rename_table,  7, 0, 0, renameTableFunc),
    FUNCTION(sqlite_rename_test,  5, 0, 0, renameTableTest),
  };
  sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
#endif  /* SQLITE_ALTER_TABLE */

Changes to test/alter.test.

684
685
686
687
688
689
690
691
692
693
694
695


696
697
698
699
700
701
702
# alter-9.X - Special test: Make sure the sqlite_rename_column() and
# rename_table() functions do not crash when handed bad input.
#
do_test alter-9.1 {
  execsql {SELECT SQLITE_RENAME_COLUMN(0,0,0,0,0,0,0,0,0)}
} {{}}
foreach {tn sql} {
    1 { SELECT SQLITE_RENAME_TABLE(0,0,0,0,0) }
    2 { SELECT SQLITE_RENAME_TABLE(10,20,30,40,50) }
    3 { SELECT SQLITE_RENAME_TABLE('foo', 'foo', 'foo', 'foo', 'foo') }
} {
  do_catchsql_test alter-9.2.$tn $sql {1 {SQL logic error}}


}

#------------------------------------------------------------------------
# alter-10.X - Make sure ALTER TABLE works with multi-byte UTF-8 characters 
# in the names.
#
do_test alter-10.1 {







|
|
|

|
>
>







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
# alter-9.X - Special test: Make sure the sqlite_rename_column() and
# rename_table() functions do not crash when handed bad input.
#
do_test alter-9.1 {
  execsql {SELECT SQLITE_RENAME_COLUMN(0,0,0,0,0,0,0,0,0)}
} {{}}
foreach {tn sql} {
    1 { SELECT SQLITE_RENAME_TABLE(0,0,0,0,0,0,0) }
    2 { SELECT SQLITE_RENAME_TABLE(10,20,30,40,50,60,70) }
    3 { SELECT SQLITE_RENAME_TABLE('foo','foo','foo','foo','foo','foo','foo') }
} {
  do_test alter-9.2.$tn {
    catch { execsql $sql }
  } 1
}

#------------------------------------------------------------------------
# alter-10.X - Make sure ALTER TABLE works with multi-byte UTF-8 characters 
# in the names.
#
do_test alter-10.1 {

Changes to test/altertab.test.

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
...
262
263
264
265
266
267
268
269







































270
271
272
  ), (
      'main', NULL, 'ddd', 'eee', 0
  );
} {}

do_execsql_test 7.2 {
  SELECT 
  sqlite_rename_table(db, sql, zOld, zNew, bTemp)
  FROM ddd;
} {{} {} {}}

#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
................................................................................
  ALTER TABLE aux.p1 RENAME TO ppp;
}

do_execsql_test 8.2 {
  INSERT INTO aux.c1 VALUES(NULL, 1);
  SELECT sql FROM aux.sqlite_master WHERE name = 'c1';
} {{CREATE TABLE c1(x INTEGER PRIMARY KEY, y REFERENCES "ppp"(a))}}








































finish_test









|







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  ), (
      'main', NULL, 'ddd', 'eee', 0
  );
} {}

do_execsql_test 7.2 {
  SELECT 
  sqlite_rename_table(db, 0, 0, sql, zOld, zNew, bTemp)
  FROM ddd;
} {{} {} {}}

#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
................................................................................
  ALTER TABLE aux.p1 RENAME TO ppp;
}

do_execsql_test 8.2 {
  INSERT INTO aux.c1 VALUES(NULL, 1);
  SELECT sql FROM aux.sqlite_master WHERE name = 'c1';
} {{CREATE TABLE c1(x INTEGER PRIMARY KEY, y REFERENCES "ppp"(a))}}

reset_db
do_execsql_test 9.0 {
  CREATE TABLE t1(a, b, c);
  CREATE VIEW v1 AS SELECT * FROM t2;
}
do_catchsql_test 9.1 {
  ALTER TABLE t1 RENAME TO t3;
} {1 {error in view v1: no such table: main.t2}}
do_execsql_test 9.2 {
  DROP VIEW v1;
  CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN
    INSERT INTO t2 VALUES(new.a);
  END;
}
do_catchsql_test 9.3 {
  ALTER TABLE t1 RENAME TO t3;
} {1 {error in trigger tr: no such table: main.t2}}

forcedelete test.db2
do_execsql_test 9.4 {
  DROP TRIGGER tr;

  ATTACH 'test.db2' AS aux;
  CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN SELECT 1, 2, 3; END;

  CREATE TABLE aux.t1(x);
  CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END;
}
do_execsql_test 9.5 {
  ALTER TABLE main.t1 RENAME TO t3;
}
do_execsql_test 9.6 {
  SELECT sql FROM sqlite_temp_master;
  SELECT sql FROM sqlite_master WHERE type='trigger';
} {
  {CREATE TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END}
  {CREATE TRIGGER tr AFTER INSERT ON "t3" BEGIN SELECT 1, 2, 3; END}
}

finish_test