/ Check-in [87743dde]
Login

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

Overview
Comment: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.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256: 87743ddef11749b4017d60abc297abfd673e02a26a2ae45ffec861327578aa30
User & Date: drh 2018-08-13 17:02:26
Context
2018-08-14
16:18
Fix ALTER TABLE RENAME COLUMN in cases where the column being renamed is an IPK declared with a separate PRIMARY KEY clause - "CREATE TABLE x(y INTEGER, PRIMARY KEY(y))". check-in: 32ca8418 user: dan tags: alter-table-rename-column
2018-08-13
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
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/alter.c.

   936    936     RenameToken *p;
   937    937     for(p=pToken; p; p=pNext){
   938    938       pNext = p->pNext;
   939    939       sqlite3DbFree(db, p);
   940    940     }
   941    941   }
   942    942   
          943  +/*
          944  +** Return the RenameToken object associated with parse tree element pPtr,
          945  +** or a NULL pointer if not found.  The RenameToken object returned is
          946  +** removed from the list of RenameToken objects attached to the Parse
          947  +** object and the caller becomes the new owner of the RenameToken object
          948  +** Hence, the caller assumes responsibility for freeing the returned
          949  +** RenameToken object.
          950  +*/
   943    951   static RenameToken *renameTokenFind(Parse *pParse, void *pPtr){
   944    952     RenameToken **pp;
   945    953     for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
   946    954       if( (*pp)->p==pPtr ){
   947    955         RenameToken *pToken = *pp;
   948    956         *pp = pToken->pNext;
   949    957         pToken->pNext = 0;
   950    958         return pToken;
   951    959       }
   952    960     }
   953    961     return 0;
   954    962   }
   955    963   
          964  +/*
          965  +** This is a Walker expression callback.
          966  +**
          967  +** For every TK_COLUMN node in the expression tree, search to see
          968  +** if the column being references is the column being renamed by an
          969  +** ALTER TABLE statement.  If it is, then attach its associated
          970  +** RenameToken object to the list of RenameToken objects being
          971  +** constructed in RenameCtx object at pWalker->u.pRename.
          972  +*/
   956    973   static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
   957    974     struct RenameCtx *p = pWalker->u.pRename;
   958    975     if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol ){
   959    976       RenameToken *pTok = renameTokenFind(pWalker->pParse, (void*)pExpr);
   960    977       if( pTok ){
   961    978         pTok->pNext = p->pList;
   962    979         p->pList = pTok;
   963    980         p->nList++;
   964    981       }
   965    982     }
   966    983     return WRC_Continue;
   967    984   }
   968    985   
          986  +/*
          987  +** The RenameCtx contains a list of tokens that reference a column that
          988  +** is being renamed by an ALTER TABLE statement.  Return the "first"
          989  +** RenameToken in the RenameCtx and remove that RenameToken from the
          990  +** RenameContext.  "First" means the first RenameToken encountered when
          991  +** the input SQL from left to right.  Repeated calls to this routine
          992  +** return all column name tokens in the order that they are encountered
          993  +** in the SQL statement.
          994  +*/
   969    995   static RenameToken *renameColumnTokenNext(struct RenameCtx *pCtx){
   970    996     RenameToken *pBest = pCtx->pList;
   971    997     RenameToken *pToken;
   972    998     RenameToken **pp;
   973    999   
   974   1000     for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){
   975   1001       if( pToken->t.z>pBest->t.z ) pBest = pToken;
................................................................................
   977   1003     for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext);
   978   1004     *pp = pBest->pNext;
   979   1005   
   980   1006     return pBest;
   981   1007   }
   982   1008   
   983   1009   /*
   984         -** sqlite_rename_column(SQL, iCol, bQuote, zNew, zTable, zOld)
         1010  +** SQL function:
         1011  +**
         1012  +**     sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
         1013  +**
         1014  +** Do a column rename operation on the CREATE statement given in zSql.
         1015  +** The iCol-th column (left-most is 0) of table zTable is renamed from zCol
         1016  +** into zNew.  The name should be quoted if bQuote is true.
         1017  +**
         1018  +** This function is used internally by the ALTER TABLE RENAME COLUMN command.
         1019  +** Though accessible to application code, it is not intended for use by
         1020  +** applications.  The existance of this function, and the way it works,
         1021  +** is subject to change without notice.
         1022  +**
         1023  +** If any of the parameters are out-of-bounds, then simply return NULL.
         1024  +** An out-of-bounds parameter can only occur when the application calls
         1025  +** this function directly.  The parameters will always be well-formed when
         1026  +** this routine is invoked by the bytecode for a legitimate ALTER TABLE
         1027  +** statement.
   985   1028   */
   986   1029   static void renameColumnFunc(
   987   1030     sqlite3_context *context,
   988   1031     int NotUsed,
   989   1032     sqlite3_value **argv
   990   1033   ){
   991   1034     sqlite3 *db = sqlite3_context_db_handle(context);
................................................................................
  1005   1048     Index *pIdx;
  1006   1049     char *zOut = 0;
  1007   1050   
  1008   1051     char *zQuot = 0;                /* Quoted version of zNew */
  1009   1052     int nQuot = 0;                  /* Length of zQuot in bytes */
  1010   1053     int i;
  1011   1054   
         1055  +  if( zSql==0 ) return;
         1056  +  if( zNew==0 ) return;
         1057  +  if( zTable==0 ) return;
         1058  +  if( zOld==0 ) return;
  1012   1059     memset(&sCtx, 0, sizeof(sCtx));
  1013   1060     sCtx.iCol = sqlite3_value_int(argv[1]);
         1061  +  if( sCtx.iCol<0 ) return;
  1014   1062   
  1015   1063     memset(&sParse, 0, sizeof(sParse));
  1016   1064     sParse.eParseMode = PARSE_MODE_RENAME_COLUMN;
  1017   1065     sParse.db = db;
  1018   1066     sParse.nQueryLoop = 1;
  1019   1067     rc = sqlite3RunParser(&sParse, zSql, &zErr);
  1020   1068     assert( sParse.pNewTable==0 || sParse.pNewIndex==0 );