/ Check-in [32edc892]
Login

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

Overview
Comment:Fix legacy comments on Token. Begin commenting the new ALTER TABLE RENAME COLUMN code. Fix a memory leak in the sqlite_rename_column() SQL function.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256: 32edc8920376aabb84ebe1900eaa9512d23f1b44d6459e4916dc6b07db66e27c
User & Date: drh 2018-08-13 15:09:48
Context
2018-08-13
17:14
Edit the WHEN and UPDATE OF clauses of trigger programs as part of ALTER TABLE RENAME COLUMN. check-in: 5fdb6b0a user: dan tags: edit-trigger-wrapper
17:02
Make the sqlite_rename_column() SQL function resistant to problems caused by OOMs and/or malformed parameters submitted by hostile application code. Also add additional comments to the RENAME COLUMN logic. check-in: 87743dde user: drh tags: alter-table-rename-column
15:09
Fix legacy comments on Token. Begin commenting the new ALTER TABLE RENAME COLUMN code. Fix a memory leak in the sqlite_rename_column() SQL function. check-in: 32edc892 user: drh tags: alter-table-rename-column
13:43
Fix issues with ALTER TABLE RENAME COLUMN associated with OOM errors. check-in: 0b28dd5c user: drh tags: alter-table-rename-column
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/alter.c.

786
787
788
789
790
791
792





793
794
795
796
797



798
799
800
801
802
803
804
805
806


807

808
809


810
811

812
813
814
815


816
817
818
819
820
821
822
823
824
825




826
827
828
829
830
831
832
...
845
846
847
848
849
850
851

















852
853
854


855
856
857




858
859
860
861
862
863




864
865
866
867
868
869
870
871
872
873
874





875
876
877
878
879
880
881
882
883
884
885



886
887
888
889
890
891
892
....
1097
1098
1099
1100
1101
1102
1103

1104
1105
1106
1107
1108
1109
1110
  sqlite3ChangeCookie(pParse, iDb);

exit_begin_add_column:
  sqlite3SrcListDelete(db, pSrc);
  return;
}






void sqlite3AlterRenameColumn(
  Parse *pParse, 
  SrcList *pSrc, 
  Token *pOld, 
  Token *pNew



){
  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 );
  zDb = db->aDb[iSchema].zDbSName;



  zOld = sqlite3NameFromToken(db, pOld);
  if( !zOld ) goto exit_rename_column;
  for(iCol=0; iCol<pTab->nCol; iCol++){
    if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break;
  }
  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) "
................................................................................
 exit_rename_column:
  sqlite3SrcListDelete(db, pSrc);
  sqlite3DbFree(db, zOld);
  sqlite3DbFree(db, zNew);
  return;
}


















struct RenameToken {
  void *p;
  Token t;


  RenameToken *pNext;
};





struct RenameCtx {
  RenameToken *pList;             /* List of tokens to overwrite */
  int nList;                      /* Number of tokens in pList */
  int iCol;                       /* Index of column being renamed */
};





void sqlite3RenameToken(Parse *pParse, void *pPtr, Token *pToken){
  RenameToken *pNew;
  pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
  if( pNew ){
    pNew->p = pPtr;
    pNew->t = *pToken;
    pNew->pNext = pParse->pRename;
    pParse->pRename = pNew;
  }
}






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 );
}




static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
  RenameToken *pNext;
  RenameToken *p;
  for(p=pToken; p; p=pNext){
    pNext = p->pNext;
    sqlite3DbFree(db, p);
  }
................................................................................
renameColumnFunc_done:
  if( sParse.pVdbe ){
    sqlite3VdbeFinalize(sParse.pVdbe);
  }
  sqlite3DeleteTable(db, sParse.pNewTable);
  if( sParse.pNewIndex ) sqlite3FreeIndex(db, sParse.pNewIndex);
  renameTokenFree(db, sParse.pRename);

  sqlite3ParserReset(&sParse);
  sqlite3_free(zQuot);
}

/*
** Register built-in functions used to help implement ALTER TABLE
*/







>
>
>
>
>

|
<
<
<
>
>
>

|


|
|
|
<
<
>
>

>


>
>

|
>




>
>










>
>
>
>







 







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

<
<
>
>
|


>
>
>
>






>
>
>
>











>
>
>
>
>











>
>
>







 







>







786
787
788
789
790
791
792
793
794
795
796
797
798
799



800
801
802
803
804
805
806
807
808
809


810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884


885
886
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
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
....
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  sqlite3ChangeCookie(pParse, iDb);

exit_begin_add_column:
  sqlite3SrcListDelete(db, pSrc);
  return;
}

/*
** Handles the following parser reduction:
**
**  cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew
*/
void sqlite3AlterRenameColumn(
  Parse *pParse,                  /* Parsing context */



  SrcList *pSrc,                  /* Table being altered.  pSrc->nSrc==1 */
  Token *pOld,                    /* Name of column being changed */
  Token *pNew                     /* New column name */
){
  sqlite3 *db = pParse->db;       /* Database connection */
  Table *pTab;                    /* Table being updated */
  int iCol;                       /* Index of column being renamed */
  char *zOld = 0;                 /* Old column name */
  char *zNew = 0;                 /* New column name */
  const char *zDb;                /* Name of schema containing the table */


  int iSchema;                    /* Index of the schema */
  int bQuote;                     /* True to quote the new name */

  /* Locate the table to be altered */
  pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
  if( !pTab ) goto exit_rename_column;

  /* Cannot alter a system table */
  if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;

  /* Which schema holds the table to be altered */  
  iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
  assert( iSchema>=0 );
  zDb = db->aDb[iSchema].zDbSName;

  /* Make sure the old name really is a column name in the table to be
  ** altered.  Set iCol to be the index of the column being renamed */
  zOld = sqlite3NameFromToken(db, pOld);
  if( !zOld ) goto exit_rename_column;
  for(iCol=0; iCol<pTab->nCol; iCol++){
    if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break;
  }
  if( iCol==pTab->nCol ){
    sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld);
    goto exit_rename_column;
  }

  /* Do the rename operation using a recursive UPDATE statement that
  ** uses the sqlite_rename_column() SQL function to compute the new
  ** CREATE statement text for the sqlite_master table.
  */
  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) "
................................................................................
 exit_rename_column:
  sqlite3SrcListDelete(db, pSrc);
  sqlite3DbFree(db, zOld);
  sqlite3DbFree(db, zNew);
  return;
}

/*
** Each RenameToken object maps an element of the parse tree into
** the token that generated that element.  The parse tree element
** might be one of:
**
**     *  A pointer to an Expr that represents an ID
**     *  The name of a table column in Column.zName
**
** A list of RenameToken objects can be constructed during parsing.
** Each new object is created by sqlite3RenameToken().
** As the parse tree is transformed, the sqlite3MoveRenameToken()
** routine is used to keep the mapping current.
**
** After the parse finishes, renameTokenFind() routine can be used
** to look up the actual token value that created some element in
** the parse tree.
*/
struct RenameToken {


  void *p;               /* Parse tree element created by token t */
  Token t;               /* The token that created parse tree element p */
  RenameToken *pNext;    /* Next is a list of all RenameToken objects */
};

/*
** The context of an ALTER TABLE RENAME COLUMN operation that gets passed
** down into the Walker.
*/
struct RenameCtx {
  RenameToken *pList;             /* List of tokens to overwrite */
  int nList;                      /* Number of tokens in pList */
  int iCol;                       /* Index of column being renamed */
};

/*
** Add a new RenameToken object mapping parse tree element pPtr into
** token *pToken to the Parse object currently under construction.
*/
void sqlite3RenameToken(Parse *pParse, void *pPtr, Token *pToken){
  RenameToken *pNew;
  pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
  if( pNew ){
    pNew->p = pPtr;
    pNew->t = *pToken;
    pNew->pNext = pParse->pRename;
    pParse->pRename = pNew;
  }
}

/*
** 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 );
}

/*
** Free the list of RenameToken objects given in the second argument
*/
static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
  RenameToken *pNext;
  RenameToken *p;
  for(p=pToken; p; p=pNext){
    pNext = p->pNext;
    sqlite3DbFree(db, p);
  }
................................................................................
renameColumnFunc_done:
  if( sParse.pVdbe ){
    sqlite3VdbeFinalize(sParse.pVdbe);
  }
  sqlite3DeleteTable(db, sParse.pNewTable);
  if( sParse.pNewIndex ) sqlite3FreeIndex(db, sParse.pNewIndex);
  renameTokenFree(db, sParse.pRename);
  renameTokenFree(db, sCtx.pList);
  sqlite3ParserReset(&sParse);
  sqlite3_free(zQuot);
}

/*
** Register built-in functions used to help implement ALTER TABLE
*/

Changes to src/sqliteInt.h.

2277
2278
2279
2280
2281
2282
2283
2284
2285
2286


2287
2288
2289
2290
2291
2292
2293
....
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
  tRowcnt *anDLt;   /* Est. number of distinct keys less than this sample */
};

/*
** Each token coming out of the lexer is an instance of
** this structure.  Tokens are also used as part of an expression.
**
** Note if Token.z==0 then Token.dyn and Token.n are undefined and
** may contain random values.  Do not make any assumptions about Token.dyn
** and Token.n when Token.z==0.


*/
struct Token {
  const char *z;     /* Text of the token.  Not NULL-terminated! */
  unsigned int n;    /* Number of characters in this token */
};

/*
................................................................................
  Table **apVtabLock;       /* Pointer to virtual tables needing locking */
#endif
  Table *pZombieTab;        /* List of Table objects to delete after code gen */
  TriggerPrg *pTriggerPrg;  /* Linked list of coded triggers */
  With *pWith;              /* Current WITH clause, or NULL */
  With *pWithToFree;        /* Free this WITH object at the end of the parse */
#ifndef SQLITE_OMIT_ALTERTABLE
  RenameToken *pRename;
#endif
};

#define PARSE_MODE_NORMAL        0
#define PARSE_MODE_DECLARE_VTAB  1
#define PARSE_MODE_RENAME_COLUMN 2








|
|
|
>
>







 







|







2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
....
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
  tRowcnt *anDLt;   /* Est. number of distinct keys less than this sample */
};

/*
** Each token coming out of the lexer is an instance of
** this structure.  Tokens are also used as part of an expression.
**
** The memory that "z" points to is owned by other objects.  Take care
** that the owner of the "z" string does not deallocate the string before
** the Token goes out of scope!  Very often, the "z" points to some place
** in the middle of the Parse.zSql text.  But it might also point to a
** static string.
*/
struct Token {
  const char *z;     /* Text of the token.  Not NULL-terminated! */
  unsigned int n;    /* Number of characters in this token */
};

/*
................................................................................
  Table **apVtabLock;       /* Pointer to virtual tables needing locking */
#endif
  Table *pZombieTab;        /* List of Table objects to delete after code gen */
  TriggerPrg *pTriggerPrg;  /* Linked list of coded triggers */
  With *pWith;              /* Current WITH clause, or NULL */
  With *pWithToFree;        /* Free this WITH object at the end of the parse */
#ifndef SQLITE_OMIT_ALTERTABLE
  RenameToken *pRename;     /* Tokens subject to renaming by ALTER TABLE */
#endif
};

#define PARSE_MODE_NORMAL        0
#define PARSE_MODE_DECLARE_VTAB  1
#define PARSE_MODE_RENAME_COLUMN 2