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 */
22b4480e94Sdan   int bIndirect;                  /* True if all changes are indirect */
23ff4d0f41Sdan   int bAutoAttach;                /* True to auto-attach tables */
244fccf43aSdan   int rc;                         /* Non-zero if an error has occurred */
254fccf43aSdan   sqlite3_session *pNext;         /* Next session object on same db. */
264fccf43aSdan   SessionTable *pTable;           /* List of attached tables */
274fccf43aSdan };
284fccf43aSdan 
294fccf43aSdan /*
30296c7658Sdan ** Structure for changeset iterators.
31296c7658Sdan */
32296c7658Sdan struct sqlite3_changeset_iter {
33296c7658Sdan   u8 *aChangeset;                 /* Pointer to buffer containing changeset */
34296c7658Sdan   int nChangeset;                 /* Number of bytes in aChangeset */
35296c7658Sdan   u8 *pNext;                      /* Pointer to next change within aChangeset */
36296c7658Sdan   int rc;                         /* Iterator error code */
37296c7658Sdan   sqlite3_stmt *pConflict;        /* Points to conflicting row, if any */
38296c7658Sdan   char *zTab;                     /* Current table */
39296c7658Sdan   int nCol;                       /* Number of columns in zTab */
40296c7658Sdan   int op;                         /* Current operation */
41b4480e94Sdan   int bIndirect;                  /* True if current change was indirect */
42244593c8Sdan   u8 *abPK;                       /* Primary key array */
43296c7658Sdan   sqlite3_value **apValue;        /* old.* and new.* values */
44296c7658Sdan };
45296c7658Sdan 
46296c7658Sdan /*
474fccf43aSdan ** Each session object maintains a set of the following structures, one
484fccf43aSdan ** for each table the session object is monitoring. The structures are
494fccf43aSdan ** stored in a linked list starting at sqlite3_session.pTable.
504fccf43aSdan **
514fccf43aSdan ** The keys of the SessionTable.aChange[] hash table are all rows that have
524fccf43aSdan ** been modified in any way since the session object was attached to the
534fccf43aSdan ** table.
544fccf43aSdan **
554fccf43aSdan ** The data associated with each hash-table entry is a structure containing
564fccf43aSdan ** a subset of the initial values that the modified row contained at the
574fccf43aSdan ** start of the session. Or no initial values if the row was inserted.
584fccf43aSdan */
594fccf43aSdan struct SessionTable {
604fccf43aSdan   SessionTable *pNext;
614fccf43aSdan   char *zName;                    /* Local name of table */
624fccf43aSdan   int nCol;                       /* Number of columns in table zName */
63e8d5648eSdan   const char **azCol;             /* Column names */
64e8d5648eSdan   u8 *abPK;                       /* Array of primary key flags */
65296c7658Sdan   int nEntry;                     /* Total number of entries in hash table */
664fccf43aSdan   int nChange;                    /* Size of apChange[] array */
674fccf43aSdan   SessionChange **apChange;       /* Hash table buckets */
684fccf43aSdan };
694fccf43aSdan 
704fccf43aSdan /*
714fccf43aSdan ** RECORD FORMAT:
724fccf43aSdan **
734fccf43aSdan ** The following record format is similar to (but not compatible with) that
744fccf43aSdan ** used in SQLite database files. This format is used as part of the
754fccf43aSdan ** change-set binary format, and so must be architecture independent.
764fccf43aSdan **
774fccf43aSdan ** Unlike the SQLite database record format, each field is self-contained -
784fccf43aSdan ** there is no separation of header and data. Each field begins with a
794fccf43aSdan ** single byte describing its type, as follows:
804fccf43aSdan **
814fccf43aSdan **       0x00: Undefined value.
824fccf43aSdan **       0x01: Integer value.
834fccf43aSdan **       0x02: Real value.
844fccf43aSdan **       0x03: Text value.
854fccf43aSdan **       0x04: Blob value.
864fccf43aSdan **       0x05: SQL NULL value.
874fccf43aSdan **
884fccf43aSdan ** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
894fccf43aSdan ** and so on in sqlite3.h. For undefined and NULL values, the field consists
904fccf43aSdan ** only of the single type byte. For other types of values, the type byte
914fccf43aSdan ** is followed by:
924fccf43aSdan **
934fccf43aSdan **   Text values:
944fccf43aSdan **     A varint containing the number of bytes in the value (encoded using
954fccf43aSdan **     UTF-8). Followed by a buffer containing the UTF-8 representation
964fccf43aSdan **     of the text value. There is no nul terminator.
974fccf43aSdan **
984fccf43aSdan **   Blob values:
994fccf43aSdan **     A varint containing the number of bytes in the value, followed by
1004fccf43aSdan **     a buffer containing the value itself.
1014fccf43aSdan **
1024fccf43aSdan **   Integer values:
1034fccf43aSdan **     An 8-byte big-endian integer value.
1044fccf43aSdan **
1054fccf43aSdan **   Real values:
1064fccf43aSdan **     An 8-byte big-endian IEEE 754-2008 real value.
1074fccf43aSdan **
1084fccf43aSdan ** Varint values are encoded in the same way as varints in the SQLite
1094fccf43aSdan ** record format.
1104fccf43aSdan **
1114fccf43aSdan ** CHANGESET FORMAT:
1124fccf43aSdan **
1134fccf43aSdan ** A changeset is a collection of DELETE, UPDATE and INSERT operations on
1144fccf43aSdan ** one or more tables. Operations on a single table are grouped together,
1154fccf43aSdan ** but may occur in any order (i.e. deletes, updates and inserts are all
1164fccf43aSdan ** mixed together).
1174fccf43aSdan **
1184fccf43aSdan ** Each group of changes begins with a table header:
1194fccf43aSdan **
1204fccf43aSdan **   1 byte: Constant 0x54 (capital 'T')
1214fccf43aSdan **   Varint: Big-endian integer set to the number of columns in the table.
1224fccf43aSdan **   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
1234fccf43aSdan **
1244fccf43aSdan ** Followed by one or more changes to the table.
1254fccf43aSdan **
1264fccf43aSdan **   1 byte: Either SQLITE_INSERT, UPDATE or DELETE.
1274fccf43aSdan **   old.* record: (delete and update only)
1284fccf43aSdan **   new.* record: (insert and update only)
1294fccf43aSdan */
1304fccf43aSdan 
1314fccf43aSdan /*
1324fccf43aSdan ** For each row modified during a session, there exists a single instance of
1334fccf43aSdan ** this structure stored in a SessionTable.aChange[] hash table.
1344fccf43aSdan */
1354fccf43aSdan struct SessionChange {
136e8d5648eSdan   int bInsert;                    /* True if row was inserted this session */
137b4480e94Sdan   int bIndirect;                  /* True if this change is "indirect" */
1384fccf43aSdan   int nRecord;                    /* Number of bytes in buffer aRecord[] */
1394fccf43aSdan   u8 *aRecord;                    /* Buffer containing old.* record */
1404fccf43aSdan   SessionChange *pNext;           /* For hash-table collisions */
1414fccf43aSdan };
1424fccf43aSdan 
143296c7658Sdan /*
144296c7658Sdan ** Instances of this structure are used to build strings or binary records.
145296c7658Sdan */
146296c7658Sdan struct SessionBuffer {
147296c7658Sdan   u8 *aBuf;                       /* Pointer to changeset buffer */
148296c7658Sdan   int nBuf;                       /* Size of buffer aBuf */
149296c7658Sdan   int nAlloc;                     /* Size of allocation containing aBuf */
150296c7658Sdan };
1514fccf43aSdan 
152296c7658Sdan /*
153296c7658Sdan ** Write a varint with value iVal into the buffer at aBuf. Return the
154296c7658Sdan ** number of bytes written.
155296c7658Sdan */
156296c7658Sdan static int sessionVarintPut(u8 *aBuf, int iVal){
157296c7658Sdan   return putVarint32(aBuf, iVal);
1584fccf43aSdan }
1594fccf43aSdan 
160296c7658Sdan /*
161296c7658Sdan ** Return the number of bytes required to store value iVal as a varint.
162296c7658Sdan */
163296c7658Sdan static int sessionVarintLen(int iVal){
164296c7658Sdan   return sqlite3VarintLen(iVal);
165296c7658Sdan }
166296c7658Sdan 
167296c7658Sdan /*
168296c7658Sdan ** Read a varint value from aBuf[] into *piVal. Return the number of
169296c7658Sdan ** bytes read.
170296c7658Sdan */
1714fccf43aSdan static int sessionVarintGet(u8 *aBuf, int *piVal){
172296c7658Sdan   return getVarint32(aBuf, *piVal);
1734fccf43aSdan }
1744fccf43aSdan 
175296c7658Sdan /*
176296c7658Sdan ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
177296c7658Sdan ** the value read.
178296c7658Sdan */
1794fccf43aSdan static sqlite3_int64 sessionGetI64(u8 *aRec){
1804fccf43aSdan   return (((sqlite3_int64)aRec[0]) << 56)
1814fccf43aSdan        + (((sqlite3_int64)aRec[1]) << 48)
1824fccf43aSdan        + (((sqlite3_int64)aRec[2]) << 40)
1834fccf43aSdan        + (((sqlite3_int64)aRec[3]) << 32)
1844fccf43aSdan        + (((sqlite3_int64)aRec[4]) << 24)
1854fccf43aSdan        + (((sqlite3_int64)aRec[5]) << 16)
1864fccf43aSdan        + (((sqlite3_int64)aRec[6]) <<  8)
1874fccf43aSdan        + (((sqlite3_int64)aRec[7]) <<  0);
1884fccf43aSdan }
1894fccf43aSdan 
1904fccf43aSdan /*
191296c7658Sdan ** Write a 64-bit big-endian integer value to the buffer aBuf[].
192296c7658Sdan */
193296c7658Sdan static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
194296c7658Sdan   aBuf[0] = (i>>56) & 0xFF;
195296c7658Sdan   aBuf[1] = (i>>48) & 0xFF;
196296c7658Sdan   aBuf[2] = (i>>40) & 0xFF;
197296c7658Sdan   aBuf[3] = (i>>32) & 0xFF;
198296c7658Sdan   aBuf[4] = (i>>24) & 0xFF;
199296c7658Sdan   aBuf[5] = (i>>16) & 0xFF;
200296c7658Sdan   aBuf[6] = (i>> 8) & 0xFF;
201296c7658Sdan   aBuf[7] = (i>> 0) & 0xFF;
202296c7658Sdan }
203296c7658Sdan 
204296c7658Sdan /*
2054fccf43aSdan ** This function is used to serialize the contents of value pValue (see
2064fccf43aSdan ** comment titled "RECORD FORMAT" above).
2074fccf43aSdan **
2084fccf43aSdan ** If it is non-NULL, the serialized form of the value is written to
2094fccf43aSdan ** buffer aBuf. *pnWrite is set to the number of bytes written before
2104fccf43aSdan ** returning. Or, if aBuf is NULL, the only thing this function does is
2114fccf43aSdan ** set *pnWrite.
2124fccf43aSdan **
2134fccf43aSdan ** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
2144fccf43aSdan ** within a call to sqlite3_value_text() (may fail if the db is utf-16))
2154fccf43aSdan ** SQLITE_NOMEM is returned.
2164fccf43aSdan */
2174fccf43aSdan static int sessionSerializeValue(
2184fccf43aSdan   u8 *aBuf,                       /* If non-NULL, write serialized value here */
2194fccf43aSdan   sqlite3_value *pValue,          /* Value to serialize */
2204fccf43aSdan   int *pnWrite                    /* IN/OUT: Increment by bytes written */
2214fccf43aSdan ){
222296c7658Sdan   int eType;                      /* Value type (SQLITE_NULL, TEXT etc.) */
223296c7658Sdan   int nByte;                      /* Size of serialized value in bytes */
2244fccf43aSdan 
2254fccf43aSdan   eType = sqlite3_value_type(pValue);
2264fccf43aSdan   if( aBuf ) aBuf[0] = eType;
2274fccf43aSdan 
2284fccf43aSdan   switch( eType ){
2294fccf43aSdan     case SQLITE_NULL:
2304fccf43aSdan       nByte = 1;
2314fccf43aSdan       break;
2324fccf43aSdan 
2334fccf43aSdan     case SQLITE_INTEGER:
2344fccf43aSdan     case SQLITE_FLOAT:
2354fccf43aSdan       if( aBuf ){
2364fccf43aSdan         /* TODO: SQLite does something special to deal with mixed-endian
2374fccf43aSdan         ** floating point values (e.g. ARM7). This code probably should
2384fccf43aSdan         ** too.  */
2394fccf43aSdan         u64 i;
2404fccf43aSdan         if( eType==SQLITE_INTEGER ){
2414fccf43aSdan           i = (u64)sqlite3_value_int64(pValue);
2424fccf43aSdan         }else{
2434fccf43aSdan           double r;
2444fccf43aSdan           assert( sizeof(double)==8 && sizeof(u64)==8 );
2454fccf43aSdan           r = sqlite3_value_double(pValue);
2464fccf43aSdan           memcpy(&i, &r, 8);
2474fccf43aSdan         }
248296c7658Sdan         sessionPutI64(&aBuf[1], i);
2494fccf43aSdan       }
2504fccf43aSdan       nByte = 9;
2514fccf43aSdan       break;
2524fccf43aSdan 
2534e895da1Sdan     default: {
2544fccf43aSdan       int n = sqlite3_value_bytes(pValue);
255296c7658Sdan       int nVarint = sessionVarintLen(n);
2564e895da1Sdan       assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
2574fccf43aSdan       if( aBuf ){
2584fccf43aSdan         sessionVarintPut(&aBuf[1], n);
2594fccf43aSdan         memcpy(&aBuf[nVarint + 1], eType==SQLITE_TEXT ?
2604fccf43aSdan             sqlite3_value_text(pValue) : sqlite3_value_blob(pValue), n
2614fccf43aSdan         );
2624fccf43aSdan       }
2634fccf43aSdan 
2644fccf43aSdan       nByte = 1 + nVarint + n;
2654fccf43aSdan       break;
2664fccf43aSdan     }
2674fccf43aSdan   }
2684fccf43aSdan 
2694fccf43aSdan   *pnWrite += nByte;
2704fccf43aSdan   return SQLITE_OK;
2714fccf43aSdan }
2724fccf43aSdan 
2734131639cSdan #define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
2744131639cSdan static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
275e8d5648eSdan   h = HASH_APPEND(h, i & 0xFFFFFFFF);
276e8d5648eSdan   return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
277e8d5648eSdan }
2784131639cSdan static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
279e8d5648eSdan   int i;
280e8d5648eSdan   for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
281e8d5648eSdan   return h;
282e8d5648eSdan }
283e8d5648eSdan 
2844fccf43aSdan /*
2854131639cSdan ** This function may only be called from within a pre-update callback.
2864131639cSdan ** It calculates a hash based on the primary key values of the old.* or
2874131639cSdan ** new.* row currently available. The value returned is guaranteed to
2884131639cSdan ** be less than pTab->nBucket.
2894fccf43aSdan */
2904131639cSdan static unsigned int sessionPreupdateHash(
291e8d5648eSdan   sqlite3 *db,                    /* Database handle */
292e8d5648eSdan   SessionTable *pTab,             /* Session table handle */
293e8d5648eSdan   int bNew,                       /* True to hash the new.* PK */
29427453faeSdan   int *piHash,                    /* OUT: Hash value */
29527453faeSdan   int *pbNullPK
296e8d5648eSdan ){
2974131639cSdan   unsigned int h = 0;             /* Hash value to return */
2984131639cSdan   int i;                          /* Used to iterate through columns */
299e8d5648eSdan 
30027453faeSdan   assert( *pbNullPK==0 );
301e8d5648eSdan   assert( pTab->nCol==sqlite3_preupdate_count(db) );
302e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
303e8d5648eSdan     if( pTab->abPK[i] ){
304e8d5648eSdan       int rc;
305e8d5648eSdan       int eType;
306e8d5648eSdan       sqlite3_value *pVal;
307e8d5648eSdan 
308e8d5648eSdan       if( bNew ){
309e8d5648eSdan         rc = sqlite3_preupdate_new(db, i, &pVal);
310e8d5648eSdan       }else{
311e8d5648eSdan         rc = sqlite3_preupdate_old(db, i, &pVal);
312e8d5648eSdan       }
31312ca0b56Sdan       if( rc!=SQLITE_OK ) return rc;
314e8d5648eSdan 
315e8d5648eSdan       eType = sqlite3_value_type(pVal);
316e8d5648eSdan       h = HASH_APPEND(h, eType);
317e8d5648eSdan       switch( eType ){
318e8d5648eSdan         case SQLITE_INTEGER:
319e8d5648eSdan         case SQLITE_FLOAT: {
320e8d5648eSdan           i64 iVal;
321e8d5648eSdan           if( eType==SQLITE_INTEGER ){
322e8d5648eSdan             iVal = sqlite3_value_int64(pVal);
323e8d5648eSdan           }else{
324e8d5648eSdan             double rVal = sqlite3_value_double(pVal);
325e8d5648eSdan             assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
326e8d5648eSdan             memcpy(&iVal, &rVal, 8);
327e8d5648eSdan           }
328e8d5648eSdan           h = sessionHashAppendI64(h, iVal);
329e8d5648eSdan           break;
330e8d5648eSdan         }
331e8d5648eSdan 
332e8d5648eSdan         case SQLITE_TEXT:
333e8d5648eSdan         case SQLITE_BLOB: {
334e8d5648eSdan           int n = sqlite3_value_bytes(pVal);
335e8d5648eSdan           const u8 *z = eType==SQLITE_TEXT ?
336e8d5648eSdan             sqlite3_value_text(pVal) : sqlite3_value_blob(pVal);
337e8d5648eSdan           h = sessionHashAppendBlob(h, n, z);
338e8d5648eSdan           break;
339e8d5648eSdan         }
34027453faeSdan 
34127453faeSdan         default:
34227453faeSdan           assert( eType==SQLITE_NULL );
34327453faeSdan           *pbNullPK = 1;
34427453faeSdan           return SQLITE_OK;
345e8d5648eSdan       }
346e8d5648eSdan     }
347e8d5648eSdan   }
348e8d5648eSdan 
349e8d5648eSdan   *piHash = (h % pTab->nChange);
350e8d5648eSdan   return SQLITE_OK;
351e8d5648eSdan }
352e8d5648eSdan 
3534131639cSdan /*
3544131639cSdan ** Based on the primary key values stored in change pChange, calculate a
3554131639cSdan ** hash key, assuming the has table has nBucket buckets. The hash keys
3564131639cSdan ** calculated by this function are compatible with those calculated by
3574131639cSdan ** sessionPreupdateHash().
3584131639cSdan */
3594131639cSdan static unsigned int sessionChangeHash(
3604131639cSdan   sqlite3 *db,                    /* Database handle */
3614131639cSdan   SessionTable *pTab,             /* Table handle */
3624131639cSdan   SessionChange *pChange,         /* Change handle */
3634131639cSdan   int nBucket                     /* Assume this many buckets in hash table */
364e8d5648eSdan ){
3654131639cSdan   unsigned int h = 0;             /* Value to return */
3664131639cSdan   int i;                          /* Used to iterate through columns */
3674131639cSdan   u8 *a = pChange->aRecord;       /* Used to iterate through change record */
368e8d5648eSdan 
369e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
370e8d5648eSdan     int eType = *a++;
371e8d5648eSdan     int isPK = pTab->abPK[i];
372e8d5648eSdan 
37327453faeSdan     /* It is not possible for eType to be SQLITE_NULL here. The session
37427453faeSdan     ** module does not record changes for rows with NULL values stored in
37527453faeSdan     ** primary key columns. */
37627453faeSdan     assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
37727453faeSdan          || eType==SQLITE_TEXT || eType==SQLITE_BLOB
37827453faeSdan     );
37927453faeSdan 
380e8d5648eSdan     if( isPK ) h = HASH_APPEND(h, eType);
38127453faeSdan     if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
38227453faeSdan       if( isPK ) h = sessionHashAppendI64(h, sessionGetI64(a));
383e8d5648eSdan       a += 8;
38427453faeSdan     }else{
385e8d5648eSdan       int n;
386e8d5648eSdan       a += sessionVarintGet(a, &n);
38727453faeSdan       if( isPK ) h = sessionHashAppendBlob(h, n, a);
388e8d5648eSdan       a += n;
389e8d5648eSdan     }
390e8d5648eSdan   }
391e8d5648eSdan   return (h % nBucket);
392e8d5648eSdan }
393e8d5648eSdan 
394e8d5648eSdan static int sessionPreupdateEqual(
395e8d5648eSdan   sqlite3 *db,
396e8d5648eSdan   SessionTable *pTab,
397e8d5648eSdan   SessionChange *pChange,
398e8d5648eSdan   int bNew,
399e8d5648eSdan   int *pbEqual
400e8d5648eSdan ){
401e8d5648eSdan   int i;
402e8d5648eSdan   u8 *a = pChange->aRecord;
403e8d5648eSdan 
404e8d5648eSdan   *pbEqual = 0;
405e8d5648eSdan 
406e8d5648eSdan   for(i=0; i<pTab->nCol; i++){
407e8d5648eSdan     int eType = *a++;
408e8d5648eSdan     if( !pTab->abPK[i] ){
409e8d5648eSdan       switch( eType ){
410e8d5648eSdan         case SQLITE_INTEGER:
411e8d5648eSdan         case SQLITE_FLOAT:
412e8d5648eSdan           a += 8;
413e8d5648eSdan           break;
414e8d5648eSdan 
415e8d5648eSdan         case SQLITE_TEXT:
416e8d5648eSdan         case SQLITE_BLOB: {
417e8d5648eSdan           int n;
418e8d5648eSdan           a += sessionVarintGet(a, &n);
419e8d5648eSdan           a += n;
420e8d5648eSdan           break;
421e8d5648eSdan         }
422e8d5648eSdan       }
423e8d5648eSdan     }else{
424e8d5648eSdan       sqlite3_value *pVal;
425e8d5648eSdan       int rc;
426e8d5648eSdan       if( bNew ){
427e8d5648eSdan         rc = sqlite3_preupdate_new(db, i, &pVal);
428e8d5648eSdan       }else{
429e8d5648eSdan         rc = sqlite3_preupdate_old(db, i, &pVal);
430e8d5648eSdan       }
431e8d5648eSdan       if( rc!=SQLITE_OK || sqlite3_value_type(pVal)!=eType ) return rc;
432e8d5648eSdan 
43312ca0b56Sdan       /* A SessionChange object never has a NULL value in a PK column */
43412ca0b56Sdan       assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
43512ca0b56Sdan            || eType==SQLITE_BLOB    || eType==SQLITE_TEXT
43612ca0b56Sdan       );
43712ca0b56Sdan 
43812ca0b56Sdan       if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
439e8d5648eSdan         i64 iVal = sessionGetI64(a);
440e8d5648eSdan         a += 8;
441e8d5648eSdan         if( eType==SQLITE_INTEGER ){
442e8d5648eSdan           if( sqlite3_value_int64(pVal)!=iVal ) return SQLITE_OK;
443e8d5648eSdan         }else{
444e8d5648eSdan           double rVal;
445e8d5648eSdan           assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
446e8d5648eSdan           memcpy(&rVal, &iVal, 8);
447e8d5648eSdan           if( sqlite3_value_double(pVal)!=rVal ) return SQLITE_OK;
448e8d5648eSdan         }
44912ca0b56Sdan       }else{
450e8d5648eSdan         int n;
451e8d5648eSdan         const u8 *z;
452e8d5648eSdan         a += sessionVarintGet(a, &n);
453e8d5648eSdan         if( sqlite3_value_bytes(pVal)!=n ) return SQLITE_OK;
45412ca0b56Sdan         if( eType==SQLITE_TEXT ){
45512ca0b56Sdan           z = sqlite3_value_text(pVal);
45612ca0b56Sdan         }else{
45712ca0b56Sdan           z = sqlite3_value_blob(pVal);
45812ca0b56Sdan         }
459e8d5648eSdan         if( memcmp(a, z, n) ) return SQLITE_OK;
460e8d5648eSdan         a += n;
461e8d5648eSdan         break;
462e8d5648eSdan       }
463e8d5648eSdan     }
464e8d5648eSdan   }
465e8d5648eSdan 
466e8d5648eSdan   *pbEqual = 1;
467e8d5648eSdan   return SQLITE_OK;
4684fccf43aSdan }
4694fccf43aSdan 
4704fccf43aSdan /*
4714fccf43aSdan ** If required, grow the hash table used to store changes on table pTab
4724fccf43aSdan ** (part of the session pSession). If a fatal OOM error occurs, set the
4734fccf43aSdan ** session object to failed and return SQLITE_ERROR. Otherwise, return
4744fccf43aSdan ** SQLITE_OK.
4754fccf43aSdan **
4764fccf43aSdan ** It is possible that a non-fatal OOM error occurs in this function. In
4774fccf43aSdan ** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
4784fccf43aSdan ** Growing the hash table in this case is a performance optimization only,
4794fccf43aSdan ** it is not required for correct operation.
4804fccf43aSdan */
4814fccf43aSdan static int sessionGrowHash(sqlite3_session *pSession, SessionTable *pTab){
4824fccf43aSdan   if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
4834fccf43aSdan     int i;
4844fccf43aSdan     SessionChange **apNew;
4854fccf43aSdan     int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
4864fccf43aSdan 
4874fccf43aSdan     apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
4884fccf43aSdan     if( apNew==0 ){
4894fccf43aSdan       if( pTab->nChange==0 ){
4904fccf43aSdan         pSession->rc = SQLITE_NOMEM;
4914fccf43aSdan         return SQLITE_ERROR;
4924fccf43aSdan       }
4934fccf43aSdan       return SQLITE_OK;
4944fccf43aSdan     }
4954fccf43aSdan     memset(apNew, 0, sizeof(SessionChange *) * nNew);
4964fccf43aSdan 
4974fccf43aSdan     for(i=0; i<pTab->nChange; i++){
4984fccf43aSdan       SessionChange *p;
4994fccf43aSdan       SessionChange *pNext;
5004fccf43aSdan       for(p=pTab->apChange[i]; p; p=pNext){
501e8d5648eSdan         int iHash = sessionChangeHash(pSession->db, pTab, p, nNew);
5024fccf43aSdan         pNext = p->pNext;
5034fccf43aSdan         p->pNext = apNew[iHash];
5044fccf43aSdan         apNew[iHash] = p;
5054fccf43aSdan       }
5064fccf43aSdan     }
5074fccf43aSdan 
5084fccf43aSdan     sqlite3_free(pTab->apChange);
5094fccf43aSdan     pTab->nChange = nNew;
5104fccf43aSdan     pTab->apChange = apNew;
5114fccf43aSdan   }
5124fccf43aSdan 
5134fccf43aSdan   return SQLITE_OK;
5144fccf43aSdan }
5154fccf43aSdan 
516296c7658Sdan /*
517e8d5648eSdan ** This function queries the database for the names of the columns of table
518e8d5648eSdan ** zThis, in schema zDb. It is expected that the table has nCol columns. If
519e8d5648eSdan ** not, SQLITE_SCHEMA is returned and none of the output variables are
520e8d5648eSdan ** populated.
521e8d5648eSdan **
522e8d5648eSdan ** Otherwise, if it is not NULL, variable *pzTab is set to point to a
523e8d5648eSdan ** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
524e8d5648eSdan ** point to an array of pointers to column names. And *pabPK (again, if not
525e8d5648eSdan ** NULL) is set to point to an array of booleans - true if the corresponding
526e8d5648eSdan ** column is part of the primary key.
527e8d5648eSdan **
528e8d5648eSdan ** For example, if the table is declared as:
529e8d5648eSdan **
530e8d5648eSdan **     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
531e8d5648eSdan **
532e8d5648eSdan ** Then the three output variables are populated as follows:
533e8d5648eSdan **
534e8d5648eSdan **     *pzTab  = "tbl1"
535e8d5648eSdan **     *pazCol = {"w", "x", "y", "z"}
536e8d5648eSdan **     *pabPK  = {1, 0, 0, 1}
537e8d5648eSdan **
538e8d5648eSdan ** All returned buffers are part of the same single allocation, which must
539e8d5648eSdan ** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then
540e8d5648eSdan ** pointer *pazCol should be freed to release all memory. Otherwise, pointer
541e8d5648eSdan ** *pabPK. It is illegal for both pazCol and pabPK to be NULL.
542e8d5648eSdan */
543e8d5648eSdan static int sessionTableInfo(
544e8d5648eSdan   sqlite3 *db,                    /* Database connection */
545e8d5648eSdan   const char *zDb,                /* Name of attached database (e.g. "main") */
546e8d5648eSdan   const char *zThis,              /* Table name */
547ca62ad57Sdan   int *pnCol,                     /* OUT: number of columns */
548e8d5648eSdan   const char **pzTab,             /* OUT: Copy of zThis */
549e8d5648eSdan   const char ***pazCol,           /* OUT: Array of column names for table */
550e8d5648eSdan   u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
551e8d5648eSdan ){
552e8d5648eSdan   char *zPragma;
553e8d5648eSdan   sqlite3_stmt *pStmt;
554e8d5648eSdan   int rc;
555e8d5648eSdan   int nByte;
556e8d5648eSdan   int nDbCol = 0;
557e8d5648eSdan   int nThis;
558e8d5648eSdan   int i;
559e8d5648eSdan   u8 *pAlloc;
560db04571cSdan   char **azCol = 0;
561e8d5648eSdan   u8 *abPK;
562e8d5648eSdan 
563db04571cSdan   assert( pazCol && pabPK );
564e8d5648eSdan 
565e8d5648eSdan   nThis = strlen(zThis);
566e8d5648eSdan   zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
567e8d5648eSdan   if( !zPragma ) return SQLITE_NOMEM;
568e8d5648eSdan 
569e8d5648eSdan   rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
570e8d5648eSdan   sqlite3_free(zPragma);
571e8d5648eSdan   if( rc!=SQLITE_OK ) return rc;
572e8d5648eSdan 
573e8d5648eSdan   nByte = nThis + 1;
574e8d5648eSdan   while( SQLITE_ROW==sqlite3_step(pStmt) ){
575e8d5648eSdan     nByte += sqlite3_column_bytes(pStmt, 1);
576e8d5648eSdan     nDbCol++;
577e8d5648eSdan   }
578e8d5648eSdan   rc = sqlite3_reset(pStmt);
579e8d5648eSdan 
580e8d5648eSdan   if( rc==SQLITE_OK ){
581e8d5648eSdan     nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
582e8d5648eSdan     pAlloc = sqlite3_malloc(nByte);
583e8d5648eSdan     if( pAlloc==0 ){
584e8d5648eSdan       rc = SQLITE_NOMEM;
585e8d5648eSdan     }
586e8d5648eSdan   }
587e8d5648eSdan   if( rc==SQLITE_OK ){
588e8d5648eSdan     azCol = (char **)pAlloc;
589ca62ad57Sdan     pAlloc = (u8 *)&azCol[nDbCol];
590e8d5648eSdan     abPK = (u8 *)pAlloc;
591ca62ad57Sdan     pAlloc = &abPK[nDbCol];
592e8d5648eSdan     if( pzTab ){
593e8d5648eSdan       memcpy(pAlloc, zThis, nThis+1);
594e8d5648eSdan       *pzTab = (char *)pAlloc;
595e8d5648eSdan       pAlloc += nThis+1;
596e8d5648eSdan     }
597e8d5648eSdan 
598e8d5648eSdan     i = 0;
599e8d5648eSdan     while( SQLITE_ROW==sqlite3_step(pStmt) ){
600e8d5648eSdan       int nName = sqlite3_column_bytes(pStmt, 1);
601e8d5648eSdan       const unsigned char *zName = sqlite3_column_text(pStmt, 1);
602e8d5648eSdan       if( zName==0 ) break;
603e8d5648eSdan       memcpy(pAlloc, zName, nName+1);
604e8d5648eSdan       azCol[i] = (char *)pAlloc;
605e8d5648eSdan       pAlloc += nName+1;
606db04571cSdan       abPK[i] = sqlite3_column_int(pStmt, 5);
607e8d5648eSdan       i++;
608e8d5648eSdan     }
609e8d5648eSdan     rc = sqlite3_reset(pStmt);
610e8d5648eSdan 
611e8d5648eSdan   }
612e8d5648eSdan 
613e8d5648eSdan   /* If successful, populate the output variables. Otherwise, zero them and
614e8d5648eSdan   ** free any allocation made. An error code will be returned in this case.
615e8d5648eSdan   */
616e8d5648eSdan   if( rc==SQLITE_OK ){
617db04571cSdan     *pazCol = (const char **)azCol;
618db04571cSdan     *pabPK = abPK;
619ca62ad57Sdan     *pnCol = nDbCol;
620e8d5648eSdan   }else{
621db04571cSdan     *pazCol = 0;
622db04571cSdan     *pabPK = 0;
623ca62ad57Sdan     *pnCol = 0;
624e8d5648eSdan     if( pzTab ) *pzTab = 0;
625db04571cSdan     sqlite3_free(azCol);
626e8d5648eSdan   }
627e8d5648eSdan   sqlite3_finalize(pStmt);
628e8d5648eSdan   return rc;
629e8d5648eSdan }
630e8d5648eSdan 
631e8d5648eSdan /*
632296c7658Sdan ** This function is only called from within a pre-update handler for a
633296c7658Sdan ** write to table pTab, part of session pSession. If this is the first
634296c7658Sdan ** write to this table, set the SessionTable.nCol variable to the number
635296c7658Sdan ** of columns in the table.
636296c7658Sdan **
637296c7658Sdan ** Otherwise, if this is not the first time this table has been written
638296c7658Sdan ** to, check that the number of columns in the table has not changed. If
639296c7658Sdan ** it has not, return zero.
640296c7658Sdan **
641296c7658Sdan ** If the number of columns in the table has changed since the last write
642296c7658Sdan ** was recorded, set the session error-code to SQLITE_SCHEMA and return
643296c7658Sdan ** non-zero. Users are not allowed to change the number of columns in a table
644296c7658Sdan ** for which changes are being recorded by the session module. If they do so,
645296c7658Sdan ** it is an error.
646296c7658Sdan */
6474fccf43aSdan static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
6484fccf43aSdan   if( pTab->nCol==0 ){
649e8d5648eSdan     assert( pTab->azCol==0 || pTab->abPK==0 );
650e8d5648eSdan     pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
651ca62ad57Sdan         pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->abPK
652e8d5648eSdan     );
653ca62ad57Sdan   }
654ca62ad57Sdan   if( pSession->rc==SQLITE_OK
655ca62ad57Sdan    && pTab->nCol!=sqlite3_preupdate_count(pSession->db)
656ca62ad57Sdan   ){
6574fccf43aSdan     pSession->rc = SQLITE_SCHEMA;
6584fccf43aSdan   }
659e8d5648eSdan   return pSession->rc;
660e8d5648eSdan }
661e8d5648eSdan 
662e8d5648eSdan static void sessionPreupdateOneChange(
663e8d5648eSdan   int op,
664e8d5648eSdan   sqlite3_session *pSession,
665e8d5648eSdan   SessionTable *pTab
666e8d5648eSdan ){
667e8d5648eSdan   sqlite3 *db = pSession->db;
668e8d5648eSdan   int iHash;
66927453faeSdan   int bNullPk = 0;
670e8d5648eSdan   int rc = SQLITE_OK;
671e8d5648eSdan 
672e8d5648eSdan   if( pSession->rc ) return;
673e8d5648eSdan 
674e8d5648eSdan   /* Load table details if required */
675e8d5648eSdan   if( sessionInitTable(pSession, pTab) ) return;
676e8d5648eSdan 
677e8d5648eSdan   /* Grow the hash table if required */
678e8d5648eSdan   if( sessionGrowHash(pSession, pTab) ) return;
679e8d5648eSdan 
680e8d5648eSdan   /* Search the hash table for an existing entry for rowid=iKey2. If
681e8d5648eSdan   ** one is found, store a pointer to it in pChange and unlink it from
682e8d5648eSdan   ** the hash table. Otherwise, set pChange to NULL.
683e8d5648eSdan   */
68427453faeSdan   rc = sessionPreupdateHash(db, pTab, op==SQLITE_INSERT, &iHash, &bNullPk);
685b4480e94Sdan   if( rc==SQLITE_OK && bNullPk==0 ){
686b4480e94Sdan     SessionChange *pC;
687e8d5648eSdan     for(pC=pTab->apChange[iHash]; rc==SQLITE_OK && pC; pC=pC->pNext){
688e8d5648eSdan       int bEqual;
689e8d5648eSdan       rc = sessionPreupdateEqual(db, pTab, pC, op==SQLITE_INSERT, &bEqual);
690e8d5648eSdan       if( bEqual ) break;
691e8d5648eSdan     }
692e8d5648eSdan     if( pC==0 ){
693e8d5648eSdan       /* Create a new change object containing all the old values (if
694e8d5648eSdan        ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
695e8d5648eSdan        ** values (if this is an INSERT). */
696b4480e94Sdan       SessionChange *pChange; /* New change object */
697e8d5648eSdan       int nByte;              /* Number of bytes to allocate */
698e8d5648eSdan       int i;                  /* Used to iterate through columns */
699e8d5648eSdan 
700b4480e94Sdan       assert( rc==SQLITE_OK );
701e8d5648eSdan       pTab->nEntry++;
702e8d5648eSdan 
703e8d5648eSdan       /* Figure out how large an allocation is required */
704e8d5648eSdan       nByte = sizeof(SessionChange);
705e8d5648eSdan       for(i=0; i<pTab->nCol && rc==SQLITE_OK; i++){
706e8d5648eSdan         sqlite3_value *p = 0;
707e8d5648eSdan         if( op!=SQLITE_INSERT ){
708e8d5648eSdan           rc = sqlite3_preupdate_old(pSession->db, i, &p);
709e8d5648eSdan         }else if( 1 || pTab->abPK[i] ){
710e8d5648eSdan           rc = sqlite3_preupdate_new(pSession->db, i, &p);
711e8d5648eSdan         }
712e8d5648eSdan         if( p && rc==SQLITE_OK ){
713e8d5648eSdan           rc = sessionSerializeValue(0, p, &nByte);
714e8d5648eSdan         }
715e8d5648eSdan       }
716e8d5648eSdan 
717e8d5648eSdan       /* Allocate the change object */
718e8d5648eSdan       pChange = (SessionChange *)sqlite3_malloc(nByte);
719e8d5648eSdan       if( !pChange ){
720e8d5648eSdan         rc = SQLITE_NOMEM;
721e8d5648eSdan       }else{
722e8d5648eSdan         memset(pChange, 0, sizeof(SessionChange));
723e8d5648eSdan         pChange->aRecord = (u8 *)&pChange[1];
724e8d5648eSdan       }
725e8d5648eSdan 
726e8d5648eSdan       /* Populate the change object */
727e8d5648eSdan       nByte = 0;
728e8d5648eSdan       for(i=0; i<pTab->nCol && rc==SQLITE_OK; i++){
729e8d5648eSdan         sqlite3_value *p = 0;
730e8d5648eSdan         if( op!=SQLITE_INSERT ){
731e8d5648eSdan           rc = sqlite3_preupdate_old(pSession->db, i, &p);
732e8d5648eSdan         }else if( 1 || pTab->abPK[i] ){
733e8d5648eSdan           rc = sqlite3_preupdate_new(pSession->db, i, &p);
734e8d5648eSdan         }
735e8d5648eSdan         if( p && rc==SQLITE_OK ){
736e8d5648eSdan           rc = sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
737e8d5648eSdan         }
738e8d5648eSdan       }
73912ca0b56Sdan       if( rc==SQLITE_OK ){
740e8d5648eSdan         /* Add the change back to the hash-table */
741b4480e94Sdan         if( pSession->bIndirect || sqlite3_preupdate_depth(pSession->db) ){
742b4480e94Sdan           pChange->bIndirect = 1;
743b4480e94Sdan         }
74412ca0b56Sdan         pChange->nRecord = nByte;
745e8d5648eSdan         pChange->bInsert = (op==SQLITE_INSERT);
746e8d5648eSdan         pChange->pNext = pTab->apChange[iHash];
747e8d5648eSdan         pTab->apChange[iHash] = pChange;
74812ca0b56Sdan       }else{
74912ca0b56Sdan         sqlite3_free(pChange);
750e8d5648eSdan       }
751b4480e94Sdan     }else if( rc==SQLITE_OK && pC->bIndirect ){
752b4480e94Sdan       /* If the existing change is considered "indirect", but this current
753b4480e94Sdan       ** change is "direct", mark the change object as direct. */
754b4480e94Sdan       if( sqlite3_preupdate_depth(pSession->db)==0 && pSession->bIndirect==0 ){
755b4480e94Sdan         pC->bIndirect = 0;
756b4480e94Sdan       }
757e8d5648eSdan     }
7584fccf43aSdan   }
75912ca0b56Sdan 
76012ca0b56Sdan   /* If an error has occurred, mark the session object as failed. */
76112ca0b56Sdan   if( rc!=SQLITE_OK ){
76212ca0b56Sdan     pSession->rc = rc;
76312ca0b56Sdan   }
76427453faeSdan }
7654fccf43aSdan 
7664fccf43aSdan /*
7674fccf43aSdan ** The 'pre-update' hook registered by this module with SQLite databases.
7684fccf43aSdan */
7694fccf43aSdan static void xPreUpdate(
7704fccf43aSdan   void *pCtx,                     /* Copy of third arg to preupdate_hook() */
7714fccf43aSdan   sqlite3 *db,                    /* Database handle */
7724fccf43aSdan   int op,                         /* SQLITE_UPDATE, DELETE or INSERT */
7734fccf43aSdan   char const *zDb,                /* Database name */
7744fccf43aSdan   char const *zName,              /* Table name */
7754fccf43aSdan   sqlite3_int64 iKey1,            /* Rowid of row about to be deleted/updated */
7764fccf43aSdan   sqlite3_int64 iKey2             /* New rowid value (for a rowid UPDATE) */
7774fccf43aSdan ){
7784fccf43aSdan   sqlite3_session *pSession;
7794fccf43aSdan   int nDb = strlen(zDb);
7804fccf43aSdan   int nName = strlen(zDb);
7814fccf43aSdan 
7824c220252Sdan   assert( sqlite3_mutex_held(db->mutex) );
7834c220252Sdan 
7844fccf43aSdan   for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
7854fccf43aSdan     SessionTable *pTab;
786296c7658Sdan 
787e8d5648eSdan     /* If this session is attached to a different database ("main", "temp"
788e8d5648eSdan     ** etc.), or if it is not currently enabled, there is nothing to do. Skip
789e8d5648eSdan     ** to the next session object attached to this database. */
790296c7658Sdan     if( pSession->bEnable==0 ) continue;
7914fccf43aSdan     if( pSession->rc ) continue;
7924fccf43aSdan     if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
793296c7658Sdan 
794ff4d0f41Sdan     for(pTab=pSession->pTable; pTab || pSession->bAutoAttach; pTab=pTab->pNext){
795ff4d0f41Sdan       if( !pTab ){
796ff4d0f41Sdan         /* This branch is taken if table zName has not yet been attached to
797ff4d0f41Sdan         ** this session and the auto-attach flag is set.  */
798ff4d0f41Sdan         pSession->rc = sqlite3session_attach(pSession,zName);
799245b49b2Sdan         if( pSession->rc ) break;
800ff4d0f41Sdan         pTab = pSession->pTable;
801ff4d0f41Sdan         assert( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) );
802ff4d0f41Sdan       }
803ff4d0f41Sdan 
8044fccf43aSdan       if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ){
805e8d5648eSdan         sessionPreupdateOneChange(op, pSession, pTab);
806e8d5648eSdan         if( op==SQLITE_UPDATE ){
807e8d5648eSdan           sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
8084fccf43aSdan         }
8094fccf43aSdan         break;
8104fccf43aSdan       }
8114fccf43aSdan     }
8124fccf43aSdan   }
813296c7658Sdan }
8144fccf43aSdan 
8154fccf43aSdan /*
8164fccf43aSdan ** Create a session object. This session object will record changes to
8174fccf43aSdan ** database zDb attached to connection db.
8184fccf43aSdan */
8194fccf43aSdan int sqlite3session_create(
8204fccf43aSdan   sqlite3 *db,                    /* Database handle */
8214fccf43aSdan   const char *zDb,                /* Name of db (e.g. "main") */
8224fccf43aSdan   sqlite3_session **ppSession     /* OUT: New session object */
8234fccf43aSdan ){
824296c7658Sdan   sqlite3_session *pNew;          /* Newly allocated session object */
825296c7658Sdan   sqlite3_session *pOld;          /* Session object already attached to db */
8264fccf43aSdan   int nDb = strlen(zDb);          /* Length of zDb in bytes */
8274fccf43aSdan 
828296c7658Sdan   /* Zero the output value in case an error occurs. */
8294fccf43aSdan   *ppSession = 0;
8304fccf43aSdan 
8314fccf43aSdan   /* Allocate and populate the new session object. */
8324fccf43aSdan   pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
8334fccf43aSdan   if( !pNew ) return SQLITE_NOMEM;
8344fccf43aSdan   memset(pNew, 0, sizeof(sqlite3_session));
8354fccf43aSdan   pNew->db = db;
8364fccf43aSdan   pNew->zDb = (char *)&pNew[1];
837296c7658Sdan   pNew->bEnable = 1;
8384fccf43aSdan   memcpy(pNew->zDb, zDb, nDb+1);
8394fccf43aSdan 
8404fccf43aSdan   /* Add the new session object to the linked list of session objects
8414fccf43aSdan   ** attached to database handle $db. Do this under the cover of the db
8424fccf43aSdan   ** handle mutex.  */
8434fccf43aSdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
8444fccf43aSdan   pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
8454fccf43aSdan   pNew->pNext = pOld;
8464fccf43aSdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
8474fccf43aSdan 
8484fccf43aSdan   *ppSession = pNew;
8494fccf43aSdan   return SQLITE_OK;
8504fccf43aSdan }
8514fccf43aSdan 
8524fccf43aSdan /*
8534fccf43aSdan ** Delete a session object previously allocated using sqlite3session_create().
8544fccf43aSdan */
8554fccf43aSdan void sqlite3session_delete(sqlite3_session *pSession){
8564fccf43aSdan   sqlite3 *db = pSession->db;
8574fccf43aSdan   sqlite3_session *pHead;
8584fccf43aSdan   sqlite3_session **pp;
8594fccf43aSdan 
860296c7658Sdan   /* Unlink the session from the linked list of sessions attached to the
861296c7658Sdan   ** database handle. Hold the db mutex while doing so.  */
8624fccf43aSdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
8634fccf43aSdan   pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
8644fccf43aSdan   for(pp=&pHead; (*pp)!=pSession; pp=&((*pp)->pNext));
8654fccf43aSdan   *pp = (*pp)->pNext;
8664fccf43aSdan   if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void *)pHead);
8674fccf43aSdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
8684fccf43aSdan 
869296c7658Sdan   /* Delete all attached table objects. And the contents of their
870296c7658Sdan   ** associated hash-tables. */
8714fccf43aSdan   while( pSession->pTable ){
8724fccf43aSdan     int i;
8734fccf43aSdan     SessionTable *pTab = pSession->pTable;
8744fccf43aSdan     pSession->pTable = pTab->pNext;
8754fccf43aSdan     for(i=0; i<pTab->nChange; i++){
8764fccf43aSdan       SessionChange *p;
8774fccf43aSdan       SessionChange *pNext;
8784fccf43aSdan       for(p=pTab->apChange[i]; p; p=pNext){
8794fccf43aSdan         pNext = p->pNext;
8804fccf43aSdan         sqlite3_free(p);
8814fccf43aSdan       }
8824fccf43aSdan     }
883e8d5648eSdan     sqlite3_free(pTab->azCol);
8844fccf43aSdan     sqlite3_free(pTab->apChange);
8854fccf43aSdan     sqlite3_free(pTab);
8864fccf43aSdan   }
8874fccf43aSdan 
888296c7658Sdan   /* Free the session object itself. */
8894fccf43aSdan   sqlite3_free(pSession);
8904fccf43aSdan }
8914fccf43aSdan 
8924fccf43aSdan /*
8934fccf43aSdan ** Attach a table to a session. All subsequent changes made to the table
8944fccf43aSdan ** while the session object is enabled will be recorded.
8954fccf43aSdan **
8964fccf43aSdan ** Only tables that have a PRIMARY KEY defined may be attached. It does
8974fccf43aSdan ** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
8984fccf43aSdan ** or not.
8994fccf43aSdan */
9004fccf43aSdan int sqlite3session_attach(
9014fccf43aSdan   sqlite3_session *pSession,      /* Session object */
9024fccf43aSdan   const char *zName               /* Table name */
9034fccf43aSdan ){
904ff4d0f41Sdan   int rc = SQLITE_OK;
905ff4d0f41Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
906ff4d0f41Sdan 
907ff4d0f41Sdan   if( !zName ){
908ff4d0f41Sdan     pSession->bAutoAttach = 1;
909ff4d0f41Sdan   }else{
910296c7658Sdan     SessionTable *pTab;           /* New table object (if required) */
911296c7658Sdan     int nName;                    /* Number of bytes in string zName */
9124fccf43aSdan 
9134fccf43aSdan     /* First search for an existing entry. If one is found, this call is
9144fccf43aSdan     ** a no-op. Return early. */
9154fccf43aSdan     nName = strlen(zName);
9164fccf43aSdan     for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
9174c220252Sdan       if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
9184fccf43aSdan     }
9194fccf43aSdan 
9204c220252Sdan     if( !pTab ){
9214fccf43aSdan       /* Allocate new SessionTable object. */
9224fccf43aSdan       pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
9234c220252Sdan       if( !pTab ){
9244c220252Sdan         rc = SQLITE_NOMEM;
9254c220252Sdan       }else{
9264fccf43aSdan         /* Populate the new SessionTable object and link it into the list. */
9274fccf43aSdan         memset(pTab, 0, sizeof(SessionTable));
9284fccf43aSdan         pTab->zName = (char *)&pTab[1];
9294fccf43aSdan         memcpy(pTab->zName, zName, nName+1);
9304fccf43aSdan         pTab->pNext = pSession->pTable;
9314fccf43aSdan         pSession->pTable = pTab;
9324c220252Sdan       }
9334c220252Sdan     }
934ff4d0f41Sdan   }
9354fccf43aSdan 
9364c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
9374c220252Sdan   return rc;
9384fccf43aSdan }
9394fccf43aSdan 
940296c7658Sdan /*
941296c7658Sdan ** Ensure that there is room in the buffer to append nByte bytes of data.
942296c7658Sdan ** If not, use sqlite3_realloc() to grow the buffer so that there is.
943296c7658Sdan **
944296c7658Sdan ** If successful, return zero. Otherwise, if an OOM condition is encountered,
945296c7658Sdan ** set *pRc to SQLITE_NOMEM and return non-zero.
946296c7658Sdan */
9474fccf43aSdan static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
9484fccf43aSdan   if( p->nAlloc-p->nBuf<nByte ){
9494fccf43aSdan     u8 *aNew;
9504fccf43aSdan     int nNew = p->nAlloc ? p->nAlloc : 128;
9514fccf43aSdan     do {
9524fccf43aSdan       nNew = nNew*2;
9534fccf43aSdan     }while( nNew<(p->nAlloc+nByte) );
9544fccf43aSdan 
9554fccf43aSdan     aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
9564fccf43aSdan     if( 0==aNew ){
9574fccf43aSdan       *pRc = SQLITE_NOMEM;
9584fccf43aSdan       return 1;
9594fccf43aSdan     }
9604fccf43aSdan     p->aBuf = aNew;
9614fccf43aSdan     p->nAlloc = nNew;
9624fccf43aSdan   }
9634fccf43aSdan   return 0;
9644fccf43aSdan }
9654fccf43aSdan 
966296c7658Sdan /*
967296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
968296c7658Sdan ** called. Otherwise, append a single byte to the buffer.
969296c7658Sdan **
970296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
971296c7658Sdan ** returning.
972296c7658Sdan */
9734fccf43aSdan static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
9744fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 1, pRc) ){
9754fccf43aSdan     p->aBuf[p->nBuf++] = v;
9764fccf43aSdan   }
9774fccf43aSdan }
9784fccf43aSdan 
979296c7658Sdan /*
980296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
981296c7658Sdan ** called. Otherwise, append a single varint to the buffer.
982296c7658Sdan **
983296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
984296c7658Sdan ** returning.
985296c7658Sdan */
9864fccf43aSdan static void sessionAppendVarint(SessionBuffer *p, sqlite3_int64 v, int *pRc){
9874fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 9, pRc) ){
9884fccf43aSdan     p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
9894fccf43aSdan   }
9904fccf43aSdan }
9914fccf43aSdan 
992296c7658Sdan /*
993296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
994296c7658Sdan ** called. Otherwise, append a blob of data to the buffer.
995296c7658Sdan **
996296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
997296c7658Sdan ** returning.
998296c7658Sdan */
9994fccf43aSdan static void sessionAppendBlob(
10004fccf43aSdan   SessionBuffer *p,
10014fccf43aSdan   const u8 *aBlob,
10024fccf43aSdan   int nBlob,
10034fccf43aSdan   int *pRc
10044fccf43aSdan ){
10054fccf43aSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nBlob, pRc) ){
10064fccf43aSdan     memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
10074fccf43aSdan     p->nBuf += nBlob;
10084fccf43aSdan   }
10094fccf43aSdan }
10104fccf43aSdan 
1011296c7658Sdan /*
1012296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1013296c7658Sdan ** called. Otherwise, append a string to the buffer. All bytes in the string
1014296c7658Sdan ** up to (but not including) the nul-terminator are written to the buffer.
1015296c7658Sdan **
1016296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
1017296c7658Sdan ** returning.
1018296c7658Sdan */
1019d5f0767cSdan static void sessionAppendStr(
1020d5f0767cSdan   SessionBuffer *p,
1021d5f0767cSdan   const char *zStr,
1022d5f0767cSdan   int *pRc
1023d5f0767cSdan ){
1024d5f0767cSdan   int nStr = strlen(zStr);
1025d5f0767cSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
1026d5f0767cSdan     memcpy(&p->aBuf[p->nBuf], zStr, nStr);
1027d5f0767cSdan     p->nBuf += nStr;
1028d5f0767cSdan   }
1029d5f0767cSdan }
1030d5f0767cSdan 
1031296c7658Sdan /*
1032296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1033296c7658Sdan ** called. Otherwise, append the string representation of integer iVal
1034296c7658Sdan ** to the buffer. No nul-terminator is written.
1035296c7658Sdan **
1036296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
1037296c7658Sdan ** returning.
1038296c7658Sdan */
1039d5f0767cSdan static void sessionAppendInteger(
1040296c7658Sdan   SessionBuffer *p,               /* Buffer to append to */
1041296c7658Sdan   int iVal,                       /* Value to write the string rep. of */
1042296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
1043d5f0767cSdan ){
1044d5f0767cSdan   char aBuf[24];
1045d5f0767cSdan   sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
1046d5f0767cSdan   sessionAppendStr(p, aBuf, pRc);
1047d5f0767cSdan }
1048d5f0767cSdan 
1049296c7658Sdan /*
1050296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1051296c7658Sdan ** called. Otherwise, append the string zStr enclosed in quotes (") and
1052296c7658Sdan ** with any embedded quote characters escaped to the buffer. No
1053296c7658Sdan ** nul-terminator byte is written.
1054296c7658Sdan **
1055296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
1056296c7658Sdan ** returning.
1057296c7658Sdan */
1058d5f0767cSdan static void sessionAppendIdent(
1059296c7658Sdan   SessionBuffer *p,               /* Buffer to a append to */
1060296c7658Sdan   const char *zStr,               /* String to quote, escape and append */
1061296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
1062d5f0767cSdan ){
1063d5f0767cSdan   int nStr = strlen(zStr)*2 + 2 + 1;
1064d5f0767cSdan   if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
1065d5f0767cSdan     char *zOut = (char *)&p->aBuf[p->nBuf];
1066d5f0767cSdan     const char *zIn = zStr;
1067d5f0767cSdan     *zOut++ = '"';
1068d5f0767cSdan     while( *zIn ){
1069d5f0767cSdan       if( *zIn=='"' ) *zOut++ = '"';
1070d5f0767cSdan       *zOut++ = *(zIn++);
1071d5f0767cSdan     }
1072d5f0767cSdan     *zOut++ = '"';
1073d5f0767cSdan     p->nBuf = ((u8 *)zOut - p->aBuf);
1074d5f0767cSdan   }
1075d5f0767cSdan }
1076d5f0767cSdan 
1077296c7658Sdan /*
1078296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1079296c7658Sdan ** called. Otherwse, it appends the serialized version of the value stored
1080296c7658Sdan ** in column iCol of the row that SQL statement pStmt currently points
1081296c7658Sdan ** to to the buffer.
1082296c7658Sdan */
10834fccf43aSdan static void sessionAppendCol(
1084296c7658Sdan   SessionBuffer *p,               /* Buffer to append to */
1085296c7658Sdan   sqlite3_stmt *pStmt,            /* Handle pointing to row containing value */
1086296c7658Sdan   int iCol,                       /* Column to read value from */
1087296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
10884fccf43aSdan ){
10894fccf43aSdan   if( *pRc==SQLITE_OK ){
10904fccf43aSdan     int eType = sqlite3_column_type(pStmt, iCol);
10914fccf43aSdan     sessionAppendByte(p, (u8)eType, pRc);
10924fccf43aSdan     if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
10934fccf43aSdan       sqlite3_int64 i;
10944fccf43aSdan       u8 aBuf[8];
10954fccf43aSdan       if( eType==SQLITE_INTEGER ){
10964fccf43aSdan         i = sqlite3_column_int64(pStmt, iCol);
10974fccf43aSdan       }else{
10984fccf43aSdan         double r = sqlite3_column_double(pStmt, iCol);
10994fccf43aSdan         memcpy(&i, &r, 8);
11004fccf43aSdan       }
1101296c7658Sdan       sessionPutI64(aBuf, i);
11024fccf43aSdan       sessionAppendBlob(p, aBuf, 8, pRc);
11034fccf43aSdan     }
11044fccf43aSdan     if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
11054fccf43aSdan       int nByte = sqlite3_column_bytes(pStmt, iCol);
11064fccf43aSdan       sessionAppendVarint(p, nByte, pRc);
11074fccf43aSdan       sessionAppendBlob(p, eType==SQLITE_BLOB ?
11084fccf43aSdan         sqlite3_column_blob(pStmt, iCol) : sqlite3_column_text(pStmt, iCol),
11094fccf43aSdan         nByte, pRc
11104fccf43aSdan       );
11114fccf43aSdan     }
11124fccf43aSdan   }
11134fccf43aSdan }
11144fccf43aSdan 
1115296c7658Sdan /*
1116296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is
1117296c7658Sdan ** called.
1118296c7658Sdan **
1119296c7658Sdan ** Otherwse, if *pRc is SQLITE_OK, then it appends an update change to
1120296c7658Sdan ** the buffer (see the comments under "CHANGESET FORMAT" at the top of the
1121296c7658Sdan ** file). An update change consists of:
1122296c7658Sdan **
1123296c7658Sdan **   1 byte:  SQLITE_UPDATE (0x17)
1124296c7658Sdan **   n bytes: old.* record (see RECORD FORMAT)
1125296c7658Sdan **   m bytes: new.* record (see RECORD FORMAT)
1126296c7658Sdan **
1127296c7658Sdan ** The SessionChange object passed as the third argument contains the
1128296c7658Sdan ** values that were stored in the row when the session began (the old.*
1129296c7658Sdan ** values). The statement handle passed as the second argument points
1130296c7658Sdan ** at the current version of the row (the new.* values).
1131296c7658Sdan **
1132296c7658Sdan ** If all of the old.* values are equal to their corresponding new.* value
1133296c7658Sdan ** (i.e. nothing has changed), then no data at all is appended to the buffer.
1134296c7658Sdan **
1135296c7658Sdan ** Otherwise, the old.* record contains all primary key values and the
1136296c7658Sdan ** original values of any fields that have been modified. The new.* record
1137296c7658Sdan ** contains the new values of only those fields that have been modified.
1138296c7658Sdan */
11394fccf43aSdan static void sessionAppendUpdate(
1140296c7658Sdan   SessionBuffer *pBuf,            /* Buffer to append to */
1141296c7658Sdan   sqlite3_stmt *pStmt,            /* Statement handle pointing at new row */
1142296c7658Sdan   SessionChange *p,               /* Object containing old values */
1143296c7658Sdan   u8 *abPK,                       /* Boolean array - true for PK columns */
1144296c7658Sdan   int *pRc                        /* IN/OUT: Error code */
11454fccf43aSdan ){
11464fccf43aSdan   if( *pRc==SQLITE_OK ){
1147296c7658Sdan     SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
1148296c7658Sdan     int bNoop = 1;                /* Set to zero if any values are modified */
11491f34f8ccSdan     int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
1150296c7658Sdan     int i;                        /* Used to iterate through columns */
1151296c7658Sdan     u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */
1152296c7658Sdan 
11534fccf43aSdan     sessionAppendByte(pBuf, SQLITE_UPDATE, pRc);
1154b4480e94Sdan     sessionAppendByte(pBuf, p->bIndirect, pRc);
11554fccf43aSdan     for(i=0; i<sqlite3_column_count(pStmt); i++){
115637f133ecSdan       int bChanged = 0;
11574fccf43aSdan       int nAdvance;
11584fccf43aSdan       int eType = *pCsr;
11594fccf43aSdan       switch( eType ){
11604fccf43aSdan         case SQLITE_NULL:
11614fccf43aSdan           nAdvance = 1;
11624fccf43aSdan           if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
116337f133ecSdan             bChanged = 1;
11644fccf43aSdan           }
11654fccf43aSdan           break;
11664fccf43aSdan 
11674fccf43aSdan         case SQLITE_FLOAT:
11684fccf43aSdan         case SQLITE_INTEGER: {
11694fccf43aSdan           nAdvance = 9;
11704fccf43aSdan           if( eType==sqlite3_column_type(pStmt, i) ){
11714fccf43aSdan             sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
11724fccf43aSdan             if( eType==SQLITE_INTEGER ){
11734fccf43aSdan               if( iVal==sqlite3_column_int64(pStmt, i) ) break;
11744fccf43aSdan             }else{
11754fccf43aSdan               double dVal;
11764fccf43aSdan               memcpy(&dVal, &iVal, 8);
11774fccf43aSdan               if( dVal==sqlite3_column_double(pStmt, i) ) break;
11784fccf43aSdan             }
11794fccf43aSdan           }
118037f133ecSdan           bChanged = 1;
11814fccf43aSdan           break;
11824fccf43aSdan         }
11834fccf43aSdan 
1184*e5754eecSdan         default: {
11854fccf43aSdan           int nByte;
11864fccf43aSdan           int nHdr = 1 + sessionVarintGet(&pCsr[1], &nByte);
1187*e5754eecSdan           assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
11884fccf43aSdan           nAdvance = nHdr + nByte;
11894fccf43aSdan           if( eType==sqlite3_column_type(pStmt, i)
11904fccf43aSdan            && nByte==sqlite3_column_bytes(pStmt, i)
11914fccf43aSdan            && 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), nByte)
11924fccf43aSdan           ){
11934fccf43aSdan             break;
11944fccf43aSdan           }
119537f133ecSdan           bChanged = 1;
11964fccf43aSdan         }
11974fccf43aSdan       }
11984fccf43aSdan 
119937f133ecSdan       if( bChanged || abPK[i] ){
120037f133ecSdan         sessionAppendBlob(pBuf, pCsr, nAdvance, pRc);
12014fccf43aSdan       }else{
120237f133ecSdan         sessionAppendByte(pBuf, 0, pRc);
120337f133ecSdan       }
120437f133ecSdan 
120537f133ecSdan       if( bChanged ){
12064fccf43aSdan         sessionAppendCol(&buf2, pStmt, i, pRc);
12074fccf43aSdan         bNoop = 0;
120837f133ecSdan       }else{
120937f133ecSdan         sessionAppendByte(&buf2, 0, pRc);
12104fccf43aSdan       }
121137f133ecSdan 
12124fccf43aSdan       pCsr += nAdvance;
12134fccf43aSdan     }
12144fccf43aSdan 
12154fccf43aSdan     if( bNoop ){
12161f34f8ccSdan       pBuf->nBuf = nRewind;
12174fccf43aSdan     }else{
12184fccf43aSdan       sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, pRc);
12194fccf43aSdan     }
12201f34f8ccSdan     sqlite3_free(buf2.aBuf);
12214fccf43aSdan   }
1222d5f0767cSdan }
12234fccf43aSdan 
1224e8d5648eSdan static int sessionSelectStmt(
1225e8d5648eSdan   sqlite3 *db,                    /* Database handle */
1226d7fb7d24Sdan   const char *zDb,                /* Database name */
1227e8d5648eSdan   const char *zTab,               /* Table name */
1228e8d5648eSdan   int nCol,
1229e8d5648eSdan   const char **azCol,
1230e8d5648eSdan   u8 *abPK,
1231e8d5648eSdan   sqlite3_stmt **ppStmt
1232d5f0767cSdan ){
1233e8d5648eSdan   int rc = SQLITE_OK;
1234d5f0767cSdan   int i;
1235e8d5648eSdan   const char *zSep = "";
1236e8d5648eSdan   SessionBuffer buf = {0, 0, 0};
1237d5f0767cSdan 
1238e8d5648eSdan   sessionAppendStr(&buf, "SELECT * FROM ", &rc);
1239d7fb7d24Sdan   sessionAppendIdent(&buf, zDb, &rc);
1240d7fb7d24Sdan   sessionAppendStr(&buf, ".", &rc);
1241e8d5648eSdan   sessionAppendIdent(&buf, zTab, &rc);
1242e8d5648eSdan   sessionAppendStr(&buf, " WHERE ", &rc);
1243e8d5648eSdan   for(i=0; i<nCol; i++){
1244e8d5648eSdan     if( abPK[i] ){
1245e8d5648eSdan       sessionAppendStr(&buf, zSep, &rc);
1246e8d5648eSdan       sessionAppendIdent(&buf, azCol[i], &rc);
1247e8d5648eSdan       sessionAppendStr(&buf, " = ?", &rc);
1248e8d5648eSdan       sessionAppendInteger(&buf, i+1, &rc);
1249e8d5648eSdan       zSep = " AND ";
1250d5f0767cSdan     }
1251d5f0767cSdan   }
1252d5f0767cSdan   if( rc==SQLITE_OK ){
1253e8d5648eSdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0);
1254d5f0767cSdan   }
1255e8d5648eSdan   sqlite3_free(buf.aBuf);
1256e8d5648eSdan   return rc;
1257d5f0767cSdan }
1258d5f0767cSdan 
1259e8d5648eSdan static int sessionSelectBind(
1260e8d5648eSdan   sqlite3_stmt *pSelect,
1261e8d5648eSdan   int nCol,
1262e8d5648eSdan   u8 *abPK,
1263*e5754eecSdan   SessionChange *pChange
1264e8d5648eSdan ){
1265e8d5648eSdan   int i;
1266e8d5648eSdan   int rc = SQLITE_OK;
1267*e5754eecSdan   u8 *a = pChange->aRecord;
1268d5f0767cSdan 
1269e8d5648eSdan   for(i=0; i<nCol && rc==SQLITE_OK; i++){
1270e8d5648eSdan     int eType = *a++;
1271e8d5648eSdan 
1272e8d5648eSdan     switch( eType ){
1273e8d5648eSdan       case SQLITE_NULL:
1274*e5754eecSdan         assert( abPK[i]==0 );
1275e8d5648eSdan         break;
1276e8d5648eSdan 
1277e8d5648eSdan       case SQLITE_INTEGER: {
1278e8d5648eSdan         if( abPK[i] ){
1279e8d5648eSdan           i64 iVal = sessionGetI64(a);
1280e8d5648eSdan           rc = sqlite3_bind_int64(pSelect, i+1, iVal);
1281e8d5648eSdan         }
1282e8d5648eSdan         a += 8;
1283e8d5648eSdan         break;
1284d5f0767cSdan       }
1285296c7658Sdan 
1286e8d5648eSdan       case SQLITE_FLOAT: {
1287e8d5648eSdan         if( abPK[i] ){
1288e8d5648eSdan           double rVal;
1289e8d5648eSdan           i64 iVal = sessionGetI64(a);
1290e8d5648eSdan           memcpy(&rVal, &iVal, 8);
12914e895da1Sdan           rc = sqlite3_bind_double(pSelect, i+1, rVal);
1292d5f0767cSdan         }
1293e8d5648eSdan         a += 8;
1294e8d5648eSdan         break;
1295e8d5648eSdan       }
1296e8d5648eSdan 
1297e8d5648eSdan       case SQLITE_TEXT: {
1298e8d5648eSdan         int n;
1299e8d5648eSdan         a += sessionVarintGet(a, &n);
1300e8d5648eSdan         if( abPK[i] ){
1301e8d5648eSdan           rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
1302e8d5648eSdan         }
1303e8d5648eSdan         a += n;
1304e8d5648eSdan         break;
1305e8d5648eSdan       }
1306e8d5648eSdan 
1307*e5754eecSdan       default: {
1308e8d5648eSdan         int n;
1309*e5754eecSdan         assert( eType==SQLITE_BLOB );
1310e8d5648eSdan         a += sessionVarintGet(a, &n);
1311e8d5648eSdan         if( abPK[i] ){
1312e8d5648eSdan           rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
1313e8d5648eSdan         }
1314e8d5648eSdan         a += n;
1315e8d5648eSdan         break;
1316e8d5648eSdan       }
1317e8d5648eSdan     }
1318e8d5648eSdan   }
1319e8d5648eSdan 
1320d5f0767cSdan   return rc;
13214fccf43aSdan }
13224fccf43aSdan 
13234fccf43aSdan /*
13244fccf43aSdan ** Obtain a changeset object containing all changes recorded by the
13254fccf43aSdan ** session object passed as the first argument.
13264fccf43aSdan **
13274fccf43aSdan ** It is the responsibility of the caller to eventually free the buffer
13284fccf43aSdan ** using sqlite3_free().
13294fccf43aSdan */
13304fccf43aSdan int sqlite3session_changeset(
13314fccf43aSdan   sqlite3_session *pSession,      /* Session object */
13324fccf43aSdan   int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
13334fccf43aSdan   void **ppChangeset              /* OUT: Buffer containing changeset */
13344fccf43aSdan ){
1335296c7658Sdan   sqlite3 *db = pSession->db;     /* Source database handle */
1336296c7658Sdan   SessionTable *pTab;             /* Used to iterate through attached tables */
1337296c7658Sdan   SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
1338296c7658Sdan   int rc;                         /* Return code */
13394fccf43aSdan 
1340296c7658Sdan   /* Zero the output variables in case an error occurs. If this session
1341296c7658Sdan   ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
1342296c7658Sdan   ** this call will be a no-op.  */
13434fccf43aSdan   *pnChangeset = 0;
13444fccf43aSdan   *ppChangeset = 0;
1345*e5754eecSdan 
1346*e5754eecSdan   if( pSession->rc ) return pSession->rc;
1347*e5754eecSdan   rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
1348*e5754eecSdan   if( rc!=SQLITE_OK ) return rc;
1349*e5754eecSdan 
1350*e5754eecSdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
13514fccf43aSdan 
13524fccf43aSdan   for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
13534fccf43aSdan     if( pTab->nEntry ){
1354d7fb7d24Sdan       const char *zName = pTab->zName;
1355a9605b91Sdan       int nCol;                   /* Number of columns in table */
1356a9605b91Sdan       u8 *abPK;                   /* Primary key array */
1357a9605b91Sdan       const char **azCol = 0;     /* Table columns */
13581f34f8ccSdan       int i;                      /* Used to iterate through hash buckets */
13591f34f8ccSdan       sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
13601f34f8ccSdan       int nRewind = buf.nBuf;     /* Initial size of write buffer */
13611f34f8ccSdan       int nNoop;                  /* Size of buffer after writing tbl header */
13624fccf43aSdan 
1363a9605b91Sdan       /* Check the table schema is still Ok. */
1364a9605b91Sdan       rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
1365a9605b91Sdan       if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
1366a9605b91Sdan         rc = SQLITE_SCHEMA;
1367a9605b91Sdan       }
1368a9605b91Sdan 
13694fccf43aSdan       /* Write a table header */
13704fccf43aSdan       sessionAppendByte(&buf, 'T', &rc);
1371e8d5648eSdan       sessionAppendVarint(&buf, nCol, &rc);
1372244593c8Sdan       sessionAppendBlob(&buf, pTab->abPK, nCol, &rc);
1373d7fb7d24Sdan       sessionAppendBlob(&buf, (u8 *)zName, strlen(zName)+1, &rc);
13744fccf43aSdan 
13754fccf43aSdan       /* Build and compile a statement to execute: */
13764fccf43aSdan       if( rc==SQLITE_OK ){
1377d7fb7d24Sdan         rc = sessionSelectStmt(
1378a9605b91Sdan             db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
13794fccf43aSdan       }
13804fccf43aSdan 
13811f34f8ccSdan       nNoop = buf.nBuf;
138212ca0b56Sdan       for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
1383e8d5648eSdan         SessionChange *p;         /* Used to iterate through changes */
1384e8d5648eSdan 
13854fccf43aSdan         for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
1386*e5754eecSdan           rc = sessionSelectBind(pSel, nCol, abPK, p);
13871f34f8ccSdan           if( sqlite3_step(pSel)==SQLITE_ROW ){
13884fccf43aSdan             int iCol;
1389e8d5648eSdan             if( p->bInsert ){
13904fccf43aSdan               sessionAppendByte(&buf, SQLITE_INSERT, &rc);
1391b4480e94Sdan               sessionAppendByte(&buf, p->bIndirect, &rc);
1392e8d5648eSdan               for(iCol=0; iCol<nCol; iCol++){
13931f34f8ccSdan                 sessionAppendCol(&buf, pSel, iCol, &rc);
13944fccf43aSdan               }
1395e8d5648eSdan             }else{
13961f34f8ccSdan               sessionAppendUpdate(&buf, pSel, p, abPK, &rc);
13974fccf43aSdan             }
1398e8d5648eSdan           }else if( !p->bInsert ){
13994fccf43aSdan             /* A DELETE change */
14004fccf43aSdan             sessionAppendByte(&buf, SQLITE_DELETE, &rc);
1401b4480e94Sdan             sessionAppendByte(&buf, p->bIndirect, &rc);
14024fccf43aSdan             sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
14034fccf43aSdan           }
140412ca0b56Sdan           if( rc==SQLITE_OK ){
14051f34f8ccSdan             rc = sqlite3_reset(pSel);
14064fccf43aSdan           }
14074fccf43aSdan         }
1408e8d5648eSdan       }
14094fccf43aSdan 
14101f34f8ccSdan       sqlite3_finalize(pSel);
14111f34f8ccSdan       if( buf.nBuf==nNoop ){
14124fccf43aSdan         buf.nBuf = nRewind;
14134fccf43aSdan       }
1414a9605b91Sdan       sqlite3_free(azCol);
14154fccf43aSdan     }
14164fccf43aSdan   }
14174fccf43aSdan 
14184fccf43aSdan   if( rc==SQLITE_OK ){
14194fccf43aSdan     *pnChangeset = buf.nBuf;
14204fccf43aSdan     *ppChangeset = buf.aBuf;
14214fccf43aSdan   }else{
14224fccf43aSdan     sqlite3_free(buf.aBuf);
14234fccf43aSdan   }
14244c220252Sdan 
1425*e5754eecSdan   sqlite3_exec(db, "RELEASE changeset", 0, 0, 0);
14264c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
14274fccf43aSdan   return rc;
14284fccf43aSdan }
14294fccf43aSdan 
1430296c7658Sdan /*
1431296c7658Sdan ** Enable or disable the session object passed as the first argument.
1432296c7658Sdan */
14334fccf43aSdan int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
14344c220252Sdan   int ret;
14354c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
1436296c7658Sdan   if( bEnable>=0 ){
1437296c7658Sdan     pSession->bEnable = bEnable;
14384fccf43aSdan   }
14394c220252Sdan   ret = pSession->bEnable;
14404c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
14414c220252Sdan   return ret;
1442296c7658Sdan }
14434fccf43aSdan 
14444fccf43aSdan /*
1445b4480e94Sdan ** Enable or disable the session object passed as the first argument.
1446b4480e94Sdan */
1447b4480e94Sdan int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){
1448b4480e94Sdan   int ret;
1449b4480e94Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
1450b4480e94Sdan   if( bIndirect>=0 ){
1451b4480e94Sdan     pSession->bIndirect = bIndirect;
1452b4480e94Sdan   }
1453b4480e94Sdan   ret = pSession->bIndirect;
1454b4480e94Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
1455b4480e94Sdan   return ret;
1456b4480e94Sdan }
1457b4480e94Sdan 
1458b4480e94Sdan /*
14594fccf43aSdan ** Create an iterator used to iterate through the contents of a changeset.
14604fccf43aSdan */
14614fccf43aSdan int sqlite3changeset_start(
1462296c7658Sdan   sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
1463296c7658Sdan   int nChangeset,                 /* Size of buffer pChangeset in bytes */
1464296c7658Sdan   void *pChangeset                /* Pointer to buffer containing changeset */
14654fccf43aSdan ){
14664fccf43aSdan   sqlite3_changeset_iter *pRet;   /* Iterator to return */
14674fccf43aSdan   int nByte;                      /* Number of bytes to allocate for iterator */
14684fccf43aSdan 
1469296c7658Sdan   /* Zero the output variable in case an error occurs. */
1470296c7658Sdan   *pp = 0;
14714fccf43aSdan 
1472296c7658Sdan   /* Allocate and initialize the iterator structure. */
14734fccf43aSdan   nByte = sizeof(sqlite3_changeset_iter);
14744fccf43aSdan   pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
14754fccf43aSdan   if( !pRet ) return SQLITE_NOMEM;
14764fccf43aSdan   memset(pRet, 0, sizeof(sqlite3_changeset_iter));
14774fccf43aSdan   pRet->aChangeset = (u8 *)pChangeset;
14784fccf43aSdan   pRet->nChangeset = nChangeset;
14794fccf43aSdan   pRet->pNext = pRet->aChangeset;
14804fccf43aSdan 
1481296c7658Sdan   /* Populate the output variable and return success. */
1482296c7658Sdan   *pp = pRet;
14834fccf43aSdan   return SQLITE_OK;
14844fccf43aSdan }
14854fccf43aSdan 
1486296c7658Sdan /*
1487296c7658Sdan ** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
1488296c7658Sdan ** for details.
1489296c7658Sdan **
1490296c7658Sdan ** When this function is called, *paChange points to the start of the record
1491296c7658Sdan ** to deserialize. Assuming no error occurs, *paChange is set to point to
1492296c7658Sdan ** one byte after the end of the same record before this function returns.
1493296c7658Sdan **
1494296c7658Sdan ** If successful, each element of the apOut[] array (allocated by the caller)
1495296c7658Sdan ** is set to point to an sqlite3_value object containing the value read
1496296c7658Sdan ** from the corresponding position in the record. If that value is not
1497296c7658Sdan ** included in the record (i.e. because the record is part of an UPDATE change
1498296c7658Sdan ** and the field was not modified), the corresponding element of apOut[] is
1499296c7658Sdan ** set to NULL.
1500296c7658Sdan **
1501296c7658Sdan ** It is the responsibility of the caller to free all sqlite_value structures
1502296c7658Sdan ** using sqlite3_free().
1503296c7658Sdan **
1504296c7658Sdan ** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
1505296c7658Sdan ** The apOut[] array may have been partially populated in this case.
1506296c7658Sdan */
15074fccf43aSdan static int sessionReadRecord(
15084fccf43aSdan   u8 **paChange,                  /* IN/OUT: Pointer to binary record */
15094fccf43aSdan   int nCol,                       /* Number of values in record */
15104fccf43aSdan   sqlite3_value **apOut           /* Write values to this array */
15114fccf43aSdan ){
1512296c7658Sdan   int i;                          /* Used to iterate through columns */
1513296c7658Sdan   u8 *aRec = *paChange;           /* Cursor for the serialized record */
15144fccf43aSdan 
15154fccf43aSdan   for(i=0; i<nCol; i++){
1516296c7658Sdan     int eType = *aRec++;          /* Type of value (SQLITE_NULL, TEXT etc.) */
151791ddd559Sdan     assert( !apOut || apOut[i]==0 );
15184fccf43aSdan     if( eType ){
151991ddd559Sdan       if( apOut ){
15204fccf43aSdan         apOut[i] = sqlite3ValueNew(0);
15214fccf43aSdan         if( !apOut[i] ) return SQLITE_NOMEM;
152291ddd559Sdan       }
15234fccf43aSdan 
15244fccf43aSdan       if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
15254fccf43aSdan         int nByte;
15264fccf43aSdan         int enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
15274fccf43aSdan         aRec += sessionVarintGet(aRec, &nByte);
152891ddd559Sdan         if( apOut ){
15294fccf43aSdan           sqlite3ValueSetStr(apOut[i], nByte, aRec, enc, SQLITE_STATIC);
153091ddd559Sdan         }
15314fccf43aSdan         aRec += nByte;
15324fccf43aSdan       }
15334fccf43aSdan       if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
153491ddd559Sdan         if( apOut ){
15354fccf43aSdan           sqlite3_int64 v = sessionGetI64(aRec);
15364fccf43aSdan           if( eType==SQLITE_INTEGER ){
15374fccf43aSdan             sqlite3VdbeMemSetInt64(apOut[i], v);
15384fccf43aSdan           }else{
15394fccf43aSdan             double d;
15404e895da1Sdan             memcpy(&d, &v, 8);
15414fccf43aSdan             sqlite3VdbeMemSetDouble(apOut[i], d);
15424fccf43aSdan           }
15434fccf43aSdan         }
154491ddd559Sdan         aRec += 8;
154591ddd559Sdan       }
15464fccf43aSdan     }
15474fccf43aSdan   }
15484fccf43aSdan 
15494fccf43aSdan   *paChange = aRec;
15504fccf43aSdan   return SQLITE_OK;
15514fccf43aSdan }
15524fccf43aSdan 
15534fccf43aSdan /*
15544fccf43aSdan ** Advance an iterator created by sqlite3changeset_start() to the next
15554fccf43aSdan ** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
15564fccf43aSdan ** or SQLITE_CORRUPT.
15574fccf43aSdan **
15584fccf43aSdan ** This function may not be called on iterators passed to a conflict handler
15594fccf43aSdan ** callback by changeset_apply().
15604fccf43aSdan */
15614fccf43aSdan int sqlite3changeset_next(sqlite3_changeset_iter *p){
15624fccf43aSdan   u8 *aChange;
15634fccf43aSdan   int i;
15644fccf43aSdan   u8 c;
15654fccf43aSdan 
1566296c7658Sdan   /* If the iterator is in the error-state, return immediately. */
15674fccf43aSdan   if( p->rc!=SQLITE_OK ) return p->rc;
15684fccf43aSdan 
1569296c7658Sdan   /* Free the current contents of p->apValue[]. */
15704fccf43aSdan   if( p->apValue ){
15714fccf43aSdan     for(i=0; i<p->nCol*2; i++){
15724fccf43aSdan       sqlite3ValueFree(p->apValue[i]);
15734fccf43aSdan     }
15744fccf43aSdan     memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
15754fccf43aSdan   }
15764fccf43aSdan 
15774fccf43aSdan   /* If the iterator is already at the end of the changeset, return DONE. */
15784fccf43aSdan   if( p->pNext>=&p->aChangeset[p->nChangeset] ){
15794fccf43aSdan     return SQLITE_DONE;
15804fccf43aSdan   }
15814fccf43aSdan   aChange = p->pNext;
15824fccf43aSdan 
15834fccf43aSdan   c = *(aChange++);
15844fccf43aSdan   if( c=='T' ){
15854fccf43aSdan     int nByte;                    /* Bytes to allocate for apValue */
15864fccf43aSdan     aChange += sessionVarintGet(aChange, &p->nCol);
1587244593c8Sdan     p->abPK = (u8 *)aChange;
1588244593c8Sdan     aChange += p->nCol;
15894fccf43aSdan     p->zTab = (char *)aChange;
15904fccf43aSdan     aChange += (strlen((char *)aChange) + 1);
15914fccf43aSdan     p->op = *(aChange++);
1592b4480e94Sdan     p->bIndirect = *(aChange++);
15934fccf43aSdan     sqlite3_free(p->apValue);
15944fccf43aSdan     nByte = sizeof(sqlite3_value *) * p->nCol * 2;
15954fccf43aSdan     p->apValue = (sqlite3_value **)sqlite3_malloc(nByte);
15964fccf43aSdan     if( !p->apValue ){
15974fccf43aSdan       return (p->rc = SQLITE_NOMEM);
15984fccf43aSdan     }
15994fccf43aSdan     memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
16004fccf43aSdan   }else{
16014fccf43aSdan     p->op = c;
1602b4480e94Sdan     p->bIndirect = *(aChange++);
16034fccf43aSdan   }
16044fccf43aSdan   if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
16054fccf43aSdan     return (p->rc = SQLITE_CORRUPT);
16064fccf43aSdan   }
16074fccf43aSdan 
16084fccf43aSdan   /* If this is an UPDATE or DELETE, read the old.* record. */
16094fccf43aSdan   if( p->op!=SQLITE_INSERT ){
16104fccf43aSdan     p->rc = sessionReadRecord(&aChange, p->nCol, p->apValue);
16114fccf43aSdan     if( p->rc!=SQLITE_OK ) return p->rc;
16124fccf43aSdan   }
16134fccf43aSdan 
16144fccf43aSdan   /* If this is an INSERT or UPDATE, read the new.* record. */
16154fccf43aSdan   if( p->op!=SQLITE_DELETE ){
16164fccf43aSdan     p->rc = sessionReadRecord(&aChange, p->nCol, &p->apValue[p->nCol]);
16174fccf43aSdan     if( p->rc!=SQLITE_OK ) return p->rc;
16184fccf43aSdan   }
16194fccf43aSdan 
16204fccf43aSdan   p->pNext = aChange;
16214fccf43aSdan   return SQLITE_ROW;
16224fccf43aSdan }
16234fccf43aSdan 
16244fccf43aSdan /*
1625244593c8Sdan ** The following function extracts information on the current change
16264fccf43aSdan ** from a changeset iterator. They may only be called after changeset_next()
16274fccf43aSdan ** has returned SQLITE_ROW.
16284fccf43aSdan */
16294fccf43aSdan int sqlite3changeset_op(
1630296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Iterator handle */
16314fccf43aSdan   const char **pzTab,             /* OUT: Pointer to table name */
16324fccf43aSdan   int *pnCol,                     /* OUT: Number of columns in table */
1633b4480e94Sdan   int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
1634b4480e94Sdan   int *pbIndirect                 /* OUT: True if change is indirect */
16354fccf43aSdan ){
16364fccf43aSdan   *pOp = pIter->op;
16374fccf43aSdan   *pnCol = pIter->nCol;
16384fccf43aSdan   *pzTab = pIter->zTab;
1639b4480e94Sdan   if( pbIndirect ) *pbIndirect = pIter->bIndirect;
16404fccf43aSdan   return SQLITE_OK;
16414fccf43aSdan }
16424fccf43aSdan 
1643244593c8Sdan int sqlite3changeset_pk(
1644244593c8Sdan   sqlite3_changeset_iter *pIter,  /* Iterator object */
1645244593c8Sdan   unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
1646244593c8Sdan   int *pnCol                      /* OUT: Number of entries in output array */
1647244593c8Sdan ){
1648244593c8Sdan   *pabPK = pIter->abPK;
1649244593c8Sdan   if( pnCol ) *pnCol = pIter->nCol;
1650244593c8Sdan   return SQLITE_OK;
1651244593c8Sdan }
1652244593c8Sdan 
1653296c7658Sdan /*
1654296c7658Sdan ** This function may only be called while the iterator is pointing to an
1655296c7658Sdan ** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
1656296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned.
1657296c7658Sdan **
1658296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the
1659296c7658Sdan ** iVal'th value in the old.* record. Or, if that particular value is not
1660296c7658Sdan ** included in the record (because the change is an UPDATE and the field
1661296c7658Sdan ** was not modified and is not a PK column), set *ppValue to NULL.
1662296c7658Sdan **
1663296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
1664296c7658Sdan ** not modified. Otherwise, SQLITE_OK.
1665296c7658Sdan */
16664fccf43aSdan int sqlite3changeset_old(
1667296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1668296c7658Sdan   int iVal,                       /* Index of old.* value to retrieve */
16694fccf43aSdan   sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
16704fccf43aSdan ){
1671d5f0767cSdan   if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
1672d5f0767cSdan     return SQLITE_MISUSE;
1673d5f0767cSdan   }
16744fccf43aSdan   if( iVal<0 || iVal>=pIter->nCol ){
16754fccf43aSdan     return SQLITE_RANGE;
16764fccf43aSdan   }
16774fccf43aSdan   *ppValue = pIter->apValue[iVal];
16784fccf43aSdan   return SQLITE_OK;
16794fccf43aSdan }
16804fccf43aSdan 
1681296c7658Sdan /*
1682296c7658Sdan ** This function may only be called while the iterator is pointing to an
1683296c7658Sdan ** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
1684296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned.
1685296c7658Sdan **
1686296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the
1687296c7658Sdan ** iVal'th value in the new.* record. Or, if that particular value is not
1688296c7658Sdan ** included in the record (because the change is an UPDATE and the field
1689296c7658Sdan ** was not modified), set *ppValue to NULL.
1690296c7658Sdan **
1691296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
1692296c7658Sdan ** not modified. Otherwise, SQLITE_OK.
1693296c7658Sdan */
16944fccf43aSdan int sqlite3changeset_new(
1695296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1696296c7658Sdan   int iVal,                       /* Index of new.* value to retrieve */
16974fccf43aSdan   sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
16984fccf43aSdan ){
1699d5f0767cSdan   if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
1700d5f0767cSdan     return SQLITE_MISUSE;
1701d5f0767cSdan   }
17024fccf43aSdan   if( iVal<0 || iVal>=pIter->nCol ){
17034fccf43aSdan     return SQLITE_RANGE;
17044fccf43aSdan   }
17054fccf43aSdan   *ppValue = pIter->apValue[pIter->nCol+iVal];
17064fccf43aSdan   return SQLITE_OK;
17074fccf43aSdan }
17084fccf43aSdan 
1709296c7658Sdan /*
17107aa469cdSdan ** The following two macros are used internally. They are similar to the
17117aa469cdSdan ** sqlite3changeset_new() and sqlite3changeset_old() functions, except that
17127aa469cdSdan ** they omit all error checking and return a pointer to the requested value.
17137aa469cdSdan */
17147aa469cdSdan #define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)]
17157aa469cdSdan #define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)]
17167aa469cdSdan 
17177aa469cdSdan /*
1718296c7658Sdan ** This function may only be called with a changeset iterator that has been
1719296c7658Sdan ** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
1720296c7658Sdan ** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
1721296c7658Sdan **
1722296c7658Sdan ** If successful, *ppValue is set to point to an sqlite3_value structure
1723296c7658Sdan ** containing the iVal'th value of the conflicting record.
1724296c7658Sdan **
1725296c7658Sdan ** If value iVal is out-of-range or some other error occurs, an SQLite error
1726296c7658Sdan ** code is returned. Otherwise, SQLITE_OK.
1727296c7658Sdan */
1728d5f0767cSdan int sqlite3changeset_conflict(
1729296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
1730296c7658Sdan   int iVal,                       /* Index of conflict record value to fetch */
1731d5f0767cSdan   sqlite3_value **ppValue         /* OUT: Value from conflicting row */
1732d5f0767cSdan ){
1733d5f0767cSdan   if( !pIter->pConflict ){
1734d5f0767cSdan     return SQLITE_MISUSE;
1735d5f0767cSdan   }
1736d5f0767cSdan   if( iVal<0 || iVal>=sqlite3_column_count(pIter->pConflict) ){
1737d5f0767cSdan     return SQLITE_RANGE;
1738d5f0767cSdan   }
1739d5f0767cSdan   *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
1740d5f0767cSdan   return SQLITE_OK;
1741d5f0767cSdan }
1742d5f0767cSdan 
17434fccf43aSdan /*
17444fccf43aSdan ** Finalize an iterator allocated with sqlite3changeset_start().
17454fccf43aSdan **
17464fccf43aSdan ** This function may not be called on iterators passed to a conflict handler
17474fccf43aSdan ** callback by changeset_apply().
17484fccf43aSdan */
17494fccf43aSdan int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
1750296c7658Sdan   int i;                          /* Used to iterate through p->apValue[] */
1751296c7658Sdan   int rc = p->rc;                 /* Return code */
175212ca0b56Sdan   if( p->apValue ){
17534fccf43aSdan     for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
175412ca0b56Sdan   }
17554fccf43aSdan   sqlite3_free(p->apValue);
17564fccf43aSdan   sqlite3_free(p);
17574fccf43aSdan   return rc;
17584fccf43aSdan }
17594fccf43aSdan 
176091ddd559Sdan /*
176191ddd559Sdan ** Invert a changeset object.
176291ddd559Sdan */
176391ddd559Sdan int sqlite3changeset_invert(
176491ddd559Sdan   int nChangeset,                 /* Number of bytes in input */
176591ddd559Sdan   void *pChangeset,               /* Input changeset */
176691ddd559Sdan   int *pnInverted,                /* OUT: Number of bytes in output changeset */
176791ddd559Sdan   void **ppInverted               /* OUT: Inverse of pChangeset */
176891ddd559Sdan ){
176991ddd559Sdan   u8 *aOut;
177091ddd559Sdan   u8 *aIn;
177191ddd559Sdan   int i;
177291ddd559Sdan   int nCol = 0;
177391ddd559Sdan 
177491ddd559Sdan   /* Zero the output variables in case an error occurs. */
177591ddd559Sdan   *ppInverted = 0;
177691ddd559Sdan   *pnInverted = 0;
177791ddd559Sdan   if( nChangeset==0 ) return SQLITE_OK;
177891ddd559Sdan 
177991ddd559Sdan   aOut = (u8 *)sqlite3_malloc(nChangeset);
178091ddd559Sdan   if( !aOut ) return SQLITE_NOMEM;
178191ddd559Sdan   aIn = (u8 *)pChangeset;
178291ddd559Sdan 
178391ddd559Sdan   i = 0;
178491ddd559Sdan   while( i<nChangeset ){
178591ddd559Sdan     u8 eType = aIn[i];
178691ddd559Sdan     switch( eType ){
178791ddd559Sdan       case 'T': {
1788244593c8Sdan         /* A 'table' record consists of:
1789244593c8Sdan         **
1790244593c8Sdan         **   * A constant 'T' character,
1791244593c8Sdan         **   * Number of columns in said table (a varint),
1792244593c8Sdan         **   * An array of nCol bytes (abPK),
1793244593c8Sdan         **   * A nul-terminated table name.
1794244593c8Sdan         */
179591ddd559Sdan         int nByte = 1 + sessionVarintGet(&aIn[i+1], &nCol);
1796244593c8Sdan         nByte += nCol;
179791ddd559Sdan         nByte += 1 + strlen((char *)&aIn[i+nByte]);
179891ddd559Sdan         memcpy(&aOut[i], &aIn[i], nByte);
179991ddd559Sdan         i += nByte;
180091ddd559Sdan         break;
180191ddd559Sdan       }
180291ddd559Sdan 
180391ddd559Sdan       case SQLITE_INSERT:
180491ddd559Sdan       case SQLITE_DELETE: {
180591ddd559Sdan         int nByte;
1806b4480e94Sdan         u8 *aEnd = &aIn[i+2];
180791ddd559Sdan 
180891ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
180991ddd559Sdan         aOut[i] = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
1810b4480e94Sdan         aOut[i+1] = aIn[i+1];
1811b4480e94Sdan         nByte = aEnd - &aIn[i+2];
1812b4480e94Sdan         memcpy(&aOut[i+2], &aIn[i+2], nByte);
1813b4480e94Sdan         i += 2 + nByte;
181491ddd559Sdan         break;
181591ddd559Sdan       }
181691ddd559Sdan 
181791ddd559Sdan       case SQLITE_UPDATE: {
181891ddd559Sdan         int nByte1;              /* Size of old.* record in bytes */
181991ddd559Sdan         int nByte2;              /* Size of new.* record in bytes */
1820b4480e94Sdan         u8 *aEnd = &aIn[i+2];
182191ddd559Sdan 
182291ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
1823b4480e94Sdan         nByte1 = aEnd - &aIn[i+2];
182491ddd559Sdan         sessionReadRecord(&aEnd, nCol, 0);
1825b4480e94Sdan         nByte2 = aEnd - &aIn[i+2] - nByte1;
182691ddd559Sdan 
182791ddd559Sdan         aOut[i] = SQLITE_UPDATE;
1828b4480e94Sdan         aOut[i+1] = aIn[i+1];
1829b4480e94Sdan         memcpy(&aOut[i+2], &aIn[i+2+nByte1], nByte2);
1830b4480e94Sdan         memcpy(&aOut[i+2+nByte2], &aIn[i+2], nByte1);
183191ddd559Sdan 
1832b4480e94Sdan         i += 2 + nByte1 + nByte2;
183391ddd559Sdan         break;
183491ddd559Sdan       }
183591ddd559Sdan 
183691ddd559Sdan       default:
183791ddd559Sdan         sqlite3_free(aOut);
183891ddd559Sdan         return SQLITE_CORRUPT;
183991ddd559Sdan     }
184091ddd559Sdan   }
184191ddd559Sdan 
184291ddd559Sdan   *pnInverted = nChangeset;
184391ddd559Sdan   *ppInverted = (void *)aOut;
184491ddd559Sdan   return SQLITE_OK;
184591ddd559Sdan }
184691ddd559Sdan 
18470c698471Sdan typedef struct SessionApplyCtx SessionApplyCtx;
18480c698471Sdan struct SessionApplyCtx {
18490c698471Sdan   sqlite3 *db;
18500c698471Sdan   sqlite3_stmt *pDelete;          /* DELETE statement */
18510c698471Sdan   sqlite3_stmt *pUpdate;          /* DELETE statement */
18520c698471Sdan   sqlite3_stmt *pInsert;          /* INSERT statement */
18530c698471Sdan   sqlite3_stmt *pSelect;          /* SELECT statement */
18540c698471Sdan   int nCol;                       /* Size of azCol[] and abPK[] arrays */
18550c698471Sdan   const char **azCol;             /* Array of column names */
18560c698471Sdan   u8 *abPK;                       /* Boolean array - true if column is in PK */
18570c698471Sdan };
18580c698471Sdan 
1859d5f0767cSdan /*
1860d5f0767cSdan ** Formulate a statement to DELETE a row from database db. Assuming a table
1861d5f0767cSdan ** structure like this:
1862d5f0767cSdan **
1863d5f0767cSdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1864d5f0767cSdan **
1865d5f0767cSdan ** The DELETE statement looks like this:
1866d5f0767cSdan **
1867db04571cSdan **     DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
1868d5f0767cSdan **
1869d5f0767cSdan ** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
1870d5f0767cSdan ** matching b and d values, or 1 otherwise. The second case comes up if the
1871d5f0767cSdan ** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
1872296c7658Sdan **
1873296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
1874296c7658Sdan ** pointing to the prepared version of the SQL statement.
1875d5f0767cSdan */
1876d5f0767cSdan static int sessionDeleteRow(
1877d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1878d5f0767cSdan   const char *zTab,               /* Table name */
18790c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1880d5f0767cSdan ){
1881296c7658Sdan   int i;
1882296c7658Sdan   const char *zSep = "";
1883d5f0767cSdan   int rc = SQLITE_OK;
1884d5f0767cSdan   SessionBuffer buf = {0, 0, 0};
18857cf7df7dSdan   int nPk = 0;
1886d5f0767cSdan 
1887d5f0767cSdan   sessionAppendStr(&buf, "DELETE FROM ", &rc);
1888d5f0767cSdan   sessionAppendIdent(&buf, zTab, &rc);
1889296c7658Sdan   sessionAppendStr(&buf, " WHERE ", &rc);
1890296c7658Sdan 
1891296c7658Sdan   for(i=0; i<p->nCol; i++){
1892296c7658Sdan     if( p->abPK[i] ){
18937cf7df7dSdan       nPk++;
1894296c7658Sdan       sessionAppendStr(&buf, zSep, &rc);
1895296c7658Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1896296c7658Sdan       sessionAppendStr(&buf, " = ?", &rc);
1897296c7658Sdan       sessionAppendInteger(&buf, i+1, &rc);
1898296c7658Sdan       zSep = " AND ";
1899296c7658Sdan     }
1900296c7658Sdan   }
1901296c7658Sdan 
19027cf7df7dSdan   if( nPk<p->nCol ){
1903296c7658Sdan     sessionAppendStr(&buf, " AND (?", &rc);
1904296c7658Sdan     sessionAppendInteger(&buf, p->nCol+1, &rc);
1905296c7658Sdan     sessionAppendStr(&buf, " OR ", &rc);
1906296c7658Sdan 
1907296c7658Sdan     zSep = "";
1908296c7658Sdan     for(i=0; i<p->nCol; i++){
1909296c7658Sdan       if( !p->abPK[i] ){
1910296c7658Sdan         sessionAppendStr(&buf, zSep, &rc);
1911296c7658Sdan         sessionAppendIdent(&buf, p->azCol[i], &rc);
1912296c7658Sdan         sessionAppendStr(&buf, " IS ?", &rc);
1913296c7658Sdan         sessionAppendInteger(&buf, i+1, &rc);
1914296c7658Sdan         zSep = "AND ";
1915296c7658Sdan       }
1916296c7658Sdan     }
1917296c7658Sdan     sessionAppendStr(&buf, ")", &rc);
19187cf7df7dSdan   }
1919d5f0767cSdan 
1920d5f0767cSdan   if( rc==SQLITE_OK ){
19210c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
1922d5f0767cSdan   }
1923d5f0767cSdan   sqlite3_free(buf.aBuf);
1924d5f0767cSdan 
1925d5f0767cSdan   return rc;
1926d5f0767cSdan }
1927d5f0767cSdan 
1928d5f0767cSdan /*
1929d5f0767cSdan ** Formulate and prepare a statement to UPDATE a row from database db.
1930d5f0767cSdan ** Assuming a table structure like this:
1931d5f0767cSdan **
1932d5f0767cSdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
1933d5f0767cSdan **
1934d5f0767cSdan ** The UPDATE statement looks like this:
1935d5f0767cSdan **
1936d5f0767cSdan **     UPDATE x SET
1937d5f0767cSdan **     a = CASE WHEN ?2  THEN ?3  ELSE a END,
1938d5f0767cSdan **     b = CASE WHEN ?5  THEN ?6  ELSE a END,
1939d5f0767cSdan **     c = CASE WHEN ?8  THEN ?9  ELSE a END,
1940d5f0767cSdan **     d = CASE WHEN ?11 THEN ?12 ELSE a END
1941d5f0767cSdan **     WHERE a = ?1 AND c = ?7 AND (?13 OR
1942d5f0767cSdan **       (?5==0 OR b IS ?4) AND (?11==0 OR b IS ?10) AND
1943d5f0767cSdan **     )
1944d5f0767cSdan **
1945d5f0767cSdan ** For each column in the table, there are three variables to bind:
1946d5f0767cSdan **
1947d5f0767cSdan **     ?(i*3+1)    The old.* value of the column, if any.
1948d5f0767cSdan **     ?(i*3+2)    A boolean flag indicating that the value is being modified.
1949d5f0767cSdan **     ?(i*3+3)    The new.* value of the column, if any.
1950d5f0767cSdan **
1951d5f0767cSdan ** Also, a boolean flag that, if set to true, causes the statement to update
1952d5f0767cSdan ** a row even if the non-PK values do not match. This is required if the
1953d5f0767cSdan ** conflict-handler is invoked with CHANGESET_DATA and returns
1954d5f0767cSdan ** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
1955d5f0767cSdan **
1956296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
1957296c7658Sdan ** pointing to the prepared version of the SQL statement.
1958d5f0767cSdan */
1959d5f0767cSdan static int sessionUpdateRow(
1960d5f0767cSdan   sqlite3 *db,                    /* Database handle */
1961d5f0767cSdan   const char *zTab,               /* Table name */
19620c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
1963d5f0767cSdan ){
1964d5f0767cSdan   int rc = SQLITE_OK;
1965d5f0767cSdan   int i;
1966d5f0767cSdan   const char *zSep = "";
1967d5f0767cSdan   SessionBuffer buf = {0, 0, 0};
1968d5f0767cSdan 
1969d5f0767cSdan   /* Append "UPDATE tbl SET " */
1970d5f0767cSdan   sessionAppendStr(&buf, "UPDATE ", &rc);
1971d5f0767cSdan   sessionAppendIdent(&buf, zTab, &rc);
1972d5f0767cSdan   sessionAppendStr(&buf, " SET ", &rc);
1973d5f0767cSdan 
1974d5f0767cSdan   /* Append the assignments */
19750c698471Sdan   for(i=0; i<p->nCol; i++){
1976d5f0767cSdan     sessionAppendStr(&buf, zSep, &rc);
19770c698471Sdan     sessionAppendIdent(&buf, p->azCol[i], &rc);
1978d5f0767cSdan     sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
1979d5f0767cSdan     sessionAppendInteger(&buf, i*3+2, &rc);
1980d5f0767cSdan     sessionAppendStr(&buf, " THEN ?", &rc);
1981d5f0767cSdan     sessionAppendInteger(&buf, i*3+3, &rc);
1982d5f0767cSdan     sessionAppendStr(&buf, " ELSE ", &rc);
19830c698471Sdan     sessionAppendIdent(&buf, p->azCol[i], &rc);
1984d5f0767cSdan     sessionAppendStr(&buf, " END", &rc);
1985d5f0767cSdan     zSep = ", ";
1986d5f0767cSdan   }
1987d5f0767cSdan 
1988d5f0767cSdan   /* Append the PK part of the WHERE clause */
1989d5f0767cSdan   sessionAppendStr(&buf, " WHERE ", &rc);
19900c698471Sdan   for(i=0; i<p->nCol; i++){
19910c698471Sdan     if( p->abPK[i] ){
19920c698471Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
1993d5f0767cSdan       sessionAppendStr(&buf, " = ?", &rc);
1994d5f0767cSdan       sessionAppendInteger(&buf, i*3+1, &rc);
1995d5f0767cSdan       sessionAppendStr(&buf, " AND ", &rc);
1996d5f0767cSdan     }
1997d5f0767cSdan   }
1998d5f0767cSdan 
1999d5f0767cSdan   /* Append the non-PK part of the WHERE clause */
2000d5f0767cSdan   sessionAppendStr(&buf, " (?", &rc);
20010c698471Sdan   sessionAppendInteger(&buf, p->nCol*3+1, &rc);
2002d5f0767cSdan   sessionAppendStr(&buf, " OR 1", &rc);
20030c698471Sdan   for(i=0; i<p->nCol; i++){
20040c698471Sdan     if( !p->abPK[i] ){
2005d5f0767cSdan       sessionAppendStr(&buf, " AND (?", &rc);
2006d5f0767cSdan       sessionAppendInteger(&buf, i*3+2, &rc);
2007d5f0767cSdan       sessionAppendStr(&buf, "=0 OR ", &rc);
20080c698471Sdan       sessionAppendIdent(&buf, p->azCol[i], &rc);
2009d5f0767cSdan       sessionAppendStr(&buf, " IS ?", &rc);
2010d5f0767cSdan       sessionAppendInteger(&buf, i*3+1, &rc);
2011d5f0767cSdan       sessionAppendStr(&buf, ")", &rc);
2012d5f0767cSdan     }
2013d5f0767cSdan   }
2014d5f0767cSdan   sessionAppendStr(&buf, ")", &rc);
2015d5f0767cSdan 
2016d5f0767cSdan   if( rc==SQLITE_OK ){
20170c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
2018d5f0767cSdan   }
2019d5f0767cSdan   sqlite3_free(buf.aBuf);
2020d5f0767cSdan 
2021d5f0767cSdan   return rc;
2022d5f0767cSdan }
2023d5f0767cSdan 
2024296c7658Sdan /*
2025296c7658Sdan ** Formulate and prepare an SQL statement to query table zTab by primary
2026296c7658Sdan ** key. Assuming the following table structure:
2027296c7658Sdan **
2028296c7658Sdan **     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
2029296c7658Sdan **
2030296c7658Sdan ** The SELECT statement looks like this:
2031296c7658Sdan **
2032296c7658Sdan **     SELECT * FROM x WHERE a = ?1 AND c = ?3
2033296c7658Sdan **
2034296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
2035296c7658Sdan ** pointing to the prepared version of the SQL statement.
2036296c7658Sdan */
2037d5f0767cSdan static int sessionSelectRow(
2038d5f0767cSdan   sqlite3 *db,                    /* Database handle */
2039d5f0767cSdan   const char *zTab,               /* Table name */
20400c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
2041d5f0767cSdan ){
2042d7fb7d24Sdan   return sessionSelectStmt(
2043d7fb7d24Sdan       db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
2044d5f0767cSdan }
2045d5f0767cSdan 
2046296c7658Sdan /*
2047296c7658Sdan ** Formulate and prepare an INSERT statement to add a record to table zTab.
2048296c7658Sdan ** For example:
2049296c7658Sdan **
2050296c7658Sdan **     INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
2051296c7658Sdan **
2052296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
2053296c7658Sdan ** pointing to the prepared version of the SQL statement.
2054296c7658Sdan */
20550c698471Sdan static int sessionInsertRow(
20560c698471Sdan   sqlite3 *db,                    /* Database handle */
20570c698471Sdan   const char *zTab,               /* Table name */
20580c698471Sdan   SessionApplyCtx *p              /* Session changeset-apply context */
20590c698471Sdan ){
20600c698471Sdan   int rc = SQLITE_OK;
20610c698471Sdan   int i;
20620c698471Sdan   SessionBuffer buf = {0, 0, 0};
20630c698471Sdan 
20640c698471Sdan   sessionAppendStr(&buf, "INSERT INTO main.", &rc);
20650c698471Sdan   sessionAppendIdent(&buf, zTab, &rc);
20660c698471Sdan   sessionAppendStr(&buf, " VALUES(?", &rc);
20670c698471Sdan   for(i=1; i<p->nCol; i++){
20680c698471Sdan     sessionAppendStr(&buf, ", ?", &rc);
20690c698471Sdan   }
20700c698471Sdan   sessionAppendStr(&buf, ")", &rc);
20710c698471Sdan 
20720c698471Sdan   if( rc==SQLITE_OK ){
20730c698471Sdan     rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
20740c698471Sdan   }
20750c698471Sdan   sqlite3_free(buf.aBuf);
20760c698471Sdan   return rc;
20770c698471Sdan }
20780c698471Sdan 
2079296c7658Sdan /*
20807aa469cdSdan ** A wrapper around sqlite3_bind_value() that detects an extra problem.
20817aa469cdSdan ** See comments in the body of this function for details.
20827aa469cdSdan */
20837aa469cdSdan static int sessionBindValue(
20847aa469cdSdan   sqlite3_stmt *pStmt,            /* Statement to bind value to */
20857aa469cdSdan   int i,                          /* Parameter number to bind to */
20867aa469cdSdan   sqlite3_value *pVal             /* Value to bind */
20877aa469cdSdan ){
20887aa469cdSdan   if( (pVal->type==SQLITE_TEXT || pVal->type==SQLITE_BLOB) && pVal->z==0 ){
20897aa469cdSdan     /* This condition occurs when an earlier OOM in a call to
20907aa469cdSdan     ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
20917aa469cdSdan     ** a conflict-hanler) has zeroed the pVal->z pointer. Return NOMEM. */
20927aa469cdSdan     return SQLITE_NOMEM;
20937aa469cdSdan   }
20947aa469cdSdan   return sqlite3_bind_value(pStmt, i, pVal);
20957aa469cdSdan }
20967aa469cdSdan 
20977aa469cdSdan /*
2098db04571cSdan ** Iterator pIter must point to an SQLITE_INSERT entry. This function
2099db04571cSdan ** transfers new.* values from the current iterator entry to statement
2100db04571cSdan ** pStmt. The table being inserted into has nCol columns.
2101db04571cSdan **
2102db04571cSdan ** New.* value $i 0 from the iterator is bound to variable ($i+1) of
2103db04571cSdan ** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
2104db04571cSdan ** are transfered to the statement. Otherwise, if abPK is not NULL, it points
2105db04571cSdan ** to an array nCol elements in size. In this case only those values for
2106db04571cSdan ** which abPK[$i] is true are read from the iterator and bound to the
2107db04571cSdan ** statement.
2108db04571cSdan **
2109db04571cSdan ** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
2110db04571cSdan */
21117aa469cdSdan static int sessionBindRow(
2112db04571cSdan   sqlite3_changeset_iter *pIter,  /* Iterator to read values from */
21137aa469cdSdan   int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
2114db04571cSdan   int nCol,                       /* Number of columns */
2115db04571cSdan   u8 *abPK,                       /* If not NULL, bind only if true */
2116db04571cSdan   sqlite3_stmt *pStmt             /* Bind values to this statement */
2117db04571cSdan ){
2118db04571cSdan   int i;
2119db04571cSdan   int rc = SQLITE_OK;
21207aa469cdSdan 
21217aa469cdSdan   /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
21227aa469cdSdan   ** argument iterator points to a suitable entry. Make sure that xValue
21237aa469cdSdan   ** is one of these to guarantee that it is safe to ignore the return
21247aa469cdSdan   ** in the code below. */
21257aa469cdSdan   assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
21267aa469cdSdan 
2127db04571cSdan   for(i=0; rc==SQLITE_OK && i<nCol; i++){
2128db04571cSdan     if( !abPK || abPK[i] ){
2129db04571cSdan       sqlite3_value *pVal;
21307aa469cdSdan       (void)xValue(pIter, i, &pVal);
21317aa469cdSdan       rc = sessionBindValue(pStmt, i+1, pVal);
2132db04571cSdan     }
2133db04571cSdan   }
2134db04571cSdan   return rc;
2135db04571cSdan }
2136db04571cSdan 
2137db04571cSdan /*
2138296c7658Sdan ** SQL statement pSelect is as generated by the sessionSelectRow() function.
2139296c7658Sdan ** This function binds the primary key values from the change that changeset
2140296c7658Sdan ** iterator pIter points to to the SELECT and attempts to seek to the table
2141296c7658Sdan ** entry. If a row is found, the SELECT statement left pointing at the row
2142296c7658Sdan ** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
2143296c7658Sdan ** has occured, the statement is reset and SQLITE_OK is returned. If an
21447aa469cdSdan ** error occurs, the statement is reset and an SQLite error code is returned.
21457aa469cdSdan **
21467aa469cdSdan ** If this function returns SQLITE_ROW, the caller must eventually reset()
21477aa469cdSdan ** statement pSelect. If any other value is returned, the statement does
21487aa469cdSdan ** not require a reset().
2149296c7658Sdan **
2150296c7658Sdan ** If the iterator currently points to an INSERT record, bind values from the
2151db04571cSdan ** new.* record to the SELECT statement. Or, if it points to a DELETE or
2152db04571cSdan ** UPDATE, bind values from the old.* record.
2153296c7658Sdan */
21540c698471Sdan static int sessionSeekToRow(
215537f133ecSdan   sqlite3 *db,                    /* Database handle */
215637f133ecSdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
215737f133ecSdan   u8 *abPK,                       /* Primary key flags array */
21580c698471Sdan   sqlite3_stmt *pSelect           /* SELECT statement from sessionSelectRow() */
215937f133ecSdan ){
21607aa469cdSdan   int rc;                         /* Return code */
2161296c7658Sdan   int nCol;                       /* Number of columns in table */
2162296c7658Sdan   int op;                         /* Changset operation (SQLITE_UPDATE etc.) */
2163296c7658Sdan   const char *zDummy;             /* Unused */
216437f133ecSdan 
2165b4480e94Sdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
21667aa469cdSdan   rc = sessionBindRow(pIter,
2167db04571cSdan       op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
2168db04571cSdan       nCol, abPK, pSelect
2169db04571cSdan   );
21700c698471Sdan 
21710c698471Sdan   if( rc==SQLITE_OK ){
21720c698471Sdan     rc = sqlite3_step(pSelect);
21730c698471Sdan     if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
21740c698471Sdan   }
21750c698471Sdan 
21760c698471Sdan   return rc;
21770c698471Sdan }
21780c698471Sdan 
2179296c7658Sdan /*
2180296c7658Sdan ** Invoke the conflict handler for the change that the changeset iterator
2181296c7658Sdan ** currently points to.
2182296c7658Sdan **
2183296c7658Sdan ** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
2184296c7658Sdan ** If argument pbReplace is NULL, then the type of conflict handler invoked
2185296c7658Sdan ** depends solely on eType, as follows:
2186296c7658Sdan **
2187296c7658Sdan **    eType value                 Value passed to xConflict
2188296c7658Sdan **    -------------------------------------------------
2189296c7658Sdan **    CHANGESET_DATA              CHANGESET_NOTFOUND
2190296c7658Sdan **    CHANGESET_CONFLICT          CHANGESET_CONSTRAINT
2191296c7658Sdan **
2192296c7658Sdan ** Or, if pbReplace is not NULL, then an attempt is made to find an existing
2193296c7658Sdan ** record with the same primary key as the record about to be deleted, updated
2194296c7658Sdan ** or inserted. If such a record can be found, it is available to the conflict
2195296c7658Sdan ** handler as the "conflicting" record. In this case the type of conflict
2196296c7658Sdan ** handler invoked is as follows:
2197296c7658Sdan **
2198296c7658Sdan **    eType value         PK Record found?   Value passed to xConflict
2199296c7658Sdan **    ----------------------------------------------------------------
2200296c7658Sdan **    CHANGESET_DATA      Yes                CHANGESET_DATA
2201296c7658Sdan **    CHANGESET_DATA      No                 CHANGESET_NOTFOUND
2202296c7658Sdan **    CHANGESET_CONFLICT  Yes                CHANGESET_CONFLICT
2203296c7658Sdan **    CHANGESET_CONFLICT  No                 CHANGESET_CONSTRAINT
2204296c7658Sdan **
2205296c7658Sdan ** If pbReplace is not NULL, and a record with a matching PK is found, and
2206296c7658Sdan ** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
2207296c7658Sdan ** is set to non-zero before returning SQLITE_OK.
2208296c7658Sdan **
2209296c7658Sdan ** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
2210296c7658Sdan ** returned. Or, if the conflict handler returns an invalid value,
2211296c7658Sdan ** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
2212296c7658Sdan ** this function returns SQLITE_OK.
2213296c7658Sdan */
22140c698471Sdan static int sessionConflictHandler(
2215296c7658Sdan   int eType,                      /* Either CHANGESET_DATA or CONFLICT */
2216296c7658Sdan   SessionApplyCtx *p,             /* changeset_apply() context */
22170c698471Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
22180c698471Sdan   int(*xConflict)(void *, int, sqlite3_changeset_iter*),
2219296c7658Sdan   void *pCtx,                     /* First argument for conflict handler */
2220296c7658Sdan   int *pbReplace                  /* OUT: Set to true if PK row is found */
22210c698471Sdan ){
2222296c7658Sdan   int res;                        /* Value returned by conflict handler */
22230c698471Sdan   int rc;
22240c698471Sdan   int nCol;
22250c698471Sdan   int op;
22260c698471Sdan   const char *zDummy;
22270c698471Sdan 
2228b4480e94Sdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
22290c698471Sdan 
22300c698471Sdan   assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
22310c698471Sdan   assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
22320c698471Sdan   assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
223337f133ecSdan 
223437f133ecSdan   /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
22350c698471Sdan   if( pbReplace ){
22360c698471Sdan     rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
22370c698471Sdan   }else{
2238db04571cSdan     rc = SQLITE_OK;
22390c698471Sdan   }
22400c698471Sdan 
22410c698471Sdan   if( rc==SQLITE_ROW ){
22420c698471Sdan     /* There exists another row with the new.* primary key. */
22430c698471Sdan     pIter->pConflict = p->pSelect;
22440c698471Sdan     res = xConflict(pCtx, eType, pIter);
22450c698471Sdan     pIter->pConflict = 0;
22460c698471Sdan     rc = sqlite3_reset(p->pSelect);
2247db04571cSdan   }else if( rc==SQLITE_OK ){
22480c698471Sdan     /* No other row with the new.* primary key. */
22490c698471Sdan     res = xConflict(pCtx, eType+1, pIter);
22500c698471Sdan     if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
225137f133ecSdan   }
225237f133ecSdan 
225337f133ecSdan   if( rc==SQLITE_OK ){
22540c698471Sdan     switch( res ){
22550c698471Sdan       case SQLITE_CHANGESET_REPLACE:
2256f51e5f6cSdan         assert( pbReplace );
2257f51e5f6cSdan         *pbReplace = 1;
22580c698471Sdan         break;
22590c698471Sdan 
22600c698471Sdan       case SQLITE_CHANGESET_OMIT:
22610c698471Sdan         break;
22620c698471Sdan 
22630c698471Sdan       case SQLITE_CHANGESET_ABORT:
22640c698471Sdan         rc = SQLITE_ABORT;
22650c698471Sdan         break;
22660c698471Sdan 
22670c698471Sdan       default:
22680c698471Sdan         rc = SQLITE_MISUSE;
22690c698471Sdan         break;
22700c698471Sdan     }
22710c698471Sdan   }
22720c698471Sdan 
22730c698471Sdan   return rc;
22740c698471Sdan }
22750c698471Sdan 
2276296c7658Sdan /*
2277296c7658Sdan ** Attempt to apply the change that the iterator passed as the first argument
2278296c7658Sdan ** currently points to to the database. If a conflict is encountered, invoke
2279296c7658Sdan ** the conflict handler callback.
2280296c7658Sdan **
2281296c7658Sdan ** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
2282296c7658Sdan ** one is encountered, update or delete the row with the matching primary key
2283296c7658Sdan ** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
2284296c7658Sdan ** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
2285296c7658Sdan ** to true before returning. In this case the caller will invoke this function
2286296c7658Sdan ** again, this time with pbRetry set to NULL.
2287296c7658Sdan **
2288296c7658Sdan ** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
2289296c7658Sdan ** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
2290296c7658Sdan ** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
2291296c7658Sdan ** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
2292296c7658Sdan ** before retrying. In this case the caller attempts to remove the conflicting
2293296c7658Sdan ** row before invoking this function again, this time with pbReplace set
2294296c7658Sdan ** to NULL.
2295296c7658Sdan **
2296296c7658Sdan ** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
2297296c7658Sdan ** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
2298296c7658Sdan ** returned.
2299296c7658Sdan */
23000c698471Sdan static int sessionApplyOneOp(
2301296c7658Sdan   sqlite3_changeset_iter *pIter,  /* Changeset iterator */
2302296c7658Sdan   SessionApplyCtx *p,             /* changeset_apply() context */
23030c698471Sdan   int(*xConflict)(void *, int, sqlite3_changeset_iter *),
2304296c7658Sdan   void *pCtx,                     /* First argument for the conflict handler */
2305296c7658Sdan   int *pbReplace,                 /* OUT: True to remove PK row and retry */
2306296c7658Sdan   int *pbRetry                    /* OUT: True to retry. */
23070c698471Sdan ){
23080c698471Sdan   const char *zDummy;
23090c698471Sdan   int op;
23100c698471Sdan   int nCol;
23110c698471Sdan   int rc = SQLITE_OK;
23120c698471Sdan 
23130c698471Sdan   assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
23140c698471Sdan   assert( p->azCol && p->abPK );
23150c698471Sdan   assert( !pbReplace || *pbReplace==0 );
23160c698471Sdan 
2317b4480e94Sdan   sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
23180c698471Sdan 
23190c698471Sdan   if( op==SQLITE_DELETE ){
23200c698471Sdan 
23210c698471Sdan     /* Bind values to the DELETE statement. */
23227aa469cdSdan     rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, 0, p->pDelete);
23237cf7df7dSdan     if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
23247cf7df7dSdan       rc = sqlite3_bind_int(p->pDelete, nCol+1, pbRetry==0);
23257cf7df7dSdan     }
23260c698471Sdan     if( rc!=SQLITE_OK ) return rc;
23270c698471Sdan 
23280c698471Sdan     sqlite3_step(p->pDelete);
23290c698471Sdan     rc = sqlite3_reset(p->pDelete);
23300c698471Sdan     if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
23310c698471Sdan       rc = sessionConflictHandler(
23320c698471Sdan           SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
23330c698471Sdan       );
23340c698471Sdan     }else if( rc==SQLITE_CONSTRAINT ){
23350c698471Sdan       rc = sessionConflictHandler(
23360c698471Sdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
23370c698471Sdan       );
23380c698471Sdan     }
23390c698471Sdan 
23400c698471Sdan   }else if( op==SQLITE_UPDATE ){
23410c698471Sdan     int i;
23420c698471Sdan 
23430c698471Sdan     /* Bind values to the UPDATE statement. */
23440c698471Sdan     for(i=0; rc==SQLITE_OK && i<nCol; i++){
23457aa469cdSdan       sqlite3_value *pOld = sessionChangesetOld(pIter, i);
23467aa469cdSdan       sqlite3_value *pNew = sessionChangesetNew(pIter, i);
23477aa469cdSdan 
23480c698471Sdan       sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
23497aa469cdSdan       if( pOld ){
23507aa469cdSdan         rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
23517aa469cdSdan       }
23527aa469cdSdan       if( rc==SQLITE_OK && pNew ){
23537aa469cdSdan         rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
23540c698471Sdan       }
23550c698471Sdan     }
23567aa469cdSdan     if( rc==SQLITE_OK ) sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0);
23570c698471Sdan     if( rc!=SQLITE_OK ) return rc;
23580c698471Sdan 
23590c698471Sdan     /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
23600c698471Sdan     ** the result will be SQLITE_OK with 0 rows modified. */
23610c698471Sdan     sqlite3_step(p->pUpdate);
23620c698471Sdan     rc = sqlite3_reset(p->pUpdate);
23630c698471Sdan 
23640c698471Sdan     if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
23650c698471Sdan       /* A NOTFOUND or DATA error. Search the table to see if it contains
23660c698471Sdan       ** a row with a matching primary key. If so, this is a DATA conflict.
23670c698471Sdan       ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
23680c698471Sdan 
23690c698471Sdan       rc = sessionConflictHandler(
23700c698471Sdan           SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
23710c698471Sdan       );
23720c698471Sdan 
23730c698471Sdan     }else if( rc==SQLITE_CONSTRAINT ){
2374db04571cSdan       /* This is always a CONSTRAINT conflict. */
2375db04571cSdan       rc = sessionConflictHandler(
2376db04571cSdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
23770c698471Sdan       );
23780c698471Sdan     }
23790c698471Sdan 
23800c698471Sdan   }else{
23810c698471Sdan     assert( op==SQLITE_INSERT );
23827aa469cdSdan     rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
23830c698471Sdan     if( rc!=SQLITE_OK ) return rc;
23840c698471Sdan 
23850c698471Sdan     sqlite3_step(p->pInsert);
23860c698471Sdan     rc = sqlite3_reset(p->pInsert);
2387db04571cSdan     if( rc==SQLITE_CONSTRAINT ){
23880c698471Sdan       rc = sessionConflictHandler(
23890c698471Sdan           SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
23900c698471Sdan       );
239137f133ecSdan     }
239237f133ecSdan   }
239337f133ecSdan 
239437f133ecSdan   return rc;
239537f133ecSdan }
239637f133ecSdan 
2397296c7658Sdan /*
2398296c7658Sdan ** Apply the changeset passed via pChangeset/nChangeset to the main database
2399296c7658Sdan ** attached to handle "db". Invoke the supplied conflict handler callback
2400296c7658Sdan ** to resolve any conflicts encountered while applying the change.
2401296c7658Sdan */
2402d5f0767cSdan int sqlite3changeset_apply(
2403296c7658Sdan   sqlite3 *db,                    /* Apply change to "main" db of this handle */
2404296c7658Sdan   int nChangeset,                 /* Size of changeset in bytes */
2405296c7658Sdan   void *pChangeset,               /* Changeset blob */
2406d5f0767cSdan   int(*xConflict)(
2407d5f0767cSdan     void *pCtx,                   /* Copy of fifth arg to _apply() */
2408d5f0767cSdan     int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
2409d5f0767cSdan     sqlite3_changeset_iter *p     /* Handle describing change and conflict */
2410d5f0767cSdan   ),
2411296c7658Sdan   void *pCtx                      /* First argument passed to xConflict */
2412d5f0767cSdan ){
2413ca62ad57Sdan   int schemaMismatch = 0;
2414296c7658Sdan   sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */
2415296c7658Sdan   int rc;                         /* Return code */
2416d5f0767cSdan   const char *zTab = 0;           /* Name of current table */
2417d5f0767cSdan   int nTab = 0;                   /* Result of strlen(zTab) */
2418296c7658Sdan   SessionApplyCtx sApply;         /* changeset_apply() context object */
2419d5f0767cSdan 
24200c698471Sdan   memset(&sApply, 0, sizeof(sApply));
242112ca0b56Sdan   rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
242212ca0b56Sdan   if( rc!=SQLITE_OK ) return rc;
24230c698471Sdan 
24244c220252Sdan   sqlite3_mutex_enter(sqlite3_db_mutex(db));
24250c698471Sdan   rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
24260c698471Sdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
24270c698471Sdan     int nCol;
2428d5f0767cSdan     int op;
24290c698471Sdan     int bReplace = 0;
24300c698471Sdan     int bRetry = 0;
24310c698471Sdan     const char *zNew;
2432ca62ad57Sdan 
2433b4480e94Sdan     sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
2434d5f0767cSdan 
24350c698471Sdan     if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
2436ca62ad57Sdan       u8 *abPK;
2437ca62ad57Sdan 
2438ca62ad57Sdan       schemaMismatch = 0;
24390c698471Sdan       sqlite3_free(sApply.azCol);
24400c698471Sdan       sqlite3_finalize(sApply.pDelete);
24410c698471Sdan       sqlite3_finalize(sApply.pUpdate);
24420c698471Sdan       sqlite3_finalize(sApply.pInsert);
24430c698471Sdan       sqlite3_finalize(sApply.pSelect);
24440c698471Sdan       memset(&sApply, 0, sizeof(sApply));
24450c698471Sdan       sApply.db = db;
244637f133ecSdan 
2447ca62ad57Sdan       sqlite3changeset_pk(pIter, &abPK, 0);
2448296c7658Sdan       rc = sessionTableInfo(
2449ca62ad57Sdan           db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
2450ca62ad57Sdan       );
2451ca62ad57Sdan       if( rc!=SQLITE_OK ) break;
24520c698471Sdan 
2453ca62ad57Sdan       if( sApply.nCol==0 ){
2454ca62ad57Sdan         schemaMismatch = 1;
2455ca62ad57Sdan         sqlite3_log(SQLITE_SCHEMA,
2456ca62ad57Sdan             "sqlite3changeset_apply(): no such table: %s", zTab
2457ca62ad57Sdan         );
2458ca62ad57Sdan       }
2459ca62ad57Sdan       else if( sApply.nCol!=nCol ){
2460ca62ad57Sdan         schemaMismatch = 1;
2461ca62ad57Sdan         sqlite3_log(SQLITE_SCHEMA,
2462ca62ad57Sdan             "sqlite3changeset_apply(): table %s has %d columns, expected %d",
2463ca62ad57Sdan             zTab, sApply.nCol, nCol
2464ca62ad57Sdan         );
2465ca62ad57Sdan       }
2466ca62ad57Sdan       else if( memcmp(sApply.abPK, abPK, nCol)!=0 ){
2467ca62ad57Sdan         schemaMismatch = 1;
2468ca62ad57Sdan         sqlite3_log(SQLITE_SCHEMA,
2469ca62ad57Sdan             "sqlite3changeset_apply(): primary key mismatch for table %s", zTab
2470ca62ad57Sdan         );
2471ca62ad57Sdan       }
2472ca62ad57Sdan       else if(
2473ca62ad57Sdan           (rc = sessionSelectRow(db, zTab, &sApply))
24740c698471Sdan        || (rc = sessionUpdateRow(db, zTab, &sApply))
24750c698471Sdan        || (rc = sessionDeleteRow(db, zTab, &sApply))
24760c698471Sdan        || (rc = sessionInsertRow(db, zTab, &sApply))
247737f133ecSdan       ){
247837f133ecSdan         break;
247937f133ecSdan       }
24800c698471Sdan       nTab = strlen(zTab);
2481d5f0767cSdan     }
2482d5f0767cSdan 
2483ca62ad57Sdan     /* If there is a schema mismatch on the current table, proceed to the
2484ca62ad57Sdan     ** next change. A log message has already been issued. */
2485ca62ad57Sdan     if( schemaMismatch ) continue;
2486ca62ad57Sdan 
24870c698471Sdan     rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
24880c698471Sdan 
24890c698471Sdan     if( rc==SQLITE_OK && bRetry ){
24900c698471Sdan       rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, 0);
24910c698471Sdan     }
24920c698471Sdan 
24930c698471Sdan     if( bReplace ){
2494db04571cSdan       assert( pIter->op==SQLITE_INSERT );
24950c698471Sdan       rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
24960c698471Sdan       if( rc==SQLITE_OK ){
24977aa469cdSdan         rc = sessionBindRow(pIter,
2498db04571cSdan             sqlite3changeset_new, sApply.nCol, sApply.abPK, sApply.pDelete);
24990c698471Sdan         sqlite3_bind_int(sApply.pDelete, sApply.nCol+1, 1);
25000c698471Sdan       }
25010c698471Sdan       if( rc==SQLITE_OK ){
25020c698471Sdan         sqlite3_step(sApply.pDelete);
25030c698471Sdan         rc = sqlite3_reset(sApply.pDelete);
25040c698471Sdan       }
25050c698471Sdan       if( rc==SQLITE_OK ){
25060c698471Sdan         rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, 0, 0);
25070c698471Sdan       }
25080c698471Sdan       if( rc==SQLITE_OK ){
25090c698471Sdan         rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
25100c698471Sdan       }
25110c698471Sdan     }
25120c698471Sdan   }
2513d5f0767cSdan 
2514296c7658Sdan   if( rc==SQLITE_OK ){
2515296c7658Sdan     rc = sqlite3changeset_finalize(pIter);
2516296c7658Sdan   }else{
2517296c7658Sdan     sqlite3changeset_finalize(pIter);
2518296c7658Sdan   }
2519d5f0767cSdan 
2520d5f0767cSdan   if( rc==SQLITE_OK ){
2521d5f0767cSdan     rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
2522d5f0767cSdan   }else{
2523d5f0767cSdan     sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
2524d5f0767cSdan     sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
2525d5f0767cSdan   }
2526d5f0767cSdan 
25270c698471Sdan   sqlite3_finalize(sApply.pInsert);
25280c698471Sdan   sqlite3_finalize(sApply.pDelete);
25290c698471Sdan   sqlite3_finalize(sApply.pUpdate);
25300c698471Sdan   sqlite3_finalize(sApply.pSelect);
25310c698471Sdan   sqlite3_free(sApply.azCol);
25324c220252Sdan   sqlite3_mutex_leave(sqlite3_db_mutex(db));
2533d5f0767cSdan   return rc;
2534d5f0767cSdan }
253591ddd559Sdan 
25364fccf43aSdan #endif        /* #ifdef SQLITE_ENABLE_SESSION */
2537