SQLite

Check-in [82c4c10a96]
Login

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

Overview
Comment:Add further tests for RENAME COLUMN.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256: 82c4c10a96db76f39edf5f6d027294d449d75b5a18da70da3667786da90e184d
User & Date: dan 2018-08-20 20:01:01.997
Context
2018-08-21
08:29
Minor changes to function tokenExpr() in order to claw back cycles lost to the rename-column change. (check-in: 479976955e user: dan tags: alter-table-rename-column)
2018-08-20
20:01
Add further tests for RENAME COLUMN. (check-in: 82c4c10a96 user: dan tags: alter-table-rename-column)
16:16
Ensure that it is not possible to rename columns of system tables, views or virtual tables. (check-in: 786b5991dc user: dan tags: alter-table-rename-column)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/alter.c.
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
  */
  zNew = sqlite3NameFromToken(db, pNew);
  if( !zNew ) goto exit_rename_column;
  assert( pNew->n>0 );
  bQuote = sqlite3Isquote(pNew->z[0]);
  sqlite3NestedParse(pParse, 
      "UPDATE \"%w\".%s SET "
      "sql = sqlite_rename_column(sql, %Q, %Q, %d, %Q, %d) "
      "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)"
      " AND sql NOT LIKE 'create virtual%%'",
      zDb, MASTER_NAME, 
      zDb, pTab->zName, iCol, zNew, bQuote,
      pTab->zName
  );








|







874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
  */
  zNew = sqlite3NameFromToken(db, pNew);
  if( !zNew ) goto exit_rename_column;
  assert( pNew->n>0 );
  bQuote = sqlite3Isquote(pNew->z[0]);
  sqlite3NestedParse(pParse, 
      "UPDATE \"%w\".%s SET "
      "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d) "
      "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)"
      " AND sql NOT LIKE 'create virtual%%'",
      zDb, MASTER_NAME, 
      zDb, pTab->zName, iCol, zNew, bQuote,
      pTab->zName
  );

953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
/*
** If there is a RenameToken object associated with parse tree element
** pFrom, then remap that object over to pTo due to a transformation
** in the parse tree.
*/
void sqlite3MoveRenameToken(Parse *pParse, void *pTo, void *pFrom){
  RenameToken *p;
  for(p=pParse->pRename; p; p=p->pNext){
    if( p->p==pFrom ){
      p->p = pTo;
      break;
    }
  }
  assert( p );
}







|







953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
/*
** If there is a RenameToken object associated with parse tree element
** pFrom, then remap that object over to pTo due to a transformation
** in the parse tree.
*/
void sqlite3MoveRenameToken(Parse *pParse, void *pTo, void *pFrom){
  RenameToken *p;
  for(p=pParse->pRename; ALWAYS(p); p=p->pNext){
    if( p->p==pFrom ){
      p->p = pTo;
      break;
    }
  }
  assert( p );
}
1060
1061
1062
1063
1064
1065
1066
1067





1068
1069
1070
1071
1072
1073
1074
1075
1076
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
1104
/*
** An error occured while parsing or otherwise processing a database
** 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, Parse *pParse){





  const char *zT;
  const char *zN;
  char *zErr;
  if( pParse->pNewTable ){
    zT = pParse->pNewTable->pSelect ? "view" : "table";
    zN = pParse->pNewTable->zName;
  }else if( pParse->pNewIndex ){
    zT = "index";
    zN = pParse->pNewIndex->zName;
  }else{
    assert( pParse->pNewTrigger );
    zT = "trigger";
    zN = pParse->pNewTrigger->zName;
  }
  zErr = sqlite3_mprintf("error processing %s %s: %s", zT, zN, pParse->zErrMsg);
  sqlite3_result_error(pCtx, zErr, -1);
  sqlite3_free(zErr);
}

/*
** SQL function:
**
**     sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
**
**   0. zSql:     SQL statement to rewrite


**   1. Database: Database name (e.g. "main")
**   2. Table:    Table name
**   3. iCol:     Index of column to rename
**   4. zNew:     New column name
**   5. bQuote: True if the new column name should be quoted
**
** 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







|
>
>
>
>
>
|
|

<
<
<
<
<
<
<
<
<
<
|











>
>
|
|
|
|
|







1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075










1076
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
/*
** An error occured while parsing or otherwise processing a database
** 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 = sqlite3_value_text(pType);
  const char *zN = sqlite3_value_text(pObject);
  char *zErr;











  zErr = sqlite3_mprintf("error processing %s %s: %s", zT, zN, pParse->zErrMsg);
  sqlite3_result_error(pCtx, zErr, -1);
  sqlite3_free(zErr);
}

/*
** SQL function:
**
**     sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
**
**   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:   True if the new column name should be quoted
**
** 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
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
  int NotUsed,
  sqlite3_value **argv
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  RenameCtx sCtx;
  const char *zSql = (const char*)sqlite3_value_text(argv[0]);
  int nSql = sqlite3_value_bytes(argv[0]);
  const char *zDb = (const char*)sqlite3_value_text(argv[1]);
  const char *zTable = (const char*)sqlite3_value_text(argv[2]);
  int iCol = sqlite3_value_int(argv[3]);
  const char *zNew = (const char*)sqlite3_value_text(argv[4]);
  int nNew = sqlite3_value_bytes(argv[4]);
  int bQuote = sqlite3_value_int(argv[5]);
  const char *zOld;

  int rc;
  char *zErr = 0;
  Parse sParse;
  Walker sWalker;
  Index *pIdx;
  char *zOut = 0;

  char *zQuot = 0;                /* Quoted version of zNew */
  int nQuot = 0;                  /* Length of zQuot in bytes */
  int i;
  Table *pTab;

  UNUSED_PARAMETER(NotUsed);
  if( zSql==0 ) return;
  if( zNew==0 ) return;
  if( zTable==0 ) return;
  if( iCol<0 ) return;
  pTab = sqlite3FindTable(db, zTable, zDb);
  if( pTab==0 || iCol>=pTab->nCol ) return;
  zOld = pTab->aCol[iCol].zName;
  memset(&sCtx, 0, sizeof(sCtx));
  sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);








|
|
|
|
|
|
















|
|







1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  int NotUsed,
  sqlite3_value **argv
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  RenameCtx sCtx;
  const char *zSql = (const char*)sqlite3_value_text(argv[0]);
  int nSql = sqlite3_value_bytes(argv[0]);
  const char *zDb = (const char*)sqlite3_value_text(argv[3]);
  const char *zTable = (const char*)sqlite3_value_text(argv[4]);
  int iCol = sqlite3_value_int(argv[5]);
  const char *zNew = (const char*)sqlite3_value_text(argv[6]);
  int nNew = sqlite3_value_bytes(argv[6]);
  int bQuote = sqlite3_value_int(argv[7]);
  const char *zOld;

  int rc;
  char *zErr = 0;
  Parse sParse;
  Walker sWalker;
  Index *pIdx;
  char *zOut = 0;

  char *zQuot = 0;                /* Quoted version of zNew */
  int nQuot = 0;                  /* Length of zQuot in bytes */
  int i;
  Table *pTab;

  UNUSED_PARAMETER(NotUsed);
  if( zSql==0 ) return;
  if( zTable==0 ) return;
  if( zNew==0 ) return;
  if( iCol<0 ) return;
  pTab = sqlite3FindTable(db, zTable, zDb);
  if( pTab==0 || iCol>=pTab->nCol ) return;
  zOld = pTab->aCol[iCol].zName;
  memset(&sCtx, 0, sizeof(sCtx));
  sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);

1268
1269
1270
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
      rc = sqlite3ResolveExprNames(&sNC, sParse.pNewTrigger->pWhen);
    }

    for(pStep=sParse.pNewTrigger->step_list; 
        rc==SQLITE_OK && pStep; 
        pStep=pStep->pNext
    ){

      if( pStep->pSelect ) sqlite3SelectPrep(&sParse, pStep->pSelect, &sNC);


      if( pStep->zTarget ){ 
        Table *pTarget = sqlite3FindTable(db, pStep->zTarget, zDb);
        if( pTarget==0 ){
          rc = SQLITE_ERROR;
        }else{
          SrcList sSrc;
          memset(&sSrc, 0, sizeof(sSrc));
          sSrc.nSrc = 1;
          sSrc.a[0].zName = pStep->zTarget;
          sSrc.a[0].pTab = pTarget;
          sNC.pSrcList = &sSrc;
          if( pStep->pWhere ){
            rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
          }
          if( rc==SQLITE_OK ){
            rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
          }

          if( pStep->pUpsert ){
            Upsert *pUpsert = pStep->pUpsert;
            if( rc==SQLITE_OK ){
              rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
            }
            if( rc==SQLITE_OK && pUpsert->pUpsertSet){
              ExprList *pUpsertSet = pUpsert->pUpsertSet;
              rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
              if( rc==SQLITE_OK && pTarget==pTab ){
                for(i=0; i<pUpsertSet->nExpr; i++){
                  char *zName = pUpsertSet->a[i].zName;
                  if( 0==sqlite3_stricmp(zName, zOld) ){







>
|
>
>
|
















>


|
|
<







1265
1266
1267
1268
1269
1270
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
      rc = sqlite3ResolveExprNames(&sNC, sParse.pNewTrigger->pWhen);
    }

    for(pStep=sParse.pNewTrigger->step_list; 
        rc==SQLITE_OK && pStep; 
        pStep=pStep->pNext
    ){
      if( pStep->pSelect ){
        sqlite3SelectPrep(&sParse, pStep->pSelect, &sNC);
        if( sParse.nErr ) rc = sParse.rc;
      }
      if( rc==SQLITE_OK && pStep->zTarget ){ 
        Table *pTarget = sqlite3FindTable(db, pStep->zTarget, zDb);
        if( pTarget==0 ){
          rc = SQLITE_ERROR;
        }else{
          SrcList sSrc;
          memset(&sSrc, 0, sizeof(sSrc));
          sSrc.nSrc = 1;
          sSrc.a[0].zName = pStep->zTarget;
          sSrc.a[0].pTab = pTarget;
          sNC.pSrcList = &sSrc;
          if( pStep->pWhere ){
            rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
          }
          if( rc==SQLITE_OK ){
            rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
          }
          assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
          if( pStep->pUpsert ){
            Upsert *pUpsert = pStep->pUpsert;
            assert( rc==SQLITE_OK );
            rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);

            if( rc==SQLITE_OK && pUpsert->pUpsertSet){
              ExprList *pUpsertSet = pUpsert->pUpsertSet;
              rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
              if( rc==SQLITE_OK && pTarget==pTab ){
                for(i=0; i<pUpsertSet->nExpr; i++){
                  char *zName = pUpsertSet->a[i].zName;
                  if( 0==sqlite3_stricmp(zName, zOld) ){
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
  }else{
    rc = SQLITE_NOMEM;
  }

renameColumnFunc_done:
  if( rc!=SQLITE_OK ){
    if( sParse.zErrMsg ){
      renameColumnParseError(context, &sParse);
    }else{
      sqlite3_result_error_code(context, rc);
    }
  }

  if( sParse.pVdbe ){
    sqlite3VdbeFinalize(sParse.pVdbe);







|







1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
  }else{
    rc = SQLITE_NOMEM;
  }

renameColumnFunc_done:
  if( rc!=SQLITE_OK ){
    if( sParse.zErrMsg ){
      renameColumnParseError(context, argv[1], argv[2], &sParse);
    }else{
      sqlite3_result_error_code(context, rc);
    }
  }

  if( sParse.pVdbe ){
    sqlite3VdbeFinalize(sParse.pVdbe);
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451

/*
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(void){
  static FuncDef aAlterTableFuncs[] = {
    FUNCTION(sqlite_rename_table,   2, 0, 0, renameTableFunc),
    FUNCTION(sqlite_rename_column,   6, 0, 0, renameColumnFunc),
#ifndef SQLITE_OMIT_TRIGGER
    FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
    FUNCTION(sqlite_rename_parent,  3, 0, 0, renameParentFunc),
#endif
  };
  sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
#endif  /* SQLITE_ALTER_TABLE */







|










1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451

/*
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(void){
  static FuncDef aAlterTableFuncs[] = {
    FUNCTION(sqlite_rename_table,   2, 0, 0, renameTableFunc),
    FUNCTION(sqlite_rename_column,   8, 0, 0, renameColumnFunc),
#ifndef SQLITE_OMIT_TRIGGER
    FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
    FUNCTION(sqlite_rename_parent,  3, 0, 0, renameParentFunc),
#endif
  };
  sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
#endif  /* SQLITE_ALTER_TABLE */
Changes to test/altercol.test.
401
402
403
404
405
406
407








408
409
410
411
412
413
414
  4 _x_ _xxx_ {
    { CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
    { CREATE TRIGGER ttt AFTER UPDATE  ON t1 BEGIN
        INSERT INTO t1 VALUES(new.a, new.b, new._x_)
          ON CONFLICT (_x_) WHERE _x_>10 DO UPDATE SET _x_ = _x_+1;
      END }
  }








} {
  do_rename_column_test 9.$tn $old $new $lSchema
}

#-------------------------------------------------------------------------
# Test that views can be edited even if there are missing collation 
# sequences or user defined functions.







>
>
>
>
>
>
>
>







401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  4 _x_ _xxx_ {
    { CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
    { CREATE TRIGGER ttt AFTER UPDATE  ON t1 BEGIN
        INSERT INTO t1 VALUES(new.a, new.b, new._x_)
          ON CONFLICT (_x_) WHERE _x_>10 DO UPDATE SET _x_ = _x_+1;
      END }
  }

  4 _x_ _xxx_ {
    { CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
    { CREATE TRIGGER ttt AFTER UPDATE  ON t1 BEGIN
        INSERT INTO t1 VALUES(new.a, new.b, new._x_)
          ON CONFLICT (_x_) WHERE _x_>10 DO NOTHING;
      END }
  }
} {
  do_rename_column_test 9.$tn $old $new $lSchema
}

#-------------------------------------------------------------------------
# Test that views can be edited even if there are missing collation 
# sequences or user defined functions.
468
469
470
471
472
473
474


475
476
477
478
479
480
481

#-------------------------------------------------------------------------
# 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.


#
reset_db
do_execsql_test 12.1.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX t1a ON t1(a);
  INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 4);
  ANALYZE;







>
>







476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491

#-------------------------------------------------------------------------
# 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.
#   4. Renaming a column that does not exist.
#   5. Renaming a column of a table that does not exist.
#
reset_db
do_execsql_test 12.1.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX t1a ON t1(a);
  INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 4);
  ANALYZE;
498
499
500
501
502
503
504
505
506
507
508
509

















































































































510
511
  ALTER TABLE v2 RENAME c TO y;
} {1 {columns of view v2 may not be renamed}}

ifcapable fts5 {
  do_execsql_test 12.3.1 {
    CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
  }
  do_catchsql_test 12.2.2 {
    ALTER TABLE ft RENAME a TO z;
  } {1 {columns of virtual table ft may not be renamed}}
}


















































































































finish_test








|




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


508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
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
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  ALTER TABLE v2 RENAME c TO y;
} {1 {columns of view v2 may not be renamed}}

ifcapable fts5 {
  do_execsql_test 12.3.1 {
    CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
  }
  do_catchsql_test 12.3.2 {
    ALTER TABLE ft RENAME a TO z;
  } {1 {columns of virtual table ft may not be renamed}}
}

do_execsql_test 12.4.1 {
  CREATE TABLE t2(x, y, z);
}
do_catchsql_test 12.4.2 {
  ALTER TABLE t2 RENAME COLUMN a TO b;
} {1 {no such column: "a"}}

do_catchsql_test 12.5.1 {
  ALTER TABLE t3 RENAME COLUMN a TO b;
} {1 {no such table: t3}}

#-------------------------------------------------------------------------
# Test the effect of some parse/resolve errors.
#
reset_db
do_execsql_test 13.1.1 {
  CREATE TABLE x1(i INTEGER, t TEXT UNIQUE);
  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 processing 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 processing 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;
} {1 {database disk image is malformed}}

do_execsql_test 13.1.8 {
  DELETE FROM sqlite_master WHERE name = 'x1i';
}

do_execsql_test 13.2.0 {
  CREATE TABLE data(x UNIQUE, y, z);
}
foreach {tn trigger error} {
  1 {
    CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
      UPDATE data SET x=x+1 WHERE zzz=new.i;
    END;
  } {no such column: zzz}

  2 {
    CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
      INSERT INTO data(x, y) VALUES(new.i, new.t, 1) 
        ON CONFLICT (x) DO UPDATE SET z=zz+1;
    END;
  } {no such column: zz}

  3 {
    CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
      INSERT INTO x1(i, t) VALUES(new.i+1, new.t||'1') 
        ON CONFLICT (tttttt) DO UPDATE SET t=i+1;
    END;
  } {no such column: tttttt}


} {
  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 processing 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);
  INSERT INTO ddd VALUES(
      'CREATE TABLE x1(i INTEGER, t TEXT)',
      'table', 'x1', 'main', 'x1', -1, 'zzz', 0
  ), (
      'CREATE TABLE x1(i INTEGER, t TEXT)',
      'table', 'x1', 'main', 'x1', 2, 'zzz', 0
  ), (
      'CREATE TABLE x1(i INTEGER, t TEXT)',
      'table', 'x1', 'main', 'notable', 0, 'zzz', 0
  );
} {}

do_execsql_test 14.2 {
  SELECT 
  sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote)
  FROM ddd;
} {{} {} {}}


finish_test

Added test/altermalloc2.test.






















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# 2018 August 20
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix altermalloc2

# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
  finish_test
  return
}

do_execsql_test 1.0 {
  CREATE TABLE t1(abcd, efgh);
}
faultsim_save_and_close

do_faultsim_test 1 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql {
    ALTER TABLE t1 RENAME abcd TO dcba
  }
} -test {
  faultsim_test_result {0 {}}
}

catch {db close}
forcedelete test.db
sqlite3 db test.db
do_execsql_test 2.0 {
  PRAGMA encoding = 'utf-16';
  CREATE TABLE t1(abcd, efgh);
}
faultsim_save_and_close

do_faultsim_test 2 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql {
    ALTER TABLE t1 RENAME abcd TO dcba
  }
} -test {
  faultsim_test_result {0 {}}
}


reset_db
do_execsql_test 3.0 {
  CREATE TABLE t1(abcd, efgh);
  CREATE VIEW v1 AS SELECT * FROM t1 WHERE abcd>efgh;
}
faultsim_save_and_close

do_faultsim_test 3 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql {
    ALTER TABLE t1 RENAME abcd TO dcba
  }
} -test {
  faultsim_test_result {0 {}}
}
finish_test