/ Check-in [24d4d5dd]
Login

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

Overview
Comment:Fix a problem with INTEGER PRIMARY KEY columns and the pre-update hook.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 24d4d5dd007197a141555bcca6f2ac9ab47cde80
User & Date: dan 2011-03-19 08:38:50
Context
2011-03-19
15:37
Fix some bugs in sqlite3changeset_apply(). check-in: 7250318d user: dan tags: sessions
08:38
Fix a problem with INTEGER PRIMARY KEY columns and the pre-update hook. check-in: 24d4d5dd user: dan tags: sessions
02:37
Merge the fix to ticket [f7b4edece25c99485] into the sessions branch. check-in: 1b736ac2 user: drh tags: sessions
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

install-sh became a regular file.


Changes to src/delete.c.

   538    538     ** be invoked unless table pTab is a system table. The difference is that
   539    539     ** the update-hook is not invoked for rows removed by REPLACE, but the 
   540    540     ** pre-update-hook is.
   541    541     */ 
   542    542     if( pTab->pSelect==0 ){
   543    543       sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
   544    544       sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
   545         -    sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
          545  +    sqlite3VdbeChangeP4(v, -1, pTab, P4_TABLE);
   546    546     }
   547    547   
   548    548     /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
   549    549     ** handle rows (possibly in other tables) that refer via a foreign key
   550    550     ** to the row just deleted. */ 
   551    551     sqlite3FkActions(pParse, pTab, 0, iOld);
   552    552   

Changes to src/insert.c.

  1287   1287             );
  1288   1288           }else{
  1289   1289             /* This OP_Delete opcode fires the pre-update-hook only. It does
  1290   1290             ** not modify the b-tree. It is more efficient to let the coming
  1291   1291             ** OP_Insert replace the existing entry than it is to delete the
  1292   1292             ** existing entry and then insert a new one. */
  1293   1293             sqlite3VdbeAddOp2(v, OP_Delete, baseCur, OPFLAG_ISNOOP);
  1294         -          sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
         1294  +          sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
  1295   1295             if( pTab->pIndex ){
  1296   1296               sqlite3MultiWrite(pParse);
  1297   1297               sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
  1298   1298             }
  1299   1299           }
  1300   1300           seenReplace = 1;
  1301   1301           break;
................................................................................
  1477   1477       pik_flags |= OPFLAG_APPEND;
  1478   1478     }
  1479   1479     if( useSeekResult ){
  1480   1480       pik_flags |= OPFLAG_USESEEKRESULT;
  1481   1481     }
  1482   1482     sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
  1483   1483     if( !pParse->nested ){
  1484         -    sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
         1484  +    sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
  1485   1485     }
  1486   1486     sqlite3VdbeChangeP5(v, pik_flags);
  1487   1487   }
  1488   1488   
  1489   1489   /*
  1490   1490   ** Generate code that will open cursors for a table and for all
  1491   1491   ** indices of that table.  The "baseCur" parameter is the cursor number used
................................................................................
  1799   1799     }else{
  1800   1800       addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
  1801   1801       assert( (pDest->tabFlags & TF_Autoincrement)==0 );
  1802   1802     }
  1803   1803     sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
  1804   1804     sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
  1805   1805     sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
  1806         -  sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
         1806  +  sqlite3VdbeChangeP4(v, -1, (char *)pDest, P4_TABLE);
  1807   1807     sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
  1808   1808     for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
  1809   1809       for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
  1810   1810         if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
  1811   1811       }
  1812   1812       assert( pSrcIdx );
  1813   1813       sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);

Changes to src/update.c.

   499    499       */
   500    500       assert( regNew==regNewRowid+1 );
   501    501       sqlite3VdbeAddOp3(v, OP_Delete, iCur,
   502    502           OPFLAG_ISUPDATE | ((hasFK || chngRowid) ? 0 : OPFLAG_ISNOOP),
   503    503           regNewRowid
   504    504       );
   505    505       if( !pParse->nested ){
   506         -      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
          506  +      sqlite3VdbeChangeP4(v, -1, pTab, P4_TABLE);
   507    507       }
   508    508       sqlite3VdbeJumpHere(v, j1);
   509    509   
   510    510       if( hasFK ){
   511    511         sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
   512    512       }
   513    513     

Changes to src/vdbe.c.

  3834   3834   ** that boosts performance by avoiding redundant seeks.
  3835   3835   **
  3836   3836   ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
  3837   3837   ** UPDATE operation.  Otherwise (if the flag is clear) then this opcode
  3838   3838   ** is part of an INSERT operation.  The difference is only important to
  3839   3839   ** the update hook.
  3840   3840   **
  3841         -** Parameter P4 may point to a string containing the table-name, or
  3842         -** may be NULL. If it is not NULL, then the update-hook 
  3843         -** (sqlite3.xUpdateCallback) is invoked following a successful insert.
         3841  +** Parameter P4 may point to a Table structure, or may be NULL. If it is 
         3842  +** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked 
         3843  +** following a successful insert.
  3844   3844   **
  3845   3845   ** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
  3846   3846   ** allocated, then ownership of P2 is transferred to the pseudo-cursor
  3847   3847   ** and register P2 becomes ephemeral.  If the cursor is changed, the
  3848   3848   ** value of register P2 will then change.  Make sure this does not
  3849   3849   ** cause any problems.)
  3850   3850   **
................................................................................
  3861   3861     Mem *pData;       /* MEM cell holding data for the record to be inserted */
  3862   3862     Mem *pKey;        /* MEM cell holding key  for the record */
  3863   3863     i64 iKey;         /* The integer ROWID or key for the record to be inserted */
  3864   3864     VdbeCursor *pC;   /* Cursor to table into which insert is written */
  3865   3865     int nZero;        /* Number of zero-bytes to append */
  3866   3866     int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
  3867   3867     const char *zDb;  /* database name - used by the update hook */
  3868         -  const char *zTbl; /* Table name - used by the opdate hook */
         3868  +  Table *pTab;      /* Table structure - used by update and pre-update hooks */
  3869   3869     int op;           /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
  3870   3870   
  3871   3871     pData = &aMem[pOp->p2];
  3872   3872     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  3873   3873     assert( memIsValid(pData) );
  3874   3874     pC = p->apCsr[pOp->p1];
  3875   3875     assert( pC!=0 );
  3876   3876     assert( pC->pCursor!=0 );
  3877   3877     assert( pC->pseudoTableReg==0 );
  3878   3878     assert( pC->isTable );
         3879  +  assert( pOp->p4type==P4_TABLE || pOp->p4type==P4_NOTUSED );
  3879   3880     REGISTER_TRACE(pOp->p2, pData);
  3880   3881   
  3881   3882     if( pOp->opcode==OP_Insert ){
  3882   3883       pKey = &aMem[pOp->p3];
  3883   3884       assert( pKey->flags & MEM_Int );
  3884   3885       assert( memIsValid(pKey) );
  3885   3886       REGISTER_TRACE(pOp->p3, pKey);
  3886   3887       iKey = pKey->u.i;
  3887   3888     }else{
  3888   3889       assert( pOp->opcode==OP_InsertInt );
  3889   3890       iKey = pOp->p3;
  3890   3891     }
  3891   3892   
  3892         -  if( pOp->p4.z && (db->xPreUpdateCallback || db->xUpdateCallback) ){
         3893  +  if( pOp->p4type==P4_TABLE && (db->xPreUpdateCallback||db->xUpdateCallback) ){
  3893   3894       assert( pC->isTable );
  3894   3895       assert( pC->iDb>=0 );
  3895   3896       zDb = db->aDb[pC->iDb].zName;
  3896         -    zTbl = pOp->p4.z;
         3897  +    pTab = pOp->p4.pTab;
  3897   3898       op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
  3898   3899     }
  3899   3900   
  3900   3901     /* Invoke the pre-update hook, if any */
  3901   3902     if( db->xPreUpdateCallback 
  3902         -   && pOp->p4.z 
         3903  +   && pOp->p4type==P4_TABLE
  3903   3904      && (!(pOp->p5 & OPFLAG_ISUPDATE) || pC->rowidIsValid==0)
  3904   3905     ){
  3905         -    sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, zTbl, iKey, pOp->p2);
         3906  +    sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, iKey, pOp->p2);
  3906   3907     }
  3907   3908   
  3908   3909     if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  3909   3910     if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey;
  3910   3911     if( pData->flags & MEM_Null ){
  3911   3912       pData->z = 0;
  3912   3913       pData->n = 0;
................................................................................
  3926   3927     );
  3927   3928     pC->rowidIsValid = 0;
  3928   3929     pC->deferredMoveto = 0;
  3929   3930     pC->cacheStatus = CACHE_STALE;
  3930   3931   
  3931   3932     /* Invoke the update-hook if required. */
  3932   3933     if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
  3933         -    db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
         3934  +    db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, iKey);
  3934   3935     }
  3935   3936     break;
  3936   3937   }
  3937   3938   
  3938   3939   /* Opcode: Delete P1 P2 P3 P4 *
  3939   3940   **
  3940   3941   ** Delete the record at which the P1 cursor is currently pointing.
................................................................................
  3946   3947   **
  3947   3948   ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
  3948   3949   ** incremented (otherwise not).
  3949   3950   **
  3950   3951   ** P1 must not be pseudo-table.  It has to be a real table with
  3951   3952   ** multiple rows.
  3952   3953   **
  3953         -** If P4 is not NULL then, either the update or pre-update hook, or both,
  3954         -** may be invoked. The P1 cursor must have been positioned using OP_NotFound 
  3955         -** prior to invoking this opcode in this case. Specifically, if one is 
  3956         -** configured, the pre-update hook is invoked if P4 is not NULL. The 
  3957         -** update-hook is invoked if one is configured, P4 is not NULL, and the 
  3958         -** OPFLAG_NCHANGE flag is set in P2.
         3954  +** If P4 is not NULL then it points to a Table struture. In this case either 
         3955  +** the update or pre-update hook, or both, may be invoked. The P1 cursor must
         3956  +** have been positioned using OP_NotFound prior to invoking this opcode in 
         3957  +** this case. Specifically, if one is configured, the pre-update hook is 
         3958  +** invoked if P4 is not NULL. The update-hook is invoked if one is configured, 
         3959  +** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
  3959   3960   **
  3960   3961   ** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
  3961   3962   ** of the memory cell that contains the value that the rowid of the row will
  3962   3963   ** be set to by the update.
  3963   3964   */
  3964   3965   case OP_Delete: {
  3965   3966     i64 iKey;
  3966   3967     VdbeCursor *pC;
  3967   3968     const char *zDb;
  3968         -  const char *zTbl;
         3969  +  Table *pTab;
  3969   3970     int opflags;
  3970   3971   
  3971   3972     opflags = pOp->p2;
  3972   3973     iKey = 0;
  3973   3974     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  3974   3975     pC = p->apCsr[pOp->p1];
  3975   3976     assert( pC!=0 );
  3976   3977     assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
         3978  +  assert( pOp->p4type==P4_TABLE || pOp->p4type==P4_NOTUSED );
  3977   3979   
  3978   3980     /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
  3979   3981     ** OP_Column on the same table without any intervening operations that
  3980   3982     ** might move or invalidate the cursor.  Hence cursor pC is always pointing
  3981   3983     ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
  3982   3984     ** below is always a no-op and cannot fail.  We will run it anyhow, though,
  3983   3985     ** to guard against future changes to the code generator.
................................................................................
  3991   3993     */
  3992   3994     if( pOp->p4.z && (db->xPreUpdateCallback || db->xUpdateCallback) ){
  3993   3995       assert( pC->iDb>=0 );
  3994   3996       assert( pC->isTable );
  3995   3997       assert( pC->rowidIsValid );  /* lastRowid set by previous OP_NotFound */
  3996   3998       iKey = pC->lastRowid;
  3997   3999       zDb = db->aDb[pC->iDb].zName;
  3998         -    zTbl = pOp->p4.z;
         4000  +    pTab = pOp->p4.pTab;
  3999   4001     }
  4000   4002   
  4001   4003     /* Invoke the pre-update-hook if required. */
  4002   4004     if( db->xPreUpdateCallback && pOp->p4.z ){
  4003   4005       assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
  4004   4006       sqlite3VdbePreUpdateHook(p, pC,
  4005   4007           (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
  4006         -        zDb, zTbl, iKey,
         4008  +        zDb, pTab, iKey,
  4007   4009           pOp->p3
  4008   4010       );
  4009   4011     }
  4010   4012   
  4011   4013     if( opflags & OPFLAG_ISNOOP ) break;
  4012   4014   
  4013   4015     sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
................................................................................
  4015   4017     pC->cacheStatus = CACHE_STALE;
  4016   4018   
  4017   4019     /* Update the change-counter and invoke the update-hook if required. */
  4018   4020     if( opflags & OPFLAG_NCHANGE ){
  4019   4021       p->nChange++;
  4020   4022       assert( pOp->p4.z );
  4021   4023       if( rc==SQLITE_OK && db->xUpdateCallback ){
  4022         -      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
         4024  +      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,iKey);
  4023   4025       }
  4024   4026     }
  4025   4027     break;
  4026   4028   }
  4027   4029   /* Opcode: ResetCount * * * * *
  4028   4030   **
  4029   4031   ** The value of the change counter is copied to the database handle

Changes to src/vdbe.h.

    57     57       VdbeFunc *pVdbeFunc;   /* Used when p4type is P4_VDBEFUNC */
    58     58       CollSeq *pColl;        /* Used when p4type is P4_COLLSEQ */
    59     59       Mem *pMem;             /* Used when p4type is P4_MEM */
    60     60       VTable *pVtab;         /* Used when p4type is P4_VTAB */
    61     61       KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    62     62       int *ai;               /* Used when p4type is P4_INTARRAY */
    63     63       SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
           64  +    Table *pTab;           /* Used when p4type is P4_TABLE */
    64     65     } p4;
    65     66   #ifdef SQLITE_DEBUG
    66     67     char *zComment;          /* Comment to improve readability */
    67     68   #endif
    68     69   #ifdef VDBE_PROFILE
    69     70     int cnt;                 /* Number of times this instruction was executed */
    70     71     u64 cycles;              /* Total time spent executing this instruction */
................................................................................
   112    113   #define P4_VTAB     (-10) /* P4 is a pointer to an sqlite3_vtab structure */
   113    114   #define P4_MPRINTF  (-11) /* P4 is a string obtained from sqlite3_mprintf() */
   114    115   #define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
   115    116   #define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
   116    117   #define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
   117    118   #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
   118    119   #define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
          120  +#define P4_TABLE    (-19) /* P4 is a pointer to a Table structure */
   119    121   
   120    122   /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
   121    123   ** is made.  That copy is freed when the Vdbe is finalized.  But if the
   122    124   ** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used.  It still
   123    125   ** gets freed when the Vdbe is finalized so it still should be obtained
   124    126   ** from a single sqliteMalloc().  But no copy is made and the calling
   125    127   ** function should *not* try to free the KeyInfo.

Changes to src/vdbeInt.h.

   340    340     VdbeCursor *pCsr;               /* Cursor to read old values from */
   341    341     int op;                         /* One of SQLITE_INSERT, UPDATE, DELETE */
   342    342     u8 *aRecord;                    /* old.* database record */
   343    343     KeyInfo keyinfo;
   344    344     UnpackedRecord *pUnpacked;      /* Unpacked version of aRecord[] */
   345    345     UnpackedRecord *pNewUnpacked;   /* Unpacked version of new.* record */
   346    346     int iNewReg;                    /* Register for new.* values */
          347  +  i64 iKey1;                      /* First key value passed to hook */
          348  +  i64 iKey2;                      /* Second key value passed to hook */
          349  +  int iPKey;                      /* If not negative index of IPK column */
   347    350     Mem *aNew;                      /* Array of new.* values */
   348    351   };
   349    352   
   350    353   /*
   351    354   ** Function prototypes
   352    355   */
   353    356   void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
................................................................................
   400    403   const char *sqlite3OpcodeName(int);
   401    404   int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
   402    405   int sqlite3VdbeCloseStatement(Vdbe *, int);
   403    406   void sqlite3VdbeFrameDelete(VdbeFrame*);
   404    407   int sqlite3VdbeFrameRestore(VdbeFrame *);
   405    408   void sqlite3VdbeMemStoreType(Mem *pMem);
   406    409   void sqlite3VdbePreUpdateHook(
   407         -    Vdbe *, VdbeCursor *, int, const char*, const char*, i64, int);
          410  +    Vdbe *, VdbeCursor *, int, const char*, Table *, i64, int);
   408    411   
   409    412   #ifdef SQLITE_DEBUG
   410    413   void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
   411    414   #endif
   412    415   
   413    416   #ifndef SQLITE_OMIT_FOREIGN_KEY
   414    417   int sqlite3VdbeCheckFk(Vdbe *, int);

Changes to src/vdbeapi.c.

  1365   1365       p->aRecord = aRecord;
  1366   1366     }
  1367   1367   
  1368   1368     if( iIdx>=p->pUnpacked->nField ){
  1369   1369       *ppValue = (sqlite3_value *)columnNullValue();
  1370   1370     }else{
  1371   1371       *ppValue = &p->pUnpacked->aMem[iIdx];
         1372  +    if( iIdx==p->iPKey ){
         1373  +      sqlite3VdbeMemSetInt64(*ppValue, p->iKey1);
         1374  +    }
  1372   1375       sqlite3VdbeMemStoreType(*ppValue);
  1373   1376     }
  1374   1377   
  1375   1378    preupdate_old_out:
  1376   1379     sqlite3Error(db, rc, 0);
  1377   1380     return sqlite3ApiExit(db, rc);
  1378   1381   }
................................................................................
  1419   1422         }
  1420   1423         p->pNewUnpacked = pUnpack;
  1421   1424       }
  1422   1425       if( iIdx>=pUnpack->nField ){
  1423   1426         pMem = (sqlite3_value *)columnNullValue();
  1424   1427       }else{
  1425   1428         pMem = &pUnpack->aMem[iIdx];
         1429  +      if( iIdx==p->iPKey ){
         1430  +        sqlite3VdbeMemSetInt64(pMem, p->iKey2);
         1431  +      }
  1426   1432         sqlite3VdbeMemStoreType(pMem);
  1427   1433       }
  1428   1434     }else{
  1429   1435       /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
  1430   1436       ** value. Make a copy of the cell contents and return a pointer to it.
  1431   1437       ** It is not safe to return a pointer to the memory cell itself as the
  1432   1438       ** caller may modify the value text encoding.
................................................................................
  1438   1444           rc = SQLITE_NOMEM;
  1439   1445           goto preupdate_new_out;
  1440   1446         }
  1441   1447       }
  1442   1448       assert( iIdx>=0 && iIdx<p->pCsr->nField );
  1443   1449       pMem = &p->aNew[iIdx];
  1444   1450       if( pMem->flags==0 ){
  1445         -      rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
  1446         -      if( rc!=SQLITE_OK ) goto preupdate_new_out;
         1451  +      if( iIdx==p->iPKey ){
         1452  +        sqlite3VdbeMemSetInt64(pMem, p->iKey2);
         1453  +      }else{
         1454  +        rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
         1455  +        if( rc!=SQLITE_OK ) goto preupdate_new_out;
         1456  +      }
  1447   1457         sqlite3VdbeMemStoreType(pMem);
  1448   1458       }
  1449   1459     }
  1450   1460     *ppValue = pMem;
  1451   1461   
  1452   1462    preupdate_new_out:
  1453   1463     sqlite3Error(db, rc, 0);
  1454   1464     return sqlite3ApiExit(db, rc);
  1455   1465   }

Changes to src/vdbeaux.c.

  3178   3178   ** the required value will be read from the row the cursor points to.
  3179   3179   */
  3180   3180   void sqlite3VdbePreUpdateHook(
  3181   3181     Vdbe *v,                        /* Vdbe pre-update hook is invoked by */
  3182   3182     VdbeCursor *pCsr,               /* Cursor to grab old.* values from */
  3183   3183     int op,                         /* SQLITE_INSERT, UPDATE or DELETE */
  3184   3184     const char *zDb,                /* Database name */
  3185         -  const char *zTbl,               /* Table name */
         3185  +  Table *pTab,                    /* Modified table */
  3186   3186     i64 iKey1,                      /* Initial key value */
  3187   3187     int iReg                        /* Register for new.* record */
  3188   3188   ){
  3189   3189     sqlite3 *db = v->db;
  3190   3190     i64 iKey2;
  3191   3191     PreUpdate preupdate;
         3192  +  const char *zTbl = pTab->zName;
  3192   3193   
  3193   3194     assert( db->pPreUpdate==0 );
  3194   3195     memset(&preupdate, 0, sizeof(PreUpdate));
  3195   3196     if( op==SQLITE_UPDATE ){
  3196   3197       iKey2 = v->aMem[iReg].u.i;
  3197   3198     }else{
  3198   3199       iKey2 = iKey1;
................................................................................
  3201   3202     preupdate.v = v;
  3202   3203     preupdate.pCsr = pCsr;
  3203   3204     preupdate.op = op;
  3204   3205     preupdate.iNewReg = iReg;
  3205   3206     preupdate.keyinfo.db = db;
  3206   3207     preupdate.keyinfo.enc = ENC(db);
  3207   3208     preupdate.keyinfo.nField = pCsr->nField;
         3209  +  preupdate.iKey1 = iKey1;
         3210  +  preupdate.iKey2 = iKey2;
         3211  +  preupdate.iPKey = pTab->iPKey;
         3212  +
  3208   3213     db->pPreUpdate = &preupdate;
  3209   3214     db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
  3210   3215     db->pPreUpdate = 0;
  3211   3216     sqlite3DbFree(db, preupdate.aRecord);
  3212   3217     if( preupdate.pUnpacked ){
  3213   3218       sqlite3VdbeDeleteUnpackedRecord(preupdate.pUnpacked);
  3214   3219     }

Changes to test/hook.test.

   618    618   do_execsql_test 7.5.2.0 {
   619    619     CREATE TABLE t8(a, b);
   620    620     INSERT INTO t8 VALUES('one', 'two');
   621    621     INSERT INTO t8 VALUES('three', 'four');
   622    622     ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx';
   623    623   }
   624    624   
   625         -# At time of writing, these two are broken. They demonstraight that the
          625  +# At time of writing, these two are broken. They demonstrate that the
   626    626   # sqlite3_preupdate_old() method does not handle the case where ALTER TABLE
   627    627   # has been used to add a column with a default value other than NULL.
   628    628   #
   629    629   do_preupdate_test 7.5.2.1 {
   630    630     DELETE FROM t8 WHERE a = 'one'
   631    631   } {
   632    632     DELETE main t8 1 1   one two xxx
   633    633   }
   634    634   do_preupdate_test 7.5.2.2 {
   635    635     UPDATE t8 SET b = 'five'
   636    636   } {
   637    637     UPDATE main t8 2 2   three four xxx  three five xxx
   638    638   }
          639  +
          640  +# This block of tests verifies that IPK values are correctly reported
          641  +# by the sqlite3_preupdate_old() and sqlite3_preupdate_new() functions.
          642  +#
          643  +do_execsql_test 7.6.1 { CREATE TABLE t9(a, b INTEGER PRIMARY KEY, c) }
          644  +do_preupdate_test 7.6.2 {
          645  +  INSERT INTO t9 VALUES(1, 2, 3);
          646  +  UPDATE t9 SET b = b+1, c = c+1;
          647  +  DELETE FROM t9 WHERE a = 1;
          648  +} {
          649  +  INSERT main t9 2 2   1 2 3
          650  +  UPDATE main t9 2 3   1 2 3   1 3 4
          651  +  DELETE main t9 3 3   1 3 4
          652  +}
          653  +
   639    654   
   640    655   finish_test
   641    656   

test/progress.test became executable.


tool/mkopts.tcl became executable.