/ Check-in [ca5184a2]
Login

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

Overview
Comment:If the new column name in an ALTER TABLE RENAME COLUMN statement is quoted, then also use quotes for the column name in the edited SQL statements.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256:ca5184a25f9150540a3e401ef67df0606efa7a294d70e3fa5edad9854003eb36
User & Date: dan 2018-08-11 20:38:33
Context
2018-08-11
20:46
Add the "atrc" test program. "Atrc" is short for "ALTER TABLE RENAME COLUMN". See the header comment on the program itself for further information. check-in: ed64a55a user: drh tags: alter-table-rename-column
20:38
If the new column name in an ALTER TABLE RENAME COLUMN statement is quoted, then also use quotes for the column name in the edited SQL statements. check-in: ca5184a2 user: dan tags: alter-table-rename-column
18:34
Avoid an assert() sometimes triggered by ALTER TABLE RENAME COLUMN in non-debug builds. check-in: 520c1c75 user: dan tags: alter-table-rename-column
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/alter.c.

799
800
801
802
803
804
805

806
807
808
809
810
811
812
...
820
821
822
823
824
825
826
827


828
829
830
831
832
833
834
835
836
837
838
839
840
841
...
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944

945
946
947
948
949
950
951
952
953
954
955
...
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
....
1055
1056
1057
1058
1059
1060
1061

1062
1063
1064
1065
1066
1067
1068
1069
....
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
  sqlite3 *db = pParse->db;
  Table *pTab;                    /* Table being updated */
  int iCol;                       /* Index of column being renamed */
  char *zOld = 0;
  char *zNew = 0;
  const char *zDb;
  int iSchema;


  pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
  if( !pTab ) goto exit_rename_column;
  if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
  
  iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
  assert( iSchema>=0 );
................................................................................
  if( iCol==pTab->nCol ){
    sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld);
    goto exit_rename_column;
  }

  zNew = sqlite3NameFromToken(db, pNew);
  if( !zNew ) goto exit_rename_column;



  sqlite3NestedParse(pParse, 
      "UPDATE \"%w\".%s SET "
      "sql = sqlite_rename_column(sql, %d, %Q, %Q, %Q) "
      "WHERE name NOT LIKE 'sqlite_%%' AND ("
      "   type = 'table' OR (type='index' AND tbl_name = %Q)"
      ")",
      zDb, MASTER_NAME, iCol, zNew, pTab->zName, zOld, pTab->zName
  );

  /* Drop and reload the database schema. */
  if( pParse->pVdbe ){
    sqlite3ChangeCookie(pParse, iSchema);
    sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iSchema, 0);
  }
................................................................................
  for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext);
  *pp = pBest->pNext;

  return pBest;
}

/*
** sqlite_rename_table(SQL, iCol, zNew, zTable, zOld)
*/
static void renameColumnFunc(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **argv
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  struct RenameCtx sCtx;
  const char *zSql = (const char*)sqlite3_value_text(argv[0]);
  int nSql = sqlite3_value_bytes(argv[0]);

  const char *zNew = (const char*)sqlite3_value_text(argv[2]);
  int nNew = sqlite3_value_bytes(argv[2]);
  const char *zTable = (const char*)sqlite3_value_text(argv[3]);
  const char *zOld = (const char*)sqlite3_value_text(argv[4]);

  int rc;
  char *zErr = 0;
  Parse sParse;
  Walker sWalker;
  Index *pIdx;
  char *zOut = 0;
................................................................................
      sqlite3_result_error_code(context, rc);
    }
    sqlite3DbFree(db, zErr);
    sqlite3_free(zQuot);
    return;
  }

  for(i=0; i<nNew; i++){
    if( sqlite3IsIdChar(zNew[i])==0 ){
      zNew = zQuot;
      nNew = nQuot;
      break;
    }
  }

#ifdef SQLITE_DEBUG
  assert( sqlite3Strlen30(zSql)==nSql );
  {
    RenameToken *pToken;
    for(pToken=sParse.pRename; pToken; pToken=pToken->pNext){
................................................................................
      }
    }
  }else{
    sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
    sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
  }


  zOut = sqlite3DbMallocZero(db, nSql + sCtx.nList*nNew + 1);
  if( zOut ){
    int nOut = nSql;
    memcpy(zOut, zSql, nSql);
    while( sCtx.pList ){
      int iOff;                   /* Offset of token to replace in zOut */
      RenameToken *pBest = renameColumnTokenNext(&sCtx);

................................................................................

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







>







 







<
>
>


|



|







 







|










>
|
|
|
|







 







|
<
|
|
<
<







 







>
|







 







|










799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
...
821
822
823
824
825
826
827

828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
...
990
991
992
993
994
995
996
997

998
999


1000
1001
1002
1003
1004
1005
1006
....
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
....
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
  sqlite3 *db = pParse->db;
  Table *pTab;                    /* Table being updated */
  int iCol;                       /* Index of column being renamed */
  char *zOld = 0;
  char *zNew = 0;
  const char *zDb;
  int iSchema;
  int bQuote;

  pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
  if( !pTab ) goto exit_rename_column;
  if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
  
  iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
  assert( iSchema>=0 );
................................................................................
  if( iCol==pTab->nCol ){
    sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld);
    goto exit_rename_column;
  }

  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, %d, %d, %Q, %Q, %Q) "
      "WHERE name NOT LIKE 'sqlite_%%' AND ("
      "   type = 'table' OR (type='index' AND tbl_name = %Q)"
      ")",
      zDb, MASTER_NAME, iCol, bQuote, zNew, pTab->zName, zOld, pTab->zName
  );

  /* Drop and reload the database schema. */
  if( pParse->pVdbe ){
    sqlite3ChangeCookie(pParse, iSchema);
    sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iSchema, 0);
  }
................................................................................
  for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext);
  *pp = pBest->pNext;

  return pBest;
}

/*
** sqlite_rename_column(SQL, iCol, bQuote, zNew, zTable, zOld)
*/
static void renameColumnFunc(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **argv
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  struct RenameCtx sCtx;
  const char *zSql = (const char*)sqlite3_value_text(argv[0]);
  int nSql = sqlite3_value_bytes(argv[0]);
  int bQuote = sqlite3_value_int(argv[2]);
  const char *zNew = (const char*)sqlite3_value_text(argv[3]);
  int nNew = sqlite3_value_bytes(argv[3]);
  const char *zTable = (const char*)sqlite3_value_text(argv[4]);
  const char *zOld = (const char*)sqlite3_value_text(argv[5]);

  int rc;
  char *zErr = 0;
  Parse sParse;
  Walker sWalker;
  Index *pIdx;
  char *zOut = 0;
................................................................................
      sqlite3_result_error_code(context, rc);
    }
    sqlite3DbFree(db, zErr);
    sqlite3_free(zQuot);
    return;
  }

  if( bQuote ){

    zNew = zQuot;
    nNew = nQuot;


  }

#ifdef SQLITE_DEBUG
  assert( sqlite3Strlen30(zSql)==nSql );
  {
    RenameToken *pToken;
    for(pToken=sParse.pRename; pToken; pToken=pToken->pNext){
................................................................................
      }
    }
  }else{
    sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
    sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
  }

  assert( nQuot>=nNew );
  zOut = sqlite3DbMallocZero(db, nSql + sCtx.nList*nQuot + 1);
  if( zOut ){
    int nOut = nSql;
    memcpy(zOut, zSql, nSql);
    while( sCtx.pList ){
      int iOff;                   /* Offset of token to replace in zOut */
      RenameToken *pBest = renameColumnTokenNext(&sCtx);

................................................................................

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

Changes to test/altercol.test.

195
196
197
198
199
200
201








202
203
204
    CHECK( length(uuid)>=40 AND rid>0 )
  );
}

do_execsql_test 6.1 {
  ALTER TABLE "blob" RENAME COLUMN "rid" TO "a1";
}









finish_test








>
>
>
>
>
>
>
>



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
    CHECK( length(uuid)>=40 AND rid>0 )
  );
}

do_execsql_test 6.1 {
  ALTER TABLE "blob" RENAME COLUMN "rid" TO "a1";
}

do_catchsql_test 6.2 {
  ALTER TABLE "blob" RENAME COLUMN "a1" TO [where];
} {0 {}}

do_execsql_test 6.3 {
  SELECT "where" FROM blob;
} {}

finish_test