/ Check-in [5d2163c7]
Login

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

Overview
Comment:Rationalize some duplicated code in alter.c. Also improve error messages for ALTER TABLE RENAME COLUMN in some cases.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256: 5d2163c734aea8c0e1611af1161734bf141e7bd02c08f0b5f2e7bac3c7dfd2a5
User & Date: dan 2018-08-21 15:06:59
Context
2018-08-21
16:32
Rename internal function sqlite3RenameToken() to sqlite3RenameTokenMap() and sqlite3MoveRenameToken() to sqlite3RenameTokenRemap(). check-in: b9ae9a0a user: dan tags: alter-table-rename-column
15:06
Rationalize some duplicated code in alter.c. Also improve error messages for ALTER TABLE RENAME COLUMN in some cases. check-in: 5d2163c7 user: dan tags: alter-table-rename-column
08:29
Minor changes to function tokenExpr() in order to claw back cycles lost to the rename-column change. check-in: 47997695 user: dan tags: alter-table-rename-column
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/alter.c.

1075
1076
1077
1078
1079
1080
1081













































1082
1083
1084
1085
1086
1087
1088
....
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
....
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306

1307
1308
1309

1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
....
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
  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
................................................................................
        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;
................................................................................
            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) ){
                    renameTokenFind(&sParse, &sCtx, (void*)zName);

                  }
                }
              }

            }
            if( rc==SQLITE_OK ){
              rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
            }
            if( rc==SQLITE_OK ){
              rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
            }
          }

          if( rc==SQLITE_OK && pTarget==pTab ){
            if( pStep->pIdList ){
              for(i=0; i<pStep->pIdList->nId; i++){
                char *zName = pStep->pIdList->a[i].zName;
                if( 0==sqlite3_stricmp(zName, zOld) ){
                  renameTokenFind(&sParse, &sCtx, (void*)zName);
                }
              }
            }
            if( pStep->op==TK_UPDATE ){
              assert( pStep->pExprList );
              for(i=0; i<pStep->pExprList->nExpr; i++){
                char *zName = pStep->pExprList->a[i].zName;
                if( 0==sqlite3_stricmp(zName, zOld) ){
                  renameTokenFind(&sParse, &sCtx, (void*)zName);
                }
              }
            }
          }
        }
      }
    }

    if( rc!=SQLITE_OK ) goto renameColumnFunc_done;

    /* Find tokens to edit in UPDATE OF clause */
    if( sParse.pTriggerTab==pTab && sParse.pNewTrigger->pColumns ){
      for(i=0; i<sParse.pNewTrigger->pColumns->nId; i++){
        char *zName = sParse.pNewTrigger->pColumns->a[i].zName;
        if( 0==sqlite3_stricmp(zName, zOld) ){
          renameTokenFind(&sParse, &sCtx, (void*)zName);
        }
      }
    }

    /* Find tokens to edit in WHEN clause */
    sqlite3WalkExpr(&sWalker, sParse.pNewTrigger->pWhen);

    /* Find tokens to edit in trigger steps */
    for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
................................................................................

/*
** 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 */







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







 







|







 







|

<
|
<
<
<
<
>
|
<
<
>










|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








|
<
|
<
<
<
<







 







|










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
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
....
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
....
1337
1338
1339
1340
1341
1342
1343
1344
1345

1346




1347
1348


1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361















1362
1363
1364
1365
1366
1367
1368
1369
1370

1371




1372
1373
1374
1375
1376
1377
1378
....
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
  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);
}

/*
** For each name in the the expression-list pEList (i.e. each
** pEList->a[i].zName) that matches the string in zOld, extract the 
** corresponding rename-token from Parse object pParse and add it
** to the RenameCtx pCtx.
*/
static void renameColumnElistNames(
  Parse *pParse, 
  RenameCtx *pCtx, 
  ExprList *pEList, 
  const char *zOld
){
  if( pEList ){
    int i;
    for(i=0; i<pEList->nExpr; i++){
      char *zName = pEList->a[i].zName;
      if( 0==sqlite3_stricmp(zName, zOld) ){
        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}

/*
** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName) 
** that matches the string in zOld, extract the corresponding rename-token 
** from Parse object pParse and add it to the RenameCtx pCtx.
*/
static void renameColumnIdlistNames(
  Parse *pParse, 
  RenameCtx *pCtx, 
  IdList *pIdList, 
  const char *zOld
){
  if( pIdList ){
    int i;
    for(i=0; i<pIdList->nId; i++){
      char *zName = pIdList->a[i].zName;
      if( 0==sqlite3_stricmp(zName, zOld) ){
        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}

/*
** SQL function:
**
**     sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
**
**   0. zSql:     SQL statement to rewrite
................................................................................
        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 = sqlite3LocateTable(&sParse, 0, 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;
................................................................................
            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 ){
              ExprList *pUpsertSet = pUpsert->pUpsertSet;

              if( pTarget==pTab ){




                renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld);
              }


              rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
            }
            if( rc==SQLITE_OK ){
              rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
            }
            if( rc==SQLITE_OK ){
              rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
            }
          }

          if( rc==SQLITE_OK && pTarget==pTab ){
            renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld);
            renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld);















          }
        }
      }
    }

    if( rc!=SQLITE_OK ) goto renameColumnFunc_done;

    /* Find tokens to edit in UPDATE OF clause */
    if( sParse.pTriggerTab==pTab ){

      renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld);




    }

    /* Find tokens to edit in WHEN clause */
    sqlite3WalkExpr(&sWalker, sParse.pNewTrigger->pWhen);

    /* Find tokens to edit in trigger steps */
    for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
................................................................................

/*
** 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.

590
591
592
593
594
595
596
597





598
599
600
601
602
603
604
  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 {







<
>
>
>
>
>







590
591
592
593
594
595
596

597
598
599
600
601
602
603
604
605
606
607
608
  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}


  4 {
    CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
      INSERT INTO nosuchtable VALUES(new.i, new.t);
    END;
  } {no such table: main.nosuchtable}
} {
  do_execsql_test 13.2.$tn.1 "
    DROP TRIGGER IF EXISTS tr1;
    $trigger
  "

  do_catchsql_test 13.2.$tn.2 {