/ Check-in [32ca8418df]
Login

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

Overview
Comment: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))".
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256: 32ca8418df8735a6c53e53153f733579e514711f091e4e09ecce83db85fe4d85
User & Date: dan 2018-08-14 16:18:19
Context
2018-08-14
18:12
Merge fixes and enhancements from trunk. check-in: dff0314b7e user: drh tags: alter-table-rename-column
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: 32ca8418df 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: 87743ddef1 user: drh tags: alter-table-rename-column
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/alter.c.

   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    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.
          944  +** Search the Parse object passed as the first argument for a RenameToken
          945  +** object associated with parse tree element pPtr. If found, remove it
          946  +** from the Parse object and add it to the list maintained by the
          947  +** RenameCtx object passed as the second argument.
   950    948   */
   951         -static RenameToken *renameTokenFind(Parse *pParse, void *pPtr){
          949  +static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
   952    950     RenameToken **pp;
   953    951     for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
   954    952       if( (*pp)->p==pPtr ){
   955    953         RenameToken *pToken = *pp;
   956    954         *pp = pToken->pNext;
   957         -      pToken->pNext = 0;
   958         -      return pToken;
          955  +      pToken->pNext = pCtx->pList;
          956  +      pCtx->pList = pToken;
          957  +      pCtx->nList++;
          958  +      break;
   959    959       }
   960    960     }
   961         -  return 0;
   962    961   }
          962  +
   963    963   
   964    964   /*
   965    965   ** This is a Walker expression callback.
   966    966   **
   967    967   ** For every TK_COLUMN node in the expression tree, search to see
   968    968   ** if the column being references is the column being renamed by an
   969    969   ** ALTER TABLE statement.  If it is, then attach its associated
   970    970   ** RenameToken object to the list of RenameToken objects being
   971    971   ** constructed in RenameCtx object at pWalker->u.pRename.
   972    972   */
   973    973   static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
   974    974     struct RenameCtx *p = pWalker->u.pRename;
   975    975     if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol ){
   976         -    RenameToken *pTok = renameTokenFind(pWalker->pParse, (void*)pExpr);
   977         -    if( pTok ){
   978         -      pTok->pNext = p->pList;
   979         -      p->pList = pTok;
   980         -      p->nList++;
   981         -    }
          976  +    renameTokenFind(pWalker->pParse, p, (void*)pExpr);
   982    977     }
   983    978     return WRC_Continue;
   984    979   }
   985    980   
   986    981   /*
   987    982   ** The RenameCtx contains a list of tokens that reference a column that
   988    983   ** is being renamed by an ALTER TABLE statement.  Return the "first"
................................................................................
  1111   1106     sWalker.xExprCallback = renameColumnExprCb;
  1112   1107     sWalker.u.pRename = &sCtx;
  1113   1108   
  1114   1109     if( sParse.pNewTable ){
  1115   1110       int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
  1116   1111       FKey *pFKey;
  1117   1112       if( bFKOnly==0 ){
  1118         -      sCtx.pList = renameTokenFind(
  1119         -          &sParse, (void*)sParse.pNewTable->aCol[sCtx.iCol].zName
         1113  +      renameTokenFind(
         1114  +          &sParse, &sCtx, (void*)sParse.pNewTable->aCol[sCtx.iCol].zName
  1120   1115         );
  1121         -      sCtx.nList = 1;
  1122   1116         assert( sCtx.iCol>=0 );
  1123   1117         if( sParse.pNewTable->iPKey==sCtx.iCol ){
         1118  +        renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
  1124   1119           sCtx.iCol = -1;
  1125   1120         }
  1126   1121         sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
  1127   1122         for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
  1128   1123           sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
  1129   1124         }
  1130   1125       }
  1131   1126   
  1132   1127       for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
  1133   1128         for(i=0; i<pFKey->nCol; i++){
  1134   1129           RenameToken *pTok = 0;
  1135   1130           if( bFKOnly==0 && pFKey->aCol[i].iFrom==sCtx.iCol ){
  1136         -          pTok = renameTokenFind(&sParse, (void*)&pFKey->aCol[i]);
  1137         -          if( pTok ){
  1138         -            pTok->pNext = sCtx.pList;
  1139         -            sCtx.pList = pTok;
  1140         -            sCtx.nList++;
  1141         -          }
         1131  +          renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
  1142   1132           }
  1143   1133           if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
  1144   1134            && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
  1145   1135           ){
  1146         -          pTok = renameTokenFind(&sParse, (void*)pFKey->aCol[i].zCol);
  1147         -          pTok->pNext = sCtx.pList;
  1148         -          sCtx.pList = pTok;
  1149         -          sCtx.nList++;
         1136  +          renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
  1150   1137           }
  1151   1138         }
  1152   1139       }
  1153   1140     }else{
  1154   1141       sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
  1155   1142       sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
  1156   1143     }

Changes to src/build.c.

  1366   1366       }
  1367   1367     }
  1368   1368     if( nTerm==1
  1369   1369      && pCol
  1370   1370      && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
  1371   1371      && sortOrder!=SQLITE_SO_DESC
  1372   1372     ){
         1373  +    if( IN_RENAME_COLUMN && pList ){
         1374  +      sqlite3MoveRenameToken(pParse, &pTab->iPKey, pList->a[0].pExpr);
         1375  +    }
  1373   1376       pTab->iPKey = iCol;
  1374   1377       pTab->keyConf = (u8)onError;
  1375   1378       assert( autoInc==0 || autoInc==1 );
  1376   1379       pTab->tabFlags |= autoInc*TF_Autoincrement;
  1377   1380       if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder;
  1378   1381     }else if( autoInc ){
  1379   1382   #ifndef SQLITE_OMIT_AUTOINCREMENT

Changes to test/altercol.test.

    61     61       {{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d, c)}}
    62     62   
    63     63    12 {CREATE TABLE t1(a, b, c);   CREATE INDEX t1i ON t1(b+b+b+b, c) WHERE b>0}
    64     64       {{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d+d+d+d, c) WHERE d>0}}
    65     65   
    66     66    13 {CREATE TABLE t1(a, b, c, FOREIGN KEY (b) REFERENCES t2)}
    67     67       {CREATE TABLE t1(a, d, c, FOREIGN KEY (d) REFERENCES t2)}
           68  +
           69  + 15 {CREATE TABLE t1(a INTEGER, b INTEGER, c BLOB, PRIMARY KEY(b))}
           70  +    {CREATE TABLE t1(a INTEGER, d INTEGER, c BLOB, PRIMARY KEY(d))}
           71  +
           72  + 16 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB)}
           73  +    {CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB)}
    68     74   
    69     75   } {
    70     76     reset_db
    71     77     do_execsql_test 1.$tn.0 $before
    72     78   
    73     79     do_execsql_test 1.$tn.1 {
    74     80       INSERT INTO t1 VALUES(1, 2, 3);