14fccf43aSdan 
24fccf43aSdan #ifdef SQLITE_ENABLE_SESSION
34fccf43aSdan 
44fccf43aSdan #include "sqlite3session.h"
54fccf43aSdan #include <assert.h>
64fccf43aSdan #include <string.h>
74fccf43aSdan 
84fccf43aSdan #include "sqliteInt.h"
94fccf43aSdan #include "vdbeInt.h"
104fccf43aSdan 
114fccf43aSdan typedef struct SessionTable SessionTable;
124fccf43aSdan typedef struct SessionChange SessionChange;
13296c7658Sdan typedef struct SessionBuffer SessionBuffer;
144fccf43aSdan 
15296c7658Sdan /*
16296c7658Sdan ** Session handle structure.
17296c7658Sdan */
184fccf43aSdan struct sqlite3_session {
194fccf43aSdan   sqlite3 *db;                    /* Database handle session is attached to */
204fccf43aSdan   char *zDb;                      /* Name of database session is attached to */
21296c7658Sdan   int bEnable;                    /* True if currently recording */
224fccf43aSdan   int rc;                         /* Non-zero if an error has occurred */
234fccf43aSdan   sqlite3_session *pNext;         /* Next session object on same db. */
244fccf43aSdan   SessionTable *pTable;           /* List of attached tables */
254fccf43aSdan };
264fccf43aSdan 
274fccf43aSdan /*
28296c7658Sdan ** Structure for changeset iterators.
29296c7658Sdan */
30296c7658Sdan struct sqlite3_changeset_iter {
31296c7658Sdan   u8 *aChangeset;                 /* Pointer to buffer containing changeset */
32296c7658Sdan   int nChangeset;                 /* Number of bytes in aChangeset */
33296c7658Sdan   u8 *pNext;                      /* Pointer to next change within aChangeset */
34296c7658Sdan   int rc;                         /* Iterator error code */
35296c7658Sdan   sqlite3_stmt *pConflict;        /* Points to conflicting row, if any */
36296c7658Sdan   char *zTab;                     /* Current table */
37296c7658Sdan   int nCol;                       /* Number of columns in zTab */
38296c7658Sdan   int op;                         /* Current operation */
39296c7658Sdan   sqlite3_value **apValue;        /* old.* and new.* values */
40296c7658Sdan };
41296c7658Sdan 
42296c7658Sdan /*
434fccf43aSdan ** Each session object maintains a set of the following structures, one
444fccf43aSdan ** for each table the session object is monitoring. The structures are
454fccf43aSdan ** stored in a linked list starting at sqlite3_session.pTable.
464fccf43aSdan **
474fccf43aSdan ** The keys of the SessionTable.aChange[] hash table are all rows that have
484fccf43aSdan ** been modified in any way since the session object was attached to the
494fccf43aSdan ** table.
504fccf43aSdan **
514fccf43aSdan ** The data associated with each hash-table entry is a structure containing
524fccf43aSdan ** a subset of the initial values that the modified row contained at the
534fccf43aSdan ** start of the session. Or no initial values if the row was inserted.
544fccf43aSdan */
554fccf43aSdan struct SessionTable {
564fccf43aSdan   SessionTable *pNext;
574fccf43aSdan   char *zName;                    /* Local name of table */
584fccf43aSdan   int nCol;                       /* Number of columns in table zName */
59e8d5648eSdan   const char **azCol;             /* Column names */
60e8d5648eSdan   u8 *abPK;                       /* Array of primary key flags */
61296c7658Sdan   int nEntry;                     /* Total number of entries in hash table */
624fccf43aSdan   int nChange;                    /* Size of apChange[] array */
634fccf43aSdan   SessionChange **apChange;       /* Hash table buckets */
644fccf43aSdan };
654fccf43aSdan 
664fccf43aSdan /*
674fccf43aSdan ** RECORD FORMAT:
684fccf43aSdan **
694fccf43aSdan ** The following record format is similar to (but not compatible with) that
704fccf43aSdan ** used in SQLite database files. This format is used as part of the
714fccf43aSdan ** change-set binary format, and so must be architecture independent.
724fccf43aSdan **
734fccf43aSdan ** Unlike the SQLite database record format, each field is self-contained -
744fccf43aSdan ** there is no separation of header and data. Each field begins with a
754fccf43aSdan ** single byte describing its type, as follows:
764fccf43aSdan **
774fccf43aSdan **       0x00: Undefined value.
784fccf43aSdan **       0x01: Integer value.
794fccf43aSdan **       0x02: Real value.
804fccf43aSdan **       0x03: Text value.
814fccf43aSdan **       0x04: Blob value.
824fccf43aSdan **       0x05: SQL NULL value.
834fccf43aSdan **
844fccf43aSdan ** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
854fccf43aSdan ** and so on in sqlite3.h. For undefined and NULL values, the field consists
864fccf43aSdan ** only of the single type byte. For other types of values, the type byte
874fccf43aSdan ** is followed by:
884fccf43aSdan **
894fccf43aSdan **   Text values:
904fccf43aSdan **     A varint containing the number of bytes in the value (encoded using
914fccf43aSdan **     UTF-8). Followed by a buffer containing the UTF-8 representation
924fccf43aSdan **     of the text value. There is no nul terminator.
934fccf43aSdan **
944fccf43aSdan **   Blob values:
954fccf43aSdan **     A varint containing the number of bytes in the value, followed by
964fccf43aSdan **     a buffer containing the value itself.
974fccf43aSdan **
984fccf43aSdan **   Integer values:
994fccf43aSdan **     An 8-byte big-endian integer value.
1004fccf43aSdan **
1014fccf43aSdan **   Real values:
1024fccf43aSdan **     An 8-byte big-endian IEEE 754-2008 real value.
1034fccf43aSdan **
1044fccf43aSdan ** Varint values are encoded in the same way as varints in the SQLite
1054fccf43aSdan ** record format.
1064fccf43aSdan **
1074fccf43aSdan ** CHANGESET FORMAT:
1084fccf43aSdan **
1094fccf43aSdan ** A changeset is a collection of DELETE, UPDATE and INSERT operations on
1104fccf43aSdan ** one or more tables. Operations on a single table are grouped together,
1114fccf43aSdan ** but may occur in any order (i.e. deletes, updates and inserts are all
1124fccf43aSdan ** mixed together).
1134fccf43aSdan **
1144fccf43aSdan ** Each group of changes begins with a table header:
1154fccf43aSdan **
1164fccf43aSdan **   1 byte: Constant 0x54 (capital 'T')
1174fccf43aSdan **   Varint: Big-endian integer set to the number of columns in the table.
1184fccf43aSdan **   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
1194fccf43aSdan **
1204fccf43aSdan ** Followed by one or more changes to the table.
1214fccf43aSdan **
1224fccf43aSdan **   1 byte: Either SQLITE_INSERT, UPDATE or DELETE.
1234fccf43aSdan **   old.* record: (delete and update only)
1244fccf43aSdan **   new.* record: (insert and update only)
1254fccf43aSdan */
1264fccf43aSdan 
1274fccf43aSdan /*
1284fccf43aSdan ** For each row modified during a session, there exists a single instance of
1294fccf43aSdan ** this structure stored in a SessionTable.aChange[] hash table.
1304fccf43aSdan */
1314fccf43aSdan struct SessionChange {
132e8d5648eSdan   int bInsert;                    /* True if row was inserted this session */
1334fccf43aSdan   int nRecord;                    /* Number of bytes in buffer aRecord[] */
1344fccf43aSdan   u8 *aRecord;                    /* Buffer containing old.* record */
1354fccf43aSdan   SessionChange *pNext;           /* For hash-table collisions */
1364fccf43aSdan };
1374fccf43aSdan 
138296c7658Sdan /*
139296c7658Sdan ** Instances of this structure are used to build strings or binary records.
140296c7658Sdan */
141296c7658Sdan struct SessionBuffer {
142296c7658Sdan   u8 *aBuf;                       /* Pointer to changeset buffer */
143296c7658Sdan   int nBuf;                       /* Size of buffer aBuf */
144296c7658Sdan   int nAlloc;                     /* Size of allocation containing aBuf */
145296c7658Sdan };
1464fccf43aSdan 
147296c7658Sdan /*
148296c7658Sdan ** Write a varint with value iVal into the buffer at aBuf. Return the
149296c7658Sdan ** number of bytes written.
150296c7658Sdan */
151296c7658Sdan static int sessionVarintPut(u8 *aBuf, int iVal){
152296c7658Sdan   return putVarint32(aBuf, iVal);
1534fccf43aSdan }
1544fccf43aSdan 
155296c7658Sdan /*
156296c7658Sdan ** Return the number of bytes required to store value iVal as a varint.
157296c7658Sdan */
158296c7658Sdan static int sessionVarintLen(int iVal){
159296c7658Sdan   return sqlite3VarintLen(iVal);
160296c7658Sdan }
161296c7658Sdan 
162296c7658Sdan /*
163296c7658Sdan ** Read a varint value from aBuf[] into *piVal. Return the number of
164296c7658Sdan ** bytes read.
165296c7658Sdan */
1664fccf43aSdan static int sessionVarintGet(u8 *aBuf, int *piVal){
167296c7658Sdan   return getVarint32(aBuf, *piVal);
1684fccf43aSdan }
1694fccf43aSdan 
170296c7658Sdan /*
171296c7658Sdan ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
172296c7658Sdan ** the value read.
173296c7658Sdan */
1744fccf43aSdan static sqlite3_int64 sessionGetI64(u8 *aRec){
1754fccf43aSdan   return (((sqlite3_int64)aRec[0]) << 56)
1764fccf43aSdan        + (((sqlite3_int64)aRec[1]) << 48)
1774fccf43aSdan        + (((sqlite3_int64)aRec[2]) << 40)
1784fccf43aSdan        + (((sqlite3_int64)aRec[3]) << 32)
1794fccf43aSdan        + (((sqlite3_int64)aRec[4]) << 24)
1804fccf43aSdan        + (((sqlite3_int64)aRec[5]) << 16)
1814fccf43aSdan        + (((sqlite3_int64)aRec[6]) <<  8)
1824fccf43aSdan        + (((sqlite3_int64)aRec[7]) <<  0);
1834fccf43aSdan }
1844fccf43aSdan 
1854fccf43aSdan /*
186296c7658Sdan ** Write a 64-bit big-endian integer value to the buffer aBuf[].
187296c7658Sdan */
188296c7658Sdan static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
189296c7658Sdan   aBuf[0] = (i>>56) & 0xFF;
190296c7658Sdan   aBuf[1] = (i>>48) & 0xFF;
191296c7658Sdan   aBuf[2] = (i>>40) & 0xFF;
192296c7658Sdan   aBuf[3] = (i>>32) & 0xFF;
193296c7658Sdan   aBuf[4] = (i>>24) & 0xFF;
194296c7658Sdan   aBuf[5] = (i>>16) & 0xFF;
195296c7658Sdan   aBuf[6] = (i>> 8) & 0xFF;
196296c7658Sdan   aBuf[7] = (i>> 0) & 0xFF;
197296c7658Sdan }
198296c7658Sdan 
199296c7658Sdan /*
2004fccf43aSdan ** This function is used to serialize the contents of value pValue (see
2014fccf43aSdan ** comment titled "RECORD FORMAT" above).
2024fccf43aSdan **
2034fccf43aSdan ** If it is non-NULL, the serialized form of the value is written to
2044fccf43aSdan ** buffer aBuf. *pnWrite is set to the number of bytes written before
2054fccf43aSdan ** returning. Or, if aBuf is NULL, the only thing this function does is
2064fccf43aSdan ** set *pnWrite.
2074fccf43aSdan **
2084fccf43aSdan ** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
2094fccf43aSdan ** within a call to sqlite3_value_text() (may fail if the db is utf-16))
2104fccf43aSdan ** SQLITE_NOMEM is returned.
2114fccf43aSdan */
2124fccf43aSdan static int sessionSerializeValue(
2134fccf43aSdan   u8 *aBuf,                       /* If non-NULL, write serialized value here */
2144fccf43aSdan   sqlite3_value *pValue,          /* Value to serialize */
2154fccf43aSdan   int *pnWrite                    /* IN/OUT: Increment by bytes written */
2164fccf43aSdan ){
217296c7658Sdan   int eType;                      /* Value type (SQLITE_NULL, TEXT etc.) */
218296c7658Sdan   int nByte;                      /* Size of serialized value in bytes */
2194fccf43aSdan 
2204fccf43aSdan   eType = sqlite3_value_type(pValue);
2214fccf43aSdan   if( aBuf ) aBuf[0] = eType;
2224fccf43aSdan 
2234fccf43aSdan   switch( eType ){
2244fccf43aSdan     case SQLITE_NULL:
2254fccf43aSdan       nByte = 1;
2264fccf43aSdan       break;
2274fccf43aSdan 
2284fccf43aSdan     case SQLITE_INTEGER:
2294fccf43aSdan     case SQLITE_FLOAT:
2304fccf43aSdan       if( aBuf ){
2314fccf43aSdan         /* TODO: SQLite does something special to deal with mixed-endian
2324fccf43aSdan         ** floating point values (e.g. ARM7). This code probably should
2334fccf43aSdan         ** too.  */
2344fccf43aSdan         u64 i;
2354fccf43aSdan         if( eType==SQLITE_INTEGER ){
2364fccf43aSdan           i = (u64)sqlite3_value_int64(pValue);
2374fccf43aSdan         }else{
2384fccf43aSdan           double r;
2394fccf43aSdan           assert( sizeof(double)==8 && sizeof(u64)==8 );
2404fccf43aSdan           r = sqlite3_value_double(pValue);
2414fccf43aSdan           memcpy(&i, &r, 8);
2424fccf43aSdan         }
243296c7658Sdan         sessionPutI64(&aBuf[1], i);
2444fccf43aSdan       }
2454fccf43aSdan       nByte = 9;
2464fccf43aSdan       break;
2474fccf43aSdan 
2484e895da1Sdan     default: {
2494fccf43aSdan       int n = sqlite3_value_bytes(pValue);
250296c7658Sdan       int nVarint = sessionVarintLen(n);
2514e895da1Sdan       assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
2524fccf43aSdan       if( aBuf ){
2534fccf43aSdan         sessionVarintPut(&aBuf[1], n);
2544fccf43aSdan         memcpy(&aBuf[nVarint + 1], eType==SQLITE_TEXT ?
2554fccf43aSdan             sqlite3_value_text(pValue) : sqlite3_value_blob(pValue), n
2564fccf43aSdan         );
2574fccf43aSdan       }
2584fccf43aSdan 
2594fccf43aSdan       nByte = 1 + nVarint + n;
2604fccf43aSdan       break;
2614fccf43aSdan     }
2624fccf43aSdan   }
2634fccf43aSdan 
2644fccf43aSdan   *pnWrite += nByte;
2654fccf43aSdan   return SQLITE_OK;
2664fccf43aSdan }
2674fccf43aSdan 
2684131639cSdan #define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
2694131639cSdan static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
270e8d5648eSdan   h = HASH_APPEND(h, i & 0xFFFFFFFF);
271e8d5648eSdan   return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
272e8d5648eSdan }
2734131639cSdan static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
274e8d5648eSdan   int i;
275e8d5648eSdan   for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
276e8d5648eSdan   return h;
277e8d5648eSdan }
278e8d5648eSdan 
2794fccf43aSdan /*
2804131639cSdan ** This function may only be called from within a pre-update callback.
2814131639cSdan ** It calculates a hash based on the primary key values of the old.* or
2824131639cSdan ** new.* row currently available. The value returned is guaranteed to
2834131639cSdan ** be less than pTab->nBucket.
2844fccf43aSdan */
2854131639cSdan static unsigned int sessionPreupdateHash(
286e8d5648eSdan   sqlite3 *db,                    /* Database handle */
287e8d5648eSdan   SessionTable *pTab,             /* Session table handle */
288e8d5648eSdan   int bNew,                       /* True to hash the new.* PK */
28927453faeSdan   int *piHash,                    /* OUT: Hash value */
29027453faeSdan   int *pbNullPK
291e8d5648eSdan ){
2924131639cSdan   unsigned int h = 0;             /* Hash value to return */
2934131639cSdan   int i;                          /* Used to iterate through columns */
294e8d5648eSdan 
29527453faeSdan   assert( *pbNullPK==0 );
296e8d5648eSdan   assert( pTab->nCol==sqlite3_preupdate_count(db) );
297e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
298e8d5648eSdan     if( pTab->abPK[i] ){
299e8d5648eSdan       int rc;
300e8d5648eSdan       int eType;
301e8d5648eSdan       sqlite3_value *pVal;
302e8d5648eSdan 
303e8d5648eSdan       if( bNew ){
304e8d5648eSdan         rc = sqlite3_preupdate_new(db, i, &pVal);
305e8d5648eSdan       }else{
306e8d5648eSdan         rc = sqlite3_preupdate_old(db, i, &pVal);
307e8d5648eSdan       }
30812ca0b56Sdan       if( rc!=SQLITE_OK ) return rc;
309e8d5648eSdan 
310e8d5648eSdan       eType = sqlite3_value_type(pVal);
311e8d5648eSdan       h = HASH_APPEND(h, eType);
312e8d5648eSdan       switch( eType ){
313e8d5648eSdan         case SQLITE_INTEGER:
314e8d5648eSdan         case SQLITE_FLOAT: {
315e8d5648eSdan           i64 iVal;
316e8d5648eSdan           if( eType==SQLITE_INTEGER ){
317e8d5648eSdan             iVal = sqlite3_value_int64(pVal);
318e8d5648eSdan           }else{
319e8d5648eSdan             double rVal = sqlite3_value_double(pVal);
320e8d5648eSdan             assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
321e8d5648eSdan             memcpy(&iVal, &rVal, 8);
322e8d5648eSdan           }
323e8d5648eSdan           h = sessionHashAppendI64(h, iVal);
324e8d5648eSdan           break;
325e8d5648eSdan         }
326e8d5648eSdan 
327e8d5648eSdan         case SQLITE_TEXT:
328e8d5648eSdan         case SQLITE_BLOB: {
329e8d5648eSdan           int n = sqlite3_value_bytes(pVal);
330e8d5648eSdan           const u8 *z = eType==SQLITE_TEXT ?
331e8d5648eSdan             sqlite3_value_text(pVal) : sqlite3_value_blob(pVal);
332e8d5648eSdan           h = sessionHashAppendBlob(h, n, z);
333e8d5648eSdan           break;
334e8d5648eSdan         }
33527453faeSdan 
33627453faeSdan         default:
33727453faeSdan           assert( eType==SQLITE_NULL );
33827453faeSdan           *pbNullPK = 1;
33927453faeSdan           return SQLITE_OK;
340e8d5648eSdan       }
341e8d5648eSdan     }
342e8d5648eSdan   }
343e8d5648eSdan 
344e8d5648eSdan   *piHash = (h % pTab->nChange);
345e8d5648eSdan   return SQLITE_OK;
346e8d5648eSdan }
347e8d5648eSdan 
3484131639cSdan /*
3494131639cSdan ** Based on the primary key values stored in change pChange, calculate a
3504131639cSdan ** hash key, assuming the has table has nBucket buckets. The hash keys
3514131639cSdan ** calculated by this function are compatible with those calculated by
3524131639cSdan ** sessionPreupdateHash().
3534131639cSdan */
3544131639cSdan static unsigned int sessionChangeHash(
3554131639cSdan   sqlite3 *db,                    /* Database handle */
3564131639cSdan   SessionTable *pTab,             /* Table handle */
3574131639cSdan   SessionChange *pChange,         /* Change handle */
3584131639cSdan   int nBucket                     /* Assume this many buckets in hash table */
359e8d5648eSdan ){
3604131639cSdan   unsigned int h = 0;             /* Value to return */
3614131639cSdan   int i;                          /* Used to iterate through columns */
3624131639cSdan   u8 *a = pChange->aRecord;       /* Used to iterate through change record */
363e8d5648eSdan 
364e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
365e8d5648eSdan     int eType = *a++;
366e8d5648eSdan     int isPK = pTab->abPK[i];
367e8d5648eSdan 
36827453faeSdan     /* It is not possible for eType to be SQLITE_NULL here. The session
36927453faeSdan     ** module does not record changes for rows with NULL values stored in
37027453faeSdan     ** primary key columns. */
37127453faeSdan     assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
37227453faeSdan          || eType==SQLITE_TEXT || eType==SQLITE_BLOB
37327453faeSdan     );
37427453faeSdan 
375e8d5648eSdan     if( isPK ) h = HASH_APPEND(h, eType);
37627453faeSdan     if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
37727453faeSdan       if( isPK ) h = sessionHashAppendI64(h, sessionGetI64(a));
378e8d5648eSdan       a += 8;
37927453faeSdan     }else{
380e8d5648eSdan       int n;
381e8d5648eSdan       a += sessionVarintGet(a, &n);
38227453faeSdan       if( isPK ) h = sessionHashAppendBlob(h, n, a);
383e8d5648eSdan       a += n;
384e8d5648eSdan     }
385e8d5648eSdan   }
386e8d5648eSdan   return (h % nBucket);
387e8d5648eSdan }
388e8d5648eSdan 
389e8d5648eSdan static int sessionPreupdateEqual(
390e8d5648eSdan   sqlite3 *db,
391e8d5648eSdan   SessionTable *pTab,
392e8d5648eSdan   SessionChange *pChange,
393e8d5648eSdan   int bNew,
394e8d5648eSdan   int *pbEqual
395e8d5648eSdan ){
396e8d5648eSdan   int i;
397e8d5648eSdan   u8 *a = pChange->aRecord;
398e8d5648eSdan 
399e8d5648eSdan   *pbEqual = 0;
400e8d5648eSdan 
401e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
402e8d5648eSdan     int eType = *a++;
403e8d5648eSdan     if( !pTab->abPK[i] ){
404e8d5648eSdan       switch( eType ){
405e8d5648eSdan         case SQLITE_INTEGER:
406e8d5648eSdan         case SQLITE_FLOAT:
407e8d5648eSdan           a += 8;
408e8d5648eSdan           break;
409e8d5648eSdan 
410e8d5648eSdan         case SQLITE_TEXT:
411e8d5648eSdan         case SQLITE_BLOB: {
412e8d5648eSdan           int n;
413e8d5648eSdan           a += sessionVarintGet(a, &n);
414e8d5648eSdan           a += n;
415e8d5648eSdan           break;
416e8d5648eSdan         }
417e8d5648eSdan       }
418e8d5648eSdan     }else{
419e8d5648eSdan       sqlite3_value *pVal;
420e8d5648eSdan       int rc;
421e8d5648eSdan       if( bNew ){
422e8d5648eSdan         rc = sqlite3_preupdate_new(db, i, &pVal);
423e8d5648eSdan       }else{
424e8d5648eSdan         rc = sqlite3_preupdate_old(db, i, &pVal);
425e8d5648eSdan       }
426e8d5648eSdan       if( rc!=SQLITE_OK || sqlite3_value_type(pVal)!=eType ) return rc;
427e8d5648eSdan 
42812ca0b56Sdan       /* A SessionChange object never has a NULL value in a PK column */
42912ca0b56Sdan       assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
43012ca0b56Sdan            || eType==SQLITE_BLOB    || eType==SQLITE_TEXT
43112ca0b56Sdan       );
43212ca0b56Sdan 
43312ca0b56Sdan       if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
434e8d5648eSdan         i64 iVal = sessionGetI64(a);
435e8d5648eSdan         a += 8;
436e8d5648eSdan         if( eType==SQLITE_INTEGER ){
437e8d5648eSdan           if( sqlite3_value_int64(pVal)!=iVal ) return SQLITE_OK;
438e8d5648eSdan         }else{
439e8d5648eSdan           double rVal;
440e8d5648eSdan           assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
441e8d5648eSdan           memcpy(&rVal, &iVal, 8);
442e8d5648eSdan           if( sqlite3_value_double(pVal)!=rVal ) return SQLITE_OK;
443e8d5648eSdan         }
44412ca0b56Sdan       }else{
445e8d5648eSdan         int n;
446e8d5648eSdan         const u8 *z;
447e8d5648eSdan         a += sessionVarintGet(a, &n);
448e8d5648eSdan         if( sqlite3_value_bytes(pVal)!=n ) return SQLITE_OK;
44912ca0b56Sdan         if( eType==SQLITE_TEXT ){
45012ca0b56Sdan           z = sqlite3_value_text(pVal);
45112ca0b56Sdan         }else{
45212ca0b56Sdan           z = sqlite3_value_blob(pVal);
45312ca0b56Sdan         }
454e8d5648eSdan         if( memcmp(a, z, n) ) return SQLITE_OK;
455e8d5648eSdan         a += n;
456e8d5648eSdan         break;
457e8d5648eSdan       }
458e8d5648eSdan     }
459e8d5648eSdan   }
460e8d5648eSdan 
461e8d5648eSdan   *pbEqual = 1;
462e8d5648eSdan   return SQLITE_OK;
4634fccf43aSdan }
4644fccf43aSdan 
4654fccf43aSdan /*
4664fccf43aSdan ** If required, grow the hash table used to store changes on table pTab
4674fccf43aSdan ** (part of the session pSession). If a fatal OOM error occurs, set the
4684fccf43aSdan ** session object to failed and return SQLITE_ERROR. Otherwise, return
4694fccf43aSdan ** SQLITE_OK.
4704fccf43aSdan **
4714fccf43aSdan ** It is possible that a non-fatal OOM error occurs in this function. In
4724fccf43aSdan ** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
4734fccf43aSdan ** Growing the hash table in this case is a performance optimization only,
4744fccf43aSdan ** it is not required for correct operation.
4754fccf43aSdan */
4764fccf43aSdan static int sessionGrowHash(sqlite3_session *pSession, SessionTable *pTab){
4774fccf43aSdan   if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
4784fccf43aSdan     int i;
4794fccf43aSdan     SessionChange **apNew;
4804fccf43aSdan     int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
4814fccf43aSdan 
4824fccf43aSdan     apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
4834fccf43aSdan     if( apNew==0 ){
4844fccf43aSdan       if( pTab->nChange==0 ){
4854fccf43aSdan         pSession->rc = SQLITE_NOMEM;
4864fccf43aSdan         return SQLITE_ERROR;
4874fccf43aSdan       }
4884fccf43aSdan       return SQLITE_OK;
4894fccf43aSdan     }
4904fccf43aSdan     memset(apNew, 0, sizeof(SessionChange *) * nNew);
4914fccf43aSdan 
4924fccf43aSdan     for(i=0; i<pTab->nChange; i++){
4934fccf43aSdan       SessionChange *p;
4944fccf43aSdan       SessionChange *pNext;
4954fccf43aSdan       for(p=pTab->apChange[i]; p; p=pNext){
496e8d5648eSdan         int iHash = sessionChangeHash(pSession->db, pTab, p, nNew);
4974fccf43aSdan         pNext = p->pNext;
4984fccf43aSdan         p->pNext = apNew[iHash];
4994fccf43aSdan         apNew[iHash] = p;
5004fccf43aSdan       }
5014fccf43aSdan     }
5024fccf43aSdan 
5034fccf43aSdan     sqlite3_free(pTab->apChange);
5044fccf43aSdan     pTab->nChange = nNew;
5054fccf43aSdan     pTab->apChange = apNew;
5064fccf43aSdan   }
5074fccf43aSdan 
5084fccf43aSdan   return SQLITE_OK;
5094fccf43aSdan }
5104fccf43aSdan 
511296c7658Sdan /*
512e8d5648eSdan ** This function queries the database for the names of the columns of table
513e8d5648eSdan ** zThis, in schema zDb. It is expected that the table has nCol columns. If
514e8d5648eSdan ** not, SQLITE_SCHEMA is returned and none of the output variables are
515e8d5648eSdan ** populated.
516e8d5648eSdan **
517e8d5648eSdan ** Otherwise, if it is not NULL, variable *pzTab is set to point to a
518e8d5648eSdan ** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
519e8d5648eSdan ** point to an array of pointers to column names. And *pabPK (again, if not
520e8d5648eSdan ** NULL) is set to point to an array of booleans - true if the corresponding
521e8d5648eSdan ** column is part of the primary key.
522e8d5648eSdan **
523e8d5648eSdan ** For example, if the table is declared as:
524e8d5648eSdan **
525e8d5648eSdan **     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
526e8d5648eSdan **
527e8d5648eSdan ** Then the three output variables are populated as follows:
528e8d5648eSdan **
529e8d5648eSdan **     *pzTab  = "tbl1"
530e8d5648eSdan **     *pazCol = {"w", "x", "y", "z"}
531e8d5648eSdan **     *pabPK  = {1, 0, 0, 1}
532e8d5648eSdan **
533e8d5648eSdan ** All returned buffers are part of the same single allocation, which must
534e8d5648eSdan ** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then
535e8d5648eSdan ** pointer *pazCol should be freed to release all memory. Otherwise, pointer
536e8d5648eSdan ** *pabPK. It is illegal for both pazCol and pabPK to be NULL.
537e8d5648eSdan */
538e8d5648eSdan static int sessionTableInfo(
539e8d5648eSdan   sqlite3 *db,                    /* Database connection */
540e8d5648eSdan   const char *zDb,                /* Name of attached database (e.g. "main") */
541e8d5648eSdan   const char *zThis,              /* Table name */
542e8d5648eSdan   int nCol,                       /* Expected number of columns */
543e8d5648eSdan   const char **pzTab,             /* OUT: Copy of zThis */
544e8d5648eSdan   const char ***pazCol,           /* OUT: Array of column names for table */
545e8d5648eSdan   u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
546e8d5648eSdan ){
547e8d5648eSdan   char *zPragma;
548e8d5648eSdan   sqlite3_stmt *pStmt;
549e8d5648eSdan   int rc;
550e8d5648eSdan   int nByte;
551e8d5648eSdan   int nDbCol = 0;
552e8d5648eSdan   int nThis;
553e8d5648eSdan   int i;
554e8d5648eSdan   u8 *pAlloc;
555*db04571cSdan   char **azCol = 0;
556e8d5648eSdan   u8 *abPK;
557e8d5648eSdan 
558*db04571cSdan   assert( pazCol && pabPK );
559e8d5648eSdan 
560e8d5648eSdan   nThis = strlen(zThis);
561e8d5648eSdan   zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
562e8d5648eSdan   if( !zPragma ) return SQLITE_NOMEM;
563e8d5648eSdan 
564e8d5648eSdan   rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
565e8d5648eSdan   sqlite3_free(zPragma);
566e8d5648eSdan   if( rc!=SQLITE_OK ) return rc;
567e8d5648eSdan 
568e8d5648eSdan   nByte = nThis + 1;
569e8d5648eSdan   while( SQLITE_ROW==sqlite3_step(pStmt) ){
570e8d5648eSdan     nByte += sqlite3_column_bytes(pStmt, 1);
571e8d5648eSdan     nDbCol++;
572e8d5648eSdan   }
573e8d5648eSdan   rc = sqlite3_reset(pStmt);
574e8d5648eSdan 
575e8d5648eSdan   if( nDbCol!=nCol ){
576e8d5648eSdan     rc = SQLITE_SCHEMA;
577e8d5648eSdan   }
578e8d5648eSdan   if( rc==SQLITE_OK ){
579e8d5648eSdan     nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
580e8d5648eSdan     pAlloc = sqlite3_malloc(nByte);
581e8d5648eSdan     if( pAlloc==0 ){
582e8d5648eSdan       rc = SQLITE_NOMEM;
583e8d5648eSdan     }
584e8d5648eSdan   }
585e8d5648eSdan   if( rc==SQLITE_OK ){
586e8d5648eSdan     azCol = (char **)pAlloc;
587e8d5648eSdan     pAlloc = (u8 *)&azCol[nCol];
588e8d5648eSdan     abPK = (u8 *)pAlloc;
589e8d5648eSdan     pAlloc = &abPK[nCol];
590e8d5648eSdan     if( pzTab ){
591e8d5648eSdan       memcpy(pAlloc, zThis, nThis+1);
592e8d5648eSdan       *pzTab = (char *)pAlloc;
593e8d5648eSdan       pAlloc += nThis+1;
594e8d5648eSdan     }
595e8d5648eSdan 
596e8d5648eSdan     i = 0;
597e8d5648eSdan     while( SQLITE_ROW==sqlite3_step(pStmt) ){
598e8d5648eSdan       int nName = sqlite3_column_bytes(pStmt, 1);
599e8d5648eSdan       const unsigned char *zName = sqlite3_column_text(pStmt, 1);
600e8d5648eSdan       if( zName==0 ) break;
601e8d5648eSdan       memcpy(pAlloc, zName, nName+1);
602e8d5648eSdan       azCol[i] = (char *)pAlloc;
603e8d5648eSdan       pAlloc += nName+1;
604*db04571cSdan       abPK[i] = sqlite3_column_int(pStmt, 5);
605e8d5648eSdan       i++;
606e8d5648eSdan     }
607e8d5648eSdan     rc = sqlite3_reset(pStmt);
608e8d5648eSdan 
609e8d5648eSdan   }
610e8d5648eSdan 
611e8d5648eSdan   /* If successful, populate the output variables. Otherwise, zero them and
612e8d5648eSdan   ** free any allocation made. An error code will be returned in this case.
613e8d5648eSdan   */
614e8d5648eSdan   if( rc==SQLITE_OK ){
615*db04571cSdan     *pazCol = (const char **)azCol;
616*db04571cSdan     *pabPK = abPK;
617e8d5648eSdan   }else{
618*db04571cSdan     *pazCol = 0;
619*db04571cSdan     *pabPK = 0;
620e8d5648eSdan     if( pzTab ) *pzTab = 0;
621*db04571cSdan     sqlite3_free(azCol);
622e8d5648eSdan   }
623e8d5648eSdan   sqlite3_finalize(pStmt);
624e8d5648eSdan   return rc;
625e8d5648eSdan }
626e8d5648eSdan 
627e8d5648eSdan /*
628296c7658Sdan ** This function is only called from within a pre-update handler for a
629296c7658Sdan ** write to table pTab, part of session pSession. If this is the first
630296c7658Sdan ** write to this table, set the SessionTable.nCol variable to the number
631296c7658Sdan ** of columns in the table.
632296c7658Sdan **
633296c7658Sdan ** Otherwise, if this is not the first time this table has been written
634296c7658Sdan ** to, check that the number of columns in the table has not changed. If
635296c7658Sdan ** it has not, return zero.
636296c7658Sdan **
637296c7658Sdan ** If the number of columns in the table has changed since the last write
638296c7658Sdan ** was recorded, set the session error-code to SQLITE_SCHEMA and return
639296c7658Sdan ** non-zero. Users are not allowed to change the number of columns in a table
640296c7658Sdan ** for which changes are being recorded by the session module. If they do so,
641296c7658Sdan ** it is an error.
642296c7658Sdan */
6434fccf43aSdan static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
6444fccf43aSdan   if( pTab->nCol==0 ){
645e8d5648eSdan     assert( pTab->azCol==0 || pTab->abPK==0 );
6464fccf43aSdan     pTab->nCol = sqlite3_preupdate_count(pSession->db);
647e8d5648eSdan     pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
648e8d5648eSdan         pTab->zName, pTab->nCol, 0, &pTab->azCol, &pTab->abPK
649e8d5648eSdan     );
650296c7658Sdan   }else if( pTab->nCol!=sqlite3_preupdate_count(pSession->db) ){
6514fccf43aSdan     pSession->rc = SQLITE_SCHEMA;
6524fccf43aSdan   }
653e8d5648eSdan   return pSession->rc;
654e8d5648eSdan }
655e8d5648eSdan 
656e8d5648eSdan static void sessionPreupdateOneChange(
657e8d5648eSdan   int op,
658e8d5648eSdan   sqlite3_session *pSession,
659e8d5648eSdan   SessionTable *pTab
660e8d5648eSdan ){
661e8d5648eSdan   sqlite3 *db = pSession->db;
662e8d5648eSdan   SessionChange *pChange;
663e8d5648eSdan   SessionChange *pC;
664e8d5648eSdan   int iHash;
66527453faeSdan   int bNullPk = 0;
666e8d5648eSdan   int rc = SQLITE_OK;
667e8d5648eSdan 
668e8d5648eSdan   if( pSession->rc ) return;
669e8d5648eSdan 
670e8d5648eSdan   /* Load table details if required */
671e8d5648eSdan   if( sessionInitTable(pSession, pTab) ) return;
672e8d5648eSdan 
673e8d5648eSdan   /* Grow the hash table if required */
674e8d5648eSdan   if( sessionGrowHash(pSession, pTab) ) return;
675e8d5648eSdan 
676e8d5648eSdan   /* Search the hash table for an existing entry for rowid=iKey2. If
677e8d5648eSdan   ** one is found, store a pointer to it in pChange and unlink it from
678e8d5648eSdan   ** the hash table. Otherwise, set pChange to NULL.
679e8d5648eSdan   */
68027453faeSdan   rc = sessionPreupdateHash(db, pTab, op==SQLITE_INSERT, &iHash, &bNullPk);
68127453faeSdan   if( bNullPk==0 ){
682e8d5648eSdan     for(pC=pTab->apChange[iHash]; rc==SQLITE_OK && pC; pC=pC->pNext){
683e8d5648eSdan       int bEqual;
684e8d5648eSdan       rc = sessionPreupdateEqual(db, pTab, pC, op==SQLITE_INSERT, &bEqual);
685e8d5648eSdan       if( bEqual ) break;
686e8d5648eSdan     }
687e8d5648eSdan     if( pC==0 ){
688e8d5648eSdan       /* Create a new change object containing all the old values (if
689e8d5648eSdan        ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
690e8d5648eSdan        ** values (if this is an INSERT). */
691e8d5648eSdan       int nByte;              /* Number of bytes to allocate */
692e8d5648eSdan       int i;                  /* Used to iterate through columns */
693e8d5648eSdan 
694e8d5648eSdan       pTab->nEntry++;
695e8d5648eSdan 
696e8d5648eSdan       /* Figure out how large an allocation is required */
697e8d5648eSdan       nByte = sizeof(SessionChange);
698e8d5648eSdan       for(i=0; i<pTab->nCol && rc==SQLITE_OK; i++){
699e8d5648eSdan         sqlite3_value *p = 0;
700e8d5648eSdan         if( op!=SQLITE_INSERT ){
701e8d5648eSdan           rc = sqlite3_preupdate_old(pSession->db, i, &p);
702e8d5648eSdan         }else if( 1 || pTab->abPK[i] ){
703e8d5648eSdan           rc = sqlite3_preupdate_new(pSession->db, i, &p);
704e8d5648eSdan         }
705e8d5648eSdan         if( p && rc==SQLITE_OK ){
706e8d5648eSdan           rc = sessionSerializeValue(0, p, &nByte);
707e8d5648eSdan         }
708e8d5648eSdan       }
709e8d5648eSdan 
710e8d5648eSdan       /* Allocate the change object */
711e8d5648eSdan       pChange = (SessionChange *)sqlite3_malloc(nByte);
712e8d5648eSdan       if( !pChange ){
713e8d5648eSdan         rc = SQLITE_NOMEM;
714e8d5648eSdan       }else{
715e8d5648eSdan         memset(pChange, 0, sizeof(SessionChange));
716e8d5648eSdan         pChange->aRecord = (u8 *)&pChange[1];
717e8d5648eSdan       }
718e8d5648eSdan 
719e8d5648eSdan       /* Populate the change object */
720e8d5648eSdan       nByte = 0;
721e8d5648eSdan       for(i=0; i<pTab->nCol && rc==SQLITE_OK; i++){
722e8d5648eSdan         sqlite3_value *p = 0;
723e8d5648eSdan         if( op!=SQLITE_INSERT ){
724e8d5648eSdan           rc = sqlite3_preupdate_old(pSession->db, i, &p);
725e8d5648eSdan         }else if( 1 || pTab->abPK[i] ){
726e8d5648eSdan           rc = sqlite3_preupdate_new(pSession->db, i, &p);
727e8d5648eSdan         }
728e8d5648eSdan         if( p && rc==SQLITE_OK ){
729e8d5648eSdan           rc = sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
730e8d5648eSdan         }
731e8d5648eSdan       }
73212ca0b56Sdan       if( rc==SQLITE_OK ){
733e8d5648eSdan         /* Add the change back to the hash-table */
73412ca0b56Sdan         pChange->nRecord = nByte;
735e8d5648eSdan         pChange->bInsert = (op==SQLITE_INSERT);
736e8d5648eSdan         pChange->pNext = pTab->apChange[iHash];
737e8d5648eSdan         pTab->apChange[iHash] = pChange;
73812ca0b56Sdan       }else{
73912ca0b56Sdan         sqlite3_free(pChange);
740e8d5648eSdan       }
741e8d5648eSdan     }
7424fccf43aSdan   }
74312ca0b56Sdan 
74412ca0b56Sdan   /* If an error has occurred, mark the session object as failed. */
74512ca0b56Sdan   if( rc!=SQLITE_OK ){
74612ca0b56Sdan     pSession->rc = rc;
74712ca0b56Sdan   }
74827453faeSdan }
7494fccf43aSdan 
7504fccf43aSdan /*
7514fccf43aSdan ** The 'pre-update' hook registered by this module with SQLite databases.
7524fccf43aSdan */
7534fccf43aSdan static void xPreUpdate(
7544fccf43aSdan   void *pCtx,                     /* Copy of third arg to preupdate_hook() */
7554fccf43aSdan   sqlite3 *db,                    /* Database handle */
7564fccf43aSdan   int op,                         /* SQLITE_UPDATE, DELETE or INSERT */
7574fccf43aSdan   char const *zDb,                /* Database name */
7584fccf43aSdan   char const *zName,              /* Table name */
7594fccf43aSdan   sqlite3_int64 iKey1,            /* Rowid of row about to be deleted/updated */
7604fccf43aSdan   sqlite3_int64 iKey2             /* New rowid value (for a rowid UPDATE) */
7614fccf43aSdan ){
7624fccf43aSdan   sqlite3_session *pSession;
7634fccf43aSdan   int nDb = strlen(zDb);
7644fccf43aSdan   int nName = strlen(zDb);
7654fccf43aSdan 
7664c220252Sdan   assert( sqlite3_mutex_held(db->mutex) );
7674c220252Sdan 
7684fccf43aSdan   for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
7694fccf43aSdan     SessionTable *pTab;
770296c7658Sdan 
771e8d5648eSdan     /* If this session is attached to a different database ("main", "temp"
772e8d5648eSdan     ** etc.), or if it is not currently enabled, there is nothing to do. Skip
773e8d5648eSdan     ** to the next session object attached to this database. */
774296c7658Sdan     if( pSession->bEnable==0 ) continue;
7754fccf43aSdan     if( pSession->rc ) continue;
7764fccf43aSdan     if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
777296c7658Sdan 
7784fccf43aSdan     for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
7794fccf43aSdan       if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ){
780e8d5648eSdan         sessionPreupdateOneChange(op, pSession, pTab);
781e8d5648eSdan         if( op==SQLITE_UPDATE ){
782e8d5648eSdan           sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
7834fccf43aSdan         }
7844fccf43aSdan         break;
7854fccf43aSdan       }
7864fccf43aSdan     }
7874fccf43aSdan   }
788296c7658Sdan }
7894fccf43aSdan 
7904fccf43aSdan /*
7914fccf43aSdan ** Create a session object. This session object will record changes to
7924fccf43aSdan ** database zDb attached to connection db.
7934fccf43aSdan */
7944fccf43aSdan int sqlite3session_create(
7954fccf43aSdan   sqlite3 *db,                    /* Database handle */
7964fccf43aSdan   const char *zDb,                /* Name of db (e.g. "main") */
7974fccf43aSdan   sqlite3_session **ppSession     /* OUT: New session object */
7984fccf43aSdan ){
799296c7658Sdan   sqlite3_session *pNew;          /* Newly allocated session object */
800296c7658Sdan   sqlite3_session *pOld;          /* Session object already attached to db */
8014fccf43aSdan   int nDb = strlen(zDb);          /* Length of zDb in bytes */
8024fccf43aSdan 
803296c7658Sdan   /* Zero the output value in case an error occurs. */
8044fccf43aSdan   *ppSession = 0;
8054fccf43aSdan 
8064fccf43aSdan   /* Allocate and populate the new session object. */
8074fccf43aSdan   pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
8084fccf43aSdan   if( !pNew ) return SQLITE_NOMEM;
8094fccf43aSdan   memset(pNew, 0, sizeof(sqlite3_session));
8104fccf43aSdan   pNew->db = db;
8114fccf43aSdan   pNew->zDb = (char *)&pNew[1];
812296c7658Sdan   pNew->bEnable = 1;
8134fccf43aSdan   memcpy(pNew->zDb, zDb, nDb+1);
8144fccf43aSdan 
8154fccf43aSdan   /* Add the new session object to the linked list of session objects
8164fccf43aSdan   ** attached to database handle $db. Do this under the cover of the db
8174fccf43aSdan   ** handle mutex.  */
8184fccf43aSdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
8194fccf43aSdan   pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
8204fccf43aSdan   pNew->pNext = pOld;
8214fccf43aSdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
8224fccf43aSdan 
8234fccf43aSdan   *ppSession = pNew;
8244fccf43aSdan   return SQLITE_OK;
8254fccf43aSdan }
8264fccf43aSdan 
8274fccf43aSdan /*
8284fccf43aSdan ** Delete a session object previously allocated using sqlite3session_create().
8294fccf43aSdan */
8304fccf43aSdan void sqlite3session_delete(sqlite3_session *pSession){
8314fccf43aSdan   sqlite3 *db = pSession->db;
8324fccf43aSdan   sqlite3_session *pHead;
8334fccf43aSdan   sqlite3_session **pp;
8344fccf43aSdan 
835296c7658Sdan   /* Unlink the session from the linked list of sessions attached to the
836296c7658Sdan   ** database handle. Hold the db mutex while doing so.  */
8374fccf43aSdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
8384fccf43aSdan   pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
8394fccf43aSdan   for(pp=&pHead; (*pp)!=pSession; pp=&((*pp)->pNext));
8404fccf43aSdan   *pp = (*pp)->pNext;
8414fccf43aSdan   if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void *)pHead);
8424fccf43aSdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
8434fccf43aSdan 
844296c7658Sdan   /* Delete all attached table objects. And the contents of their
845296c7658Sdan   ** associated hash-tables. */
8464fccf43aSdan   while( pSession->pTable ){
8474fccf43aSdan     int i;
8484fccf43aSdan     SessionTable *pTab = pSession->pTable;
8494fccf43aSdan     pSession->pTable = pTab->pNext;
8504fccf43aSdan     for(i=0; i<pTab->nChange; i++){
8514fccf43aSdan       SessionChange *p;
8524fccf43aSdan       SessionChange *pNext;
8534fccf43aSdan       for(p=pTab->apChange[i]; p; p=pNext){
8544fccf43aSdan         pNext = p->pNext;
8554fccf43aSdan         sqlite3_free(p);
8564fccf43aSdan       }
8574fccf43aSdan     }
858e8d5648eSdan     sqlite3_free(pTab->azCol);
8594fccf43aSdan     sqlite3_free(pTab->apChange);
8604fccf43aSdan     sqlite3_free(pTab);
8614fccf43aSdan   }
8624fccf43aSdan 
863296c7658Sdan   /* Free the session object itself. */
8644fccf43aSdan   sqlite3_free(pSession);
8654fccf43aSdan }
8664fccf43aSdan 
8674fccf43aSdan /*
8684fccf43aSdan ** Attach a table to a session. All subsequent changes made to the table
8694fccf43aSdan ** while the session object is enabled will be recorded.
8704fccf43aSdan **
8714fccf43aSdan ** Only tables that have a PRIMARY KEY defined may be attached. It does
8724fccf43aSdan ** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
8734fccf43aSdan ** or not.
8744fccf43aSdan */
8754fccf43aSdan int sqlite3session_attach(
8764fccf43aSdan   sqlite3_session *pSession,      /* Session object */
8774fccf43aSdan   const char *zName               /* Table name */
8784fccf43aSdan ){
879296c7658Sdan   SessionTable *pTab;             /* New table object (if required) */
880296c7658Sdan   int nName;                      /* Number of bytes in string zName */
8814c220252Sdan   int rc = SQLITE_OK;
8824c220252Sdan 
8834c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
8844fccf43aSdan 
8854fccf43aSdan   /* First search for an existing entry. If one is found, this call is
8864fccf43aSdan   ** a no-op. Return early. */
8874fccf43aSdan   nName = strlen(zName);
8884fccf43aSdan   for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
8894c220252Sdan     if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
8904fccf43aSdan   }
8914fccf43aSdan 
8924c220252Sdan   if( !pTab ){
8934fccf43aSdan     /* Allocate new SessionTable object. */
8944fccf43aSdan     pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
8954c220252Sdan     if( !pTab ){
8964c220252Sdan       rc = SQLITE_NOMEM;
8974c220252Sdan     }else{
8984fccf43aSdan       /* Populate the new SessionTable object and link it into the list. */
8994fccf43aSdan       memset(pTab, 0, sizeof(SessionTable));
9004fccf43aSdan       pTab->zName = (char *)&pTab[1];
9014fccf43aSdan       memcpy(pTab->zName, zName, nName+1);
9024fccf43aSdan       pTab->pNext = pSession->pTable;
9034fccf43aSdan       pSession->pTable = pTab;
9044c220252Sdan     }
9054c220252Sdan   }
9064fccf43aSdan 
9074c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
9084c220252Sdan   return rc;
9094fccf43aSdan }
9104fccf43aSdan 
911296c7658Sdan /*
912296c7658Sdan ** Ensure that there is room in the buffer to append nByte bytes of data.
913296c7658Sdan ** If not, use sqlite3_realloc() to grow the buffer so that there is.
914296c7658Sdan **
915296c7658Sdan ** If successful, return zero. Otherwise, if an OOM condition is encountered,
916296c7658Sdan ** set *pRc to SQLITE_NOMEM and return non-zero.
917296c7658Sdan */
9184fccf43aSdan static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
9194fccf43aSdan   if( p->nAlloc-p->nBuf<nByte ){
9204fccf43aSdan     u8 *aNew;
9214fccf43aSdan     int nNew = p->nAlloc ? p->nAlloc : 128;
9224fccf43aSdan     do {
9234fccf43aSdan       nNew = nNew*2;
9244fccf43aSdan     }while( nNew<(p->nAlloc+nByte) );
9254fccf43aSdan 
9264fccf43aSdan     aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
9274fccf43aSdan     if( 0==aNew ){
9284fccf43aSdan       *pRc = SQLITE_NOMEM;
9294fccf43aSdan       return 1;
9304fccf43aSdan     }
9314fccf43aSdan     p->aBuf = aNew;
9324fccf43aSdan     p->nAlloc = nNew;
9334fccf43aSdan   }
9344fccf43aSdan   return 0;
9354fccf43aSdan }
9364fccf43aSdan 
937296c7658Sdan /*
938296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
939296c7658Sdan ** called. Otherwise, append a single byte to the buffer.
940296c7658Sdan **
941296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
942296c7658Sdan ** returning.
943296c7658Sdan */
9444fccf43aSdan static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
9454fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 1, pRc) ){
9464fccf43aSdan     p->aBuf[p->nBuf++] = v;
9474fccf43aSdan   }
9484fccf43aSdan }
9494fccf43aSdan 
950296c7658Sdan /*
951296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
952296c7658Sdan ** called. Otherwise, append a single varint to the buffer.
953296c7658Sdan **
954296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
955296c7658Sdan ** returning.
956296c7658Sdan */
9574fccf43aSdan static void sessionAppendVarint(SessionBuffer *p, sqlite3_int64 v, int *pRc){
9584fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 9, pRc) ){
9594fccf43aSdan     p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
9604fccf43aSdan   }
9614fccf43aSdan }
9624fccf43aSdan 
963296c7658Sdan /*
964296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
965296c7658Sdan ** called. Otherwise, append a blob of data to the buffer.
966296c7658Sdan **
967296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
968296c7658Sdan ** returning.
969296c7658Sdan */
9704fccf43aSdan static void sessionAppendBlob(
9714fccf43aSdan   SessionBuffer *p,
9724fccf43aSdan   const u8 *aBlob,
9734fccf43aSdan   int nBlob,
9744fccf43aSdan   int *pRc
9754fccf43aSdan ){
9764fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nBlob, pRc) ){
9774fccf43aSdan     memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
9784fccf43aSdan     p->nBuf += nBlob;
9794fccf43aSdan   }
9804fccf43aSdan }
9814fccf43aSdan 
982296c7658Sdan /*
983296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
984296c7658Sdan ** called. Otherwise, append a string to the buffer. All bytes in the string
985296c7658Sdan ** up to (but not including) the nul-terminator are written to the buffer.
986296c7658Sdan **
987296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
988296c7658Sdan ** returning.
989296c7658Sdan */
990d5f0767cSdan static void sessionAppendStr(
991d5f0767cSdan   SessionBuffer *p,
992d5f0767cSdan   const char *zStr,
993d5f0767cSdan   int *pRc
994d5f0767cSdan ){
995d5f0767cSdan   int nStr = strlen(zStr);
996d5f0767cSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
997d5f0767cSdan     memcpy(&p->aBuf[p->nBuf], zStr, nStr);
998d5f0767cSdan     p->nBuf += nStr;
999d5f0767cSdan   }
1000d5f0767cSdan }
1001d5f0767cSdan 
1002296c7658Sdan /*
1003296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1004296c7658Sdan ** called. Otherwise, append the string representation of integer iVal
1005296c7658Sdan ** to the buffer. No nul-terminator is written.
1006296c7658Sdan **
1007296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
1008296c7658Sdan ** returning.
1009296c7658Sdan */
1010d5f0767cSdan static void sessionAppendInteger(
1011296c7658Sdan   SessionBuffer *p,               /* Buffer to append to */
1012296c7658Sdan   int iVal,                       /* Value to write the string rep. of */
1013296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
1014d5f0767cSdan ){
1015d5f0767cSdan   char aBuf[24];
1016d5f0767cSdan   sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
1017d5f0767cSdan   sessionAppendStr(p, aBuf, pRc);
1018d5f0767cSdan }
1019d5f0767cSdan 
1020296c7658Sdan /*
1021296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1022296c7658Sdan ** called. Otherwise, append the string zStr enclosed in quotes (") and
1023296c7658Sdan ** with any embedded quote characters escaped to the buffer. No
1024296c7658Sdan ** nul-terminator byte is written.
1025296c7658Sdan **
1026296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
1027296c7658Sdan ** returning.
1028296c7658Sdan */
1029d5f0767cSdan static void sessionAppendIdent(
1030296c7658Sdan   SessionBuffer *p,               /* Buffer to a append to */
1031296c7658Sdan   const char *zStr,               /* String to quote, escape and append */
1032296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
1033d5f0767cSdan ){
1034d5f0767cSdan   int nStr = strlen(zStr)*2 + 2 + 1;
1035d5f0767cSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
1036d5f0767cSdan     char *zOut = (char *)&p->aBuf[p->nBuf];
1037d5f0767cSdan     const char *zIn = zStr;
1038d5f0767cSdan     *zOut++ = '"';
1039d5f0767cSdan     while( *zIn ){
1040d5f0767cSdan       if( *zIn=='"' ) *zOut++ = '"';
1041d5f0767cSdan       *zOut++ = *(zIn++);
1042d5f0767cSdan     }
1043d5f0767cSdan     *zOut++ = '"';
1044d5f0767cSdan     p->nBuf = ((u8 *)zOut - p->aBuf);
1045d5f0767cSdan   }
1046d5f0767cSdan }
1047d5f0767cSdan 
1048296c7658Sdan /*
1049296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1050296c7658Sdan ** called. Otherwse, it appends the serialized version of the value stored
1051296c7658Sdan ** in column iCol of the row that SQL statement pStmt currently points
1052296c7658Sdan ** to to the buffer.
1053296c7658Sdan */
10544fccf43aSdan static void sessionAppendCol(
1055296c7658Sdan   SessionBuffer *p,               /* Buffer to append to */
1056296c7658Sdan   sqlite3_stmt *pStmt,            /* Handle pointing to row containing value */
1057296c7658Sdan   int iCol,                       /* Column to read value from */
1058296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
10594fccf43aSdan ){
10604fccf43aSdan   if( *pRc==SQLITE_OK ){
10614fccf43aSdan     int eType = sqlite3_column_type(pStmt, iCol);
10624fccf43aSdan     sessionAppendByte(p, (u8)eType, pRc);
10634fccf43aSdan     if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
10644fccf43aSdan       sqlite3_int64 i;
10654fccf43aSdan       u8 aBuf[8];
10664fccf43aSdan       if( eType==SQLITE_INTEGER ){
10674fccf43aSdan         i = sqlite3_column_int64(pStmt, iCol);
10684fccf43aSdan       }else{
10694fccf43aSdan         double r = sqlite3_column_double(pStmt, iCol);
10704fccf43aSdan         memcpy(&i, &r, 8);
10714fccf43aSdan       }
1072296c7658Sdan       sessionPutI64(aBuf, i);
10734fccf43aSdan       sessionAppendBlob(p, aBuf, 8, pRc);
10744fccf43aSdan     }
10754fccf43aSdan     if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
10764fccf43aSdan       int nByte = sqlite3_column_bytes(pStmt, iCol);
10774fccf43aSdan       sessionAppendVarint(p, nByte, pRc);
10784fccf43aSdan       sessionAppendBlob(p, eType==SQLITE_BLOB ?
10794fccf43aSdan         sqlite3_column_blob(pStmt, iCol) : sqlite3_column_text(pStmt, iCol),
10804fccf43aSdan         nByte, pRc
10814fccf43aSdan       );
10824fccf43aSdan     }
10834fccf43aSdan   }
10844fccf43aSdan }
10854fccf43aSdan 
1086296c7658Sdan /*
1087296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1088296c7658Sdan ** called.
1089296c7658Sdan **
1090296c7658Sdan ** Otherwse, if *pRc is SQLITE_OK, then it appends an update change to
1091296c7658Sdan ** the buffer (see the comments under "CHANGESET FORMAT" at the top of the
1092296c7658Sdan ** file). An update change consists of:
1093296c7658Sdan **
1094296c7658Sdan **   1 byte:  SQLITE_UPDATE (0x17)
1095296c7658Sdan **   n bytes: old.* record (see RECORD FORMAT)
1096296c7658Sdan **   m bytes: new.* record (see RECORD FORMAT)
1097296c7658Sdan **
1098296c7658Sdan ** The SessionChange object passed as the third argument contains the
1099296c7658Sdan ** values that were stored in the row when the session began (the old.*
1100296c7658Sdan ** values). The statement handle passed as the second argument points
1101296c7658Sdan ** at the current version of the row (the new.* values).
1102296c7658Sdan **
1103296c7658Sdan ** If all of the old.* values are equal to their corresponding new.* value
1104296c7658Sdan ** (i.e. nothing has changed), then no data at all is appended to the buffer.
1105296c7658Sdan **
1106296c7658Sdan ** Otherwise, the old.* record contains all primary key values and the
1107296c7658Sdan ** original values of any fields that have been modified. The new.* record
1108296c7658Sdan ** contains the new values of only those fields that have been modified.
1109296c7658Sdan */
11104fccf43aSdan static void sessionAppendUpdate(
1111296c7658Sdan   SessionBuffer *pBuf,            /* Buffer to append to */
1112296c7658Sdan   sqlite3_stmt *pStmt,            /* Statement handle pointing at new row */
1113296c7658Sdan   SessionChange *p,               /* Object containing old values */
1114296c7658Sdan   u8 *abPK,                       /* Boolean array - true for PK columns */
1115296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
11164fccf43aSdan ){
11174fccf43aSdan   if( *pRc==SQLITE_OK ){
1118296c7658Sdan     SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
1119296c7658Sdan     int bNoop = 1;                /* Set to zero if any values are modified */
11201f34f8ccSdan     int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
1121296c7658Sdan     int i;                        /* Used to iterate through columns */
1122296c7658Sdan     u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */
1123296c7658Sdan 
11244fccf43aSdan     sessionAppendByte(pBuf, SQLITE_UPDATE, pRc);
11254fccf43aSdan     for(i=0; i<sqlite3_column_count(pStmt); i++){
112637f133ecSdan       int bChanged = 0;
11274fccf43aSdan       int nAdvance;
11284fccf43aSdan       int eType = *pCsr;
11294fccf43aSdan       switch( eType ){
11304fccf43aSdan         case SQLITE_NULL:
11314fccf43aSdan           nAdvance = 1;
11324fccf43aSdan           if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
113337f133ecSdan             bChanged = 1;
11344fccf43aSdan           }
11354fccf43aSdan           break;
11364fccf43aSdan 
11374fccf43aSdan         case SQLITE_FLOAT:
11384fccf43aSdan         case SQLITE_INTEGER: {
11394fccf43aSdan           nAdvance = 9;
11404fccf43aSdan           if( eType==sqlite3_column_type(pStmt, i) ){
11414fccf43aSdan             sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
11424fccf43aSdan             if( eType==SQLITE_INTEGER ){
11434fccf43aSdan               if( iVal==sqlite3_column_int64(pStmt, i) ) break;
11444fccf43aSdan             }else{
11454fccf43aSdan               double dVal;
11464fccf43aSdan               memcpy(&dVal, &iVal, 8);
11474fccf43aSdan               if( dVal==sqlite3_column_double(pStmt, i) ) break;
11484fccf43aSdan             }
11494fccf43aSdan           }
115037f133ecSdan           bChanged = 1;
11514fccf43aSdan           break;
11524fccf43aSdan         }
11534fccf43aSdan 
11544fccf43aSdan         case SQLITE_TEXT:
11554fccf43aSdan         case SQLITE_BLOB: {
11564fccf43aSdan           int nByte;
11574fccf43aSdan           int nHdr = 1 + sessionVarintGet(&pCsr[1], &nByte);
11584fccf43aSdan           nAdvance = nHdr + nByte;
11594fccf43aSdan           if( eType==sqlite3_column_type(pStmt, i)
11604fccf43aSdan            && nByte==sqlite3_column_bytes(pStmt, i)
11614fccf43aSdan            && 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), nByte)
11624fccf43aSdan           ){
11634fccf43aSdan             break;
11644fccf43aSdan           }
116537f133ecSdan           bChanged = 1;
11664fccf43aSdan         }
11674fccf43aSdan       }
11684fccf43aSdan 
116937f133ecSdan       if( bChanged || abPK[i] ){
117037f133ecSdan         sessionAppendBlob(pBuf, pCsr, nAdvance, pRc);
11714fccf43aSdan       }else{
117237f133ecSdan         sessionAppendByte(pBuf, 0, pRc);
117337f133ecSdan       }
117437f133ecSdan 
117537f133ecSdan       if( bChanged ){
11764fccf43aSdan         sessionAppendCol(&buf2, pStmt, i, pRc);
11774fccf43aSdan         bNoop = 0;
117837f133ecSdan       }else{
117937f133ecSdan         sessionAppendByte(&buf2, 0, pRc);
11804fccf43aSdan       }
118137f133ecSdan 
11824fccf43aSdan       pCsr += nAdvance;
11834fccf43aSdan     }
11844fccf43aSdan 
11854fccf43aSdan     if( bNoop ){
11861f34f8ccSdan       pBuf->nBuf = nRewind;
11874fccf43aSdan     }else{
11884fccf43aSdan       sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, pRc);
11894fccf43aSdan     }
11901f34f8ccSdan     sqlite3_free(buf2.aBuf);
11914fccf43aSdan   }
1192d5f0767cSdan }
11934fccf43aSdan 
1194e8d5648eSdan static int sessionSelectStmt(
1195e8d5648eSdan   sqlite3 *db,                    /* Database handle */
1196d7fb7d24Sdan   const char *zDb,                /* Database name */
1197e8d5648eSdan   const char *zTab,               /* Table name */
1198e8d5648eSdan   int nCol,
1199e8d5648eSdan   const char **azCol,
1200e8d5648eSdan   u8 *abPK,
1201e8d5648eSdan   sqlite3_stmt **ppStmt
1202d5f0767cSdan ){
1203e8d5648eSdan   int rc = SQLITE_OK;
1204d5f0767cSdan   int i;
1205e8d5648eSdan   const char *zSep = "";
1206e8d5648eSdan   SessionBuffer buf = {0, 0, 0};
1207d5f0767cSdan 
1208e8d5648eSdan   sessionAppendStr(&buf, "SELECT * FROM ", &rc);
1209d7fb7d24Sdan   sessionAppendIdent(&buf, zDb, &rc);
1210d7fb7d24Sdan   sessionAppendStr(&buf, ".", &rc);
1211e8d5648eSdan   sessionAppendIdent(&buf, zTab, &rc);
1212e8d5648eSdan   sessionAppendStr(&buf, " WHERE ", &rc);
1213e8d5648eSdan   for(i=0; i<nCol; i++){
1214e8d5648eSdan     if( abPK[i] ){
1215e8d5648eSdan       sessionAppendStr(&buf, zSep, &rc);
1216e8d5648eSdan       sessionAppendIdent(&buf, azCol[i], &rc);
1217e8d5648eSdan       sessionAppendStr(&buf, " = ?", &rc);
1218e8d5648eSdan       sessionAppendInteger(&buf, i+1, &rc);
1219e8d5648eSdan       zSep = " AND ";
1220d5f0767cSdan     }
1221d5f0767cSdan   }
1222d5f0767cSdan   if( rc==SQLITE_OK ){
1223e8d5648eSdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0);
1224d5f0767cSdan   }
1225e8d5648eSdan   sqlite3_free(buf.aBuf);
1226e8d5648eSdan   return rc;
1227d5f0767cSdan }
1228d5f0767cSdan 
1229e8d5648eSdan static int sessionSelectBind(
1230e8d5648eSdan   sqlite3_stmt *pSelect,
1231e8d5648eSdan   int nCol,
1232e8d5648eSdan   u8 *abPK,
1233e8d5648eSdan   u8 *aRecord,
1234e8d5648eSdan   int nRecord
1235e8d5648eSdan ){
1236e8d5648eSdan   int i;
1237e8d5648eSdan   int rc = SQLITE_OK;
1238e8d5648eSdan   u8 *a = aRecord;
1239d5f0767cSdan 
1240e8d5648eSdan   for(i=0; i<nCol && rc==SQLITE_OK; i++){
1241e8d5648eSdan     int eType = *a++;
1242e8d5648eSdan 
1243e8d5648eSdan     switch( eType ){
1244e8d5648eSdan       case SQLITE_NULL:
1245e8d5648eSdan         if( abPK[i] ) rc = sqlite3_bind_null(pSelect, i+1);
1246e8d5648eSdan         break;
1247e8d5648eSdan 
1248e8d5648eSdan       case SQLITE_INTEGER: {
1249e8d5648eSdan         if( abPK[i] ){
1250e8d5648eSdan           i64 iVal = sessionGetI64(a);
1251e8d5648eSdan           rc = sqlite3_bind_int64(pSelect, i+1, iVal);
1252e8d5648eSdan         }
1253e8d5648eSdan         a += 8;
1254e8d5648eSdan         break;
1255d5f0767cSdan       }
1256296c7658Sdan 
1257e8d5648eSdan       case SQLITE_FLOAT: {
1258e8d5648eSdan         if( abPK[i] ){
1259e8d5648eSdan           double rVal;
1260e8d5648eSdan           i64 iVal = sessionGetI64(a);
1261e8d5648eSdan           memcpy(&rVal, &iVal, 8);
12624e895da1Sdan           rc = sqlite3_bind_double(pSelect, i+1, rVal);
1263d5f0767cSdan         }
1264e8d5648eSdan         a += 8;
1265e8d5648eSdan         break;
1266e8d5648eSdan       }
1267e8d5648eSdan 
1268e8d5648eSdan       case SQLITE_TEXT: {
1269e8d5648eSdan         int n;
1270e8d5648eSdan         a += sessionVarintGet(a, &n);
1271e8d5648eSdan         if( abPK[i] ){
1272e8d5648eSdan           rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
1273e8d5648eSdan         }
1274e8d5648eSdan         a += n;
1275e8d5648eSdan         break;
1276e8d5648eSdan       }
1277e8d5648eSdan 
1278e8d5648eSdan       case SQLITE_BLOB: {
1279e8d5648eSdan         int n;
1280e8d5648eSdan         a += sessionVarintGet(a, &n);
1281e8d5648eSdan         if( abPK[i] ){
1282e8d5648eSdan           rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
1283e8d5648eSdan         }
1284e8d5648eSdan         a += n;
1285e8d5648eSdan         break;
1286e8d5648eSdan       }
1287e8d5648eSdan     }
1288e8d5648eSdan   }
1289e8d5648eSdan 
1290d5f0767cSdan   return rc;
12914fccf43aSdan }
12924fccf43aSdan 
12934fccf43aSdan /*
12944fccf43aSdan ** Obtain a changeset object containing all changes recorded by the
12954fccf43aSdan ** session object passed as the first argument.
12964fccf43aSdan **
12974fccf43aSdan ** It is the responsibility of the caller to eventually free the buffer
12984fccf43aSdan ** using sqlite3_free().
12994fccf43aSdan */
13004fccf43aSdan int sqlite3session_changeset(
13014fccf43aSdan   sqlite3_session *pSession,      /* Session object */
13024fccf43aSdan   int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
13034fccf43aSdan   void **ppChangeset              /* OUT: Buffer containing changeset */
13044fccf43aSdan ){
1305296c7658Sdan   sqlite3 *db = pSession->db;     /* Source database handle */
1306296c7658Sdan   SessionTable *pTab;             /* Used to iterate through attached tables */
1307296c7658Sdan   SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
1308296c7658Sdan   int rc;                         /* Return code */
13094fccf43aSdan 
13104c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
13114c220252Sdan 
1312296c7658Sdan   /* Zero the output variables in case an error occurs. If this session
1313296c7658Sdan   ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
1314296c7658Sdan   ** this call will be a no-op.  */
13154fccf43aSdan   *pnChangeset = 0;
13164fccf43aSdan   *ppChangeset = 0;
13174fccf43aSdan   rc = pSession->rc;
13184fccf43aSdan 
13194fccf43aSdan   for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
13204fccf43aSdan     if( pTab->nEntry ){
1321d7fb7d24Sdan       const char *zName = pTab->zName;
1322e8d5648eSdan       int nCol = pTab->nCol;      /* Local copy of member variable */
1323e8d5648eSdan       u8 *abPK = pTab->abPK;      /* Local copy of member variable */
13241f34f8ccSdan       int i;                      /* Used to iterate through hash buckets */
13251f34f8ccSdan       sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
13261f34f8ccSdan       int nRewind = buf.nBuf;     /* Initial size of write buffer */
13271f34f8ccSdan       int nNoop;                  /* Size of buffer after writing tbl header */
13284fccf43aSdan 
13294fccf43aSdan       /* Write a table header */
13304fccf43aSdan       sessionAppendByte(&buf, 'T', &rc);
1331e8d5648eSdan       sessionAppendVarint(&buf, nCol, &rc);
1332d7fb7d24Sdan       sessionAppendBlob(&buf, (u8 *)zName, strlen(zName)+1, &rc);
13334fccf43aSdan 
13344fccf43aSdan       /* Build and compile a statement to execute: */
13354fccf43aSdan       if( rc==SQLITE_OK ){
1336d7fb7d24Sdan         rc = sessionSelectStmt(
1337d7fb7d24Sdan             db, pSession->zDb, zName, nCol, pTab->azCol, abPK, &pSel);
13384fccf43aSdan       }
13394fccf43aSdan 
13401f34f8ccSdan       if( rc==SQLITE_OK && nCol!=sqlite3_column_count(pSel) ){
13414fccf43aSdan         rc = SQLITE_SCHEMA;
13424fccf43aSdan       }
13434fccf43aSdan 
13441f34f8ccSdan       nNoop = buf.nBuf;
134512ca0b56Sdan       for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
1346e8d5648eSdan         SessionChange *p;         /* Used to iterate through changes */
1347e8d5648eSdan 
13484fccf43aSdan         for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
13491f34f8ccSdan           rc = sessionSelectBind(pSel, nCol, abPK, p->aRecord, p->nRecord);
1350e8d5648eSdan           if( rc==SQLITE_OK ){
13511f34f8ccSdan             if( sqlite3_step(pSel)==SQLITE_ROW ){
13524fccf43aSdan               int iCol;
1353e8d5648eSdan               if( p->bInsert ){
13544fccf43aSdan                 sessionAppendByte(&buf, SQLITE_INSERT, &rc);
1355e8d5648eSdan                 for(iCol=0; iCol<nCol; iCol++){
13561f34f8ccSdan                   sessionAppendCol(&buf, pSel, iCol, &rc);
13574fccf43aSdan                 }
1358e8d5648eSdan               }else{
13591f34f8ccSdan                 sessionAppendUpdate(&buf, pSel, p, abPK, &rc);
13604fccf43aSdan               }
1361e8d5648eSdan             }else if( !p->bInsert ){
13624fccf43aSdan               /* A DELETE change */
13634fccf43aSdan               sessionAppendByte(&buf, SQLITE_DELETE, &rc);
13644fccf43aSdan               sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
13654fccf43aSdan             }
136612ca0b56Sdan             if( rc==SQLITE_OK ){
13671f34f8ccSdan               rc = sqlite3_reset(pSel);
13684fccf43aSdan             }
13694fccf43aSdan           }
1370e8d5648eSdan         }
137112ca0b56Sdan       }
13724fccf43aSdan 
13731f34f8ccSdan       sqlite3_finalize(pSel);
13741f34f8ccSdan       if( buf.nBuf==nNoop ){
13754fccf43aSdan         buf.nBuf = nRewind;
13764fccf43aSdan       }
13774fccf43aSdan     }
13784fccf43aSdan   }
13794fccf43aSdan 
13804fccf43aSdan   if( rc==SQLITE_OK ){
13814fccf43aSdan     *pnChangeset = buf.nBuf;
13824fccf43aSdan     *ppChangeset = buf.aBuf;
13834fccf43aSdan   }else{
13844fccf43aSdan     sqlite3_free(buf.aBuf);
13854fccf43aSdan   }
13864c220252Sdan 
13874c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
13884fccf43aSdan   return rc;
13894fccf43aSdan }
13904fccf43aSdan 
1391296c7658Sdan /*
1392296c7658Sdan ** Enable or disable the session object passed as the first argument.
1393296c7658Sdan */
13944fccf43aSdan int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
13954c220252Sdan   int ret;
13964c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
1397296c7658Sdan   if( bEnable>=0 ){
1398296c7658Sdan     pSession->bEnable = bEnable;
13994fccf43aSdan   }
14004c220252Sdan   ret = pSession->bEnable;
14014c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
14024c220252Sdan   return ret;
1403296c7658Sdan }
14044fccf43aSdan 
14054fccf43aSdan /*
14064fccf43aSdan ** Create an iterator used to iterate through the contents of a changeset.
14074fccf43aSdan */
14084fccf43aSdan int sqlite3changeset_start(
1409296c7658Sdan   sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
1410296c7658Sdan   int nChangeset,                 /* Size of buffer pChangeset in bytes */
1411296c7658Sdan   void *pChangeset                /* Pointer to buffer containing changeset */
14124fccf43aSdan ){
14134fccf43aSdan   sqlite3_changeset_iter *pRet;   /* Iterator to return */
14144fccf43aSdan   int nByte;                      /* Number of bytes to allocate for iterator */
14154fccf43aSdan 
1416296c7658Sdan   /* Zero the output variable in case an error occurs. */
1417296c7658Sdan   *pp = 0;
14184fccf43aSdan 
1419296c7658Sdan   /* Allocate and initialize the iterator structure. */
14204fccf43aSdan   nByte = sizeof(sqlite3_changeset_iter);
14214fccf43aSdan   pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
14224fccf43aSdan   if( !pRet ) return SQLITE_NOMEM;
14234fccf43aSdan   memset(pRet, 0, sizeof(sqlite3_changeset_iter));
14244fccf43aSdan   pRet->aChangeset = (u8 *)pChangeset;
14254fccf43aSdan   pRet->nChangeset = nChangeset;
14264fccf43aSdan   pRet->pNext = pRet->aChangeset;
14274fccf43aSdan 
1428296c7658Sdan   /* Populate the output variable and return success. */
1429296c7658Sdan   *pp = pRet;
14304fccf43aSdan   return SQLITE_OK;
14314fccf43aSdan }
14324fccf43aSdan 
1433296c7658Sdan /*
1434296c7658Sdan ** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
1435296c7658Sdan ** for details.
1436296c7658Sdan **
1437296c7658Sdan ** When this function is called, *paChange points to the start of the record
1438296c7658Sdan ** to deserialize. Assuming no error occurs, *paChange is set to point to
1439296c7658Sdan ** one byte after the end of the same record before this function returns.
1440296c7658Sdan **
1441296c7658Sdan ** If successful, each element of the apOut[] array (allocated by the caller)
1442296c7658Sdan ** is set to point to an sqlite3_value object containing the value read
1443296c7658Sdan ** from the corresponding position in the record. If that value is not
1444296c7658Sdan ** included in the record (i.e. because the record is part of an UPDATE change
1445296c7658Sdan ** and the field was not modified), the corresponding element of apOut[] is
1446296c7658Sdan ** set to NULL.
1447296c7658Sdan **
1448296c7658Sdan ** It is the responsibility of the caller to free all sqlite_value structures
1449296c7658Sdan ** using sqlite3_free().
1450296c7658Sdan **
1451296c7658Sdan ** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
1452296c7658Sdan ** The apOut[] array may have been partially populated in this case.
1453296c7658Sdan */
14544fccf43aSdan static int sessionReadRecord(
14554fccf43aSdan   u8 **paChange,                  /* IN/OUT: Pointer to binary record */
14564fccf43aSdan   int nCol,                       /* Number of values in record */
14574fccf43aSdan   sqlite3_value **apOut           /* Write values to this array */
14584fccf43aSdan ){
1459296c7658Sdan   int i;                          /* Used to iterate through columns */
1460296c7658Sdan   u8 *aRec = *paChange;           /* Cursor for the serialized record */
14614fccf43aSdan 
14624fccf43aSdan   for(i=0; i<nCol; i++){
1463296c7658Sdan     int eType = *aRec++;          /* Type of value (SQLITE_NULL, TEXT etc.) */
146491ddd559Sdan     assert( !apOut || apOut[i]==0 );
14654fccf43aSdan     if( eType ){
146691ddd559Sdan       if( apOut ){
14674fccf43aSdan         apOut[i] = sqlite3ValueNew(0);
14684fccf43aSdan         if( !apOut[i] ) return SQLITE_NOMEM;
146991ddd559Sdan       }
14704fccf43aSdan 
14714fccf43aSdan       if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
14724fccf43aSdan         int nByte;
14734fccf43aSdan         int enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
14744fccf43aSdan         aRec += sessionVarintGet(aRec, &nByte);
147591ddd559Sdan         if( apOut ){
14764fccf43aSdan           sqlite3ValueSetStr(apOut[i], nByte, aRec, enc, SQLITE_STATIC);
147791ddd559Sdan         }
14784fccf43aSdan         aRec += nByte;
14794fccf43aSdan       }
14804fccf43aSdan       if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
148191ddd559Sdan         if( apOut ){
14824fccf43aSdan           sqlite3_int64 v = sessionGetI64(aRec);
14834fccf43aSdan           if( eType==SQLITE_INTEGER ){
14844fccf43aSdan             sqlite3VdbeMemSetInt64(apOut[i], v);
14854fccf43aSdan           }else{
14864fccf43aSdan             double d;
14874e895da1Sdan             memcpy(&d, &v, 8);
14884fccf43aSdan             sqlite3VdbeMemSetDouble(apOut[i], d);
14894fccf43aSdan           }
14904fccf43aSdan         }
149191ddd559Sdan         aRec += 8;
149291ddd559Sdan       }
14934fccf43aSdan     }
14944fccf43aSdan   }
14954fccf43aSdan 
14964fccf43aSdan   *paChange = aRec;
14974fccf43aSdan   return SQLITE_OK;
14984fccf43aSdan }
14994fccf43aSdan 
15004fccf43aSdan /*
15014fccf43aSdan ** Advance an iterator created by sqlite3changeset_start() to the next
15024fccf43aSdan ** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
15034fccf43aSdan ** or SQLITE_CORRUPT.
15044fccf43aSdan **
15054fccf43aSdan ** This function may not be called on iterators passed to a conflict handler
15064fccf43aSdan ** callback by changeset_apply().
15074fccf43aSdan */
15084fccf43aSdan int sqlite3changeset_next(sqlite3_changeset_iter *p){
15094fccf43aSdan   u8 *aChange;
15104fccf43aSdan   int i;
15114fccf43aSdan   u8 c;
15124fccf43aSdan 
1513296c7658Sdan   /* If the iterator is in the error-state, return immediately. */
15144fccf43aSdan   if( p->rc!=SQLITE_OK ) return p->rc;
15154fccf43aSdan 
1516296c7658Sdan   /* Free the current contents of p->apValue[]. */
15174fccf43aSdan   if( p->apValue ){
15184fccf43aSdan     for(i=0; i<p->nCol*2; i++){
15194fccf43aSdan       sqlite3ValueFree(p->apValue[i]);
15204fccf43aSdan     }
15214fccf43aSdan     memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
15224fccf43aSdan   }
15234fccf43aSdan 
15244fccf43aSdan   /* If the iterator is already at the end of the changeset, return DONE. */
15254fccf43aSdan   if( p->pNext>=&p->aChangeset[p->nChangeset] ){
15264fccf43aSdan     return SQLITE_DONE;
15274fccf43aSdan   }
15284fccf43aSdan   aChange = p->pNext;
15294fccf43aSdan 
15304fccf43aSdan   c = *(aChange++);
15314fccf43aSdan   if( c=='T' ){
15324fccf43aSdan     int nByte;                    /* Bytes to allocate for apValue */
15334fccf43aSdan     aChange += sessionVarintGet(aChange, &p->nCol);
15344fccf43aSdan     p->zTab = (char *)aChange;
15354fccf43aSdan     aChange += (strlen((char *)aChange) + 1);
15364fccf43aSdan     p->op = *(aChange++);
15374fccf43aSdan     sqlite3_free(p->apValue);
15384fccf43aSdan     nByte = sizeof(sqlite3_value *) * p->nCol * 2;
15394fccf43aSdan     p->apValue = (sqlite3_value **)sqlite3_malloc(nByte);
15404fccf43aSdan     if( !p->apValue ){
15414fccf43aSdan       return (p->rc = SQLITE_NOMEM);
15424fccf43aSdan     }
15434fccf43aSdan     memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
15444fccf43aSdan   }else{
15454fccf43aSdan     p->op = c;
15464fccf43aSdan   }
15474fccf43aSdan   if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
15484fccf43aSdan     return (p->rc = SQLITE_CORRUPT);
15494fccf43aSdan   }
15504fccf43aSdan 
15514fccf43aSdan   /* If this is an UPDATE or DELETE, read the old.* record. */
15524fccf43aSdan   if( p->op!=SQLITE_INSERT ){
15534fccf43aSdan     p->rc = sessionReadRecord(&aChange, p->nCol, p->apValue);
15544fccf43aSdan     if( p->rc!=SQLITE_OK ) return p->rc;
15554fccf43aSdan   }
15564fccf43aSdan 
15574fccf43aSdan   /* If this is an INSERT or UPDATE, read the new.* record. */
15584fccf43aSdan   if( p->op!=SQLITE_DELETE ){
15594fccf43aSdan     p->rc = sessionReadRecord(&aChange, p->nCol, &p->apValue[p->nCol]);
15604fccf43aSdan     if( p->rc!=SQLITE_OK ) return p->rc;
15614fccf43aSdan   }
15624fccf43aSdan 
15634fccf43aSdan   p->pNext = aChange;
15644fccf43aSdan   return SQLITE_ROW;
15654fccf43aSdan }
15664fccf43aSdan 
15674fccf43aSdan /*
15684fccf43aSdan ** The following three functions extract information on the current change
15694fccf43aSdan ** from a changeset iterator. They may only be called after changeset_next()
15704fccf43aSdan ** has returned SQLITE_ROW.
15714fccf43aSdan */
15724fccf43aSdan int sqlite3changeset_op(
1573296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Iterator handle */
15744fccf43aSdan   const char **pzTab,             /* OUT: Pointer to table name */
15754fccf43aSdan   int *pnCol,                     /* OUT: Number of columns in table */
15764fccf43aSdan   int *pOp                        /* OUT: SQLITE_INSERT, DELETE or UPDATE */
15774fccf43aSdan ){
15784fccf43aSdan   *pOp = pIter->op;
15794fccf43aSdan   *pnCol = pIter->nCol;
15804fccf43aSdan   *pzTab = pIter->zTab;
15814fccf43aSdan   return SQLITE_OK;
15824fccf43aSdan }
15834fccf43aSdan 
1584296c7658Sdan /*
1585296c7658Sdan ** This function may only be called while the iterator is pointing to an
1586296c7658Sdan ** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
1587296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned.
1588296c7658Sdan **
1589296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the
1590296c7658Sdan ** iVal'th value in the old.* record. Or, if that particular value is not
1591296c7658Sdan ** included in the record (because the change is an UPDATE and the field
1592296c7658Sdan ** was not modified and is not a PK column), set *ppValue to NULL.
1593296c7658Sdan **
1594296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
1595296c7658Sdan ** not modified. Otherwise, SQLITE_OK.
1596296c7658Sdan */
15974fccf43aSdan int sqlite3changeset_old(
1598296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1599296c7658Sdan   int iVal,                       /* Index of old.* value to retrieve */
16004fccf43aSdan   sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
16014fccf43aSdan ){
1602d5f0767cSdan   if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
1603d5f0767cSdan     return SQLITE_MISUSE;
1604d5f0767cSdan   }
16054fccf43aSdan   if( iVal<0 || iVal>=pIter->nCol ){
16064fccf43aSdan     return SQLITE_RANGE;
16074fccf43aSdan   }
16084fccf43aSdan   *ppValue = pIter->apValue[iVal];
16094fccf43aSdan   return SQLITE_OK;
16104fccf43aSdan }
16114fccf43aSdan 
1612296c7658Sdan /*
1613296c7658Sdan ** This function may only be called while the iterator is pointing to an
1614296c7658Sdan ** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
1615296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned.
1616296c7658Sdan **
1617296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the
1618296c7658Sdan ** iVal'th value in the new.* record. Or, if that particular value is not
1619296c7658Sdan ** included in the record (because the change is an UPDATE and the field
1620296c7658Sdan ** was not modified), set *ppValue to NULL.
1621296c7658Sdan **
1622296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
1623296c7658Sdan ** not modified. Otherwise, SQLITE_OK.
1624296c7658Sdan */
16254fccf43aSdan int sqlite3changeset_new(
1626296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1627296c7658Sdan   int iVal,                       /* Index of new.* value to retrieve */
16284fccf43aSdan   sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
16294fccf43aSdan ){
1630d5f0767cSdan   if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
1631d5f0767cSdan     return SQLITE_MISUSE;
1632d5f0767cSdan   }
16334fccf43aSdan   if( iVal<0 || iVal>=pIter->nCol ){
16344fccf43aSdan     return SQLITE_RANGE;
16354fccf43aSdan   }
16364fccf43aSdan   *ppValue = pIter->apValue[pIter->nCol+iVal];
16374fccf43aSdan   return SQLITE_OK;
16384fccf43aSdan }
16394fccf43aSdan 
1640296c7658Sdan /*
1641296c7658Sdan ** This function may only be called with a changeset iterator that has been
1642296c7658Sdan ** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
1643296c7658Sdan ** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
1644296c7658Sdan **
1645296c7658Sdan ** If successful, *ppValue is set to point to an sqlite3_value structure
1646296c7658Sdan ** containing the iVal'th value of the conflicting record.
1647296c7658Sdan **
1648296c7658Sdan ** If value iVal is out-of-range or some other error occurs, an SQLite error
1649296c7658Sdan ** code is returned. Otherwise, SQLITE_OK.
1650296c7658Sdan */
1651d5f0767cSdan int sqlite3changeset_conflict(
1652296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1653296c7658Sdan   int iVal,                       /* Index of conflict record value to fetch */
1654d5f0767cSdan   sqlite3_value **ppValue         /* OUT: Value from conflicting row */
1655d5f0767cSdan ){
1656d5f0767cSdan   if( !pIter->pConflict ){
1657d5f0767cSdan     return SQLITE_MISUSE;
1658d5f0767cSdan   }
1659d5f0767cSdan   if( iVal<0 || iVal>=sqlite3_column_count(pIter->pConflict) ){
1660d5f0767cSdan     return SQLITE_RANGE;
1661d5f0767cSdan   }
1662d5f0767cSdan   *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
1663d5f0767cSdan   return SQLITE_OK;
1664d5f0767cSdan }
1665d5f0767cSdan 
16664fccf43aSdan /*
16674fccf43aSdan ** Finalize an iterator allocated with sqlite3changeset_start().
16684fccf43aSdan **
16694fccf43aSdan ** This function may not be called on iterators passed to a conflict handler
16704fccf43aSdan ** callback by changeset_apply().
16714fccf43aSdan */
16724fccf43aSdan int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
1673296c7658Sdan   int i;                          /* Used to iterate through p->apValue[] */
1674296c7658Sdan   int rc = p->rc;                 /* Return code */
167512ca0b56Sdan   if( p->apValue ){
16764fccf43aSdan     for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
167712ca0b56Sdan   }
16784fccf43aSdan   sqlite3_free(p->apValue);
16794fccf43aSdan   sqlite3_free(p);
16804fccf43aSdan   return rc;
16814fccf43aSdan }
16824fccf43aSdan 
168391ddd559Sdan /*
168491ddd559Sdan ** Invert a changeset object.
168591ddd559Sdan */
168691ddd559Sdan int sqlite3changeset_invert(
168791ddd559Sdan   int nChangeset,                 /* Number of bytes in input */
168891ddd559Sdan   void *pChangeset,               /* Input changeset */
168991ddd559Sdan   int *pnInverted,                /* OUT: Number of bytes in output changeset */
169091ddd559Sdan   void **ppInverted               /* OUT: Inverse of pChangeset */
169191ddd559Sdan ){
169291ddd559Sdan   u8 *aOut;
169391ddd559Sdan   u8 *aIn;
169491ddd559Sdan   int i;
169591ddd559Sdan   int nCol = 0;
169691ddd559Sdan 
169791ddd559Sdan   /* Zero the output variables in case an error occurs. */
169891ddd559Sdan   *ppInverted = 0;
169991ddd559Sdan   *pnInverted = 0;
170091ddd559Sdan   if( nChangeset==0 ) return SQLITE_OK;
170191ddd559Sdan 
170291ddd559Sdan   aOut = (u8 *)sqlite3_malloc(nChangeset);
170391ddd559Sdan   if( !aOut ) return SQLITE_NOMEM;
170491ddd559Sdan   aIn = (u8 *)pChangeset;
170591ddd559Sdan 
170691ddd559Sdan   i = 0;
170791ddd559Sdan   while( i<nChangeset ){
170891ddd559Sdan     u8 eType = aIn[i];
170991ddd559Sdan     switch( eType ){
171091ddd559Sdan       case 'T': {
171191ddd559Sdan         int nByte = 1 + sessionVarintGet(&aIn[i+1], &nCol);
171291ddd559Sdan         nByte += 1 + strlen((char *)&aIn[i+nByte]);
171391ddd559Sdan         memcpy(&aOut[i], &aIn[i], nByte);
171491ddd559Sdan         i += nByte;
171591ddd559Sdan         break;
171691ddd559Sdan       }
171791ddd559Sdan 
171891ddd559Sdan       case SQLITE_INSERT:
171991ddd559Sdan       case SQLITE_DELETE: {
172091ddd559Sdan         int nByte;
172191ddd559Sdan         u8 *aEnd = &aIn[i+1];
172291ddd559Sdan 
172391ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
172491ddd559Sdan         aOut[i] = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
172591ddd559Sdan         nByte = aEnd - &aIn[i+1];
172691ddd559Sdan         memcpy(&aOut[i+1], &aIn[i+1], nByte);
172791ddd559Sdan         i += 1 + nByte;
172891ddd559Sdan         break;
172991ddd559Sdan       }
173091ddd559Sdan 
173191ddd559Sdan       case SQLITE_UPDATE: {
173291ddd559Sdan         int nByte1;              /* Size of old.* record in bytes */
173391ddd559Sdan         int nByte2;              /* Size of new.* record in bytes */
173491ddd559Sdan         u8 *aEnd = &aIn[i+1];
173591ddd559Sdan 
173691ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
173791ddd559Sdan         nByte1 = aEnd - &aIn[i+1];
173891ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
173991ddd559Sdan         nByte2 = aEnd - &aIn[i+1] - nByte1;
174091ddd559Sdan 
174191ddd559Sdan         aOut[i] = SQLITE_UPDATE;
174291ddd559Sdan         memcpy(&aOut[i+1], &aIn[i+1+nByte1], nByte2);
174391ddd559Sdan         memcpy(&aOut[i+1+nByte2], &aIn[i+1], nByte1);
174491ddd559Sdan 
174591ddd559Sdan         i += 1 + nByte1 + nByte2;
174691ddd559Sdan         break;
174791ddd559Sdan       }
174891ddd559Sdan 
174991ddd559Sdan       default:
175091ddd559Sdan         sqlite3_free(aOut);
175191ddd559Sdan         return SQLITE_CORRUPT;
175291ddd559Sdan     }
175391ddd559Sdan   }
175491ddd559Sdan 
175591ddd559Sdan   *pnInverted = nChangeset;
175691ddd559Sdan   *ppInverted = (void *)aOut;
175791ddd559Sdan   return SQLITE_OK;
175891ddd559Sdan }
175991ddd559Sdan 
17600c698471Sdan typedef struct SessionApplyCtx SessionApplyCtx;
17610c698471Sdan struct SessionApplyCtx {
17620c698471Sdan   sqlite3 *db;
17630c698471Sdan   sqlite3_stmt *pDelete;          /* DELETE statement */
17640c698471Sdan   sqlite3_stmt *pUpdate;          /* DELETE statement */
17650c698471Sdan   sqlite3_stmt *pInsert;          /* INSERT statement */
17660c698471Sdan   sqlite3_stmt *pSelect;          /* SELECT statement */
17670c698471Sdan   int nCol;                       /* Size of azCol[] and abPK[] arrays */
17680c698471Sdan   const char **azCol;             /* Array of column names */
17690c698471Sdan   u8 *abPK;                       /* Boolean array - true if column is in PK */
17700c698471Sdan };
17710c698471Sdan 
1772d5f0767cSdan /*
1773d5f0767cSdan ** Formulate a statement to DELETE a row from database db. Assuming a table
1774d5f0767cSdan ** structure like this:
1775d5f0767cSdan **
1776d5f0767cSdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1777d5f0767cSdan **
1778d5f0767cSdan ** The DELETE statement looks like this:
1779d5f0767cSdan **
1780*db04571cSdan **     DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
1781d5f0767cSdan **
1782d5f0767cSdan ** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
1783d5f0767cSdan ** matching b and d values, or 1 otherwise. The second case comes up if the
1784d5f0767cSdan ** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
1785296c7658Sdan **
1786296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
1787296c7658Sdan ** pointing to the prepared version of the SQL statement.
1788d5f0767cSdan */
1789d5f0767cSdan static int sessionDeleteRow(
1790d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1791d5f0767cSdan   const char *zTab,               /* Table name */
17920c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1793d5f0767cSdan ){
1794296c7658Sdan   int i;
1795296c7658Sdan   const char *zSep = "";
1796d5f0767cSdan   int rc = SQLITE_OK;
1797d5f0767cSdan   SessionBuffer buf = {0, 0, 0};
17987cf7df7dSdan   int nPk = 0;
1799d5f0767cSdan 
1800d5f0767cSdan   sessionAppendStr(&buf, "DELETE FROM ", &rc);
1801d5f0767cSdan   sessionAppendIdent(&buf, zTab, &rc);
1802296c7658Sdan   sessionAppendStr(&buf, " WHERE ", &rc);
1803296c7658Sdan 
1804296c7658Sdan   for(i=0; i<p->nCol; i++){
1805296c7658Sdan     if( p->abPK[i] ){
18067cf7df7dSdan       nPk++;
1807296c7658Sdan       sessionAppendStr(&buf, zSep, &rc);
1808296c7658Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1809296c7658Sdan       sessionAppendStr(&buf, " = ?", &rc);
1810296c7658Sdan       sessionAppendInteger(&buf, i+1, &rc);
1811296c7658Sdan       zSep = " AND ";
1812296c7658Sdan     }
1813296c7658Sdan   }
1814296c7658Sdan 
18157cf7df7dSdan   if( nPk<p->nCol ){
1816296c7658Sdan     sessionAppendStr(&buf, " AND (?", &rc);
1817296c7658Sdan     sessionAppendInteger(&buf, p->nCol+1, &rc);
1818296c7658Sdan     sessionAppendStr(&buf, " OR ", &rc);
1819296c7658Sdan 
1820296c7658Sdan     zSep = "";
1821296c7658Sdan     for(i=0; i<p->nCol; i++){
1822296c7658Sdan       if( !p->abPK[i] ){
1823296c7658Sdan         sessionAppendStr(&buf, zSep, &rc);
1824296c7658Sdan         sessionAppendIdent(&buf, p->azCol[i], &rc);
1825296c7658Sdan         sessionAppendStr(&buf, " IS ?", &rc);
1826296c7658Sdan         sessionAppendInteger(&buf, i+1, &rc);
1827296c7658Sdan         zSep = "AND ";
1828296c7658Sdan       }
1829296c7658Sdan     }
1830296c7658Sdan     sessionAppendStr(&buf, ")", &rc);
18317cf7df7dSdan   }
1832d5f0767cSdan 
1833d5f0767cSdan   if( rc==SQLITE_OK ){
18340c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
1835d5f0767cSdan   }
1836d5f0767cSdan   sqlite3_free(buf.aBuf);
1837d5f0767cSdan 
1838d5f0767cSdan   return rc;
1839d5f0767cSdan }
1840d5f0767cSdan 
1841d5f0767cSdan /*
1842d5f0767cSdan ** Formulate and prepare a statement to UPDATE a row from database db.
1843d5f0767cSdan ** Assuming a table structure like this:
1844d5f0767cSdan **
1845d5f0767cSdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1846d5f0767cSdan **
1847d5f0767cSdan ** The UPDATE statement looks like this:
1848d5f0767cSdan **
1849d5f0767cSdan **     UPDATE x SET
1850d5f0767cSdan **     a = CASE WHEN ?2  THEN ?3  ELSE a END,
1851d5f0767cSdan **     b = CASE WHEN ?5  THEN ?6  ELSE a END,
1852d5f0767cSdan **     c = CASE WHEN ?8  THEN ?9  ELSE a END,
1853d5f0767cSdan **     d = CASE WHEN ?11 THEN ?12 ELSE a END
1854d5f0767cSdan **     WHERE a = ?1 AND c = ?7 AND (?13 OR
1855d5f0767cSdan **       (?5==0 OR b IS ?4) AND (?11==0 OR b IS ?10) AND
1856d5f0767cSdan **     )
1857d5f0767cSdan **
1858d5f0767cSdan ** For each column in the table, there are three variables to bind:
1859d5f0767cSdan **
1860d5f0767cSdan **     ?(i*3+1)    The old.* value of the column, if any.
1861d5f0767cSdan **     ?(i*3+2)    A boolean flag indicating that the value is being modified.
1862d5f0767cSdan **     ?(i*3+3)    The new.* value of the column, if any.
1863d5f0767cSdan **
1864d5f0767cSdan ** Also, a boolean flag that, if set to true, causes the statement to update
1865d5f0767cSdan ** a row even if the non-PK values do not match. This is required if the
1866d5f0767cSdan ** conflict-handler is invoked with CHANGESET_DATA and returns
1867d5f0767cSdan ** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
1868d5f0767cSdan **
1869296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
1870296c7658Sdan ** pointing to the prepared version of the SQL statement.
1871d5f0767cSdan */
1872d5f0767cSdan static int sessionUpdateRow(
1873d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1874d5f0767cSdan   const char *zTab,               /* Table name */
18750c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1876d5f0767cSdan ){
1877d5f0767cSdan   int rc = SQLITE_OK;
1878d5f0767cSdan   int i;
1879d5f0767cSdan   const char *zSep = "";
1880d5f0767cSdan   SessionBuffer buf = {0, 0, 0};
1881d5f0767cSdan 
1882d5f0767cSdan   /* Append "UPDATE tbl SET " */
1883d5f0767cSdan   sessionAppendStr(&buf, "UPDATE ", &rc);
1884d5f0767cSdan   sessionAppendIdent(&buf, zTab, &rc);
1885d5f0767cSdan   sessionAppendStr(&buf, " SET ", &rc);
1886d5f0767cSdan 
1887d5f0767cSdan   /* Append the assignments */
18880c698471Sdan   for(i=0; i<p->nCol; i++){
1889d5f0767cSdan     sessionAppendStr(&buf, zSep, &rc);
18900c698471Sdan     sessionAppendIdent(&buf, p->azCol[i], &rc);
1891d5f0767cSdan     sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
1892d5f0767cSdan     sessionAppendInteger(&buf, i*3+2, &rc);
1893d5f0767cSdan     sessionAppendStr(&buf, " THEN ?", &rc);
1894d5f0767cSdan     sessionAppendInteger(&buf, i*3+3, &rc);
1895d5f0767cSdan     sessionAppendStr(&buf, " ELSE ", &rc);
18960c698471Sdan     sessionAppendIdent(&buf, p->azCol[i], &rc);
1897d5f0767cSdan     sessionAppendStr(&buf, " END", &rc);
1898d5f0767cSdan     zSep = ", ";
1899d5f0767cSdan   }
1900d5f0767cSdan 
1901d5f0767cSdan   /* Append the PK part of the WHERE clause */
1902d5f0767cSdan   sessionAppendStr(&buf, " WHERE ", &rc);
19030c698471Sdan   for(i=0; i<p->nCol; i++){
19040c698471Sdan     if( p->abPK[i] ){
19050c698471Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1906d5f0767cSdan       sessionAppendStr(&buf, " = ?", &rc);
1907d5f0767cSdan       sessionAppendInteger(&buf, i*3+1, &rc);
1908d5f0767cSdan       sessionAppendStr(&buf, " AND ", &rc);
1909d5f0767cSdan     }
1910d5f0767cSdan   }
1911d5f0767cSdan 
1912d5f0767cSdan   /* Append the non-PK part of the WHERE clause */
1913d5f0767cSdan   sessionAppendStr(&buf, " (?", &rc);
19140c698471Sdan   sessionAppendInteger(&buf, p->nCol*3+1, &rc);
1915d5f0767cSdan   sessionAppendStr(&buf, " OR 1", &rc);
19160c698471Sdan   for(i=0; i<p->nCol; i++){
19170c698471Sdan     if( !p->abPK[i] ){
1918d5f0767cSdan       sessionAppendStr(&buf, " AND (?", &rc);
1919d5f0767cSdan       sessionAppendInteger(&buf, i*3+2, &rc);
1920d5f0767cSdan       sessionAppendStr(&buf, "=0 OR ", &rc);
19210c698471Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1922d5f0767cSdan       sessionAppendStr(&buf, " IS ?", &rc);
1923d5f0767cSdan       sessionAppendInteger(&buf, i*3+1, &rc);
1924d5f0767cSdan       sessionAppendStr(&buf, ")", &rc);
1925d5f0767cSdan     }
1926d5f0767cSdan   }
1927d5f0767cSdan   sessionAppendStr(&buf, ")", &rc);
1928d5f0767cSdan 
1929d5f0767cSdan   if( rc==SQLITE_OK ){
19300c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
1931d5f0767cSdan   }
1932d5f0767cSdan   sqlite3_free(buf.aBuf);
1933d5f0767cSdan 
1934d5f0767cSdan   return rc;
1935d5f0767cSdan }
1936d5f0767cSdan 
1937296c7658Sdan /*
1938296c7658Sdan ** Formulate and prepare an SQL statement to query table zTab by primary
1939296c7658Sdan ** key. Assuming the following table structure:
1940296c7658Sdan **
1941296c7658Sdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1942296c7658Sdan **
1943296c7658Sdan ** The SELECT statement looks like this:
1944296c7658Sdan **
1945296c7658Sdan **     SELECT * FROM x WHERE a = ?1 AND c = ?3
1946296c7658Sdan **
1947296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
1948296c7658Sdan ** pointing to the prepared version of the SQL statement.
1949296c7658Sdan */
1950d5f0767cSdan static int sessionSelectRow(
1951d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1952d5f0767cSdan   const char *zTab,               /* Table name */
19530c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1954d5f0767cSdan ){
1955d7fb7d24Sdan   return sessionSelectStmt(
1956d7fb7d24Sdan       db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
1957d5f0767cSdan }
1958d5f0767cSdan 
1959296c7658Sdan /*
1960296c7658Sdan ** Formulate and prepare an INSERT statement to add a record to table zTab.
1961296c7658Sdan ** For example:
1962296c7658Sdan **
1963296c7658Sdan **     INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
1964296c7658Sdan **
1965296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
1966296c7658Sdan ** pointing to the prepared version of the SQL statement.
1967296c7658Sdan */
19680c698471Sdan static int sessionInsertRow(
19690c698471Sdan   sqlite3 *db,                    /* Database handle */
19700c698471Sdan   const char *zTab,               /* Table name */
19710c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
19720c698471Sdan ){
19730c698471Sdan   int rc = SQLITE_OK;
19740c698471Sdan   int i;
19750c698471Sdan   SessionBuffer buf = {0, 0, 0};
19760c698471Sdan 
19770c698471Sdan   sessionAppendStr(&buf, "INSERT INTO main.", &rc);
19780c698471Sdan   sessionAppendIdent(&buf, zTab, &rc);
19790c698471Sdan   sessionAppendStr(&buf, " VALUES(?", &rc);
19800c698471Sdan   for(i=1; i<p->nCol; i++){
19810c698471Sdan     sessionAppendStr(&buf, ", ?", &rc);
19820c698471Sdan   }
19830c698471Sdan   sessionAppendStr(&buf, ")", &rc);
19840c698471Sdan 
19850c698471Sdan   if( rc==SQLITE_OK ){
19860c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
19870c698471Sdan   }
19880c698471Sdan   sqlite3_free(buf.aBuf);
19890c698471Sdan   return rc;
19900c698471Sdan }
19910c698471Sdan 
1992296c7658Sdan /*
1993*db04571cSdan ** Iterator pIter must point to an SQLITE_INSERT entry. This function
1994*db04571cSdan ** transfers new.* values from the current iterator entry to statement
1995*db04571cSdan ** pStmt. The table being inserted into has nCol columns.
1996*db04571cSdan **
1997*db04571cSdan ** New.* value $i 0 from the iterator is bound to variable ($i+1) of
1998*db04571cSdan ** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
1999*db04571cSdan ** are transfered to the statement. Otherwise, if abPK is not NULL, it points
2000*db04571cSdan ** to an array nCol elements in size. In this case only those values for
2001*db04571cSdan ** which abPK[$i] is true are read from the iterator and bound to the
2002*db04571cSdan ** statement.
2003*db04571cSdan **
2004*db04571cSdan ** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
2005*db04571cSdan */
2006*db04571cSdan static int sessionBindValues(
2007*db04571cSdan   sqlite3_changeset_iter *pIter,  /* Iterator to read values from */
2008*db04571cSdan   int(*xIterValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
2009*db04571cSdan   int nCol,                       /* Number of columns */
2010*db04571cSdan   u8 *abPK,                       /* If not NULL, bind only if true */
2011*db04571cSdan   sqlite3_stmt *pStmt             /* Bind values to this statement */
2012*db04571cSdan ){
2013*db04571cSdan   int i;
2014*db04571cSdan   int rc = SQLITE_OK;
2015*db04571cSdan   for(i=0; rc==SQLITE_OK && i<nCol; i++){
2016*db04571cSdan     if( !abPK || abPK[i] ){
2017*db04571cSdan       sqlite3_value *pVal;
2018*db04571cSdan       rc = xIterValue(pIter, i, &pVal);
2019*db04571cSdan       if( rc==SQLITE_OK ){
2020*db04571cSdan         rc = sqlite3_bind_value(pStmt, i+1, pVal);
2021*db04571cSdan       }
2022*db04571cSdan     }
2023*db04571cSdan   }
2024*db04571cSdan   return rc;
2025*db04571cSdan }
2026*db04571cSdan 
2027*db04571cSdan /*
2028296c7658Sdan ** SQL statement pSelect is as generated by the sessionSelectRow() function.
2029296c7658Sdan ** This function binds the primary key values from the change that changeset
2030296c7658Sdan ** iterator pIter points to to the SELECT and attempts to seek to the table
2031296c7658Sdan ** entry. If a row is found, the SELECT statement left pointing at the row
2032296c7658Sdan ** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
2033296c7658Sdan ** has occured, the statement is reset and SQLITE_OK is returned. If an
2034296c7658Sdan ** error occurs, an SQLite error code is returned.
2035296c7658Sdan **
2036296c7658Sdan ** If the iterator currently points to an INSERT record, bind values from the
2037*db04571cSdan ** new.* record to the SELECT statement. Or, if it points to a DELETE or
2038*db04571cSdan ** UPDATE, bind values from the old.* record.
2039296c7658Sdan */
20400c698471Sdan static int sessionSeekToRow(
204137f133ecSdan   sqlite3 *db,                    /* Database handle */
204237f133ecSdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
204337f133ecSdan   u8 *abPK,                       /* Primary key flags array */
20440c698471Sdan   sqlite3_stmt *pSelect           /* SELECT statement from sessionSelectRow() */
204537f133ecSdan ){
2046296c7658Sdan   int rc = SQLITE_OK;             /* Return code */
2047296c7658Sdan   int nCol;                       /* Number of columns in table */
2048296c7658Sdan   int op;                         /* Changset operation (SQLITE_UPDATE etc.) */
2049296c7658Sdan   const char *zDummy;             /* Unused */
205037f133ecSdan 
205137f133ecSdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op);
2052*db04571cSdan   rc = sessionBindValues(pIter,
2053*db04571cSdan       op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
2054*db04571cSdan       nCol, abPK, pSelect
2055*db04571cSdan   );
20560c698471Sdan 
20570c698471Sdan   if( rc==SQLITE_OK ){
20580c698471Sdan     rc = sqlite3_step(pSelect);
20590c698471Sdan     if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
20600c698471Sdan   }
20610c698471Sdan 
20620c698471Sdan   return rc;
20630c698471Sdan }
20640c698471Sdan 
2065296c7658Sdan /*
2066296c7658Sdan ** Invoke the conflict handler for the change that the changeset iterator
2067296c7658Sdan ** currently points to.
2068296c7658Sdan **
2069296c7658Sdan ** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
2070296c7658Sdan ** If argument pbReplace is NULL, then the type of conflict handler invoked
2071296c7658Sdan ** depends solely on eType, as follows:
2072296c7658Sdan **
2073296c7658Sdan **    eType value                 Value passed to xConflict
2074296c7658Sdan **    -------------------------------------------------
2075296c7658Sdan **    CHANGESET_DATA              CHANGESET_NOTFOUND
2076296c7658Sdan **    CHANGESET_CONFLICT          CHANGESET_CONSTRAINT
2077296c7658Sdan **
2078296c7658Sdan ** Or, if pbReplace is not NULL, then an attempt is made to find an existing
2079296c7658Sdan ** record with the same primary key as the record about to be deleted, updated
2080296c7658Sdan ** or inserted. If such a record can be found, it is available to the conflict
2081296c7658Sdan ** handler as the "conflicting" record. In this case the type of conflict
2082296c7658Sdan ** handler invoked is as follows:
2083296c7658Sdan **
2084296c7658Sdan **    eType value         PK Record found?   Value passed to xConflict
2085296c7658Sdan **    ----------------------------------------------------------------
2086296c7658Sdan **    CHANGESET_DATA      Yes                CHANGESET_DATA
2087296c7658Sdan **    CHANGESET_DATA      No                 CHANGESET_NOTFOUND
2088296c7658Sdan **    CHANGESET_CONFLICT  Yes                CHANGESET_CONFLICT
2089296c7658Sdan **    CHANGESET_CONFLICT  No                 CHANGESET_CONSTRAINT
2090296c7658Sdan **
2091296c7658Sdan ** If pbReplace is not NULL, and a record with a matching PK is found, and
2092296c7658Sdan ** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
2093296c7658Sdan ** is set to non-zero before returning SQLITE_OK.
2094296c7658Sdan **
2095296c7658Sdan ** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
2096296c7658Sdan ** returned. Or, if the conflict handler returns an invalid value,
2097296c7658Sdan ** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
2098296c7658Sdan ** this function returns SQLITE_OK.
2099296c7658Sdan */
21000c698471Sdan static int sessionConflictHandler(
2101296c7658Sdan   int eType,                      /* Either CHANGESET_DATA or CONFLICT */
2102296c7658Sdan   SessionApplyCtx *p,             /* changeset_apply() context */
21030c698471Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
21040c698471Sdan   int(*xConflict)(void *, int, sqlite3_changeset_iter*),
2105296c7658Sdan   void *pCtx,                     /* First argument for conflict handler */
2106296c7658Sdan   int *pbReplace                  /* OUT: Set to true if PK row is found */
21070c698471Sdan ){
2108296c7658Sdan   int res;                        /* Value returned by conflict handler */
21090c698471Sdan   int rc;
21100c698471Sdan   int nCol;
21110c698471Sdan   int op;
21120c698471Sdan   const char *zDummy;
21130c698471Sdan 
21140c698471Sdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op);
21150c698471Sdan 
21160c698471Sdan   assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
21170c698471Sdan   assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
21180c698471Sdan   assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
211937f133ecSdan 
212037f133ecSdan   /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
21210c698471Sdan   if( pbReplace ){
21220c698471Sdan     rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
21230c698471Sdan   }else{
2124*db04571cSdan     rc = SQLITE_OK;
21250c698471Sdan   }
21260c698471Sdan 
21270c698471Sdan   if( rc==SQLITE_ROW ){
21280c698471Sdan     /* There exists another row with the new.* primary key. */
21290c698471Sdan     pIter->pConflict = p->pSelect;
21300c698471Sdan     res = xConflict(pCtx, eType, pIter);
21310c698471Sdan     pIter->pConflict = 0;
21320c698471Sdan     rc = sqlite3_reset(p->pSelect);
2133*db04571cSdan   }else if( rc==SQLITE_OK ){
21340c698471Sdan     /* No other row with the new.* primary key. */
21350c698471Sdan     rc = sqlite3_reset(p->pSelect);
21360c698471Sdan     if( rc==SQLITE_OK ){
21370c698471Sdan       res = xConflict(pCtx, eType+1, pIter);
21380c698471Sdan       if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
213937f133ecSdan     }
214037f133ecSdan   }
214137f133ecSdan 
214237f133ecSdan   if( rc==SQLITE_OK ){
21430c698471Sdan     switch( res ){
21440c698471Sdan       case SQLITE_CHANGESET_REPLACE:
21450c698471Sdan         if( pbReplace ) *pbReplace = 1;
21460c698471Sdan         break;
21470c698471Sdan 
21480c698471Sdan       case SQLITE_CHANGESET_OMIT:
21490c698471Sdan         break;
21500c698471Sdan 
21510c698471Sdan       case SQLITE_CHANGESET_ABORT:
21520c698471Sdan         rc = SQLITE_ABORT;
21530c698471Sdan         break;
21540c698471Sdan 
21550c698471Sdan       default:
21560c698471Sdan         rc = SQLITE_MISUSE;
21570c698471Sdan         break;
21580c698471Sdan     }
21590c698471Sdan   }
21600c698471Sdan 
21610c698471Sdan   return rc;
21620c698471Sdan }
21630c698471Sdan 
2164296c7658Sdan /*
2165296c7658Sdan ** Attempt to apply the change that the iterator passed as the first argument
2166296c7658Sdan ** currently points to to the database. If a conflict is encountered, invoke
2167296c7658Sdan ** the conflict handler callback.
2168296c7658Sdan **
2169296c7658Sdan ** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
2170296c7658Sdan ** one is encountered, update or delete the row with the matching primary key
2171296c7658Sdan ** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
2172296c7658Sdan ** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
2173296c7658Sdan ** to true before returning. In this case the caller will invoke this function
2174296c7658Sdan ** again, this time with pbRetry set to NULL.
2175296c7658Sdan **
2176296c7658Sdan ** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
2177296c7658Sdan ** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
2178296c7658Sdan ** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
2179296c7658Sdan ** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
2180296c7658Sdan ** before retrying. In this case the caller attempts to remove the conflicting
2181296c7658Sdan ** row before invoking this function again, this time with pbReplace set
2182296c7658Sdan ** to NULL.
2183296c7658Sdan **
2184296c7658Sdan ** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
2185296c7658Sdan ** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
2186296c7658Sdan ** returned.
2187296c7658Sdan */
21880c698471Sdan static int sessionApplyOneOp(
2189296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
2190296c7658Sdan   SessionApplyCtx *p,             /* changeset_apply() context */
21910c698471Sdan   int(*xConflict)(void *, int, sqlite3_changeset_iter *),
2192296c7658Sdan   void *pCtx,                     /* First argument for the conflict handler */
2193296c7658Sdan   int *pbReplace,                 /* OUT: True to remove PK row and retry */
2194296c7658Sdan   int *pbRetry                    /* OUT: True to retry. */
21950c698471Sdan ){
21960c698471Sdan   const char *zDummy;
21970c698471Sdan   int op;
21980c698471Sdan   int nCol;
21990c698471Sdan   int rc = SQLITE_OK;
22000c698471Sdan 
22010c698471Sdan   assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
22020c698471Sdan   assert( p->azCol && p->abPK );
22030c698471Sdan   assert( !pbReplace || *pbReplace==0 );
22040c698471Sdan 
22050c698471Sdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op);
22060c698471Sdan 
22070c698471Sdan   if( op==SQLITE_DELETE ){
22080c698471Sdan 
22090c698471Sdan     /* Bind values to the DELETE statement. */
2210*db04571cSdan     rc = sessionBindValues(pIter, sqlite3changeset_old, nCol, 0, p->pDelete);
22117cf7df7dSdan     if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
22127cf7df7dSdan       rc = sqlite3_bind_int(p->pDelete, nCol+1, pbRetry==0);
22137cf7df7dSdan     }
22140c698471Sdan     if( rc!=SQLITE_OK ) return rc;
22150c698471Sdan 
22160c698471Sdan     sqlite3_step(p->pDelete);
22170c698471Sdan     rc = sqlite3_reset(p->pDelete);
22180c698471Sdan     if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
22190c698471Sdan       rc = sessionConflictHandler(
22200c698471Sdan           SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
22210c698471Sdan       );
22220c698471Sdan     }else if( rc==SQLITE_CONSTRAINT ){
22230c698471Sdan       rc = sessionConflictHandler(
22240c698471Sdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
22250c698471Sdan       );
22260c698471Sdan     }
22270c698471Sdan 
22280c698471Sdan   }else if( op==SQLITE_UPDATE ){
22290c698471Sdan     int i;
22300c698471Sdan 
22310c698471Sdan     /* Bind values to the UPDATE statement. */
22320c698471Sdan     for(i=0; rc==SQLITE_OK && i<nCol; i++){
22330c698471Sdan       sqlite3_value *pOld = 0;
22340c698471Sdan       sqlite3_value *pNew = 0;
22350c698471Sdan       rc = sqlite3changeset_old(pIter, i, &pOld);
22360c698471Sdan       if( rc==SQLITE_OK ){
22370c698471Sdan         rc = sqlite3changeset_new(pIter, i, &pNew);
22380c698471Sdan       }
22390c698471Sdan       if( rc==SQLITE_OK ){
22400c698471Sdan         if( pOld ) sqlite3_bind_value(p->pUpdate, i*3+1, pOld);
22410c698471Sdan         sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
22420c698471Sdan         if( pNew ) sqlite3_bind_value(p->pUpdate, i*3+3, pNew);
22430c698471Sdan       }
22440c698471Sdan     }
22450c698471Sdan     if( rc==SQLITE_OK ) rc = sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0);
22460c698471Sdan     if( rc!=SQLITE_OK ) return rc;
22470c698471Sdan 
22480c698471Sdan     /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
22490c698471Sdan     ** the result will be SQLITE_OK with 0 rows modified. */
22500c698471Sdan     sqlite3_step(p->pUpdate);
22510c698471Sdan     rc = sqlite3_reset(p->pUpdate);
22520c698471Sdan 
22530c698471Sdan     if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
22540c698471Sdan       /* A NOTFOUND or DATA error. Search the table to see if it contains
22550c698471Sdan       ** a row with a matching primary key. If so, this is a DATA conflict.
22560c698471Sdan       ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
22570c698471Sdan 
22580c698471Sdan       rc = sessionConflictHandler(
22590c698471Sdan           SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
22600c698471Sdan       );
22610c698471Sdan 
22620c698471Sdan     }else if( rc==SQLITE_CONSTRAINT ){
2263*db04571cSdan       /* This is always a CONSTRAINT conflict. */
2264*db04571cSdan       rc = sessionConflictHandler(
2265*db04571cSdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
22660c698471Sdan       );
22670c698471Sdan     }
22680c698471Sdan 
22690c698471Sdan   }else{
22700c698471Sdan     assert( op==SQLITE_INSERT );
2271*db04571cSdan     rc = sessionBindValues(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
22720c698471Sdan     if( rc!=SQLITE_OK ) return rc;
22730c698471Sdan 
22740c698471Sdan     sqlite3_step(p->pInsert);
22750c698471Sdan     rc = sqlite3_reset(p->pInsert);
2276*db04571cSdan     if( rc==SQLITE_CONSTRAINT ){
22770c698471Sdan       rc = sessionConflictHandler(
22780c698471Sdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
22790c698471Sdan       );
228037f133ecSdan     }
228137f133ecSdan   }
228237f133ecSdan 
228337f133ecSdan   return rc;
228437f133ecSdan }
228537f133ecSdan 
2286296c7658Sdan /*
2287296c7658Sdan ** Apply the changeset passed via pChangeset/nChangeset to the main database
2288296c7658Sdan ** attached to handle "db". Invoke the supplied conflict handler callback
2289296c7658Sdan ** to resolve any conflicts encountered while applying the change.
2290296c7658Sdan */
2291d5f0767cSdan int sqlite3changeset_apply(
2292296c7658Sdan   sqlite3 *db,                    /* Apply change to "main" db of this handle */
2293296c7658Sdan   int nChangeset,                 /* Size of changeset in bytes */
2294296c7658Sdan   void *pChangeset,               /* Changeset blob */
2295d5f0767cSdan   int(*xConflict)(
2296d5f0767cSdan     void *pCtx,                   /* Copy of fifth arg to _apply() */
2297d5f0767cSdan     int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
2298d5f0767cSdan     sqlite3_changeset_iter *p     /* Handle describing change and conflict */
2299d5f0767cSdan   ),
2300296c7658Sdan   void *pCtx                      /* First argument passed to xConflict */
2301d5f0767cSdan ){
2302296c7658Sdan   sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */
2303296c7658Sdan   int rc;                         /* Return code */
2304d5f0767cSdan   const char *zTab = 0;           /* Name of current table */
2305d5f0767cSdan   int nTab = 0;                   /* Result of strlen(zTab) */
2306296c7658Sdan   SessionApplyCtx sApply;         /* changeset_apply() context object */
2307d5f0767cSdan 
23080c698471Sdan   memset(&sApply, 0, sizeof(sApply));
230912ca0b56Sdan   rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
231012ca0b56Sdan   if( rc!=SQLITE_OK ) return rc;
23110c698471Sdan 
23124c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
23130c698471Sdan   rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
23140c698471Sdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
23150c698471Sdan     int nCol;
2316d5f0767cSdan     int op;
23170c698471Sdan     int bReplace = 0;
23180c698471Sdan     int bRetry = 0;
23190c698471Sdan     const char *zNew;
23200c698471Sdan     sqlite3changeset_op(pIter, &zNew, &nCol, &op);
2321d5f0767cSdan 
23220c698471Sdan     if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
23230c698471Sdan       sqlite3_free(sApply.azCol);
23240c698471Sdan       sqlite3_finalize(sApply.pDelete);
23250c698471Sdan       sqlite3_finalize(sApply.pUpdate);
23260c698471Sdan       sqlite3_finalize(sApply.pInsert);
23270c698471Sdan       sqlite3_finalize(sApply.pSelect);
23280c698471Sdan       memset(&sApply, 0, sizeof(sApply));
23290c698471Sdan       sApply.db = db;
23300c698471Sdan       sApply.nCol = nCol;
233137f133ecSdan 
2332296c7658Sdan       rc = sessionTableInfo(
2333296c7658Sdan           db, "main", zNew, nCol, &zTab, &sApply.azCol, &sApply.abPK);
23340c698471Sdan 
23350c698471Sdan       if( rc!=SQLITE_OK
23360c698471Sdan        || (rc = sessionSelectRow(db, zTab, &sApply))
23370c698471Sdan        || (rc = sessionUpdateRow(db, zTab, &sApply))
23380c698471Sdan        || (rc = sessionDeleteRow(db, zTab, &sApply))
23390c698471Sdan        || (rc = sessionInsertRow(db, zTab, &sApply))
234037f133ecSdan       ){
234137f133ecSdan         break;
234237f133ecSdan       }
23430c698471Sdan 
23440c698471Sdan       nTab = strlen(zTab);
2345d5f0767cSdan     }
2346d5f0767cSdan 
23470c698471Sdan     rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
23480c698471Sdan 
23490c698471Sdan     if( rc==SQLITE_OK && bRetry ){
23500c698471Sdan       rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, 0);
23510c698471Sdan     }
23520c698471Sdan 
23530c698471Sdan     if( bReplace ){
2354*db04571cSdan       assert( pIter->op==SQLITE_INSERT );
23550c698471Sdan       rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
23560c698471Sdan       if( rc==SQLITE_OK ){
2357*db04571cSdan         rc = sessionBindValues(pIter,
2358*db04571cSdan             sqlite3changeset_new, sApply.nCol, sApply.abPK, sApply.pDelete);
23590c698471Sdan         sqlite3_bind_int(sApply.pDelete, sApply.nCol+1, 1);
23600c698471Sdan       }
23610c698471Sdan       if( rc==SQLITE_OK ){
23620c698471Sdan         sqlite3_step(sApply.pDelete);
23630c698471Sdan         rc = sqlite3_reset(sApply.pDelete);
23640c698471Sdan       }
23650c698471Sdan       if( rc==SQLITE_OK ){
23660c698471Sdan         rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, 0, 0);
23670c698471Sdan       }
23680c698471Sdan       if( rc==SQLITE_OK ){
23690c698471Sdan         rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
23700c698471Sdan       }
23710c698471Sdan     }
23720c698471Sdan   }
2373d5f0767cSdan 
2374296c7658Sdan   if( rc==SQLITE_OK ){
2375296c7658Sdan     rc = sqlite3changeset_finalize(pIter);
2376296c7658Sdan   }else{
2377296c7658Sdan     sqlite3changeset_finalize(pIter);
2378296c7658Sdan   }
2379d5f0767cSdan 
2380d5f0767cSdan   if( rc==SQLITE_OK ){
2381d5f0767cSdan     rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
2382d5f0767cSdan   }else{
2383d5f0767cSdan     sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
2384d5f0767cSdan     sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
2385d5f0767cSdan   }
2386d5f0767cSdan 
23870c698471Sdan   sqlite3_finalize(sApply.pInsert);
23880c698471Sdan   sqlite3_finalize(sApply.pDelete);
23890c698471Sdan   sqlite3_finalize(sApply.pUpdate);
23900c698471Sdan   sqlite3_finalize(sApply.pSelect);
23910c698471Sdan   sqlite3_free(sApply.azCol);
23924c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
2393d5f0767cSdan   return rc;
2394d5f0767cSdan }
239591ddd559Sdan 
23964fccf43aSdan #endif        /* #ifdef SQLITE_ENABLE_SESSION */
2397