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 
248*4e895da1Sdan     default: {
2494fccf43aSdan       int n = sqlite3_value_bytes(pValue);
250296c7658Sdan       int nVarint = sessionVarintLen(n);
251*4e895da1Sdan       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 */
289e8d5648eSdan   int *piHash                     /* OUT: Hash value */
290e8d5648eSdan ){
2914131639cSdan   unsigned int h = 0;             /* Hash value to return */
2924131639cSdan   int i;                          /* Used to iterate through columns */
293e8d5648eSdan 
294e8d5648eSdan   assert( pTab->nCol==sqlite3_preupdate_count(db) );
295e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
296e8d5648eSdan     if( pTab->abPK[i] ){
297e8d5648eSdan       int rc;
298e8d5648eSdan       int eType;
299e8d5648eSdan       sqlite3_value *pVal;
300e8d5648eSdan 
301e8d5648eSdan       if( bNew ){
302e8d5648eSdan         rc = sqlite3_preupdate_new(db, i, &pVal);
303e8d5648eSdan       }else{
304e8d5648eSdan         rc = sqlite3_preupdate_old(db, i, &pVal);
305e8d5648eSdan       }
306e8d5648eSdan 
307e8d5648eSdan       eType = sqlite3_value_type(pVal);
308e8d5648eSdan       h = HASH_APPEND(h, eType);
309e8d5648eSdan       switch( eType ){
310e8d5648eSdan         case SQLITE_INTEGER:
311e8d5648eSdan         case SQLITE_FLOAT: {
312e8d5648eSdan           i64 iVal;
313e8d5648eSdan           if( eType==SQLITE_INTEGER ){
314e8d5648eSdan             iVal = sqlite3_value_int64(pVal);
315e8d5648eSdan           }else{
316e8d5648eSdan             double rVal = sqlite3_value_double(pVal);
317e8d5648eSdan             assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
318e8d5648eSdan             memcpy(&iVal, &rVal, 8);
319e8d5648eSdan           }
320e8d5648eSdan           h = sessionHashAppendI64(h, iVal);
321e8d5648eSdan           break;
322e8d5648eSdan         }
323e8d5648eSdan 
324e8d5648eSdan         case SQLITE_TEXT:
325e8d5648eSdan         case SQLITE_BLOB: {
326e8d5648eSdan           int n = sqlite3_value_bytes(pVal);
327e8d5648eSdan           const u8 *z = eType==SQLITE_TEXT ?
328e8d5648eSdan             sqlite3_value_text(pVal) : sqlite3_value_blob(pVal);
329e8d5648eSdan           h = sessionHashAppendBlob(h, n, z);
330e8d5648eSdan           break;
331e8d5648eSdan         }
332e8d5648eSdan       }
333e8d5648eSdan     }
334e8d5648eSdan   }
335e8d5648eSdan 
336e8d5648eSdan   *piHash = (h % pTab->nChange);
337e8d5648eSdan   return SQLITE_OK;
338e8d5648eSdan }
339e8d5648eSdan 
3404131639cSdan /*
3414131639cSdan ** Based on the primary key values stored in change pChange, calculate a
3424131639cSdan ** hash key, assuming the has table has nBucket buckets. The hash keys
3434131639cSdan ** calculated by this function are compatible with those calculated by
3444131639cSdan ** sessionPreupdateHash().
3454131639cSdan */
3464131639cSdan static unsigned int sessionChangeHash(
3474131639cSdan   sqlite3 *db,                    /* Database handle */
3484131639cSdan   SessionTable *pTab,             /* Table handle */
3494131639cSdan   SessionChange *pChange,         /* Change handle */
3504131639cSdan   int nBucket                     /* Assume this many buckets in hash table */
351e8d5648eSdan ){
3524131639cSdan   unsigned int h = 0;             /* Value to return */
3534131639cSdan   int i;                          /* Used to iterate through columns */
3544131639cSdan   u8 *a = pChange->aRecord;       /* Used to iterate through change record */
355e8d5648eSdan 
356e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
357e8d5648eSdan     int eType = *a++;
358e8d5648eSdan     int isPK = pTab->abPK[i];
359e8d5648eSdan 
360e8d5648eSdan     if( isPK ) h = HASH_APPEND(h, eType);
361e8d5648eSdan     switch( eType ){
362e8d5648eSdan       case SQLITE_INTEGER:
363e8d5648eSdan       case SQLITE_FLOAT: {
364e8d5648eSdan         if( isPK ){
365e8d5648eSdan           i64 iVal = sessionGetI64(a);
366e8d5648eSdan           h = sessionHashAppendI64(h, iVal);
367e8d5648eSdan         }
368e8d5648eSdan         a += 8;
369e8d5648eSdan         break;
370e8d5648eSdan       }
371e8d5648eSdan       case SQLITE_TEXT:
372e8d5648eSdan       case SQLITE_BLOB: {
373e8d5648eSdan         int n;
374e8d5648eSdan         a += sessionVarintGet(a, &n);
375e8d5648eSdan         if( isPK ){
376e8d5648eSdan           h = sessionHashAppendBlob(h, n, a);
377e8d5648eSdan         }
378e8d5648eSdan         a += n;
379e8d5648eSdan         break;
380e8d5648eSdan       }
381e8d5648eSdan     }
382e8d5648eSdan   }
383e8d5648eSdan   return (h % nBucket);
384e8d5648eSdan }
385e8d5648eSdan 
386e8d5648eSdan static int sessionPreupdateEqual(
387e8d5648eSdan   sqlite3 *db,
388e8d5648eSdan   SessionTable *pTab,
389e8d5648eSdan   SessionChange *pChange,
390e8d5648eSdan   int bNew,
391e8d5648eSdan   int *pbEqual
392e8d5648eSdan ){
393e8d5648eSdan   int i;
394e8d5648eSdan   u8 *a = pChange->aRecord;
395e8d5648eSdan 
396e8d5648eSdan   *pbEqual = 0;
397e8d5648eSdan 
398e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
399e8d5648eSdan     int eType = *a++;
400e8d5648eSdan     if( !pTab->abPK[i] ){
401e8d5648eSdan       switch( eType ){
402e8d5648eSdan         case SQLITE_INTEGER:
403e8d5648eSdan         case SQLITE_FLOAT:
404e8d5648eSdan           a += 8;
405e8d5648eSdan           break;
406e8d5648eSdan 
407e8d5648eSdan         case SQLITE_TEXT:
408e8d5648eSdan         case SQLITE_BLOB: {
409e8d5648eSdan           int n;
410e8d5648eSdan           a += sessionVarintGet(a, &n);
411e8d5648eSdan           a += n;
412e8d5648eSdan           break;
413e8d5648eSdan         }
414e8d5648eSdan       }
415e8d5648eSdan     }else{
416e8d5648eSdan       sqlite3_value *pVal;
417e8d5648eSdan       int rc;
418e8d5648eSdan       if( bNew ){
419e8d5648eSdan         rc = sqlite3_preupdate_new(db, i, &pVal);
420e8d5648eSdan       }else{
421e8d5648eSdan         rc = sqlite3_preupdate_old(db, i, &pVal);
422e8d5648eSdan       }
423e8d5648eSdan       if( rc!=SQLITE_OK || sqlite3_value_type(pVal)!=eType ) return rc;
424e8d5648eSdan 
425e8d5648eSdan       switch( eType ){
426e8d5648eSdan         case SQLITE_INTEGER:
427e8d5648eSdan         case SQLITE_FLOAT: {
428e8d5648eSdan           i64 iVal = sessionGetI64(a);
429e8d5648eSdan           a += 8;
430e8d5648eSdan           if( eType==SQLITE_INTEGER ){
431e8d5648eSdan             if( sqlite3_value_int64(pVal)!=iVal ) return SQLITE_OK;
432e8d5648eSdan           }else{
433e8d5648eSdan             double rVal;
434e8d5648eSdan             assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
435e8d5648eSdan             memcpy(&rVal, &iVal, 8);
436e8d5648eSdan             if( sqlite3_value_double(pVal)!=rVal ) return SQLITE_OK;
437e8d5648eSdan           }
438e8d5648eSdan           break;
439e8d5648eSdan         }
440e8d5648eSdan         case SQLITE_TEXT:
441e8d5648eSdan         case SQLITE_BLOB: {
442e8d5648eSdan           int n;
443e8d5648eSdan           const u8 *z;
444e8d5648eSdan           a += sessionVarintGet(a, &n);
445e8d5648eSdan           if( sqlite3_value_bytes(pVal)!=n ) return SQLITE_OK;
446e8d5648eSdan           z = eType==SQLITE_TEXT ?
447e8d5648eSdan             sqlite3_value_text(pVal) : sqlite3_value_blob(pVal);
448e8d5648eSdan           if( memcmp(a, z, n) ) return SQLITE_OK;
449e8d5648eSdan           a += n;
450e8d5648eSdan           break;
451e8d5648eSdan         }
452e8d5648eSdan       }
453e8d5648eSdan     }
454e8d5648eSdan   }
455e8d5648eSdan 
456e8d5648eSdan   *pbEqual = 1;
457e8d5648eSdan   return SQLITE_OK;
4584fccf43aSdan }
4594fccf43aSdan 
4604fccf43aSdan /*
4614fccf43aSdan ** If required, grow the hash table used to store changes on table pTab
4624fccf43aSdan ** (part of the session pSession). If a fatal OOM error occurs, set the
4634fccf43aSdan ** session object to failed and return SQLITE_ERROR. Otherwise, return
4644fccf43aSdan ** SQLITE_OK.
4654fccf43aSdan **
4664fccf43aSdan ** It is possible that a non-fatal OOM error occurs in this function. In
4674fccf43aSdan ** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
4684fccf43aSdan ** Growing the hash table in this case is a performance optimization only,
4694fccf43aSdan ** it is not required for correct operation.
4704fccf43aSdan */
4714fccf43aSdan static int sessionGrowHash(sqlite3_session *pSession, SessionTable *pTab){
4724fccf43aSdan   if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
4734fccf43aSdan     int i;
4744fccf43aSdan     SessionChange **apNew;
4754fccf43aSdan     int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
4764fccf43aSdan 
4774fccf43aSdan     apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
4784fccf43aSdan     if( apNew==0 ){
4794fccf43aSdan       if( pTab->nChange==0 ){
4804fccf43aSdan         pSession->rc = SQLITE_NOMEM;
4814fccf43aSdan         return SQLITE_ERROR;
4824fccf43aSdan       }
4834fccf43aSdan       return SQLITE_OK;
4844fccf43aSdan     }
4854fccf43aSdan     memset(apNew, 0, sizeof(SessionChange *) * nNew);
4864fccf43aSdan 
4874fccf43aSdan     for(i=0; i<pTab->nChange; i++){
4884fccf43aSdan       SessionChange *p;
4894fccf43aSdan       SessionChange *pNext;
4904fccf43aSdan       for(p=pTab->apChange[i]; p; p=pNext){
491e8d5648eSdan         int iHash = sessionChangeHash(pSession->db, pTab, p, nNew);
4924fccf43aSdan         pNext = p->pNext;
4934fccf43aSdan         p->pNext = apNew[iHash];
4944fccf43aSdan         apNew[iHash] = p;
4954fccf43aSdan       }
4964fccf43aSdan     }
4974fccf43aSdan 
4984fccf43aSdan     sqlite3_free(pTab->apChange);
4994fccf43aSdan     pTab->nChange = nNew;
5004fccf43aSdan     pTab->apChange = apNew;
5014fccf43aSdan   }
5024fccf43aSdan 
5034fccf43aSdan   return SQLITE_OK;
5044fccf43aSdan }
5054fccf43aSdan 
506296c7658Sdan /*
507e8d5648eSdan ** This function queries the database for the names of the columns of table
508e8d5648eSdan ** zThis, in schema zDb. It is expected that the table has nCol columns. If
509e8d5648eSdan ** not, SQLITE_SCHEMA is returned and none of the output variables are
510e8d5648eSdan ** populated.
511e8d5648eSdan **
512e8d5648eSdan ** Otherwise, if it is not NULL, variable *pzTab is set to point to a
513e8d5648eSdan ** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
514e8d5648eSdan ** point to an array of pointers to column names. And *pabPK (again, if not
515e8d5648eSdan ** NULL) is set to point to an array of booleans - true if the corresponding
516e8d5648eSdan ** column is part of the primary key.
517e8d5648eSdan **
518e8d5648eSdan ** For example, if the table is declared as:
519e8d5648eSdan **
520e8d5648eSdan **     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
521e8d5648eSdan **
522e8d5648eSdan ** Then the three output variables are populated as follows:
523e8d5648eSdan **
524e8d5648eSdan **     *pzTab  = "tbl1"
525e8d5648eSdan **     *pazCol = {"w", "x", "y", "z"}
526e8d5648eSdan **     *pabPK  = {1, 0, 0, 1}
527e8d5648eSdan **
528e8d5648eSdan ** All returned buffers are part of the same single allocation, which must
529e8d5648eSdan ** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then
530e8d5648eSdan ** pointer *pazCol should be freed to release all memory. Otherwise, pointer
531e8d5648eSdan ** *pabPK. It is illegal for both pazCol and pabPK to be NULL.
532e8d5648eSdan */
533e8d5648eSdan static int sessionTableInfo(
534e8d5648eSdan   sqlite3 *db,                    /* Database connection */
535e8d5648eSdan   const char *zDb,                /* Name of attached database (e.g. "main") */
536e8d5648eSdan   const char *zThis,              /* Table name */
537e8d5648eSdan   int nCol,                       /* Expected number of columns */
538e8d5648eSdan   const char **pzTab,             /* OUT: Copy of zThis */
539e8d5648eSdan   const char ***pazCol,           /* OUT: Array of column names for table */
540e8d5648eSdan   u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
541e8d5648eSdan ){
542e8d5648eSdan   char *zPragma;
543e8d5648eSdan   sqlite3_stmt *pStmt;
544e8d5648eSdan   int rc;
545e8d5648eSdan   int nByte;
546e8d5648eSdan   int nDbCol = 0;
547e8d5648eSdan   int nThis;
548e8d5648eSdan   int i;
549e8d5648eSdan   u8 *pAlloc;
550e8d5648eSdan   u8 *pFree = 0;
551e8d5648eSdan   char **azCol;
552e8d5648eSdan   u8 *abPK;
553e8d5648eSdan 
554e8d5648eSdan   assert( pazCol || pabPK );
555e8d5648eSdan 
556e8d5648eSdan   nThis = strlen(zThis);
557e8d5648eSdan   zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
558e8d5648eSdan   if( !zPragma ) return SQLITE_NOMEM;
559e8d5648eSdan 
560e8d5648eSdan   rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
561e8d5648eSdan   sqlite3_free(zPragma);
562e8d5648eSdan   if( rc!=SQLITE_OK ) return rc;
563e8d5648eSdan 
564e8d5648eSdan   nByte = nThis + 1;
565e8d5648eSdan   while( SQLITE_ROW==sqlite3_step(pStmt) ){
566e8d5648eSdan     nByte += sqlite3_column_bytes(pStmt, 1);
567e8d5648eSdan     nDbCol++;
568e8d5648eSdan   }
569e8d5648eSdan   rc = sqlite3_reset(pStmt);
570e8d5648eSdan 
571e8d5648eSdan   if( nDbCol!=nCol ){
572e8d5648eSdan     rc = SQLITE_SCHEMA;
573e8d5648eSdan   }
574e8d5648eSdan   if( rc==SQLITE_OK ){
575e8d5648eSdan     nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
576e8d5648eSdan     pAlloc = sqlite3_malloc(nByte);
577e8d5648eSdan     if( pAlloc==0 ){
578e8d5648eSdan       rc = SQLITE_NOMEM;
579e8d5648eSdan     }
580e8d5648eSdan   }
581e8d5648eSdan   if( rc==SQLITE_OK ){
582e8d5648eSdan     pFree = pAlloc;
583e8d5648eSdan     if( pazCol ){
584e8d5648eSdan       azCol = (char **)pAlloc;
585e8d5648eSdan       pAlloc = (u8 *)&azCol[nCol];
586e8d5648eSdan     }
587e8d5648eSdan     if( pabPK ){
588e8d5648eSdan       abPK = (u8 *)pAlloc;
589e8d5648eSdan       pAlloc = &abPK[nCol];
590e8d5648eSdan     }
591e8d5648eSdan     if( pzTab ){
592e8d5648eSdan       memcpy(pAlloc, zThis, nThis+1);
593e8d5648eSdan       *pzTab = (char *)pAlloc;
594e8d5648eSdan       pAlloc += nThis+1;
595e8d5648eSdan     }
596e8d5648eSdan 
597e8d5648eSdan     i = 0;
598e8d5648eSdan     while( SQLITE_ROW==sqlite3_step(pStmt) ){
599e8d5648eSdan       int nName = sqlite3_column_bytes(pStmt, 1);
600e8d5648eSdan       const unsigned char *zName = sqlite3_column_text(pStmt, 1);
601e8d5648eSdan       if( zName==0 ) break;
602e8d5648eSdan       if( pazCol ){
603e8d5648eSdan         memcpy(pAlloc, zName, nName+1);
604e8d5648eSdan         azCol[i] = (char *)pAlloc;
605e8d5648eSdan         pAlloc += nName+1;
606e8d5648eSdan       }
607e8d5648eSdan       if( pabPK ) abPK[i] = sqlite3_column_int(pStmt, 5);
608e8d5648eSdan       i++;
609e8d5648eSdan     }
610e8d5648eSdan     rc = sqlite3_reset(pStmt);
611e8d5648eSdan 
612e8d5648eSdan   }
613e8d5648eSdan 
614e8d5648eSdan   /* If successful, populate the output variables. Otherwise, zero them and
615e8d5648eSdan   ** free any allocation made. An error code will be returned in this case.
616e8d5648eSdan   */
617e8d5648eSdan   if( rc==SQLITE_OK ){
618e8d5648eSdan     if( pazCol ) *pazCol = (const char **)azCol;
619e8d5648eSdan     if( pabPK ) *pabPK = abPK;
620e8d5648eSdan   }else{
621e8d5648eSdan     if( pazCol ) *pazCol = 0;
622e8d5648eSdan     if( pabPK ) *pabPK = 0;
623e8d5648eSdan     if( pzTab ) *pzTab = 0;
624e8d5648eSdan     sqlite3_free(pFree);
625e8d5648eSdan   }
626e8d5648eSdan   sqlite3_finalize(pStmt);
627e8d5648eSdan   return rc;
628e8d5648eSdan }
629e8d5648eSdan 
630e8d5648eSdan /*
631296c7658Sdan ** This function is only called from within a pre-update handler for a
632296c7658Sdan ** write to table pTab, part of session pSession. If this is the first
633296c7658Sdan ** write to this table, set the SessionTable.nCol variable to the number
634296c7658Sdan ** of columns in the table.
635296c7658Sdan **
636296c7658Sdan ** Otherwise, if this is not the first time this table has been written
637296c7658Sdan ** to, check that the number of columns in the table has not changed. If
638296c7658Sdan ** it has not, return zero.
639296c7658Sdan **
640296c7658Sdan ** If the number of columns in the table has changed since the last write
641296c7658Sdan ** was recorded, set the session error-code to SQLITE_SCHEMA and return
642296c7658Sdan ** non-zero. Users are not allowed to change the number of columns in a table
643296c7658Sdan ** for which changes are being recorded by the session module. If they do so,
644296c7658Sdan ** it is an error.
645296c7658Sdan */
6464fccf43aSdan static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
6474fccf43aSdan   if( pTab->nCol==0 ){
648e8d5648eSdan     assert( pTab->azCol==0 || pTab->abPK==0 );
6494fccf43aSdan     pTab->nCol = sqlite3_preupdate_count(pSession->db);
650e8d5648eSdan     pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
651e8d5648eSdan         pTab->zName, pTab->nCol, 0, &pTab->azCol, &pTab->abPK
652e8d5648eSdan     );
653296c7658Sdan   }else if( pTab->nCol!=sqlite3_preupdate_count(pSession->db) ){
6544fccf43aSdan     pSession->rc = SQLITE_SCHEMA;
6554fccf43aSdan   }
656e8d5648eSdan   return pSession->rc;
657e8d5648eSdan }
658e8d5648eSdan 
659e8d5648eSdan static void sessionPreupdateOneChange(
660e8d5648eSdan   int op,
661e8d5648eSdan   sqlite3_session *pSession,
662e8d5648eSdan   SessionTable *pTab
663e8d5648eSdan ){
664e8d5648eSdan   sqlite3 *db = pSession->db;
665e8d5648eSdan   SessionChange *pChange;
666e8d5648eSdan   SessionChange *pC;
667e8d5648eSdan   int iHash;
668e8d5648eSdan   int rc = SQLITE_OK;
669e8d5648eSdan 
670e8d5648eSdan   if( pSession->rc ) return;
671e8d5648eSdan 
672e8d5648eSdan   /* Load table details if required */
673e8d5648eSdan   if( sessionInitTable(pSession, pTab) ) return;
674e8d5648eSdan 
675e8d5648eSdan   /* Grow the hash table if required */
676e8d5648eSdan   if( sessionGrowHash(pSession, pTab) ) return;
677e8d5648eSdan 
678e8d5648eSdan   /* Search the hash table for an existing entry for rowid=iKey2. If
679e8d5648eSdan    ** one is found, store a pointer to it in pChange and unlink it from
680e8d5648eSdan    ** the hash table. Otherwise, set pChange to NULL.
681e8d5648eSdan    */
682e8d5648eSdan   rc = sessionPreupdateHash(db, pTab, op==SQLITE_INSERT, &iHash);
683e8d5648eSdan   for(pC=pTab->apChange[iHash]; rc==SQLITE_OK && pC; pC=pC->pNext){
684e8d5648eSdan     int bEqual;
685e8d5648eSdan     rc = sessionPreupdateEqual(db, pTab, pC, op==SQLITE_INSERT, &bEqual);
686e8d5648eSdan     if( bEqual ) break;
687e8d5648eSdan   }
688e8d5648eSdan   if( pC==0 ){
689e8d5648eSdan     /* Create a new change object containing all the old values (if
690e8d5648eSdan      ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
691e8d5648eSdan      ** values (if this is an INSERT). */
692e8d5648eSdan     int nByte;              /* Number of bytes to allocate */
693e8d5648eSdan     int i;                  /* Used to iterate through columns */
694e8d5648eSdan 
695e8d5648eSdan     pTab->nEntry++;
696e8d5648eSdan 
697e8d5648eSdan     /* Figure out how large an allocation is required */
698e8d5648eSdan     nByte = sizeof(SessionChange);
699e8d5648eSdan     for(i=0; i<pTab->nCol && rc==SQLITE_OK; i++){
700e8d5648eSdan       sqlite3_value *p = 0;
701e8d5648eSdan       if( op!=SQLITE_INSERT ){
702e8d5648eSdan         rc = sqlite3_preupdate_old(pSession->db, i, &p);
703e8d5648eSdan       }else if( 1 || pTab->abPK[i] ){
704e8d5648eSdan         rc = sqlite3_preupdate_new(pSession->db, i, &p);
705e8d5648eSdan       }
706e8d5648eSdan       if( p && rc==SQLITE_OK ){
707e8d5648eSdan         rc = sessionSerializeValue(0, p, &nByte);
708e8d5648eSdan       }
709e8d5648eSdan     }
710e8d5648eSdan 
711e8d5648eSdan     /* Allocate the change object */
712e8d5648eSdan     pChange = (SessionChange *)sqlite3_malloc(nByte);
713e8d5648eSdan     if( !pChange ){
714e8d5648eSdan       rc = SQLITE_NOMEM;
715e8d5648eSdan     }else{
716e8d5648eSdan       memset(pChange, 0, sizeof(SessionChange));
717e8d5648eSdan       pChange->aRecord = (u8 *)&pChange[1];
718e8d5648eSdan     }
719e8d5648eSdan 
720e8d5648eSdan     /* Populate the change object */
721e8d5648eSdan     nByte = 0;
722e8d5648eSdan     for(i=0; i<pTab->nCol && rc==SQLITE_OK; i++){
723e8d5648eSdan       sqlite3_value *p = 0;
724e8d5648eSdan       if( op!=SQLITE_INSERT ){
725e8d5648eSdan         rc = sqlite3_preupdate_old(pSession->db, i, &p);
726e8d5648eSdan       }else if( 1 || pTab->abPK[i] ){
727e8d5648eSdan         rc = sqlite3_preupdate_new(pSession->db, i, &p);
728e8d5648eSdan       }
729e8d5648eSdan       if( p && rc==SQLITE_OK ){
730e8d5648eSdan         rc = sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
731e8d5648eSdan       }
732e8d5648eSdan     }
733e8d5648eSdan     pChange->nRecord = nByte;
734e8d5648eSdan 
735e8d5648eSdan     /* If an error has occurred, mark the session object as failed. */
736e8d5648eSdan     if( rc!=SQLITE_OK ){
737e8d5648eSdan       sqlite3_free(pChange);
738e8d5648eSdan       pSession->rc = rc;
739e8d5648eSdan     }else{
740e8d5648eSdan       /* Add the change back to the hash-table */
741e8d5648eSdan       pChange->bInsert = (op==SQLITE_INSERT);
742e8d5648eSdan       pChange->pNext = pTab->apChange[iHash];
743e8d5648eSdan       pTab->apChange[iHash] = pChange;
744e8d5648eSdan     }
745e8d5648eSdan   }
7464fccf43aSdan }
7474fccf43aSdan 
7484fccf43aSdan /*
7494fccf43aSdan ** The 'pre-update' hook registered by this module with SQLite databases.
7504fccf43aSdan */
7514fccf43aSdan static void xPreUpdate(
7524fccf43aSdan   void *pCtx,                     /* Copy of third arg to preupdate_hook() */
7534fccf43aSdan   sqlite3 *db,                    /* Database handle */
7544fccf43aSdan   int op,                         /* SQLITE_UPDATE, DELETE or INSERT */
7554fccf43aSdan   char const *zDb,                /* Database name */
7564fccf43aSdan   char const *zName,              /* Table name */
7574fccf43aSdan   sqlite3_int64 iKey1,            /* Rowid of row about to be deleted/updated */
7584fccf43aSdan   sqlite3_int64 iKey2             /* New rowid value (for a rowid UPDATE) */
7594fccf43aSdan ){
7604fccf43aSdan   sqlite3_session *pSession;
7614fccf43aSdan   int nDb = strlen(zDb);
7624fccf43aSdan   int nName = strlen(zDb);
7634fccf43aSdan 
7644c220252Sdan   assert( sqlite3_mutex_held(db->mutex) );
7654c220252Sdan 
7664fccf43aSdan   for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
7674fccf43aSdan     SessionTable *pTab;
768296c7658Sdan 
769e8d5648eSdan     /* If this session is attached to a different database ("main", "temp"
770e8d5648eSdan     ** etc.), or if it is not currently enabled, there is nothing to do. Skip
771e8d5648eSdan     ** to the next session object attached to this database. */
772296c7658Sdan     if( pSession->bEnable==0 ) continue;
7734fccf43aSdan     if( pSession->rc ) continue;
7744fccf43aSdan     if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
775296c7658Sdan 
7764fccf43aSdan     for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
7774fccf43aSdan       if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ){
778e8d5648eSdan         sessionPreupdateOneChange(op, pSession, pTab);
779e8d5648eSdan         if( op==SQLITE_UPDATE ){
780e8d5648eSdan           sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
7814fccf43aSdan         }
7824fccf43aSdan         break;
7834fccf43aSdan       }
7844fccf43aSdan     }
7854fccf43aSdan   }
786296c7658Sdan }
7874fccf43aSdan 
7884fccf43aSdan /*
7894fccf43aSdan ** Create a session object. This session object will record changes to
7904fccf43aSdan ** database zDb attached to connection db.
7914fccf43aSdan */
7924fccf43aSdan int sqlite3session_create(
7934fccf43aSdan   sqlite3 *db,                    /* Database handle */
7944fccf43aSdan   const char *zDb,                /* Name of db (e.g. "main") */
7954fccf43aSdan   sqlite3_session **ppSession     /* OUT: New session object */
7964fccf43aSdan ){
797296c7658Sdan   sqlite3_session *pNew;          /* Newly allocated session object */
798296c7658Sdan   sqlite3_session *pOld;          /* Session object already attached to db */
7994fccf43aSdan   int nDb = strlen(zDb);          /* Length of zDb in bytes */
8004fccf43aSdan 
801296c7658Sdan   /* Zero the output value in case an error occurs. */
8024fccf43aSdan   *ppSession = 0;
8034fccf43aSdan 
8044fccf43aSdan   /* Allocate and populate the new session object. */
8054fccf43aSdan   pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
8064fccf43aSdan   if( !pNew ) return SQLITE_NOMEM;
8074fccf43aSdan   memset(pNew, 0, sizeof(sqlite3_session));
8084fccf43aSdan   pNew->db = db;
8094fccf43aSdan   pNew->zDb = (char *)&pNew[1];
810296c7658Sdan   pNew->bEnable = 1;
8114fccf43aSdan   memcpy(pNew->zDb, zDb, nDb+1);
8124fccf43aSdan 
8134fccf43aSdan   /* Add the new session object to the linked list of session objects
8144fccf43aSdan   ** attached to database handle $db. Do this under the cover of the db
8154fccf43aSdan   ** handle mutex.  */
8164fccf43aSdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
8174fccf43aSdan   pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
8184fccf43aSdan   pNew->pNext = pOld;
8194fccf43aSdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
8204fccf43aSdan 
8214fccf43aSdan   *ppSession = pNew;
8224fccf43aSdan   return SQLITE_OK;
8234fccf43aSdan }
8244fccf43aSdan 
8254fccf43aSdan /*
8264fccf43aSdan ** Delete a session object previously allocated using sqlite3session_create().
8274fccf43aSdan */
8284fccf43aSdan void sqlite3session_delete(sqlite3_session *pSession){
8294fccf43aSdan   sqlite3 *db = pSession->db;
8304fccf43aSdan   sqlite3_session *pHead;
8314fccf43aSdan   sqlite3_session **pp;
8324fccf43aSdan 
833296c7658Sdan   /* Unlink the session from the linked list of sessions attached to the
834296c7658Sdan   ** database handle. Hold the db mutex while doing so.  */
8354fccf43aSdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
8364fccf43aSdan   pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
8374fccf43aSdan   for(pp=&pHead; (*pp)!=pSession; pp=&((*pp)->pNext));
8384fccf43aSdan   *pp = (*pp)->pNext;
8394fccf43aSdan   if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void *)pHead);
8404fccf43aSdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
8414fccf43aSdan 
842296c7658Sdan   /* Delete all attached table objects. And the contents of their
843296c7658Sdan   ** associated hash-tables. */
8444fccf43aSdan   while( pSession->pTable ){
8454fccf43aSdan     int i;
8464fccf43aSdan     SessionTable *pTab = pSession->pTable;
8474fccf43aSdan     pSession->pTable = pTab->pNext;
8484fccf43aSdan     for(i=0; i<pTab->nChange; i++){
8494fccf43aSdan       SessionChange *p;
8504fccf43aSdan       SessionChange *pNext;
8514fccf43aSdan       for(p=pTab->apChange[i]; p; p=pNext){
8524fccf43aSdan         pNext = p->pNext;
8534fccf43aSdan         sqlite3_free(p);
8544fccf43aSdan       }
8554fccf43aSdan     }
856e8d5648eSdan     sqlite3_free(pTab->azCol);
8574fccf43aSdan     sqlite3_free(pTab->apChange);
8584fccf43aSdan     sqlite3_free(pTab);
8594fccf43aSdan   }
8604fccf43aSdan 
861296c7658Sdan   /* Free the session object itself. */
8624fccf43aSdan   sqlite3_free(pSession);
8634fccf43aSdan }
8644fccf43aSdan 
8654fccf43aSdan /*
8664fccf43aSdan ** Attach a table to a session. All subsequent changes made to the table
8674fccf43aSdan ** while the session object is enabled will be recorded.
8684fccf43aSdan **
8694fccf43aSdan ** Only tables that have a PRIMARY KEY defined may be attached. It does
8704fccf43aSdan ** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
8714fccf43aSdan ** or not.
8724fccf43aSdan */
8734fccf43aSdan int sqlite3session_attach(
8744fccf43aSdan   sqlite3_session *pSession,      /* Session object */
8754fccf43aSdan   const char *zName               /* Table name */
8764fccf43aSdan ){
877296c7658Sdan   SessionTable *pTab;             /* New table object (if required) */
878296c7658Sdan   int nName;                      /* Number of bytes in string zName */
8794c220252Sdan   int rc = SQLITE_OK;
8804c220252Sdan 
8814c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
8824fccf43aSdan 
8834fccf43aSdan   /* First search for an existing entry. If one is found, this call is
8844fccf43aSdan   ** a no-op. Return early. */
8854fccf43aSdan   nName = strlen(zName);
8864fccf43aSdan   for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
8874c220252Sdan     if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
8884fccf43aSdan   }
8894fccf43aSdan 
8904c220252Sdan   if( !pTab ){
8914fccf43aSdan     /* Allocate new SessionTable object. */
8924fccf43aSdan     pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
8934c220252Sdan     if( !pTab ){
8944c220252Sdan       rc = SQLITE_NOMEM;
8954c220252Sdan     }else{
8964fccf43aSdan       /* Populate the new SessionTable object and link it into the list. */
8974fccf43aSdan       memset(pTab, 0, sizeof(SessionTable));
8984fccf43aSdan       pTab->zName = (char *)&pTab[1];
8994fccf43aSdan       memcpy(pTab->zName, zName, nName+1);
9004fccf43aSdan       pTab->pNext = pSession->pTable;
9014fccf43aSdan       pSession->pTable = pTab;
9024c220252Sdan     }
9034c220252Sdan   }
9044fccf43aSdan 
9054c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
9064c220252Sdan   return rc;
9074fccf43aSdan }
9084fccf43aSdan 
909296c7658Sdan /*
910296c7658Sdan ** Ensure that there is room in the buffer to append nByte bytes of data.
911296c7658Sdan ** If not, use sqlite3_realloc() to grow the buffer so that there is.
912296c7658Sdan **
913296c7658Sdan ** If successful, return zero. Otherwise, if an OOM condition is encountered,
914296c7658Sdan ** set *pRc to SQLITE_NOMEM and return non-zero.
915296c7658Sdan */
9164fccf43aSdan static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
9174fccf43aSdan   if( p->nAlloc-p->nBuf<nByte ){
9184fccf43aSdan     u8 *aNew;
9194fccf43aSdan     int nNew = p->nAlloc ? p->nAlloc : 128;
9204fccf43aSdan     do {
9214fccf43aSdan       nNew = nNew*2;
9224fccf43aSdan     }while( nNew<(p->nAlloc+nByte) );
9234fccf43aSdan 
9244fccf43aSdan     aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
9254fccf43aSdan     if( 0==aNew ){
9264fccf43aSdan       *pRc = SQLITE_NOMEM;
9274fccf43aSdan       return 1;
9284fccf43aSdan     }
9294fccf43aSdan     p->aBuf = aNew;
9304fccf43aSdan     p->nAlloc = nNew;
9314fccf43aSdan   }
9324fccf43aSdan   return 0;
9334fccf43aSdan }
9344fccf43aSdan 
935296c7658Sdan /*
936296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
937296c7658Sdan ** called. Otherwise, append a single byte to the buffer.
938296c7658Sdan **
939296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
940296c7658Sdan ** returning.
941296c7658Sdan */
9424fccf43aSdan static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
9434fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 1, pRc) ){
9444fccf43aSdan     p->aBuf[p->nBuf++] = v;
9454fccf43aSdan   }
9464fccf43aSdan }
9474fccf43aSdan 
948296c7658Sdan /*
949296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
950296c7658Sdan ** called. Otherwise, append a single varint to the buffer.
951296c7658Sdan **
952296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
953296c7658Sdan ** returning.
954296c7658Sdan */
9554fccf43aSdan static void sessionAppendVarint(SessionBuffer *p, sqlite3_int64 v, int *pRc){
9564fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 9, pRc) ){
9574fccf43aSdan     p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
9584fccf43aSdan   }
9594fccf43aSdan }
9604fccf43aSdan 
961296c7658Sdan /*
962296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
963296c7658Sdan ** called. Otherwise, append a blob of data to the buffer.
964296c7658Sdan **
965296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
966296c7658Sdan ** returning.
967296c7658Sdan */
9684fccf43aSdan static void sessionAppendBlob(
9694fccf43aSdan   SessionBuffer *p,
9704fccf43aSdan   const u8 *aBlob,
9714fccf43aSdan   int nBlob,
9724fccf43aSdan   int *pRc
9734fccf43aSdan ){
9744fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nBlob, pRc) ){
9754fccf43aSdan     memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
9764fccf43aSdan     p->nBuf += nBlob;
9774fccf43aSdan   }
9784fccf43aSdan }
9794fccf43aSdan 
980296c7658Sdan /*
981296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
982296c7658Sdan ** called. Otherwise, append a string to the buffer. All bytes in the string
983296c7658Sdan ** up to (but not including) the nul-terminator are written to the buffer.
984296c7658Sdan **
985296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
986296c7658Sdan ** returning.
987296c7658Sdan */
988d5f0767cSdan static void sessionAppendStr(
989d5f0767cSdan   SessionBuffer *p,
990d5f0767cSdan   const char *zStr,
991d5f0767cSdan   int *pRc
992d5f0767cSdan ){
993d5f0767cSdan   int nStr = strlen(zStr);
994d5f0767cSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
995d5f0767cSdan     memcpy(&p->aBuf[p->nBuf], zStr, nStr);
996d5f0767cSdan     p->nBuf += nStr;
997d5f0767cSdan   }
998d5f0767cSdan }
999d5f0767cSdan 
1000296c7658Sdan /*
1001296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1002296c7658Sdan ** called. Otherwise, append the string representation of integer iVal
1003296c7658Sdan ** to the buffer. No nul-terminator is written.
1004296c7658Sdan **
1005296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
1006296c7658Sdan ** returning.
1007296c7658Sdan */
1008d5f0767cSdan static void sessionAppendInteger(
1009296c7658Sdan   SessionBuffer *p,               /* Buffer to append to */
1010296c7658Sdan   int iVal,                       /* Value to write the string rep. of */
1011296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
1012d5f0767cSdan ){
1013d5f0767cSdan   char aBuf[24];
1014d5f0767cSdan   sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
1015d5f0767cSdan   sessionAppendStr(p, aBuf, pRc);
1016d5f0767cSdan }
1017d5f0767cSdan 
1018296c7658Sdan /*
1019296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1020296c7658Sdan ** called. Otherwise, append the string zStr enclosed in quotes (") and
1021296c7658Sdan ** with any embedded quote characters escaped to the buffer. No
1022296c7658Sdan ** nul-terminator byte is written.
1023296c7658Sdan **
1024296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
1025296c7658Sdan ** returning.
1026296c7658Sdan */
1027d5f0767cSdan static void sessionAppendIdent(
1028296c7658Sdan   SessionBuffer *p,               /* Buffer to a append to */
1029296c7658Sdan   const char *zStr,               /* String to quote, escape and append */
1030296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
1031d5f0767cSdan ){
1032d5f0767cSdan   int nStr = strlen(zStr)*2 + 2 + 1;
1033d5f0767cSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
1034d5f0767cSdan     char *zOut = (char *)&p->aBuf[p->nBuf];
1035d5f0767cSdan     const char *zIn = zStr;
1036d5f0767cSdan     *zOut++ = '"';
1037d5f0767cSdan     while( *zIn ){
1038d5f0767cSdan       if( *zIn=='"' ) *zOut++ = '"';
1039d5f0767cSdan       *zOut++ = *(zIn++);
1040d5f0767cSdan     }
1041d5f0767cSdan     *zOut++ = '"';
1042d5f0767cSdan     p->nBuf = ((u8 *)zOut - p->aBuf);
1043d5f0767cSdan   }
1044d5f0767cSdan }
1045d5f0767cSdan 
1046296c7658Sdan /*
1047296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1048296c7658Sdan ** called. Otherwse, it appends the serialized version of the value stored
1049296c7658Sdan ** in column iCol of the row that SQL statement pStmt currently points
1050296c7658Sdan ** to to the buffer.
1051296c7658Sdan */
10524fccf43aSdan static void sessionAppendCol(
1053296c7658Sdan   SessionBuffer *p,               /* Buffer to append to */
1054296c7658Sdan   sqlite3_stmt *pStmt,            /* Handle pointing to row containing value */
1055296c7658Sdan   int iCol,                       /* Column to read value from */
1056296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
10574fccf43aSdan ){
10584fccf43aSdan   if( *pRc==SQLITE_OK ){
10594fccf43aSdan     int eType = sqlite3_column_type(pStmt, iCol);
10604fccf43aSdan     sessionAppendByte(p, (u8)eType, pRc);
10614fccf43aSdan     if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
10624fccf43aSdan       sqlite3_int64 i;
10634fccf43aSdan       u8 aBuf[8];
10644fccf43aSdan       if( eType==SQLITE_INTEGER ){
10654fccf43aSdan         i = sqlite3_column_int64(pStmt, iCol);
10664fccf43aSdan       }else{
10674fccf43aSdan         double r = sqlite3_column_double(pStmt, iCol);
10684fccf43aSdan         memcpy(&i, &r, 8);
10694fccf43aSdan       }
1070296c7658Sdan       sessionPutI64(aBuf, i);
10714fccf43aSdan       sessionAppendBlob(p, aBuf, 8, pRc);
10724fccf43aSdan     }
10734fccf43aSdan     if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
10744fccf43aSdan       int nByte = sqlite3_column_bytes(pStmt, iCol);
10754fccf43aSdan       sessionAppendVarint(p, nByte, pRc);
10764fccf43aSdan       sessionAppendBlob(p, eType==SQLITE_BLOB ?
10774fccf43aSdan         sqlite3_column_blob(pStmt, iCol) : sqlite3_column_text(pStmt, iCol),
10784fccf43aSdan         nByte, pRc
10794fccf43aSdan       );
10804fccf43aSdan     }
10814fccf43aSdan   }
10824fccf43aSdan }
10834fccf43aSdan 
1084296c7658Sdan /*
1085296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1086296c7658Sdan ** called.
1087296c7658Sdan **
1088296c7658Sdan ** Otherwse, if *pRc is SQLITE_OK, then it appends an update change to
1089296c7658Sdan ** the buffer (see the comments under "CHANGESET FORMAT" at the top of the
1090296c7658Sdan ** file). An update change consists of:
1091296c7658Sdan **
1092296c7658Sdan **   1 byte:  SQLITE_UPDATE (0x17)
1093296c7658Sdan **   n bytes: old.* record (see RECORD FORMAT)
1094296c7658Sdan **   m bytes: new.* record (see RECORD FORMAT)
1095296c7658Sdan **
1096296c7658Sdan ** The SessionChange object passed as the third argument contains the
1097296c7658Sdan ** values that were stored in the row when the session began (the old.*
1098296c7658Sdan ** values). The statement handle passed as the second argument points
1099296c7658Sdan ** at the current version of the row (the new.* values).
1100296c7658Sdan **
1101296c7658Sdan ** If all of the old.* values are equal to their corresponding new.* value
1102296c7658Sdan ** (i.e. nothing has changed), then no data at all is appended to the buffer.
1103296c7658Sdan **
1104296c7658Sdan ** Otherwise, the old.* record contains all primary key values and the
1105296c7658Sdan ** original values of any fields that have been modified. The new.* record
1106296c7658Sdan ** contains the new values of only those fields that have been modified.
1107296c7658Sdan */
11084fccf43aSdan static void sessionAppendUpdate(
1109296c7658Sdan   SessionBuffer *pBuf,            /* Buffer to append to */
1110296c7658Sdan   sqlite3_stmt *pStmt,            /* Statement handle pointing at new row */
1111296c7658Sdan   SessionChange *p,               /* Object containing old values */
1112296c7658Sdan   u8 *abPK,                       /* Boolean array - true for PK columns */
1113296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
11144fccf43aSdan ){
11154fccf43aSdan   if( *pRc==SQLITE_OK ){
1116296c7658Sdan     SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
1117296c7658Sdan     int bNoop = 1;                /* Set to zero if any values are modified */
11181f34f8ccSdan     int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
1119296c7658Sdan     int i;                        /* Used to iterate through columns */
1120296c7658Sdan     u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */
1121296c7658Sdan 
11224fccf43aSdan     sessionAppendByte(pBuf, SQLITE_UPDATE, pRc);
11234fccf43aSdan     for(i=0; i<sqlite3_column_count(pStmt); i++){
112437f133ecSdan       int bChanged = 0;
11254fccf43aSdan       int nAdvance;
11264fccf43aSdan       int eType = *pCsr;
11274fccf43aSdan       switch( eType ){
11284fccf43aSdan         case SQLITE_NULL:
11294fccf43aSdan           nAdvance = 1;
11304fccf43aSdan           if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
113137f133ecSdan             bChanged = 1;
11324fccf43aSdan           }
11334fccf43aSdan           break;
11344fccf43aSdan 
11354fccf43aSdan         case SQLITE_FLOAT:
11364fccf43aSdan         case SQLITE_INTEGER: {
11374fccf43aSdan           nAdvance = 9;
11384fccf43aSdan           if( eType==sqlite3_column_type(pStmt, i) ){
11394fccf43aSdan             sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
11404fccf43aSdan             if( eType==SQLITE_INTEGER ){
11414fccf43aSdan               if( iVal==sqlite3_column_int64(pStmt, i) ) break;
11424fccf43aSdan             }else{
11434fccf43aSdan               double dVal;
11444fccf43aSdan               memcpy(&dVal, &iVal, 8);
11454fccf43aSdan               if( dVal==sqlite3_column_double(pStmt, i) ) break;
11464fccf43aSdan             }
11474fccf43aSdan           }
114837f133ecSdan           bChanged = 1;
11494fccf43aSdan           break;
11504fccf43aSdan         }
11514fccf43aSdan 
11524fccf43aSdan         case SQLITE_TEXT:
11534fccf43aSdan         case SQLITE_BLOB: {
11544fccf43aSdan           int nByte;
11554fccf43aSdan           int nHdr = 1 + sessionVarintGet(&pCsr[1], &nByte);
11564fccf43aSdan           nAdvance = nHdr + nByte;
11574fccf43aSdan           if( eType==sqlite3_column_type(pStmt, i)
11584fccf43aSdan            && nByte==sqlite3_column_bytes(pStmt, i)
11594fccf43aSdan            && 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), nByte)
11604fccf43aSdan           ){
11614fccf43aSdan             break;
11624fccf43aSdan           }
116337f133ecSdan           bChanged = 1;
11644fccf43aSdan         }
11654fccf43aSdan       }
11664fccf43aSdan 
116737f133ecSdan       if( bChanged || abPK[i] ){
116837f133ecSdan         sessionAppendBlob(pBuf, pCsr, nAdvance, pRc);
11694fccf43aSdan       }else{
117037f133ecSdan         sessionAppendByte(pBuf, 0, pRc);
117137f133ecSdan       }
117237f133ecSdan 
117337f133ecSdan       if( bChanged ){
11744fccf43aSdan         sessionAppendCol(&buf2, pStmt, i, pRc);
11754fccf43aSdan         bNoop = 0;
117637f133ecSdan       }else{
117737f133ecSdan         sessionAppendByte(&buf2, 0, pRc);
11784fccf43aSdan       }
117937f133ecSdan 
11804fccf43aSdan       pCsr += nAdvance;
11814fccf43aSdan     }
11824fccf43aSdan 
11834fccf43aSdan     if( bNoop ){
11841f34f8ccSdan       pBuf->nBuf = nRewind;
11854fccf43aSdan     }else{
11864fccf43aSdan       sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, pRc);
11874fccf43aSdan     }
11881f34f8ccSdan     sqlite3_free(buf2.aBuf);
11894fccf43aSdan   }
1190d5f0767cSdan }
11914fccf43aSdan 
1192e8d5648eSdan static int sessionSelectStmt(
1193e8d5648eSdan   sqlite3 *db,                    /* Database handle */
1194d7fb7d24Sdan   const char *zDb,                /* Database name */
1195e8d5648eSdan   const char *zTab,               /* Table name */
1196e8d5648eSdan   int nCol,
1197e8d5648eSdan   const char **azCol,
1198e8d5648eSdan   u8 *abPK,
1199e8d5648eSdan   sqlite3_stmt **ppStmt
1200d5f0767cSdan ){
1201e8d5648eSdan   int rc = SQLITE_OK;
1202d5f0767cSdan   int i;
1203e8d5648eSdan   const char *zSep = "";
1204e8d5648eSdan   SessionBuffer buf = {0, 0, 0};
1205d5f0767cSdan 
1206e8d5648eSdan   sessionAppendStr(&buf, "SELECT * FROM ", &rc);
1207d7fb7d24Sdan   sessionAppendIdent(&buf, zDb, &rc);
1208d7fb7d24Sdan   sessionAppendStr(&buf, ".", &rc);
1209e8d5648eSdan   sessionAppendIdent(&buf, zTab, &rc);
1210e8d5648eSdan   sessionAppendStr(&buf, " WHERE ", &rc);
1211e8d5648eSdan   for(i=0; i<nCol; i++){
1212e8d5648eSdan     if( abPK[i] ){
1213e8d5648eSdan       sessionAppendStr(&buf, zSep, &rc);
1214e8d5648eSdan       sessionAppendIdent(&buf, azCol[i], &rc);
1215e8d5648eSdan       sessionAppendStr(&buf, " = ?", &rc);
1216e8d5648eSdan       sessionAppendInteger(&buf, i+1, &rc);
1217e8d5648eSdan       zSep = " AND ";
1218d5f0767cSdan     }
1219d5f0767cSdan   }
1220d5f0767cSdan   if( rc==SQLITE_OK ){
1221e8d5648eSdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0);
1222d5f0767cSdan   }
1223e8d5648eSdan   sqlite3_free(buf.aBuf);
1224e8d5648eSdan   return rc;
1225d5f0767cSdan }
1226d5f0767cSdan 
1227e8d5648eSdan static int sessionSelectBind(
1228e8d5648eSdan   sqlite3_stmt *pSelect,
1229e8d5648eSdan   int nCol,
1230e8d5648eSdan   u8 *abPK,
1231e8d5648eSdan   u8 *aRecord,
1232e8d5648eSdan   int nRecord
1233e8d5648eSdan ){
1234e8d5648eSdan   int i;
1235e8d5648eSdan   int rc = SQLITE_OK;
1236e8d5648eSdan   u8 *a = aRecord;
1237d5f0767cSdan 
1238e8d5648eSdan   for(i=0; i<nCol && rc==SQLITE_OK; i++){
1239e8d5648eSdan     int eType = *a++;
1240e8d5648eSdan 
1241e8d5648eSdan     switch( eType ){
1242e8d5648eSdan       case SQLITE_NULL:
1243e8d5648eSdan         if( abPK[i] ) rc = sqlite3_bind_null(pSelect, i+1);
1244e8d5648eSdan         break;
1245e8d5648eSdan 
1246e8d5648eSdan       case SQLITE_INTEGER: {
1247e8d5648eSdan         if( abPK[i] ){
1248e8d5648eSdan           i64 iVal = sessionGetI64(a);
1249e8d5648eSdan           rc = sqlite3_bind_int64(pSelect, i+1, iVal);
1250e8d5648eSdan         }
1251e8d5648eSdan         a += 8;
1252e8d5648eSdan         break;
1253d5f0767cSdan       }
1254296c7658Sdan 
1255e8d5648eSdan       case SQLITE_FLOAT: {
1256e8d5648eSdan         if( abPK[i] ){
1257e8d5648eSdan           double rVal;
1258e8d5648eSdan           i64 iVal = sessionGetI64(a);
1259e8d5648eSdan           memcpy(&rVal, &iVal, 8);
1260*4e895da1Sdan           rc = sqlite3_bind_double(pSelect, i+1, rVal);
1261d5f0767cSdan         }
1262e8d5648eSdan         a += 8;
1263e8d5648eSdan         break;
1264e8d5648eSdan       }
1265e8d5648eSdan 
1266e8d5648eSdan       case SQLITE_TEXT: {
1267e8d5648eSdan         int n;
1268e8d5648eSdan         a += sessionVarintGet(a, &n);
1269e8d5648eSdan         if( abPK[i] ){
1270e8d5648eSdan           rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
1271e8d5648eSdan         }
1272e8d5648eSdan         a += n;
1273e8d5648eSdan         break;
1274e8d5648eSdan       }
1275e8d5648eSdan 
1276e8d5648eSdan       case SQLITE_BLOB: {
1277e8d5648eSdan         int n;
1278e8d5648eSdan         a += sessionVarintGet(a, &n);
1279e8d5648eSdan         if( abPK[i] ){
1280e8d5648eSdan           rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
1281e8d5648eSdan         }
1282e8d5648eSdan         a += n;
1283e8d5648eSdan         break;
1284e8d5648eSdan       }
1285e8d5648eSdan     }
1286e8d5648eSdan   }
1287e8d5648eSdan 
1288d5f0767cSdan   return rc;
12894fccf43aSdan }
12904fccf43aSdan 
12914fccf43aSdan /*
12924fccf43aSdan ** Obtain a changeset object containing all changes recorded by the
12934fccf43aSdan ** session object passed as the first argument.
12944fccf43aSdan **
12954fccf43aSdan ** It is the responsibility of the caller to eventually free the buffer
12964fccf43aSdan ** using sqlite3_free().
12974fccf43aSdan */
12984fccf43aSdan int sqlite3session_changeset(
12994fccf43aSdan   sqlite3_session *pSession,      /* Session object */
13004fccf43aSdan   int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
13014fccf43aSdan   void **ppChangeset              /* OUT: Buffer containing changeset */
13024fccf43aSdan ){
1303296c7658Sdan   sqlite3 *db = pSession->db;     /* Source database handle */
1304296c7658Sdan   SessionTable *pTab;             /* Used to iterate through attached tables */
1305296c7658Sdan   SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
1306296c7658Sdan   int rc;                         /* Return code */
13074fccf43aSdan 
13084c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
13094c220252Sdan 
1310296c7658Sdan   /* Zero the output variables in case an error occurs. If this session
1311296c7658Sdan   ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
1312296c7658Sdan   ** this call will be a no-op.  */
13134fccf43aSdan   *pnChangeset = 0;
13144fccf43aSdan   *ppChangeset = 0;
13154fccf43aSdan   rc = pSession->rc;
13164fccf43aSdan 
13174fccf43aSdan   for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
13184fccf43aSdan     if( pTab->nEntry ){
1319d7fb7d24Sdan       const char *zName = pTab->zName;
1320e8d5648eSdan       int nCol = pTab->nCol;      /* Local copy of member variable */
1321e8d5648eSdan       u8 *abPK = pTab->abPK;      /* Local copy of member variable */
13221f34f8ccSdan       int i;                      /* Used to iterate through hash buckets */
13231f34f8ccSdan       sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
13241f34f8ccSdan       int nRewind = buf.nBuf;     /* Initial size of write buffer */
13251f34f8ccSdan       int nNoop;                  /* Size of buffer after writing tbl header */
13264fccf43aSdan 
13274fccf43aSdan       /* Write a table header */
13284fccf43aSdan       sessionAppendByte(&buf, 'T', &rc);
1329e8d5648eSdan       sessionAppendVarint(&buf, nCol, &rc);
1330d7fb7d24Sdan       sessionAppendBlob(&buf, (u8 *)zName, strlen(zName)+1, &rc);
13314fccf43aSdan 
13324fccf43aSdan       /* Build and compile a statement to execute: */
13334fccf43aSdan       if( rc==SQLITE_OK ){
1334d7fb7d24Sdan         rc = sessionSelectStmt(
1335d7fb7d24Sdan             db, pSession->zDb, zName, nCol, pTab->azCol, abPK, &pSel);
13364fccf43aSdan       }
13374fccf43aSdan 
13381f34f8ccSdan       if( rc==SQLITE_OK && nCol!=sqlite3_column_count(pSel) ){
13394fccf43aSdan         rc = SQLITE_SCHEMA;
13404fccf43aSdan       }
13414fccf43aSdan 
13421f34f8ccSdan       nNoop = buf.nBuf;
13434fccf43aSdan       for(i=0; i<pTab->nChange; i++){
1344e8d5648eSdan         SessionChange *p;         /* Used to iterate through changes */
1345e8d5648eSdan 
13464fccf43aSdan         for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
13471f34f8ccSdan           rc = sessionSelectBind(pSel, nCol, abPK, p->aRecord, p->nRecord);
1348e8d5648eSdan           if( rc==SQLITE_OK ){
13491f34f8ccSdan             if( sqlite3_step(pSel)==SQLITE_ROW ){
13504fccf43aSdan               int iCol;
1351e8d5648eSdan               if( p->bInsert ){
13524fccf43aSdan                 sessionAppendByte(&buf, SQLITE_INSERT, &rc);
1353e8d5648eSdan                 for(iCol=0; iCol<nCol; iCol++){
13541f34f8ccSdan                   sessionAppendCol(&buf, pSel, iCol, &rc);
13554fccf43aSdan                 }
1356e8d5648eSdan               }else{
13571f34f8ccSdan                 sessionAppendUpdate(&buf, pSel, p, abPK, &rc);
13584fccf43aSdan               }
1359e8d5648eSdan             }else if( !p->bInsert ){
13604fccf43aSdan               /* A DELETE change */
13614fccf43aSdan               sessionAppendByte(&buf, SQLITE_DELETE, &rc);
13624fccf43aSdan               sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
13634fccf43aSdan             }
13641f34f8ccSdan             rc = sqlite3_reset(pSel);
13654fccf43aSdan           }
13664fccf43aSdan         }
1367e8d5648eSdan       }
13684fccf43aSdan 
13691f34f8ccSdan       sqlite3_finalize(pSel);
13704fccf43aSdan 
13711f34f8ccSdan       if( buf.nBuf==nNoop ){
13724fccf43aSdan         buf.nBuf = nRewind;
13734fccf43aSdan       }
13744fccf43aSdan     }
13754fccf43aSdan   }
13764fccf43aSdan 
13774fccf43aSdan   if( rc==SQLITE_OK ){
13784fccf43aSdan     *pnChangeset = buf.nBuf;
13794fccf43aSdan     *ppChangeset = buf.aBuf;
13804fccf43aSdan   }else{
13814fccf43aSdan     sqlite3_free(buf.aBuf);
13824fccf43aSdan   }
13834c220252Sdan 
13844c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
13854fccf43aSdan   return rc;
13864fccf43aSdan }
13874fccf43aSdan 
1388296c7658Sdan /*
1389296c7658Sdan ** Enable or disable the session object passed as the first argument.
1390296c7658Sdan */
13914fccf43aSdan int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
13924c220252Sdan   int ret;
13934c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
1394296c7658Sdan   if( bEnable>=0 ){
1395296c7658Sdan     pSession->bEnable = bEnable;
13964fccf43aSdan   }
13974c220252Sdan   ret = pSession->bEnable;
13984c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
13994c220252Sdan   return ret;
1400296c7658Sdan }
14014fccf43aSdan 
14024fccf43aSdan /*
14034fccf43aSdan ** Create an iterator used to iterate through the contents of a changeset.
14044fccf43aSdan */
14054fccf43aSdan int sqlite3changeset_start(
1406296c7658Sdan   sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
1407296c7658Sdan   int nChangeset,                 /* Size of buffer pChangeset in bytes */
1408296c7658Sdan   void *pChangeset                /* Pointer to buffer containing changeset */
14094fccf43aSdan ){
14104fccf43aSdan   sqlite3_changeset_iter *pRet;   /* Iterator to return */
14114fccf43aSdan   int nByte;                      /* Number of bytes to allocate for iterator */
14124fccf43aSdan 
1413296c7658Sdan   /* Zero the output variable in case an error occurs. */
1414296c7658Sdan   *pp = 0;
14154fccf43aSdan 
1416296c7658Sdan   /* Allocate and initialize the iterator structure. */
14174fccf43aSdan   nByte = sizeof(sqlite3_changeset_iter);
14184fccf43aSdan   pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
14194fccf43aSdan   if( !pRet ) return SQLITE_NOMEM;
14204fccf43aSdan   memset(pRet, 0, sizeof(sqlite3_changeset_iter));
14214fccf43aSdan   pRet->aChangeset = (u8 *)pChangeset;
14224fccf43aSdan   pRet->nChangeset = nChangeset;
14234fccf43aSdan   pRet->pNext = pRet->aChangeset;
14244fccf43aSdan 
1425296c7658Sdan   /* Populate the output variable and return success. */
1426296c7658Sdan   *pp = pRet;
14274fccf43aSdan   return SQLITE_OK;
14284fccf43aSdan }
14294fccf43aSdan 
1430296c7658Sdan /*
1431296c7658Sdan ** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
1432296c7658Sdan ** for details.
1433296c7658Sdan **
1434296c7658Sdan ** When this function is called, *paChange points to the start of the record
1435296c7658Sdan ** to deserialize. Assuming no error occurs, *paChange is set to point to
1436296c7658Sdan ** one byte after the end of the same record before this function returns.
1437296c7658Sdan **
1438296c7658Sdan ** If successful, each element of the apOut[] array (allocated by the caller)
1439296c7658Sdan ** is set to point to an sqlite3_value object containing the value read
1440296c7658Sdan ** from the corresponding position in the record. If that value is not
1441296c7658Sdan ** included in the record (i.e. because the record is part of an UPDATE change
1442296c7658Sdan ** and the field was not modified), the corresponding element of apOut[] is
1443296c7658Sdan ** set to NULL.
1444296c7658Sdan **
1445296c7658Sdan ** It is the responsibility of the caller to free all sqlite_value structures
1446296c7658Sdan ** using sqlite3_free().
1447296c7658Sdan **
1448296c7658Sdan ** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
1449296c7658Sdan ** The apOut[] array may have been partially populated in this case.
1450296c7658Sdan */
14514fccf43aSdan static int sessionReadRecord(
14524fccf43aSdan   u8 **paChange,                  /* IN/OUT: Pointer to binary record */
14534fccf43aSdan   int nCol,                       /* Number of values in record */
14544fccf43aSdan   sqlite3_value **apOut           /* Write values to this array */
14554fccf43aSdan ){
1456296c7658Sdan   int i;                          /* Used to iterate through columns */
1457296c7658Sdan   u8 *aRec = *paChange;           /* Cursor for the serialized record */
14584fccf43aSdan 
14594fccf43aSdan   for(i=0; i<nCol; i++){
1460296c7658Sdan     int eType = *aRec++;          /* Type of value (SQLITE_NULL, TEXT etc.) */
146191ddd559Sdan     assert( !apOut || apOut[i]==0 );
14624fccf43aSdan     if( eType ){
146391ddd559Sdan       if( apOut ){
14644fccf43aSdan         apOut[i] = sqlite3ValueNew(0);
14654fccf43aSdan         if( !apOut[i] ) return SQLITE_NOMEM;
146691ddd559Sdan       }
14674fccf43aSdan 
14684fccf43aSdan       if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
14694fccf43aSdan         int nByte;
14704fccf43aSdan         int enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
14714fccf43aSdan         aRec += sessionVarintGet(aRec, &nByte);
147291ddd559Sdan         if( apOut ){
14734fccf43aSdan           sqlite3ValueSetStr(apOut[i], nByte, aRec, enc, SQLITE_STATIC);
147491ddd559Sdan         }
14754fccf43aSdan         aRec += nByte;
14764fccf43aSdan       }
14774fccf43aSdan       if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
147891ddd559Sdan         if( apOut ){
14794fccf43aSdan           sqlite3_int64 v = sessionGetI64(aRec);
14804fccf43aSdan           if( eType==SQLITE_INTEGER ){
14814fccf43aSdan             sqlite3VdbeMemSetInt64(apOut[i], v);
14824fccf43aSdan           }else{
14834fccf43aSdan             double d;
1484*4e895da1Sdan             memcpy(&d, &v, 8);
14854fccf43aSdan             sqlite3VdbeMemSetDouble(apOut[i], d);
14864fccf43aSdan           }
14874fccf43aSdan         }
148891ddd559Sdan         aRec += 8;
148991ddd559Sdan       }
14904fccf43aSdan     }
14914fccf43aSdan   }
14924fccf43aSdan 
14934fccf43aSdan   *paChange = aRec;
14944fccf43aSdan   return SQLITE_OK;
14954fccf43aSdan }
14964fccf43aSdan 
14974fccf43aSdan /*
14984fccf43aSdan ** Advance an iterator created by sqlite3changeset_start() to the next
14994fccf43aSdan ** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
15004fccf43aSdan ** or SQLITE_CORRUPT.
15014fccf43aSdan **
15024fccf43aSdan ** This function may not be called on iterators passed to a conflict handler
15034fccf43aSdan ** callback by changeset_apply().
15044fccf43aSdan */
15054fccf43aSdan int sqlite3changeset_next(sqlite3_changeset_iter *p){
15064fccf43aSdan   u8 *aChange;
15074fccf43aSdan   int i;
15084fccf43aSdan   u8 c;
15094fccf43aSdan 
1510296c7658Sdan   /* If the iterator is in the error-state, return immediately. */
15114fccf43aSdan   if( p->rc!=SQLITE_OK ) return p->rc;
15124fccf43aSdan 
1513296c7658Sdan   /* Free the current contents of p->apValue[]. */
15144fccf43aSdan   if( p->apValue ){
15154fccf43aSdan     for(i=0; i<p->nCol*2; i++){
15164fccf43aSdan       sqlite3ValueFree(p->apValue[i]);
15174fccf43aSdan     }
15184fccf43aSdan     memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
15194fccf43aSdan   }
15204fccf43aSdan 
15214fccf43aSdan   /* If the iterator is already at the end of the changeset, return DONE. */
15224fccf43aSdan   if( p->pNext>=&p->aChangeset[p->nChangeset] ){
15234fccf43aSdan     return SQLITE_DONE;
15244fccf43aSdan   }
15254fccf43aSdan   aChange = p->pNext;
15264fccf43aSdan 
15274fccf43aSdan   c = *(aChange++);
15284fccf43aSdan   if( c=='T' ){
15294fccf43aSdan     int nByte;                    /* Bytes to allocate for apValue */
15304fccf43aSdan     aChange += sessionVarintGet(aChange, &p->nCol);
15314fccf43aSdan     p->zTab = (char *)aChange;
15324fccf43aSdan     aChange += (strlen((char *)aChange) + 1);
15334fccf43aSdan     p->op = *(aChange++);
15344fccf43aSdan     sqlite3_free(p->apValue);
15354fccf43aSdan     nByte = sizeof(sqlite3_value *) * p->nCol * 2;
15364fccf43aSdan     p->apValue = (sqlite3_value **)sqlite3_malloc(nByte);
15374fccf43aSdan     if( !p->apValue ){
15384fccf43aSdan       return (p->rc = SQLITE_NOMEM);
15394fccf43aSdan     }
15404fccf43aSdan     memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
15414fccf43aSdan   }else{
15424fccf43aSdan     p->op = c;
15434fccf43aSdan   }
15444fccf43aSdan   if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
15454fccf43aSdan     return (p->rc = SQLITE_CORRUPT);
15464fccf43aSdan   }
15474fccf43aSdan 
15484fccf43aSdan   /* If this is an UPDATE or DELETE, read the old.* record. */
15494fccf43aSdan   if( p->op!=SQLITE_INSERT ){
15504fccf43aSdan     p->rc = sessionReadRecord(&aChange, p->nCol, p->apValue);
15514fccf43aSdan     if( p->rc!=SQLITE_OK ) return p->rc;
15524fccf43aSdan   }
15534fccf43aSdan 
15544fccf43aSdan   /* If this is an INSERT or UPDATE, read the new.* record. */
15554fccf43aSdan   if( p->op!=SQLITE_DELETE ){
15564fccf43aSdan     p->rc = sessionReadRecord(&aChange, p->nCol, &p->apValue[p->nCol]);
15574fccf43aSdan     if( p->rc!=SQLITE_OK ) return p->rc;
15584fccf43aSdan   }
15594fccf43aSdan 
15604fccf43aSdan   p->pNext = aChange;
15614fccf43aSdan   return SQLITE_ROW;
15624fccf43aSdan }
15634fccf43aSdan 
15644fccf43aSdan /*
15654fccf43aSdan ** The following three functions extract information on the current change
15664fccf43aSdan ** from a changeset iterator. They may only be called after changeset_next()
15674fccf43aSdan ** has returned SQLITE_ROW.
15684fccf43aSdan */
15694fccf43aSdan int sqlite3changeset_op(
1570296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Iterator handle */
15714fccf43aSdan   const char **pzTab,             /* OUT: Pointer to table name */
15724fccf43aSdan   int *pnCol,                     /* OUT: Number of columns in table */
15734fccf43aSdan   int *pOp                        /* OUT: SQLITE_INSERT, DELETE or UPDATE */
15744fccf43aSdan ){
15754fccf43aSdan   *pOp = pIter->op;
15764fccf43aSdan   *pnCol = pIter->nCol;
15774fccf43aSdan   *pzTab = pIter->zTab;
15784fccf43aSdan   return SQLITE_OK;
15794fccf43aSdan }
15804fccf43aSdan 
1581296c7658Sdan /*
1582296c7658Sdan ** This function may only be called while the iterator is pointing to an
1583296c7658Sdan ** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
1584296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned.
1585296c7658Sdan **
1586296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the
1587296c7658Sdan ** iVal'th value in the old.* record. Or, if that particular value is not
1588296c7658Sdan ** included in the record (because the change is an UPDATE and the field
1589296c7658Sdan ** was not modified and is not a PK column), set *ppValue to NULL.
1590296c7658Sdan **
1591296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
1592296c7658Sdan ** not modified. Otherwise, SQLITE_OK.
1593296c7658Sdan */
15944fccf43aSdan int sqlite3changeset_old(
1595296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1596296c7658Sdan   int iVal,                       /* Index of old.* value to retrieve */
15974fccf43aSdan   sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
15984fccf43aSdan ){
1599d5f0767cSdan   if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
1600d5f0767cSdan     return SQLITE_MISUSE;
1601d5f0767cSdan   }
16024fccf43aSdan   if( iVal<0 || iVal>=pIter->nCol ){
16034fccf43aSdan     return SQLITE_RANGE;
16044fccf43aSdan   }
16054fccf43aSdan   *ppValue = pIter->apValue[iVal];
16064fccf43aSdan   return SQLITE_OK;
16074fccf43aSdan }
16084fccf43aSdan 
1609296c7658Sdan /*
1610296c7658Sdan ** This function may only be called while the iterator is pointing to an
1611296c7658Sdan ** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
1612296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned.
1613296c7658Sdan **
1614296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the
1615296c7658Sdan ** iVal'th value in the new.* record. Or, if that particular value is not
1616296c7658Sdan ** included in the record (because the change is an UPDATE and the field
1617296c7658Sdan ** was not modified), set *ppValue to NULL.
1618296c7658Sdan **
1619296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
1620296c7658Sdan ** not modified. Otherwise, SQLITE_OK.
1621296c7658Sdan */
16224fccf43aSdan int sqlite3changeset_new(
1623296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1624296c7658Sdan   int iVal,                       /* Index of new.* value to retrieve */
16254fccf43aSdan   sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
16264fccf43aSdan ){
1627d5f0767cSdan   if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
1628d5f0767cSdan     return SQLITE_MISUSE;
1629d5f0767cSdan   }
16304fccf43aSdan   if( iVal<0 || iVal>=pIter->nCol ){
16314fccf43aSdan     return SQLITE_RANGE;
16324fccf43aSdan   }
16334fccf43aSdan   *ppValue = pIter->apValue[pIter->nCol+iVal];
16344fccf43aSdan   return SQLITE_OK;
16354fccf43aSdan }
16364fccf43aSdan 
1637296c7658Sdan /*
1638296c7658Sdan ** This function may only be called with a changeset iterator that has been
1639296c7658Sdan ** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
1640296c7658Sdan ** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
1641296c7658Sdan **
1642296c7658Sdan ** If successful, *ppValue is set to point to an sqlite3_value structure
1643296c7658Sdan ** containing the iVal'th value of the conflicting record.
1644296c7658Sdan **
1645296c7658Sdan ** If value iVal is out-of-range or some other error occurs, an SQLite error
1646296c7658Sdan ** code is returned. Otherwise, SQLITE_OK.
1647296c7658Sdan */
1648d5f0767cSdan int sqlite3changeset_conflict(
1649296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1650296c7658Sdan   int iVal,                       /* Index of conflict record value to fetch */
1651d5f0767cSdan   sqlite3_value **ppValue         /* OUT: Value from conflicting row */
1652d5f0767cSdan ){
1653d5f0767cSdan   if( !pIter->pConflict ){
1654d5f0767cSdan     return SQLITE_MISUSE;
1655d5f0767cSdan   }
1656d5f0767cSdan   if( iVal<0 || iVal>=sqlite3_column_count(pIter->pConflict) ){
1657d5f0767cSdan     return SQLITE_RANGE;
1658d5f0767cSdan   }
1659d5f0767cSdan   *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
1660d5f0767cSdan   return SQLITE_OK;
1661d5f0767cSdan }
1662d5f0767cSdan 
16634fccf43aSdan /*
16644fccf43aSdan ** Finalize an iterator allocated with sqlite3changeset_start().
16654fccf43aSdan **
16664fccf43aSdan ** This function may not be called on iterators passed to a conflict handler
16674fccf43aSdan ** callback by changeset_apply().
16684fccf43aSdan */
16694fccf43aSdan int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
1670296c7658Sdan   int i;                          /* Used to iterate through p->apValue[] */
1671296c7658Sdan   int rc = p->rc;                 /* Return code */
16724fccf43aSdan   for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
16734fccf43aSdan   sqlite3_free(p->apValue);
16744fccf43aSdan   sqlite3_free(p);
16754fccf43aSdan   return rc;
16764fccf43aSdan }
16774fccf43aSdan 
167891ddd559Sdan /*
167991ddd559Sdan ** Invert a changeset object.
168091ddd559Sdan */
168191ddd559Sdan int sqlite3changeset_invert(
168291ddd559Sdan   int nChangeset,                 /* Number of bytes in input */
168391ddd559Sdan   void *pChangeset,               /* Input changeset */
168491ddd559Sdan   int *pnInverted,                /* OUT: Number of bytes in output changeset */
168591ddd559Sdan   void **ppInverted               /* OUT: Inverse of pChangeset */
168691ddd559Sdan ){
168791ddd559Sdan   u8 *aOut;
168891ddd559Sdan   u8 *aIn;
168991ddd559Sdan   int i;
169091ddd559Sdan   int nCol = 0;
169191ddd559Sdan 
169291ddd559Sdan   /* Zero the output variables in case an error occurs. */
169391ddd559Sdan   *ppInverted = 0;
169491ddd559Sdan   *pnInverted = 0;
169591ddd559Sdan   if( nChangeset==0 ) return SQLITE_OK;
169691ddd559Sdan 
169791ddd559Sdan   aOut = (u8 *)sqlite3_malloc(nChangeset);
169891ddd559Sdan   if( !aOut ) return SQLITE_NOMEM;
169991ddd559Sdan   aIn = (u8 *)pChangeset;
170091ddd559Sdan 
170191ddd559Sdan   i = 0;
170291ddd559Sdan   while( i<nChangeset ){
170391ddd559Sdan     u8 eType = aIn[i];
170491ddd559Sdan     switch( eType ){
170591ddd559Sdan       case 'T': {
170691ddd559Sdan         int nByte = 1 + sessionVarintGet(&aIn[i+1], &nCol);
170791ddd559Sdan         nByte += 1 + strlen((char *)&aIn[i+nByte]);
170891ddd559Sdan         memcpy(&aOut[i], &aIn[i], nByte);
170991ddd559Sdan         i += nByte;
171091ddd559Sdan         break;
171191ddd559Sdan       }
171291ddd559Sdan 
171391ddd559Sdan       case SQLITE_INSERT:
171491ddd559Sdan       case SQLITE_DELETE: {
171591ddd559Sdan         int nByte;
171691ddd559Sdan         u8 *aEnd = &aIn[i+1];
171791ddd559Sdan 
171891ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
171991ddd559Sdan         aOut[i] = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
172091ddd559Sdan         nByte = aEnd - &aIn[i+1];
172191ddd559Sdan         memcpy(&aOut[i+1], &aIn[i+1], nByte);
172291ddd559Sdan         i += 1 + nByte;
172391ddd559Sdan         break;
172491ddd559Sdan       }
172591ddd559Sdan 
172691ddd559Sdan       case SQLITE_UPDATE: {
172791ddd559Sdan         int nByte1;              /* Size of old.* record in bytes */
172891ddd559Sdan         int nByte2;              /* Size of new.* record in bytes */
172991ddd559Sdan         u8 *aEnd = &aIn[i+1];
173091ddd559Sdan 
173191ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
173291ddd559Sdan         nByte1 = aEnd - &aIn[i+1];
173391ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
173491ddd559Sdan         nByte2 = aEnd - &aIn[i+1] - nByte1;
173591ddd559Sdan 
173691ddd559Sdan         aOut[i] = SQLITE_UPDATE;
173791ddd559Sdan         memcpy(&aOut[i+1], &aIn[i+1+nByte1], nByte2);
173891ddd559Sdan         memcpy(&aOut[i+1+nByte2], &aIn[i+1], nByte1);
173991ddd559Sdan 
174091ddd559Sdan         i += 1 + nByte1 + nByte2;
174191ddd559Sdan         break;
174291ddd559Sdan       }
174391ddd559Sdan 
174491ddd559Sdan       default:
174591ddd559Sdan         sqlite3_free(aOut);
174691ddd559Sdan         return SQLITE_CORRUPT;
174791ddd559Sdan     }
174891ddd559Sdan   }
174991ddd559Sdan 
175091ddd559Sdan   *pnInverted = nChangeset;
175191ddd559Sdan   *ppInverted = (void *)aOut;
175291ddd559Sdan   return SQLITE_OK;
175391ddd559Sdan }
175491ddd559Sdan 
17550c698471Sdan typedef struct SessionApplyCtx SessionApplyCtx;
17560c698471Sdan struct SessionApplyCtx {
17570c698471Sdan   sqlite3 *db;
17580c698471Sdan   sqlite3_stmt *pDelete;          /* DELETE statement */
17590c698471Sdan   sqlite3_stmt *pUpdate;          /* DELETE statement */
17600c698471Sdan   sqlite3_stmt *pInsert;          /* INSERT statement */
17610c698471Sdan   sqlite3_stmt *pSelect;          /* SELECT statement */
17620c698471Sdan   int nCol;                       /* Size of azCol[] and abPK[] arrays */
17630c698471Sdan   const char **azCol;             /* Array of column names */
17640c698471Sdan   u8 *abPK;                       /* Boolean array - true if column is in PK */
17650c698471Sdan };
17660c698471Sdan 
1767d5f0767cSdan /*
1768d5f0767cSdan ** Formulate a statement to DELETE a row from database db. Assuming a table
1769d5f0767cSdan ** structure like this:
1770d5f0767cSdan **
1771d5f0767cSdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1772d5f0767cSdan **
1773d5f0767cSdan ** The DELETE statement looks like this:
1774d5f0767cSdan **
1775d5f0767cSdan **     DELETE FROM x WHERE a = :1 AND c = :3 AND :5 OR (b IS :2 AND d IS :4)
1776d5f0767cSdan **
1777d5f0767cSdan ** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
1778d5f0767cSdan ** matching b and d values, or 1 otherwise. The second case comes up if the
1779d5f0767cSdan ** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
1780296c7658Sdan **
1781296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
1782296c7658Sdan ** pointing to the prepared version of the SQL statement.
1783d5f0767cSdan */
1784d5f0767cSdan static int sessionDeleteRow(
1785d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1786d5f0767cSdan   const char *zTab,               /* Table name */
17870c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1788d5f0767cSdan ){
1789296c7658Sdan   int i;
1790296c7658Sdan   const char *zSep = "";
1791d5f0767cSdan   int rc = SQLITE_OK;
1792d5f0767cSdan   SessionBuffer buf = {0, 0, 0};
17937cf7df7dSdan   int nPk = 0;
1794d5f0767cSdan 
1795d5f0767cSdan   sessionAppendStr(&buf, "DELETE FROM ", &rc);
1796d5f0767cSdan   sessionAppendIdent(&buf, zTab, &rc);
1797296c7658Sdan   sessionAppendStr(&buf, " WHERE ", &rc);
1798296c7658Sdan 
1799296c7658Sdan   for(i=0; i<p->nCol; i++){
1800296c7658Sdan     if( p->abPK[i] ){
18017cf7df7dSdan       nPk++;
1802296c7658Sdan       sessionAppendStr(&buf, zSep, &rc);
1803296c7658Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1804296c7658Sdan       sessionAppendStr(&buf, " = ?", &rc);
1805296c7658Sdan       sessionAppendInteger(&buf, i+1, &rc);
1806296c7658Sdan       zSep = " AND ";
1807296c7658Sdan     }
1808296c7658Sdan   }
1809296c7658Sdan 
18107cf7df7dSdan   if( nPk<p->nCol ){
1811296c7658Sdan     sessionAppendStr(&buf, " AND (?", &rc);
1812296c7658Sdan     sessionAppendInteger(&buf, p->nCol+1, &rc);
1813296c7658Sdan     sessionAppendStr(&buf, " OR ", &rc);
1814296c7658Sdan 
1815296c7658Sdan     zSep = "";
1816296c7658Sdan     for(i=0; i<p->nCol; i++){
1817296c7658Sdan       if( !p->abPK[i] ){
1818296c7658Sdan         sessionAppendStr(&buf, zSep, &rc);
1819296c7658Sdan         sessionAppendIdent(&buf, p->azCol[i], &rc);
1820296c7658Sdan         sessionAppendStr(&buf, " IS ?", &rc);
1821296c7658Sdan         sessionAppendInteger(&buf, i+1, &rc);
1822296c7658Sdan         zSep = "AND ";
1823296c7658Sdan       }
1824296c7658Sdan     }
1825296c7658Sdan     sessionAppendStr(&buf, ")", &rc);
18267cf7df7dSdan   }
1827d5f0767cSdan 
1828d5f0767cSdan   if( rc==SQLITE_OK ){
18290c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
1830d5f0767cSdan   }
1831d5f0767cSdan   sqlite3_free(buf.aBuf);
1832d5f0767cSdan 
1833d5f0767cSdan   return rc;
1834d5f0767cSdan }
1835d5f0767cSdan 
1836d5f0767cSdan /*
1837d5f0767cSdan ** Formulate and prepare a statement to UPDATE a row from database db.
1838d5f0767cSdan ** Assuming a table structure like this:
1839d5f0767cSdan **
1840d5f0767cSdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1841d5f0767cSdan **
1842d5f0767cSdan ** The UPDATE statement looks like this:
1843d5f0767cSdan **
1844d5f0767cSdan **     UPDATE x SET
1845d5f0767cSdan **     a = CASE WHEN ?2  THEN ?3  ELSE a END,
1846d5f0767cSdan **     b = CASE WHEN ?5  THEN ?6  ELSE a END,
1847d5f0767cSdan **     c = CASE WHEN ?8  THEN ?9  ELSE a END,
1848d5f0767cSdan **     d = CASE WHEN ?11 THEN ?12 ELSE a END
1849d5f0767cSdan **     WHERE a = ?1 AND c = ?7 AND (?13 OR
1850d5f0767cSdan **       (?5==0 OR b IS ?4) AND (?11==0 OR b IS ?10) AND
1851d5f0767cSdan **     )
1852d5f0767cSdan **
1853d5f0767cSdan ** For each column in the table, there are three variables to bind:
1854d5f0767cSdan **
1855d5f0767cSdan **     ?(i*3+1)    The old.* value of the column, if any.
1856d5f0767cSdan **     ?(i*3+2)    A boolean flag indicating that the value is being modified.
1857d5f0767cSdan **     ?(i*3+3)    The new.* value of the column, if any.
1858d5f0767cSdan **
1859d5f0767cSdan ** Also, a boolean flag that, if set to true, causes the statement to update
1860d5f0767cSdan ** a row even if the non-PK values do not match. This is required if the
1861d5f0767cSdan ** conflict-handler is invoked with CHANGESET_DATA and returns
1862d5f0767cSdan ** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
1863d5f0767cSdan **
1864296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
1865296c7658Sdan ** pointing to the prepared version of the SQL statement.
1866d5f0767cSdan */
1867d5f0767cSdan static int sessionUpdateRow(
1868d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1869d5f0767cSdan   const char *zTab,               /* Table name */
18700c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1871d5f0767cSdan ){
1872d5f0767cSdan   int rc = SQLITE_OK;
1873d5f0767cSdan   int i;
1874d5f0767cSdan   const char *zSep = "";
1875d5f0767cSdan   SessionBuffer buf = {0, 0, 0};
1876d5f0767cSdan 
1877d5f0767cSdan   /* Append "UPDATE tbl SET " */
1878d5f0767cSdan   sessionAppendStr(&buf, "UPDATE ", &rc);
1879d5f0767cSdan   sessionAppendIdent(&buf, zTab, &rc);
1880d5f0767cSdan   sessionAppendStr(&buf, " SET ", &rc);
1881d5f0767cSdan 
1882d5f0767cSdan   /* Append the assignments */
18830c698471Sdan   for(i=0; i<p->nCol; i++){
1884d5f0767cSdan     sessionAppendStr(&buf, zSep, &rc);
18850c698471Sdan     sessionAppendIdent(&buf, p->azCol[i], &rc);
1886d5f0767cSdan     sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
1887d5f0767cSdan     sessionAppendInteger(&buf, i*3+2, &rc);
1888d5f0767cSdan     sessionAppendStr(&buf, " THEN ?", &rc);
1889d5f0767cSdan     sessionAppendInteger(&buf, i*3+3, &rc);
1890d5f0767cSdan     sessionAppendStr(&buf, " ELSE ", &rc);
18910c698471Sdan     sessionAppendIdent(&buf, p->azCol[i], &rc);
1892d5f0767cSdan     sessionAppendStr(&buf, " END", &rc);
1893d5f0767cSdan     zSep = ", ";
1894d5f0767cSdan   }
1895d5f0767cSdan 
1896d5f0767cSdan   /* Append the PK part of the WHERE clause */
1897d5f0767cSdan   sessionAppendStr(&buf, " WHERE ", &rc);
18980c698471Sdan   for(i=0; i<p->nCol; i++){
18990c698471Sdan     if( p->abPK[i] ){
19000c698471Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1901d5f0767cSdan       sessionAppendStr(&buf, " = ?", &rc);
1902d5f0767cSdan       sessionAppendInteger(&buf, i*3+1, &rc);
1903d5f0767cSdan       sessionAppendStr(&buf, " AND ", &rc);
1904d5f0767cSdan     }
1905d5f0767cSdan   }
1906d5f0767cSdan 
1907d5f0767cSdan   /* Append the non-PK part of the WHERE clause */
1908d5f0767cSdan   sessionAppendStr(&buf, " (?", &rc);
19090c698471Sdan   sessionAppendInteger(&buf, p->nCol*3+1, &rc);
1910d5f0767cSdan   sessionAppendStr(&buf, " OR 1", &rc);
19110c698471Sdan   for(i=0; i<p->nCol; i++){
19120c698471Sdan     if( !p->abPK[i] ){
1913d5f0767cSdan       sessionAppendStr(&buf, " AND (?", &rc);
1914d5f0767cSdan       sessionAppendInteger(&buf, i*3+2, &rc);
1915d5f0767cSdan       sessionAppendStr(&buf, "=0 OR ", &rc);
19160c698471Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1917d5f0767cSdan       sessionAppendStr(&buf, " IS ?", &rc);
1918d5f0767cSdan       sessionAppendInteger(&buf, i*3+1, &rc);
1919d5f0767cSdan       sessionAppendStr(&buf, ")", &rc);
1920d5f0767cSdan     }
1921d5f0767cSdan   }
1922d5f0767cSdan   sessionAppendStr(&buf, ")", &rc);
1923d5f0767cSdan 
1924d5f0767cSdan   if( rc==SQLITE_OK ){
19250c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
1926d5f0767cSdan   }
1927d5f0767cSdan   sqlite3_free(buf.aBuf);
1928d5f0767cSdan 
1929d5f0767cSdan   return rc;
1930d5f0767cSdan }
1931d5f0767cSdan 
1932296c7658Sdan /*
1933296c7658Sdan ** Formulate and prepare an SQL statement to query table zTab by primary
1934296c7658Sdan ** key. Assuming the following table structure:
1935296c7658Sdan **
1936296c7658Sdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1937296c7658Sdan **
1938296c7658Sdan ** The SELECT statement looks like this:
1939296c7658Sdan **
1940296c7658Sdan **     SELECT * FROM x WHERE a = ?1 AND c = ?3
1941296c7658Sdan **
1942296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
1943296c7658Sdan ** pointing to the prepared version of the SQL statement.
1944296c7658Sdan */
1945d5f0767cSdan static int sessionSelectRow(
1946d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1947d5f0767cSdan   const char *zTab,               /* Table name */
19480c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1949d5f0767cSdan ){
1950d7fb7d24Sdan   return sessionSelectStmt(
1951d7fb7d24Sdan       db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
1952d5f0767cSdan }
1953d5f0767cSdan 
1954296c7658Sdan /*
1955296c7658Sdan ** Formulate and prepare an INSERT statement to add a record to table zTab.
1956296c7658Sdan ** For example:
1957296c7658Sdan **
1958296c7658Sdan **     INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
1959296c7658Sdan **
1960296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
1961296c7658Sdan ** pointing to the prepared version of the SQL statement.
1962296c7658Sdan */
19630c698471Sdan static int sessionInsertRow(
19640c698471Sdan   sqlite3 *db,                    /* Database handle */
19650c698471Sdan   const char *zTab,               /* Table name */
19660c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
19670c698471Sdan ){
19680c698471Sdan   int rc = SQLITE_OK;
19690c698471Sdan   int i;
19700c698471Sdan   SessionBuffer buf = {0, 0, 0};
19710c698471Sdan 
19720c698471Sdan   sessionAppendStr(&buf, "INSERT INTO main.", &rc);
19730c698471Sdan   sessionAppendIdent(&buf, zTab, &rc);
19740c698471Sdan   sessionAppendStr(&buf, " VALUES(?", &rc);
19750c698471Sdan   for(i=1; i<p->nCol; i++){
19760c698471Sdan     sessionAppendStr(&buf, ", ?", &rc);
19770c698471Sdan   }
19780c698471Sdan   sessionAppendStr(&buf, ")", &rc);
19790c698471Sdan 
19800c698471Sdan   if( rc==SQLITE_OK ){
19810c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
19820c698471Sdan   }
19830c698471Sdan   sqlite3_free(buf.aBuf);
19840c698471Sdan   return rc;
19850c698471Sdan }
19860c698471Sdan 
1987296c7658Sdan /*
1988296c7658Sdan ** SQL statement pSelect is as generated by the sessionSelectRow() function.
1989296c7658Sdan ** This function binds the primary key values from the change that changeset
1990296c7658Sdan ** iterator pIter points to to the SELECT and attempts to seek to the table
1991296c7658Sdan ** entry. If a row is found, the SELECT statement left pointing at the row
1992296c7658Sdan ** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
1993296c7658Sdan ** has occured, the statement is reset and SQLITE_OK is returned. If an
1994296c7658Sdan ** error occurs, an SQLite error code is returned.
1995296c7658Sdan **
1996296c7658Sdan ** If the iterator currently points to an INSERT record, bind values from the
1997296c7658Sdan ** new.* record to the SELECT statement. Or, if it points to a DELETE, bind
1998296c7658Sdan ** values from the old.* record. If the changeset iterator points to an
1999296c7658Sdan ** UPDATE, bind values from the new.* record, but use old.* values in place
2000296c7658Sdan ** of any undefined new.* values.
2001296c7658Sdan */
20020c698471Sdan static int sessionSeekToRow(
200337f133ecSdan   sqlite3 *db,                    /* Database handle */
200437f133ecSdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
200537f133ecSdan   u8 *abPK,                       /* Primary key flags array */
20060c698471Sdan   sqlite3_stmt *pSelect           /* SELECT statement from sessionSelectRow() */
200737f133ecSdan ){
2008296c7658Sdan   int rc = SQLITE_OK;             /* Return code */
2009296c7658Sdan   int i;                          /* Used to iterate through table columns */
2010296c7658Sdan   int nCol;                       /* Number of columns in table */
2011296c7658Sdan   int op;                         /* Changset operation (SQLITE_UPDATE etc.) */
2012296c7658Sdan   const char *zDummy;             /* Unused */
201337f133ecSdan 
201437f133ecSdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op);
20150c698471Sdan 
20160c698471Sdan   for(i=0; rc==SQLITE_OK && i<nCol; i++){
20170c698471Sdan     if( abPK[i] ){
20180c698471Sdan       sqlite3_value *pVal = 0;
20190c698471Sdan       if( op!=SQLITE_DELETE ){
20200c698471Sdan         rc = sqlite3changeset_new(pIter, i, &pVal);
20210c698471Sdan       }
20220c698471Sdan       if( pVal==0 ){
20230c698471Sdan         rc = sqlite3changeset_old(pIter, i, &pVal);
20240c698471Sdan       }
20250c698471Sdan       if( rc==SQLITE_OK ){
20260c698471Sdan         rc = sqlite3_bind_value(pSelect, i+1, pVal);
20270c698471Sdan       }
20280c698471Sdan     }
20290c698471Sdan   }
20300c698471Sdan 
20310c698471Sdan   if( rc==SQLITE_OK ){
20320c698471Sdan     rc = sqlite3_step(pSelect);
20330c698471Sdan     if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
20340c698471Sdan   }
20350c698471Sdan 
20360c698471Sdan   return rc;
20370c698471Sdan }
20380c698471Sdan 
2039296c7658Sdan /*
2040296c7658Sdan ** Invoke the conflict handler for the change that the changeset iterator
2041296c7658Sdan ** currently points to.
2042296c7658Sdan **
2043296c7658Sdan ** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
2044296c7658Sdan ** If argument pbReplace is NULL, then the type of conflict handler invoked
2045296c7658Sdan ** depends solely on eType, as follows:
2046296c7658Sdan **
2047296c7658Sdan **    eType value                 Value passed to xConflict
2048296c7658Sdan **    -------------------------------------------------
2049296c7658Sdan **    CHANGESET_DATA              CHANGESET_NOTFOUND
2050296c7658Sdan **    CHANGESET_CONFLICT          CHANGESET_CONSTRAINT
2051296c7658Sdan **
2052296c7658Sdan ** Or, if pbReplace is not NULL, then an attempt is made to find an existing
2053296c7658Sdan ** record with the same primary key as the record about to be deleted, updated
2054296c7658Sdan ** or inserted. If such a record can be found, it is available to the conflict
2055296c7658Sdan ** handler as the "conflicting" record. In this case the type of conflict
2056296c7658Sdan ** handler invoked is as follows:
2057296c7658Sdan **
2058296c7658Sdan **    eType value         PK Record found?   Value passed to xConflict
2059296c7658Sdan **    ----------------------------------------------------------------
2060296c7658Sdan **    CHANGESET_DATA      Yes                CHANGESET_DATA
2061296c7658Sdan **    CHANGESET_DATA      No                 CHANGESET_NOTFOUND
2062296c7658Sdan **    CHANGESET_CONFLICT  Yes                CHANGESET_CONFLICT
2063296c7658Sdan **    CHANGESET_CONFLICT  No                 CHANGESET_CONSTRAINT
2064296c7658Sdan **
2065296c7658Sdan ** If pbReplace is not NULL, and a record with a matching PK is found, and
2066296c7658Sdan ** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
2067296c7658Sdan ** is set to non-zero before returning SQLITE_OK.
2068296c7658Sdan **
2069296c7658Sdan ** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
2070296c7658Sdan ** returned. Or, if the conflict handler returns an invalid value,
2071296c7658Sdan ** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
2072296c7658Sdan ** this function returns SQLITE_OK.
2073296c7658Sdan */
20740c698471Sdan static int sessionConflictHandler(
2075296c7658Sdan   int eType,                      /* Either CHANGESET_DATA or CONFLICT */
2076296c7658Sdan   SessionApplyCtx *p,             /* changeset_apply() context */
20770c698471Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
20780c698471Sdan   int(*xConflict)(void *, int, sqlite3_changeset_iter*),
2079296c7658Sdan   void *pCtx,                     /* First argument for conflict handler */
2080296c7658Sdan   int *pbReplace                  /* OUT: Set to true if PK row is found */
20810c698471Sdan ){
2082296c7658Sdan   int res;                        /* Value returned by conflict handler */
20830c698471Sdan   int rc;
20840c698471Sdan   int nCol;
20850c698471Sdan   int op;
20860c698471Sdan   const char *zDummy;
20870c698471Sdan 
20880c698471Sdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op);
20890c698471Sdan 
20900c698471Sdan   assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
20910c698471Sdan   assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
20920c698471Sdan   assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
209337f133ecSdan 
209437f133ecSdan   /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
20950c698471Sdan   if( pbReplace ){
20960c698471Sdan     rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
20970c698471Sdan   }else{
20980c698471Sdan     rc = SQLITE_DONE;
20990c698471Sdan   }
21000c698471Sdan 
21010c698471Sdan   if( rc==SQLITE_ROW ){
21020c698471Sdan     /* There exists another row with the new.* primary key. */
21030c698471Sdan     pIter->pConflict = p->pSelect;
21040c698471Sdan     res = xConflict(pCtx, eType, pIter);
21050c698471Sdan     pIter->pConflict = 0;
21060c698471Sdan     rc = sqlite3_reset(p->pSelect);
21070c698471Sdan   }else{
21080c698471Sdan     /* No other row with the new.* primary key. */
21090c698471Sdan     rc = sqlite3_reset(p->pSelect);
21100c698471Sdan     if( rc==SQLITE_OK ){
21110c698471Sdan       res = xConflict(pCtx, eType+1, pIter);
21120c698471Sdan       if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
211337f133ecSdan     }
211437f133ecSdan   }
211537f133ecSdan 
211637f133ecSdan   if( rc==SQLITE_OK ){
21170c698471Sdan     switch( res ){
21180c698471Sdan       case SQLITE_CHANGESET_REPLACE:
21190c698471Sdan         if( pbReplace ) *pbReplace = 1;
21200c698471Sdan         break;
21210c698471Sdan 
21220c698471Sdan       case SQLITE_CHANGESET_OMIT:
21230c698471Sdan         break;
21240c698471Sdan 
21250c698471Sdan       case SQLITE_CHANGESET_ABORT:
21260c698471Sdan         rc = SQLITE_ABORT;
21270c698471Sdan         break;
21280c698471Sdan 
21290c698471Sdan       default:
21300c698471Sdan         rc = SQLITE_MISUSE;
21310c698471Sdan         break;
21320c698471Sdan     }
21330c698471Sdan   }
21340c698471Sdan 
21350c698471Sdan   return rc;
21360c698471Sdan }
21370c698471Sdan 
2138296c7658Sdan /*
2139296c7658Sdan ** Attempt to apply the change that the iterator passed as the first argument
2140296c7658Sdan ** currently points to to the database. If a conflict is encountered, invoke
2141296c7658Sdan ** the conflict handler callback.
2142296c7658Sdan **
2143296c7658Sdan ** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
2144296c7658Sdan ** one is encountered, update or delete the row with the matching primary key
2145296c7658Sdan ** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
2146296c7658Sdan ** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
2147296c7658Sdan ** to true before returning. In this case the caller will invoke this function
2148296c7658Sdan ** again, this time with pbRetry set to NULL.
2149296c7658Sdan **
2150296c7658Sdan ** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
2151296c7658Sdan ** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
2152296c7658Sdan ** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
2153296c7658Sdan ** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
2154296c7658Sdan ** before retrying. In this case the caller attempts to remove the conflicting
2155296c7658Sdan ** row before invoking this function again, this time with pbReplace set
2156296c7658Sdan ** to NULL.
2157296c7658Sdan **
2158296c7658Sdan ** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
2159296c7658Sdan ** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
2160296c7658Sdan ** returned.
2161296c7658Sdan */
21620c698471Sdan static int sessionApplyOneOp(
2163296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
2164296c7658Sdan   SessionApplyCtx *p,             /* changeset_apply() context */
21650c698471Sdan   int(*xConflict)(void *, int, sqlite3_changeset_iter *),
2166296c7658Sdan   void *pCtx,                     /* First argument for the conflict handler */
2167296c7658Sdan   int *pbReplace,                 /* OUT: True to remove PK row and retry */
2168296c7658Sdan   int *pbRetry                    /* OUT: True to retry. */
21690c698471Sdan ){
21700c698471Sdan   const char *zDummy;
21710c698471Sdan   int op;
21720c698471Sdan   int nCol;
21730c698471Sdan   int rc = SQLITE_OK;
21740c698471Sdan 
21750c698471Sdan   assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
21760c698471Sdan   assert( p->azCol && p->abPK );
21770c698471Sdan   assert( !pbReplace || *pbReplace==0 );
21780c698471Sdan 
21790c698471Sdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op);
21800c698471Sdan 
21810c698471Sdan   if( op==SQLITE_DELETE ){
21820c698471Sdan     int i;
21830c698471Sdan 
21840c698471Sdan     /* Bind values to the DELETE statement. */
21850c698471Sdan     for(i=0; rc==SQLITE_OK && i<nCol; i++){
21860c698471Sdan       sqlite3_value *pVal;
21870c698471Sdan       rc = sqlite3changeset_old(pIter, i, &pVal);
21880c698471Sdan       if( rc==SQLITE_OK ){
21890c698471Sdan         rc = sqlite3_bind_value(p->pDelete, i+1, pVal);
21900c698471Sdan       }
21910c698471Sdan     }
21927cf7df7dSdan     if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
21937cf7df7dSdan       rc = sqlite3_bind_int(p->pDelete, nCol+1, pbRetry==0);
21947cf7df7dSdan     }
21950c698471Sdan     if( rc!=SQLITE_OK ) return rc;
21960c698471Sdan 
21970c698471Sdan     sqlite3_step(p->pDelete);
21980c698471Sdan     rc = sqlite3_reset(p->pDelete);
21990c698471Sdan     if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
22000c698471Sdan       rc = sessionConflictHandler(
22010c698471Sdan           SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
22020c698471Sdan       );
22030c698471Sdan     }else if( rc==SQLITE_CONSTRAINT ){
22040c698471Sdan       rc = sessionConflictHandler(
22050c698471Sdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
22060c698471Sdan       );
22070c698471Sdan     }
22080c698471Sdan 
22090c698471Sdan   }else if( op==SQLITE_UPDATE ){
22100c698471Sdan     int i;
22110c698471Sdan 
22120c698471Sdan     /* Bind values to the UPDATE statement. */
22130c698471Sdan     for(i=0; rc==SQLITE_OK && i<nCol; i++){
22140c698471Sdan       sqlite3_value *pOld = 0;
22150c698471Sdan       sqlite3_value *pNew = 0;
22160c698471Sdan       rc = sqlite3changeset_old(pIter, i, &pOld);
22170c698471Sdan       if( rc==SQLITE_OK ){
22180c698471Sdan         rc = sqlite3changeset_new(pIter, i, &pNew);
22190c698471Sdan       }
22200c698471Sdan       if( rc==SQLITE_OK ){
22210c698471Sdan         if( pOld ) sqlite3_bind_value(p->pUpdate, i*3+1, pOld);
22220c698471Sdan         sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
22230c698471Sdan         if( pNew ) sqlite3_bind_value(p->pUpdate, i*3+3, pNew);
22240c698471Sdan       }
22250c698471Sdan     }
22260c698471Sdan     if( rc==SQLITE_OK ) rc = sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0);
22270c698471Sdan     if( rc!=SQLITE_OK ) return rc;
22280c698471Sdan 
22290c698471Sdan     /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
22300c698471Sdan     ** the result will be SQLITE_OK with 0 rows modified. */
22310c698471Sdan     sqlite3_step(p->pUpdate);
22320c698471Sdan     rc = sqlite3_reset(p->pUpdate);
22330c698471Sdan 
22340c698471Sdan     if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
22350c698471Sdan       /* A NOTFOUND or DATA error. Search the table to see if it contains
22360c698471Sdan       ** a row with a matching primary key. If so, this is a DATA conflict.
22370c698471Sdan       ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
22380c698471Sdan 
22390c698471Sdan       rc = sessionConflictHandler(
22400c698471Sdan           SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
22410c698471Sdan       );
22420c698471Sdan 
22430c698471Sdan     }else if( rc==SQLITE_CONSTRAINT ){
22440c698471Sdan       /* This may be a CONSTRAINT or CONFLICT error. It is a CONFLICT if
22450c698471Sdan       ** the only problem is a duplicate PRIMARY KEY, or a CONSTRAINT
22460c698471Sdan       ** otherwise. */
22470c698471Sdan       int bPKChange = 0;
22480c698471Sdan 
22490c698471Sdan       /* Check if the PK has been modified. */
22500c698471Sdan       rc = SQLITE_OK;
22510c698471Sdan       for(i=0; i<nCol && rc==SQLITE_OK; i++){
22520c698471Sdan         if( p->abPK[i] ){
22530c698471Sdan           sqlite3_value *pNew;
22540c698471Sdan           rc = sqlite3changeset_new(pIter, i, &pNew);
22550c698471Sdan           if( rc==SQLITE_OK && pNew ){
22560c698471Sdan             bPKChange = 1;
22570c698471Sdan             break;
22580c698471Sdan           }
22590c698471Sdan         }
22600c698471Sdan       }
22610c698471Sdan 
22620c698471Sdan       rc = sessionConflictHandler(SQLITE_CHANGESET_CONFLICT,
22630c698471Sdan           p, pIter, xConflict, pCtx, (bPKChange ? pbReplace : 0)
22640c698471Sdan       );
22650c698471Sdan     }
22660c698471Sdan 
22670c698471Sdan   }else{
22680c698471Sdan     int i;
22690c698471Sdan     assert( op==SQLITE_INSERT );
22700c698471Sdan     for(i=0; rc==SQLITE_OK && i<nCol; i++){
22710c698471Sdan       sqlite3_value *pVal;
22720c698471Sdan       rc = sqlite3changeset_new(pIter, i, &pVal);
22730c698471Sdan       if( rc==SQLITE_OK ){
22740c698471Sdan         rc = sqlite3_bind_value(p->pInsert, i+1, pVal);
22750c698471Sdan       }
22760c698471Sdan     }
22770c698471Sdan     if( rc!=SQLITE_OK ) return rc;
22780c698471Sdan 
22790c698471Sdan     sqlite3_step(p->pInsert);
22800c698471Sdan     rc = sqlite3_reset(p->pInsert);
22810c698471Sdan     if( rc==SQLITE_CONSTRAINT && xConflict ){
22820c698471Sdan       rc = sessionConflictHandler(
22830c698471Sdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
22840c698471Sdan       );
228537f133ecSdan     }
228637f133ecSdan   }
228737f133ecSdan 
228837f133ecSdan   return rc;
228937f133ecSdan }
229037f133ecSdan 
2291296c7658Sdan /*
2292296c7658Sdan ** Apply the changeset passed via pChangeset/nChangeset to the main database
2293296c7658Sdan ** attached to handle "db". Invoke the supplied conflict handler callback
2294296c7658Sdan ** to resolve any conflicts encountered while applying the change.
2295296c7658Sdan */
2296d5f0767cSdan int sqlite3changeset_apply(
2297296c7658Sdan   sqlite3 *db,                    /* Apply change to "main" db of this handle */
2298296c7658Sdan   int nChangeset,                 /* Size of changeset in bytes */
2299296c7658Sdan   void *pChangeset,               /* Changeset blob */
2300d5f0767cSdan   int(*xConflict)(
2301d5f0767cSdan     void *pCtx,                   /* Copy of fifth arg to _apply() */
2302d5f0767cSdan     int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
2303d5f0767cSdan     sqlite3_changeset_iter *p     /* Handle describing change and conflict */
2304d5f0767cSdan   ),
2305296c7658Sdan   void *pCtx                      /* First argument passed to xConflict */
2306d5f0767cSdan ){
2307296c7658Sdan   sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */
2308296c7658Sdan   int rc;                         /* Return code */
2309d5f0767cSdan   const char *zTab = 0;           /* Name of current table */
2310d5f0767cSdan   int nTab = 0;                   /* Result of strlen(zTab) */
2311296c7658Sdan   SessionApplyCtx sApply;         /* changeset_apply() context object */
2312d5f0767cSdan 
23130c698471Sdan   memset(&sApply, 0, sizeof(sApply));
2314d5f0767cSdan   sqlite3changeset_start(&pIter, nChangeset, pChangeset);
23150c698471Sdan 
23164c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
23170c698471Sdan   rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
23180c698471Sdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
23190c698471Sdan     int nCol;
2320d5f0767cSdan     int op;
23210c698471Sdan     int bReplace = 0;
23220c698471Sdan     int bRetry = 0;
23230c698471Sdan     const char *zNew;
23240c698471Sdan     sqlite3changeset_op(pIter, &zNew, &nCol, &op);
2325d5f0767cSdan 
23260c698471Sdan     if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
23270c698471Sdan       sqlite3_free(sApply.azCol);
23280c698471Sdan       sqlite3_finalize(sApply.pDelete);
23290c698471Sdan       sqlite3_finalize(sApply.pUpdate);
23300c698471Sdan       sqlite3_finalize(sApply.pInsert);
23310c698471Sdan       sqlite3_finalize(sApply.pSelect);
23320c698471Sdan       memset(&sApply, 0, sizeof(sApply));
23330c698471Sdan       sApply.db = db;
23340c698471Sdan       sApply.nCol = nCol;
233537f133ecSdan 
2336296c7658Sdan       rc = sessionTableInfo(
2337296c7658Sdan           db, "main", zNew, nCol, &zTab, &sApply.azCol, &sApply.abPK);
23380c698471Sdan 
23390c698471Sdan       if( rc!=SQLITE_OK
23400c698471Sdan        || (rc = sessionSelectRow(db, zTab, &sApply))
23410c698471Sdan        || (rc = sessionUpdateRow(db, zTab, &sApply))
23420c698471Sdan        || (rc = sessionDeleteRow(db, zTab, &sApply))
23430c698471Sdan        || (rc = sessionInsertRow(db, zTab, &sApply))
234437f133ecSdan       ){
234537f133ecSdan         break;
234637f133ecSdan       }
23470c698471Sdan 
23480c698471Sdan       nTab = strlen(zTab);
2349d5f0767cSdan     }
2350d5f0767cSdan 
23510c698471Sdan     rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
23520c698471Sdan 
23530c698471Sdan     if( rc==SQLITE_OK && bRetry ){
23540c698471Sdan       rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, 0);
23550c698471Sdan     }
23560c698471Sdan 
23570c698471Sdan     if( bReplace ){
23580c698471Sdan       rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
23590c698471Sdan       if( rc==SQLITE_OK ){
2360d5f0767cSdan         int i;
23610c698471Sdan         for(i=0; i<sApply.nCol; i++){
23620c698471Sdan           if( sApply.abPK[i] ){
2363d5f0767cSdan             sqlite3_value *pVal;
2364d5f0767cSdan             rc = sqlite3changeset_new(pIter, i, &pVal);
23650c698471Sdan             if( rc==SQLITE_OK && pVal==0 ){
23660c698471Sdan               rc = sqlite3changeset_old(pIter, i, &pVal);
23670c698471Sdan             }
2368d5f0767cSdan             if( rc==SQLITE_OK ){
23690c698471Sdan               rc = sqlite3_bind_value(sApply.pDelete, i+1, pVal);
2370d5f0767cSdan             }
2371d5f0767cSdan           }
23720c698471Sdan         }
23730c698471Sdan         sqlite3_bind_int(sApply.pDelete, sApply.nCol+1, 1);
23740c698471Sdan       }
23750c698471Sdan       if( rc==SQLITE_OK ){
23760c698471Sdan         sqlite3_step(sApply.pDelete);
23770c698471Sdan         rc = sqlite3_reset(sApply.pDelete);
23780c698471Sdan       }
23790c698471Sdan       if( rc==SQLITE_OK ){
23800c698471Sdan         rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, 0, 0);
23810c698471Sdan       }
23820c698471Sdan       if( rc==SQLITE_OK ){
23830c698471Sdan         rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
23840c698471Sdan       }
23850c698471Sdan     }
23860c698471Sdan   }
2387d5f0767cSdan 
2388296c7658Sdan   if( rc==SQLITE_OK ){
2389296c7658Sdan     rc = sqlite3changeset_finalize(pIter);
2390296c7658Sdan   }else{
2391296c7658Sdan     sqlite3changeset_finalize(pIter);
2392296c7658Sdan   }
2393d5f0767cSdan 
2394d5f0767cSdan   if( rc==SQLITE_OK ){
2395d5f0767cSdan     rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
2396d5f0767cSdan   }else{
2397d5f0767cSdan     sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
2398d5f0767cSdan     sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
2399d5f0767cSdan   }
2400d5f0767cSdan 
24010c698471Sdan   sqlite3_finalize(sApply.pInsert);
24020c698471Sdan   sqlite3_finalize(sApply.pDelete);
24030c698471Sdan   sqlite3_finalize(sApply.pUpdate);
24040c698471Sdan   sqlite3_finalize(sApply.pSelect);
24050c698471Sdan   sqlite3_free(sApply.azCol);
24064c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
2407d5f0767cSdan   return rc;
2408d5f0767cSdan }
240991ddd559Sdan 
24104fccf43aSdan #endif        /* #ifdef SQLITE_ENABLE_SESSION */
2411