14fccf43aSdan 29b1c62d4Sdrh #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) 34fccf43aSdan 44fccf43aSdan #include "sqlite3session.h" 54fccf43aSdan #include <assert.h> 64fccf43aSdan #include <string.h> 74fccf43aSdan 85d8a2984Sdan #ifndef SQLITE_AMALGAMATION 94fccf43aSdan # include "sqliteInt.h" 104fccf43aSdan # include "vdbeInt.h" 115d8a2984Sdan #endif 124fccf43aSdan 134fccf43aSdan typedef struct SessionTable SessionTable; 144fccf43aSdan typedef struct SessionChange SessionChange; 15296c7658Sdan typedef struct SessionBuffer SessionBuffer; 164fccf43aSdan 17296c7658Sdan /* 18296c7658Sdan ** Session handle structure. 19296c7658Sdan */ 204fccf43aSdan struct sqlite3_session { 214fccf43aSdan sqlite3 *db; /* Database handle session is attached to */ 224fccf43aSdan char *zDb; /* Name of database session is attached to */ 23296c7658Sdan int bEnable; /* True if currently recording */ 24b4480e94Sdan int bIndirect; /* True if all changes are indirect */ 25ff4d0f41Sdan int bAutoAttach; /* True to auto-attach tables */ 264fccf43aSdan int rc; /* Non-zero if an error has occurred */ 274fccf43aSdan sqlite3_session *pNext; /* Next session object on same db. */ 284fccf43aSdan SessionTable *pTable; /* List of attached tables */ 294fccf43aSdan }; 304fccf43aSdan 314fccf43aSdan /* 32296c7658Sdan ** Structure for changeset iterators. 33296c7658Sdan */ 34296c7658Sdan struct sqlite3_changeset_iter { 35296c7658Sdan u8 *aChangeset; /* Pointer to buffer containing changeset */ 36296c7658Sdan int nChangeset; /* Number of bytes in aChangeset */ 37296c7658Sdan u8 *pNext; /* Pointer to next change within aChangeset */ 38296c7658Sdan int rc; /* Iterator error code */ 39296c7658Sdan sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ 40296c7658Sdan char *zTab; /* Current table */ 41296c7658Sdan int nCol; /* Number of columns in zTab */ 42296c7658Sdan int op; /* Current operation */ 43b4480e94Sdan int bIndirect; /* True if current change was indirect */ 44244593c8Sdan u8 *abPK; /* Primary key array */ 45296c7658Sdan sqlite3_value **apValue; /* old.* and new.* values */ 46296c7658Sdan }; 47296c7658Sdan 48296c7658Sdan /* 494fccf43aSdan ** Each session object maintains a set of the following structures, one 504fccf43aSdan ** for each table the session object is monitoring. The structures are 514fccf43aSdan ** stored in a linked list starting at sqlite3_session.pTable. 524fccf43aSdan ** 534fccf43aSdan ** The keys of the SessionTable.aChange[] hash table are all rows that have 544fccf43aSdan ** been modified in any way since the session object was attached to the 554fccf43aSdan ** table. 564fccf43aSdan ** 574fccf43aSdan ** The data associated with each hash-table entry is a structure containing 584fccf43aSdan ** a subset of the initial values that the modified row contained at the 594fccf43aSdan ** start of the session. Or no initial values if the row was inserted. 604fccf43aSdan */ 614fccf43aSdan struct SessionTable { 624fccf43aSdan SessionTable *pNext; 634fccf43aSdan char *zName; /* Local name of table */ 644fccf43aSdan int nCol; /* Number of columns in table zName */ 65e8d5648eSdan const char **azCol; /* Column names */ 66e8d5648eSdan u8 *abPK; /* Array of primary key flags */ 67296c7658Sdan int nEntry; /* Total number of entries in hash table */ 684fccf43aSdan int nChange; /* Size of apChange[] array */ 694fccf43aSdan SessionChange **apChange; /* Hash table buckets */ 704fccf43aSdan }; 714fccf43aSdan 724fccf43aSdan /* 734fccf43aSdan ** RECORD FORMAT: 744fccf43aSdan ** 754fccf43aSdan ** The following record format is similar to (but not compatible with) that 764fccf43aSdan ** used in SQLite database files. This format is used as part of the 774fccf43aSdan ** change-set binary format, and so must be architecture independent. 784fccf43aSdan ** 794fccf43aSdan ** Unlike the SQLite database record format, each field is self-contained - 804fccf43aSdan ** there is no separation of header and data. Each field begins with a 814fccf43aSdan ** single byte describing its type, as follows: 824fccf43aSdan ** 834fccf43aSdan ** 0x00: Undefined value. 844fccf43aSdan ** 0x01: Integer value. 854fccf43aSdan ** 0x02: Real value. 864fccf43aSdan ** 0x03: Text value. 874fccf43aSdan ** 0x04: Blob value. 884fccf43aSdan ** 0x05: SQL NULL value. 894fccf43aSdan ** 904fccf43aSdan ** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT 914fccf43aSdan ** and so on in sqlite3.h. For undefined and NULL values, the field consists 924fccf43aSdan ** only of the single type byte. For other types of values, the type byte 934fccf43aSdan ** is followed by: 944fccf43aSdan ** 954fccf43aSdan ** Text values: 964fccf43aSdan ** A varint containing the number of bytes in the value (encoded using 974fccf43aSdan ** UTF-8). Followed by a buffer containing the UTF-8 representation 984fccf43aSdan ** of the text value. There is no nul terminator. 994fccf43aSdan ** 1004fccf43aSdan ** Blob values: 1014fccf43aSdan ** A varint containing the number of bytes in the value, followed by 1024fccf43aSdan ** a buffer containing the value itself. 1034fccf43aSdan ** 1044fccf43aSdan ** Integer values: 1054fccf43aSdan ** An 8-byte big-endian integer value. 1064fccf43aSdan ** 1074fccf43aSdan ** Real values: 1084fccf43aSdan ** An 8-byte big-endian IEEE 754-2008 real value. 1094fccf43aSdan ** 1104fccf43aSdan ** Varint values are encoded in the same way as varints in the SQLite 1114fccf43aSdan ** record format. 1124fccf43aSdan ** 1134fccf43aSdan ** CHANGESET FORMAT: 1144fccf43aSdan ** 1154fccf43aSdan ** A changeset is a collection of DELETE, UPDATE and INSERT operations on 1164fccf43aSdan ** one or more tables. Operations on a single table are grouped together, 1174fccf43aSdan ** but may occur in any order (i.e. deletes, updates and inserts are all 1184fccf43aSdan ** mixed together). 1194fccf43aSdan ** 1204fccf43aSdan ** Each group of changes begins with a table header: 1214fccf43aSdan ** 1224fccf43aSdan ** 1 byte: Constant 0x54 (capital 'T') 1234fccf43aSdan ** Varint: Big-endian integer set to the number of columns in the table. 1244fccf43aSdan ** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated. 1254fccf43aSdan ** 1264fccf43aSdan ** Followed by one or more changes to the table. 1274fccf43aSdan ** 1284fccf43aSdan ** 1 byte: Either SQLITE_INSERT, UPDATE or DELETE. 1295d607a6eSdan ** 1 byte: The "indirect-change" flag. 1304fccf43aSdan ** old.* record: (delete and update only) 1314fccf43aSdan ** new.* record: (insert and update only) 1324fccf43aSdan */ 1334fccf43aSdan 1344fccf43aSdan /* 1354fccf43aSdan ** For each row modified during a session, there exists a single instance of 1364fccf43aSdan ** this structure stored in a SessionTable.aChange[] hash table. 1374fccf43aSdan */ 1384fccf43aSdan struct SessionChange { 139798693b2Sdan int op; /* One of UPDATE, DELETE, INSERT */ 140b4480e94Sdan int bIndirect; /* True if this change is "indirect" */ 1414fccf43aSdan int nRecord; /* Number of bytes in buffer aRecord[] */ 1424fccf43aSdan u8 *aRecord; /* Buffer containing old.* record */ 1434fccf43aSdan SessionChange *pNext; /* For hash-table collisions */ 1444fccf43aSdan }; 1454fccf43aSdan 146296c7658Sdan /* 147296c7658Sdan ** Instances of this structure are used to build strings or binary records. 148296c7658Sdan */ 149296c7658Sdan struct SessionBuffer { 150296c7658Sdan u8 *aBuf; /* Pointer to changeset buffer */ 151296c7658Sdan int nBuf; /* Size of buffer aBuf */ 152296c7658Sdan int nAlloc; /* Size of allocation containing aBuf */ 153296c7658Sdan }; 1544fccf43aSdan 155296c7658Sdan /* 156296c7658Sdan ** Write a varint with value iVal into the buffer at aBuf. Return the 157296c7658Sdan ** number of bytes written. 158296c7658Sdan */ 159296c7658Sdan static int sessionVarintPut(u8 *aBuf, int iVal){ 160296c7658Sdan return putVarint32(aBuf, iVal); 1614fccf43aSdan } 1624fccf43aSdan 163296c7658Sdan /* 164296c7658Sdan ** Return the number of bytes required to store value iVal as a varint. 165296c7658Sdan */ 166296c7658Sdan static int sessionVarintLen(int iVal){ 167296c7658Sdan return sqlite3VarintLen(iVal); 168296c7658Sdan } 169296c7658Sdan 170296c7658Sdan /* 171296c7658Sdan ** Read a varint value from aBuf[] into *piVal. Return the number of 172296c7658Sdan ** bytes read. 173296c7658Sdan */ 1744fccf43aSdan static int sessionVarintGet(u8 *aBuf, int *piVal){ 175296c7658Sdan return getVarint32(aBuf, *piVal); 1764fccf43aSdan } 1774fccf43aSdan 178296c7658Sdan /* 179296c7658Sdan ** Read a 64-bit big-endian integer value from buffer aRec[]. Return 180296c7658Sdan ** the value read. 181296c7658Sdan */ 1824fccf43aSdan static sqlite3_int64 sessionGetI64(u8 *aRec){ 1834fccf43aSdan return (((sqlite3_int64)aRec[0]) << 56) 1844fccf43aSdan + (((sqlite3_int64)aRec[1]) << 48) 1854fccf43aSdan + (((sqlite3_int64)aRec[2]) << 40) 1864fccf43aSdan + (((sqlite3_int64)aRec[3]) << 32) 1874fccf43aSdan + (((sqlite3_int64)aRec[4]) << 24) 1884fccf43aSdan + (((sqlite3_int64)aRec[5]) << 16) 1894fccf43aSdan + (((sqlite3_int64)aRec[6]) << 8) 1904fccf43aSdan + (((sqlite3_int64)aRec[7]) << 0); 1914fccf43aSdan } 1924fccf43aSdan 1934fccf43aSdan /* 194296c7658Sdan ** Write a 64-bit big-endian integer value to the buffer aBuf[]. 195296c7658Sdan */ 196296c7658Sdan static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){ 197296c7658Sdan aBuf[0] = (i>>56) & 0xFF; 198296c7658Sdan aBuf[1] = (i>>48) & 0xFF; 199296c7658Sdan aBuf[2] = (i>>40) & 0xFF; 200296c7658Sdan aBuf[3] = (i>>32) & 0xFF; 201296c7658Sdan aBuf[4] = (i>>24) & 0xFF; 202296c7658Sdan aBuf[5] = (i>>16) & 0xFF; 203296c7658Sdan aBuf[6] = (i>> 8) & 0xFF; 204296c7658Sdan aBuf[7] = (i>> 0) & 0xFF; 205296c7658Sdan } 206296c7658Sdan 207296c7658Sdan /* 2084fccf43aSdan ** This function is used to serialize the contents of value pValue (see 2094fccf43aSdan ** comment titled "RECORD FORMAT" above). 2104fccf43aSdan ** 2114fccf43aSdan ** If it is non-NULL, the serialized form of the value is written to 2124fccf43aSdan ** buffer aBuf. *pnWrite is set to the number of bytes written before 2134fccf43aSdan ** returning. Or, if aBuf is NULL, the only thing this function does is 2144fccf43aSdan ** set *pnWrite. 2154fccf43aSdan ** 2164fccf43aSdan ** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs 2174fccf43aSdan ** within a call to sqlite3_value_text() (may fail if the db is utf-16)) 2184fccf43aSdan ** SQLITE_NOMEM is returned. 2194fccf43aSdan */ 2204fccf43aSdan static int sessionSerializeValue( 2214fccf43aSdan u8 *aBuf, /* If non-NULL, write serialized value here */ 2224fccf43aSdan sqlite3_value *pValue, /* Value to serialize */ 2234fccf43aSdan int *pnWrite /* IN/OUT: Increment by bytes written */ 2244fccf43aSdan ){ 225296c7658Sdan int nByte; /* Size of serialized value in bytes */ 2264fccf43aSdan 22780fe2d93Sdan if( pValue ){ 22880fe2d93Sdan int eType; /* Value type (SQLITE_NULL, TEXT etc.) */ 22980fe2d93Sdan 2304fccf43aSdan eType = sqlite3_value_type(pValue); 2314fccf43aSdan if( aBuf ) aBuf[0] = eType; 2324fccf43aSdan 2334fccf43aSdan switch( eType ){ 2344fccf43aSdan case SQLITE_NULL: 2354fccf43aSdan nByte = 1; 2364fccf43aSdan break; 2374fccf43aSdan 2384fccf43aSdan case SQLITE_INTEGER: 2394fccf43aSdan case SQLITE_FLOAT: 2404fccf43aSdan if( aBuf ){ 2414fccf43aSdan /* TODO: SQLite does something special to deal with mixed-endian 2424fccf43aSdan ** floating point values (e.g. ARM7). This code probably should 2434fccf43aSdan ** too. */ 2444fccf43aSdan u64 i; 2454fccf43aSdan if( eType==SQLITE_INTEGER ){ 2464fccf43aSdan i = (u64)sqlite3_value_int64(pValue); 2474fccf43aSdan }else{ 2484fccf43aSdan double r; 2494fccf43aSdan assert( sizeof(double)==8 && sizeof(u64)==8 ); 2504fccf43aSdan r = sqlite3_value_double(pValue); 2514fccf43aSdan memcpy(&i, &r, 8); 2524fccf43aSdan } 253296c7658Sdan sessionPutI64(&aBuf[1], i); 2544fccf43aSdan } 2554fccf43aSdan nByte = 9; 2564fccf43aSdan break; 2574fccf43aSdan 2584e895da1Sdan default: { 25980fe2d93Sdan u8 *z; 26080fe2d93Sdan int n; 26180fe2d93Sdan int nVarint; 26280fe2d93Sdan 2634e895da1Sdan assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); 26480fe2d93Sdan if( eType==SQLITE_TEXT ){ 26580fe2d93Sdan z = (u8 *)sqlite3_value_text(pValue); 26680fe2d93Sdan }else{ 26780fe2d93Sdan z = (u8 *)sqlite3_value_blob(pValue); 26880fe2d93Sdan } 26980fe2d93Sdan if( z==0 ) return SQLITE_NOMEM; 27080fe2d93Sdan n = sqlite3_value_bytes(pValue); 27180fe2d93Sdan nVarint = sessionVarintLen(n); 27280fe2d93Sdan 2734fccf43aSdan if( aBuf ){ 2744fccf43aSdan sessionVarintPut(&aBuf[1], n); 2754fccf43aSdan memcpy(&aBuf[nVarint + 1], eType==SQLITE_TEXT ? 2764fccf43aSdan sqlite3_value_text(pValue) : sqlite3_value_blob(pValue), n 2774fccf43aSdan ); 2784fccf43aSdan } 2794fccf43aSdan 2804fccf43aSdan nByte = 1 + nVarint + n; 2814fccf43aSdan break; 2824fccf43aSdan } 2834fccf43aSdan } 28480fe2d93Sdan }else{ 28580fe2d93Sdan nByte = 1; 28680fe2d93Sdan if( aBuf ) aBuf[0] = '\0'; 28780fe2d93Sdan } 2884fccf43aSdan 2894fccf43aSdan *pnWrite += nByte; 2904fccf43aSdan return SQLITE_OK; 2914fccf43aSdan } 2924fccf43aSdan 293798693b2Sdan /* 294798693b2Sdan ** This macro is used to calculate hash key values for data structures. In 295798693b2Sdan ** order to use this macro, the entire data structure must be represented 296798693b2Sdan ** as a series of unsigned integers. In order to calculate a hash-key value 297798693b2Sdan ** for a data structure represented as three such integers, the macro may 298798693b2Sdan ** then be used as follows: 299798693b2Sdan ** 300798693b2Sdan ** int hash_key_value; 301798693b2Sdan ** hash_key_value = HASH_APPEND(0, <value 1>); 302798693b2Sdan ** hash_key_value = HASH_APPEND(hash_key_value, <value 2>); 303798693b2Sdan ** hash_key_value = HASH_APPEND(hash_key_value, <value 3>); 304798693b2Sdan ** 305798693b2Sdan ** In practice, the data structures this macro is used for are the primary 306798693b2Sdan ** key values of modified rows. 307798693b2Sdan */ 3084131639cSdan #define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add) 309798693b2Sdan 310798693b2Sdan /* 311798693b2Sdan ** Append the hash of the 64-bit integer passed as the second argument to the 312798693b2Sdan ** hash-key value passed as the first. Return the new hash-key value. 313798693b2Sdan */ 3144131639cSdan static unsigned int sessionHashAppendI64(unsigned int h, i64 i){ 315e8d5648eSdan h = HASH_APPEND(h, i & 0xFFFFFFFF); 316e8d5648eSdan return HASH_APPEND(h, (i>>32)&0xFFFFFFFF); 317e8d5648eSdan } 318798693b2Sdan 319798693b2Sdan /* 320798693b2Sdan ** Append the hash of the blob passed via the second and third arguments to 321798693b2Sdan ** the hash-key value passed as the first. Return the new hash-key value. 322798693b2Sdan */ 3234131639cSdan static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){ 324e8d5648eSdan int i; 325e8d5648eSdan for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]); 326e8d5648eSdan return h; 327e8d5648eSdan } 328e8d5648eSdan 3294fccf43aSdan /* 330798693b2Sdan ** Append the hash of the data type passed as the second argument to the 331798693b2Sdan ** hash-key value passed as the first. Return the new hash-key value. 332798693b2Sdan */ 333798693b2Sdan static unsigned int sessionHashAppendType(unsigned int h, int eType){ 334798693b2Sdan return HASH_APPEND(h, eType); 335798693b2Sdan } 336798693b2Sdan 337798693b2Sdan /* 3384131639cSdan ** This function may only be called from within a pre-update callback. 3394131639cSdan ** It calculates a hash based on the primary key values of the old.* or 340798693b2Sdan ** new.* row currently available and, assuming no error occurs, writes it to 341798693b2Sdan ** *piHash before returning. If the primary key contains one or more NULL 342798693b2Sdan ** values, *pbNullPK is set to true before returning. 343798693b2Sdan ** 344798693b2Sdan ** If an error occurs, an SQLite error code is returned and the final values 345798693b2Sdan ** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned 346798693b2Sdan ** and the output variables are set as described above. 3474fccf43aSdan */ 348798693b2Sdan static int sessionPreupdateHash( 349e8d5648eSdan sqlite3 *db, /* Database handle */ 350e8d5648eSdan SessionTable *pTab, /* Session table handle */ 351e8d5648eSdan int bNew, /* True to hash the new.* PK */ 35227453faeSdan int *piHash, /* OUT: Hash value */ 353798693b2Sdan int *pbNullPK /* OUT: True if there are NULL values in PK */ 354e8d5648eSdan ){ 3554131639cSdan unsigned int h = 0; /* Hash value to return */ 3564131639cSdan int i; /* Used to iterate through columns */ 357e8d5648eSdan 35827453faeSdan assert( *pbNullPK==0 ); 359e8d5648eSdan assert( pTab->nCol==sqlite3_preupdate_count(db) ); 360e8d5648eSdan for(i=0; i<pTab->nCol; i++){ 361e8d5648eSdan if( pTab->abPK[i] ){ 362e8d5648eSdan int rc; 363e8d5648eSdan int eType; 364e8d5648eSdan sqlite3_value *pVal; 365e8d5648eSdan 366e8d5648eSdan if( bNew ){ 367e8d5648eSdan rc = sqlite3_preupdate_new(db, i, &pVal); 368e8d5648eSdan }else{ 369e8d5648eSdan rc = sqlite3_preupdate_old(db, i, &pVal); 370e8d5648eSdan } 37112ca0b56Sdan if( rc!=SQLITE_OK ) return rc; 372e8d5648eSdan 373e8d5648eSdan eType = sqlite3_value_type(pVal); 374798693b2Sdan h = sessionHashAppendType(h, eType); 3756734007dSdan if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ 376e8d5648eSdan i64 iVal; 377e8d5648eSdan if( eType==SQLITE_INTEGER ){ 378e8d5648eSdan iVal = sqlite3_value_int64(pVal); 379e8d5648eSdan }else{ 380e8d5648eSdan double rVal = sqlite3_value_double(pVal); 381e8d5648eSdan assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); 382e8d5648eSdan memcpy(&iVal, &rVal, 8); 383e8d5648eSdan } 384e8d5648eSdan h = sessionHashAppendI64(h, iVal); 3856734007dSdan }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ 3866734007dSdan const u8 *z; 3876734007dSdan if( eType==SQLITE_TEXT ){ 3886734007dSdan z = (const u8 *)sqlite3_value_text(pVal); 3896734007dSdan }else{ 3906734007dSdan z = (const u8 *)sqlite3_value_blob(pVal); 391e8d5648eSdan } 3926734007dSdan if( !z ) return SQLITE_NOMEM; 3936734007dSdan h = sessionHashAppendBlob(h, sqlite3_value_bytes(pVal), z); 3946734007dSdan }else{ 39527453faeSdan assert( eType==SQLITE_NULL ); 39627453faeSdan *pbNullPK = 1; 397e8d5648eSdan } 398e8d5648eSdan } 399e8d5648eSdan } 400e8d5648eSdan 401e8d5648eSdan *piHash = (h % pTab->nChange); 402e8d5648eSdan return SQLITE_OK; 403e8d5648eSdan } 404e8d5648eSdan 4054131639cSdan /* 4066cda207fSdan ** The buffer that the argument points to contains a serialized SQL value. 4076cda207fSdan ** Return the number of bytes of space occupied by the value (including 4086cda207fSdan ** the type byte). 4096cda207fSdan */ 4106cda207fSdan static int sessionSerialLen(u8 *a){ 4116cda207fSdan int e = *a; 4126cda207fSdan int n; 4136cda207fSdan if( e==0 ) return 1; 4146cda207fSdan if( e==SQLITE_NULL ) return 1; 4156cda207fSdan if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9; 4166cda207fSdan return sessionVarintGet(&a[1], &n) + 1 + n; 4176cda207fSdan } 4186cda207fSdan 4196cda207fSdan /* 4205d607a6eSdan ** Based on the primary key values stored in change aRecord, calculate a 421798693b2Sdan ** hash key. Assume the has table has nBucket buckets. The hash keys 4224131639cSdan ** calculated by this function are compatible with those calculated by 4234131639cSdan ** sessionPreupdateHash(). 4244131639cSdan */ 4254131639cSdan static unsigned int sessionChangeHash( 4264131639cSdan SessionTable *pTab, /* Table handle */ 4275d607a6eSdan u8 *aRecord, /* Change record */ 4284131639cSdan int nBucket /* Assume this many buckets in hash table */ 429e8d5648eSdan ){ 4304131639cSdan unsigned int h = 0; /* Value to return */ 4314131639cSdan int i; /* Used to iterate through columns */ 4325d607a6eSdan u8 *a = aRecord; /* Used to iterate through change record */ 433e8d5648eSdan 434e8d5648eSdan for(i=0; i<pTab->nCol; i++){ 4356cda207fSdan int eType = *a; 436e8d5648eSdan int isPK = pTab->abPK[i]; 437e8d5648eSdan 43827453faeSdan /* It is not possible for eType to be SQLITE_NULL here. The session 43927453faeSdan ** module does not record changes for rows with NULL values stored in 44027453faeSdan ** primary key columns. */ 44127453faeSdan assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT 44227453faeSdan || eType==SQLITE_TEXT || eType==SQLITE_BLOB 4436cda207fSdan || eType==SQLITE_NULL || eType==0 44427453faeSdan ); 4456cda207fSdan assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) ); 44627453faeSdan 4476cda207fSdan if( isPK ){ 4486cda207fSdan a++; 449798693b2Sdan h = sessionHashAppendType(h, eType); 45027453faeSdan if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ 4516734007dSdan h = sessionHashAppendI64(h, sessionGetI64(a)); 452e8d5648eSdan a += 8; 45327453faeSdan }else{ 454e8d5648eSdan int n; 455e8d5648eSdan a += sessionVarintGet(a, &n); 4566734007dSdan h = sessionHashAppendBlob(h, n, a); 457e8d5648eSdan a += n; 458e8d5648eSdan } 4596cda207fSdan }else{ 4606cda207fSdan a += sessionSerialLen(a); 4616cda207fSdan } 462e8d5648eSdan } 463e8d5648eSdan return (h % nBucket); 464e8d5648eSdan } 465e8d5648eSdan 466798693b2Sdan /* 467798693b2Sdan ** Arguments aLeft and aRight are pointers to change records for table pTab. 468798693b2Sdan ** This function returns true if the two records apply to the same row (i.e. 469798693b2Sdan ** have the same values stored in the primary key columns), or false 470798693b2Sdan ** otherwise. 471798693b2Sdan */ 4725d607a6eSdan static int sessionChangeEqual( 473798693b2Sdan SessionTable *pTab, /* Table used for PK definition */ 4745d607a6eSdan u8 *aLeft, /* Change record */ 4755d607a6eSdan u8 *aRight /* Change record */ 4765d607a6eSdan ){ 477798693b2Sdan u8 *a1 = aLeft; /* Cursor to iterate through aLeft */ 478798693b2Sdan u8 *a2 = aRight; /* Cursor to iterate through aRight */ 479798693b2Sdan int iCol; /* Used to iterate through table columns */ 4805d607a6eSdan 481798693b2Sdan for(iCol=0; iCol<pTab->nCol; iCol++){ 4825d607a6eSdan int n1 = sessionSerialLen(a1); 4835d607a6eSdan int n2 = sessionSerialLen(a2); 4845d607a6eSdan 485798693b2Sdan if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){ 4865d607a6eSdan return 0; 4875d607a6eSdan } 4885d607a6eSdan a1 += n1; 4896cda207fSdan a2 += n2; 4905d607a6eSdan } 4915d607a6eSdan 4925d607a6eSdan return 1; 4935d607a6eSdan } 4945d607a6eSdan 495798693b2Sdan /* 496798693b2Sdan ** Arguments aLeft and aRight both point to buffers containing change 497798693b2Sdan ** records with nCol columns. This function "merges" the two records into 498798693b2Sdan ** a single records which is written to the buffer at *paOut. *paOut is 499798693b2Sdan ** then set to point to one byte after the last byte written before 500798693b2Sdan ** returning. 501798693b2Sdan ** 502798693b2Sdan ** The merging of records is done as follows: For each column, if the 503798693b2Sdan ** aRight record contains a value for the column, copy the value from 504798693b2Sdan ** their. Otherwise, if aLeft contains a value, copy it. If neither 505798693b2Sdan ** record contains a value for a given column, then neither does the 506798693b2Sdan ** output record. 507798693b2Sdan */ 5085d607a6eSdan static void sessionMergeRecord( 5095d607a6eSdan u8 **paOut, 510798693b2Sdan int nCol, 5115d607a6eSdan u8 *aLeft, 5125d607a6eSdan u8 *aRight 5135d607a6eSdan ){ 514798693b2Sdan u8 *a1 = aLeft; /* Cursor used to iterate through aLeft */ 515798693b2Sdan u8 *a2 = aRight; /* Cursor used to iterate through aRight */ 516798693b2Sdan u8 *aOut = *paOut; /* Output cursor */ 517798693b2Sdan int iCol; /* Used to iterate from 0 to nCol */ 5185d607a6eSdan 519798693b2Sdan for(iCol=0; iCol<nCol; iCol++){ 5205d607a6eSdan int n1 = sessionSerialLen(a1); 5215d607a6eSdan int n2 = sessionSerialLen(a2); 5225d607a6eSdan if( *a2 ){ 5235d607a6eSdan memcpy(aOut, a2, n2); 5245d607a6eSdan aOut += n2; 5255d607a6eSdan }else{ 5265d607a6eSdan memcpy(aOut, a1, n1); 5275d607a6eSdan aOut += n1; 5285d607a6eSdan } 5295d607a6eSdan a1 += n1; 5305d607a6eSdan a2 += n2; 5315d607a6eSdan } 5325d607a6eSdan 5335d607a6eSdan *paOut = aOut; 5345d607a6eSdan } 5355d607a6eSdan 536798693b2Sdan /* 537798693b2Sdan ** This is a helper function used by sessionMergeUpdate(). 538798693b2Sdan ** 539798693b2Sdan ** When this function is called, both *paOne and *paTwo point to a value 540798693b2Sdan ** within a change record. Before it returns, both have been advanced so 541798693b2Sdan ** as to point to the next value in the record. 542798693b2Sdan ** 543798693b2Sdan ** If, when this function is called, *paTwo points to a valid value (i.e. 544798693b2Sdan ** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paOne 545798693b2Sdan ** pointer is returned and *pnVal is set to the number of bytes in the 546798693b2Sdan ** serialized value. Otherwise, a copy of *paOne is returned and *pnVal 547798693b2Sdan ** set to the number of bytes in the value at *paOne. If *paOne points 548798693b2Sdan ** to the "no value" placeholder, *pnVal is set to 1. 549798693b2Sdan */ 5505d607a6eSdan static u8 *sessionMergeValue( 551798693b2Sdan u8 **paOne, /* IN/OUT: Left-hand buffer pointer */ 552798693b2Sdan u8 **paTwo, /* IN/OUT: Right-hand buffer pointer */ 553798693b2Sdan int *pnVal /* OUT: Bytes in returned value */ 5545d607a6eSdan ){ 5555d607a6eSdan u8 *a1 = *paOne; 5565d607a6eSdan u8 *a2 = *paTwo; 5575d607a6eSdan u8 *pRet = 0; 5585d607a6eSdan int n1; 5595d607a6eSdan 5605d607a6eSdan assert( a1 ); 5615d607a6eSdan if( a2 ){ 5625d607a6eSdan int n2 = sessionSerialLen(a2); 5635d607a6eSdan if( *a2 ){ 5645d607a6eSdan *pnVal = n2; 5655d607a6eSdan pRet = a2; 5665d607a6eSdan } 5675d607a6eSdan *paTwo = &a2[n2]; 5685d607a6eSdan } 5695d607a6eSdan 5705d607a6eSdan n1 = sessionSerialLen(a1); 5715d607a6eSdan if( pRet==0 ){ 5725d607a6eSdan *pnVal = n1; 5735d607a6eSdan pRet = a1; 5745d607a6eSdan } 5755d607a6eSdan *paOne = &a1[n1]; 5765d607a6eSdan 5775d607a6eSdan return pRet; 5785d607a6eSdan } 5795d607a6eSdan 580798693b2Sdan /* 581798693b2Sdan ** This function is used by changeset_concat() to merge two UPDATE changes 582798693b2Sdan ** on the same row. 583798693b2Sdan */ 5845d607a6eSdan static int sessionMergeUpdate( 585798693b2Sdan u8 **paOut, /* IN/OUT: Pointer to output buffer */ 586798693b2Sdan SessionTable *pTab, /* Table change pertains to */ 587798693b2Sdan u8 *aOldRecord1, /* old.* record for first change */ 588798693b2Sdan u8 *aOldRecord2, /* old.* record for second change */ 589798693b2Sdan u8 *aNewRecord1, /* new.* record for first change */ 590798693b2Sdan u8 *aNewRecord2 /* new.* record for second change */ 5915d607a6eSdan ){ 5925d607a6eSdan u8 *aOld1 = aOldRecord1; 5935d607a6eSdan u8 *aOld2 = aOldRecord2; 5945d607a6eSdan u8 *aNew1 = aNewRecord1; 5955d607a6eSdan u8 *aNew2 = aNewRecord2; 5965d607a6eSdan 5975d607a6eSdan u8 *aOut = *paOut; 5985d607a6eSdan int i; 5995d607a6eSdan int bRequired = 0; 6005d607a6eSdan 6015d607a6eSdan assert( aOldRecord1 && aNewRecord1 ); 6025d607a6eSdan 6035d607a6eSdan /* Write the old.* vector first. */ 6045d607a6eSdan for(i=0; i<pTab->nCol; i++){ 6055d607a6eSdan int nOld; 6065d607a6eSdan u8 *aOld; 6075d607a6eSdan int nNew; 6085d607a6eSdan u8 *aNew; 6095d607a6eSdan 6105d607a6eSdan aOld = sessionMergeValue(&aOld1, &aOld2, &nOld); 6115d607a6eSdan aNew = sessionMergeValue(&aNew1, &aNew2, &nNew); 6125d607a6eSdan if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){ 6135d607a6eSdan if( pTab->abPK[i]==0 ) bRequired = 1; 6145d607a6eSdan memcpy(aOut, aOld, nOld); 6155d607a6eSdan aOut += nOld; 6165d607a6eSdan }else{ 6175d607a6eSdan *(aOut++) = '\0'; 6185d607a6eSdan } 6195d607a6eSdan } 6205d607a6eSdan 6215d607a6eSdan if( !bRequired ) return 0; 6225d607a6eSdan 6235d607a6eSdan /* Write the new.* vector */ 6245d607a6eSdan aOld1 = aOldRecord1; 6255d607a6eSdan aOld2 = aOldRecord2; 6265d607a6eSdan aNew1 = aNewRecord1; 6275d607a6eSdan aNew2 = aNewRecord2; 6285d607a6eSdan for(i=0; i<pTab->nCol; i++){ 6295d607a6eSdan int nOld; 6305d607a6eSdan u8 *aOld; 6315d607a6eSdan int nNew; 6325d607a6eSdan u8 *aNew; 6335d607a6eSdan 6345d607a6eSdan aOld = sessionMergeValue(&aOld1, &aOld2, &nOld); 6355d607a6eSdan aNew = sessionMergeValue(&aNew1, &aNew2, &nNew); 6365d607a6eSdan if( pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew)) ){ 6375d607a6eSdan *(aOut++) = '\0'; 6385d607a6eSdan }else{ 6395d607a6eSdan memcpy(aOut, aNew, nNew); 6405d607a6eSdan aOut += nNew; 6415d607a6eSdan } 6425d607a6eSdan } 6435d607a6eSdan 6445d607a6eSdan *paOut = aOut; 6455d607a6eSdan return 1; 6465d607a6eSdan } 6475d607a6eSdan 64877fc1d5bSdan /* 64977fc1d5bSdan ** This function is only called from within a pre-update-hook callback. 65077fc1d5bSdan ** It determines if the current pre-update-hook change affects the same row 65177fc1d5bSdan ** as the change stored in argument pChange. If so, it returns true. Otherwise 65277fc1d5bSdan ** if the pre-update-hook does not affect the same row as pChange, it returns 65377fc1d5bSdan ** false. 65477fc1d5bSdan */ 65577fc1d5bSdan static int sessionPreupdateEqual( 65677fc1d5bSdan sqlite3 *db, /* Database handle */ 65777fc1d5bSdan SessionTable *pTab, /* Table associated with change */ 65877fc1d5bSdan SessionChange *pChange, /* Change to compare to */ 65977fc1d5bSdan int op /* Current pre-update operation */ 660e8d5648eSdan ){ 66177fc1d5bSdan int iCol; /* Used to iterate through columns */ 66277fc1d5bSdan u8 *a = pChange->aRecord; /* Cursor used to scan change record */ 663e8d5648eSdan 66477fc1d5bSdan assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 66577fc1d5bSdan for(iCol=0; iCol<pTab->nCol; iCol++){ 66677fc1d5bSdan if( !pTab->abPK[iCol] ){ 667798693b2Sdan a += sessionSerialLen(a); 668e8d5648eSdan }else{ 6696734007dSdan sqlite3_value *pVal; /* Value returned by preupdate_new/old */ 6706734007dSdan int rc; /* Error code from preupdate_new/old */ 671798693b2Sdan int eType = *a++; /* Type of value from change record */ 6726734007dSdan 6736734007dSdan /* The following calls to preupdate_new() and preupdate_old() can not 6746734007dSdan ** fail. This is because they cache their return values, and by the 6756734007dSdan ** time control flows to here they have already been called once from 6766734007dSdan ** within sessionPreupdateHash(). The first two asserts below verify 6776734007dSdan ** this (that the method has already been called). */ 67877fc1d5bSdan if( op==SQLITE_INSERT ){ 6796734007dSdan assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); 68077fc1d5bSdan rc = sqlite3_preupdate_new(db, iCol, &pVal); 681e8d5648eSdan }else{ 6826734007dSdan assert( db->pPreUpdate->pUnpacked ); 68377fc1d5bSdan rc = sqlite3_preupdate_old(db, iCol, &pVal); 684e8d5648eSdan } 6856734007dSdan assert( rc==SQLITE_OK ); 68677fc1d5bSdan if( sqlite3_value_type(pVal)!=eType ) return 0; 687e8d5648eSdan 68812ca0b56Sdan /* A SessionChange object never has a NULL value in a PK column */ 68912ca0b56Sdan assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT 69012ca0b56Sdan || eType==SQLITE_BLOB || eType==SQLITE_TEXT 69112ca0b56Sdan ); 69212ca0b56Sdan 69312ca0b56Sdan if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ 694e8d5648eSdan i64 iVal = sessionGetI64(a); 695e8d5648eSdan a += 8; 696e8d5648eSdan if( eType==SQLITE_INTEGER ){ 69777fc1d5bSdan if( sqlite3_value_int64(pVal)!=iVal ) return 0; 698e8d5648eSdan }else{ 699e8d5648eSdan double rVal; 700e8d5648eSdan assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); 701e8d5648eSdan memcpy(&rVal, &iVal, 8); 70277fc1d5bSdan if( sqlite3_value_double(pVal)!=rVal ) return 0; 703e8d5648eSdan } 70412ca0b56Sdan }else{ 705e8d5648eSdan int n; 706e8d5648eSdan const u8 *z; 707e8d5648eSdan a += sessionVarintGet(a, &n); 70877fc1d5bSdan if( sqlite3_value_bytes(pVal)!=n ) return 0; 70912ca0b56Sdan if( eType==SQLITE_TEXT ){ 71012ca0b56Sdan z = sqlite3_value_text(pVal); 71112ca0b56Sdan }else{ 71212ca0b56Sdan z = sqlite3_value_blob(pVal); 71312ca0b56Sdan } 71477fc1d5bSdan if( memcmp(a, z, n) ) return 0; 715e8d5648eSdan a += n; 716e8d5648eSdan break; 717e8d5648eSdan } 718e8d5648eSdan } 719e8d5648eSdan } 720e8d5648eSdan 72177fc1d5bSdan return 1; 7224fccf43aSdan } 7234fccf43aSdan 7244fccf43aSdan /* 7254fccf43aSdan ** If required, grow the hash table used to store changes on table pTab 7264fccf43aSdan ** (part of the session pSession). If a fatal OOM error occurs, set the 7274fccf43aSdan ** session object to failed and return SQLITE_ERROR. Otherwise, return 7284fccf43aSdan ** SQLITE_OK. 7294fccf43aSdan ** 7304fccf43aSdan ** It is possible that a non-fatal OOM error occurs in this function. In 7314fccf43aSdan ** that case the hash-table does not grow, but SQLITE_OK is returned anyway. 7324fccf43aSdan ** Growing the hash table in this case is a performance optimization only, 7334fccf43aSdan ** it is not required for correct operation. 7344fccf43aSdan */ 7355d607a6eSdan static int sessionGrowHash(SessionTable *pTab){ 7364fccf43aSdan if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){ 7374fccf43aSdan int i; 7384fccf43aSdan SessionChange **apNew; 7394fccf43aSdan int nNew = (pTab->nChange ? pTab->nChange : 128) * 2; 7404fccf43aSdan 7414fccf43aSdan apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew); 7424fccf43aSdan if( apNew==0 ){ 7434fccf43aSdan if( pTab->nChange==0 ){ 7444fccf43aSdan return SQLITE_ERROR; 7454fccf43aSdan } 7464fccf43aSdan return SQLITE_OK; 7474fccf43aSdan } 7484fccf43aSdan memset(apNew, 0, sizeof(SessionChange *) * nNew); 7494fccf43aSdan 7504fccf43aSdan for(i=0; i<pTab->nChange; i++){ 7514fccf43aSdan SessionChange *p; 7524fccf43aSdan SessionChange *pNext; 7534fccf43aSdan for(p=pTab->apChange[i]; p; p=pNext){ 7545d607a6eSdan int iHash = sessionChangeHash(pTab, p->aRecord, nNew); 7554fccf43aSdan pNext = p->pNext; 7564fccf43aSdan p->pNext = apNew[iHash]; 7574fccf43aSdan apNew[iHash] = p; 7584fccf43aSdan } 7594fccf43aSdan } 7604fccf43aSdan 7614fccf43aSdan sqlite3_free(pTab->apChange); 7624fccf43aSdan pTab->nChange = nNew; 7634fccf43aSdan pTab->apChange = apNew; 7644fccf43aSdan } 7654fccf43aSdan 7664fccf43aSdan return SQLITE_OK; 7674fccf43aSdan } 7684fccf43aSdan 769296c7658Sdan /* 770e8d5648eSdan ** This function queries the database for the names of the columns of table 771e8d5648eSdan ** zThis, in schema zDb. It is expected that the table has nCol columns. If 772e8d5648eSdan ** not, SQLITE_SCHEMA is returned and none of the output variables are 773e8d5648eSdan ** populated. 774e8d5648eSdan ** 77577fc1d5bSdan ** Otherwise, if they are not NULL, variable *pnCol is set to the number 77677fc1d5bSdan ** of columns in the database table and variable *pzTab is set to point to a 777e8d5648eSdan ** nul-terminated copy of the table name. *pazCol (if not NULL) is set to 778e8d5648eSdan ** point to an array of pointers to column names. And *pabPK (again, if not 779e8d5648eSdan ** NULL) is set to point to an array of booleans - true if the corresponding 780e8d5648eSdan ** column is part of the primary key. 781e8d5648eSdan ** 782e8d5648eSdan ** For example, if the table is declared as: 783e8d5648eSdan ** 784e8d5648eSdan ** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z)); 785e8d5648eSdan ** 78677fc1d5bSdan ** Then the four output variables are populated as follows: 787e8d5648eSdan ** 78877fc1d5bSdan ** *pnCol = 4 789e8d5648eSdan ** *pzTab = "tbl1" 790e8d5648eSdan ** *pazCol = {"w", "x", "y", "z"} 791e8d5648eSdan ** *pabPK = {1, 0, 0, 1} 792e8d5648eSdan ** 793e8d5648eSdan ** All returned buffers are part of the same single allocation, which must 794e8d5648eSdan ** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then 795e8d5648eSdan ** pointer *pazCol should be freed to release all memory. Otherwise, pointer 796e8d5648eSdan ** *pabPK. It is illegal for both pazCol and pabPK to be NULL. 797e8d5648eSdan */ 798e8d5648eSdan static int sessionTableInfo( 799e8d5648eSdan sqlite3 *db, /* Database connection */ 800e8d5648eSdan const char *zDb, /* Name of attached database (e.g. "main") */ 801e8d5648eSdan const char *zThis, /* Table name */ 802ca62ad57Sdan int *pnCol, /* OUT: number of columns */ 803e8d5648eSdan const char **pzTab, /* OUT: Copy of zThis */ 804e8d5648eSdan const char ***pazCol, /* OUT: Array of column names for table */ 805e8d5648eSdan u8 **pabPK /* OUT: Array of booleans - true for PK col */ 806e8d5648eSdan ){ 807e8d5648eSdan char *zPragma; 808e8d5648eSdan sqlite3_stmt *pStmt; 809e8d5648eSdan int rc; 810e8d5648eSdan int nByte; 811e8d5648eSdan int nDbCol = 0; 812e8d5648eSdan int nThis; 813e8d5648eSdan int i; 814e8d5648eSdan u8 *pAlloc; 815db04571cSdan char **azCol = 0; 816e8d5648eSdan u8 *abPK; 817e8d5648eSdan 818db04571cSdan assert( pazCol && pabPK ); 819e8d5648eSdan 820cfdbde21Sdrh nThis = sqlite3Strlen30(zThis); 821e8d5648eSdan zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); 822e8d5648eSdan if( !zPragma ) return SQLITE_NOMEM; 823e8d5648eSdan 824e8d5648eSdan rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); 825e8d5648eSdan sqlite3_free(zPragma); 826e8d5648eSdan if( rc!=SQLITE_OK ) return rc; 827e8d5648eSdan 828e8d5648eSdan nByte = nThis + 1; 829e8d5648eSdan while( SQLITE_ROW==sqlite3_step(pStmt) ){ 830e8d5648eSdan nByte += sqlite3_column_bytes(pStmt, 1); 831e8d5648eSdan nDbCol++; 832e8d5648eSdan } 833e8d5648eSdan rc = sqlite3_reset(pStmt); 834e8d5648eSdan 835e8d5648eSdan if( rc==SQLITE_OK ){ 836e8d5648eSdan nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); 837e8d5648eSdan pAlloc = sqlite3_malloc(nByte); 838e8d5648eSdan if( pAlloc==0 ){ 839e8d5648eSdan rc = SQLITE_NOMEM; 840e8d5648eSdan } 841e8d5648eSdan } 842e8d5648eSdan if( rc==SQLITE_OK ){ 843e8d5648eSdan azCol = (char **)pAlloc; 844ca62ad57Sdan pAlloc = (u8 *)&azCol[nDbCol]; 845e8d5648eSdan abPK = (u8 *)pAlloc; 846ca62ad57Sdan pAlloc = &abPK[nDbCol]; 847e8d5648eSdan if( pzTab ){ 848e8d5648eSdan memcpy(pAlloc, zThis, nThis+1); 849e8d5648eSdan *pzTab = (char *)pAlloc; 850e8d5648eSdan pAlloc += nThis+1; 851e8d5648eSdan } 852e8d5648eSdan 853e8d5648eSdan i = 0; 854e8d5648eSdan while( SQLITE_ROW==sqlite3_step(pStmt) ){ 855e8d5648eSdan int nName = sqlite3_column_bytes(pStmt, 1); 856e8d5648eSdan const unsigned char *zName = sqlite3_column_text(pStmt, 1); 857e8d5648eSdan if( zName==0 ) break; 858e8d5648eSdan memcpy(pAlloc, zName, nName+1); 859e8d5648eSdan azCol[i] = (char *)pAlloc; 860e8d5648eSdan pAlloc += nName+1; 861db04571cSdan abPK[i] = sqlite3_column_int(pStmt, 5); 862e8d5648eSdan i++; 863e8d5648eSdan } 864e8d5648eSdan rc = sqlite3_reset(pStmt); 865e8d5648eSdan 866e8d5648eSdan } 867e8d5648eSdan 868e8d5648eSdan /* If successful, populate the output variables. Otherwise, zero them and 869e8d5648eSdan ** free any allocation made. An error code will be returned in this case. 870e8d5648eSdan */ 871e8d5648eSdan if( rc==SQLITE_OK ){ 872db04571cSdan *pazCol = (const char **)azCol; 873db04571cSdan *pabPK = abPK; 874ca62ad57Sdan *pnCol = nDbCol; 875e8d5648eSdan }else{ 876db04571cSdan *pazCol = 0; 877db04571cSdan *pabPK = 0; 878ca62ad57Sdan *pnCol = 0; 879e8d5648eSdan if( pzTab ) *pzTab = 0; 880db04571cSdan sqlite3_free(azCol); 881e8d5648eSdan } 882e8d5648eSdan sqlite3_finalize(pStmt); 883e8d5648eSdan return rc; 884e8d5648eSdan } 885e8d5648eSdan 886e8d5648eSdan /* 887296c7658Sdan ** This function is only called from within a pre-update handler for a 888296c7658Sdan ** write to table pTab, part of session pSession. If this is the first 889296c7658Sdan ** write to this table, set the SessionTable.nCol variable to the number 890296c7658Sdan ** of columns in the table. 891296c7658Sdan ** 892296c7658Sdan ** Otherwise, if this is not the first time this table has been written 893296c7658Sdan ** to, check that the number of columns in the table has not changed. If 894296c7658Sdan ** it has not, return zero. 895296c7658Sdan ** 896296c7658Sdan ** If the number of columns in the table has changed since the last write 897296c7658Sdan ** was recorded, set the session error-code to SQLITE_SCHEMA and return 898296c7658Sdan ** non-zero. Users are not allowed to change the number of columns in a table 899296c7658Sdan ** for which changes are being recorded by the session module. If they do so, 900296c7658Sdan ** it is an error. 901296c7658Sdan */ 9024fccf43aSdan static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ 9034fccf43aSdan if( pTab->nCol==0 ){ 904e8d5648eSdan assert( pTab->azCol==0 || pTab->abPK==0 ); 905e8d5648eSdan pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, 906ca62ad57Sdan pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->abPK 907e8d5648eSdan ); 908ca62ad57Sdan } 909ca62ad57Sdan if( pSession->rc==SQLITE_OK 910ca62ad57Sdan && pTab->nCol!=sqlite3_preupdate_count(pSession->db) 911ca62ad57Sdan ){ 9124fccf43aSdan pSession->rc = SQLITE_SCHEMA; 9134fccf43aSdan } 914e8d5648eSdan return pSession->rc; 915e8d5648eSdan } 916e8d5648eSdan 91777fc1d5bSdan /* 91877fc1d5bSdan ** This function is only called from with a pre-update-hook reporting a 91977fc1d5bSdan ** change on table pTab (attached to session pSession). The type of change 92077fc1d5bSdan ** (UPDATE, INSERT, DELETE) is specified by the first argument. 92177fc1d5bSdan ** 92277fc1d5bSdan ** Unless one is already present or an error occurs, an entry is added 92377fc1d5bSdan ** to the changed-rows hash table associated with table pTab. 92477fc1d5bSdan */ 925e8d5648eSdan static void sessionPreupdateOneChange( 92677fc1d5bSdan int op, /* One of SQLITE_UPDATE, INSERT, DELETE */ 92777fc1d5bSdan sqlite3_session *pSession, /* Session object pTab is attached to */ 92877fc1d5bSdan SessionTable *pTab /* Table that change applies to */ 929e8d5648eSdan ){ 930e8d5648eSdan sqlite3 *db = pSession->db; 931e8d5648eSdan int iHash; 93227453faeSdan int bNullPk = 0; 933e8d5648eSdan int rc = SQLITE_OK; 934e8d5648eSdan 935e8d5648eSdan if( pSession->rc ) return; 936e8d5648eSdan 937e8d5648eSdan /* Load table details if required */ 938e8d5648eSdan if( sessionInitTable(pSession, pTab) ) return; 939e8d5648eSdan 940e8d5648eSdan /* Grow the hash table if required */ 9415d607a6eSdan if( sessionGrowHash(pTab) ){ 9425d607a6eSdan pSession->rc = SQLITE_NOMEM; 9435d607a6eSdan return; 9445d607a6eSdan } 945e8d5648eSdan 94680fe2d93Sdan /* Calculate the hash-key for this change. If the primary key of the row 94780fe2d93Sdan ** includes a NULL value, exit early. Such changes are ignored by the 94880fe2d93Sdan ** session module. */ 94927453faeSdan rc = sessionPreupdateHash(db, pTab, op==SQLITE_INSERT, &iHash, &bNullPk); 95080fe2d93Sdan if( rc!=SQLITE_OK ) goto error_out; 95180fe2d93Sdan 95280fe2d93Sdan if( bNullPk==0 ){ 95380fe2d93Sdan /* Search the hash table for an existing record for this row. */ 954b4480e94Sdan SessionChange *pC; 9556734007dSdan for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){ 95677fc1d5bSdan if( sessionPreupdateEqual(db, pTab, pC, op) ) break; 957e8d5648eSdan } 95880fe2d93Sdan 959e8d5648eSdan if( pC==0 ){ 960e8d5648eSdan /* Create a new change object containing all the old values (if 961e8d5648eSdan ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK 962e8d5648eSdan ** values (if this is an INSERT). */ 963b4480e94Sdan SessionChange *pChange; /* New change object */ 964e8d5648eSdan int nByte; /* Number of bytes to allocate */ 965e8d5648eSdan int i; /* Used to iterate through columns */ 966e8d5648eSdan 967b4480e94Sdan assert( rc==SQLITE_OK ); 968e8d5648eSdan pTab->nEntry++; 969e8d5648eSdan 970e8d5648eSdan /* Figure out how large an allocation is required */ 971e8d5648eSdan nByte = sizeof(SessionChange); 97280fe2d93Sdan for(i=0; i<pTab->nCol; i++){ 973e8d5648eSdan sqlite3_value *p = 0; 974e8d5648eSdan if( op!=SQLITE_INSERT ){ 97580fe2d93Sdan TESTONLY(int trc = ) sqlite3_preupdate_old(pSession->db, i, &p); 97680fe2d93Sdan assert( trc==SQLITE_OK ); 97780fe2d93Sdan }else if( pTab->abPK[i] ){ 97880fe2d93Sdan TESTONLY(int trc = ) sqlite3_preupdate_new(pSession->db, i, &p); 97980fe2d93Sdan assert( trc==SQLITE_OK ); 980e8d5648eSdan } 98180fe2d93Sdan 98280fe2d93Sdan /* This may fail if SQLite value p contains a utf-16 string that must 98380fe2d93Sdan ** be converted to utf-8 and an OOM error occurs while doing so. */ 984e8d5648eSdan rc = sessionSerializeValue(0, p, &nByte); 98580fe2d93Sdan if( rc!=SQLITE_OK ) goto error_out; 986e8d5648eSdan } 987e8d5648eSdan 988e8d5648eSdan /* Allocate the change object */ 989e8d5648eSdan pChange = (SessionChange *)sqlite3_malloc(nByte); 990e8d5648eSdan if( !pChange ){ 991e8d5648eSdan rc = SQLITE_NOMEM; 99280fe2d93Sdan goto error_out; 993e8d5648eSdan }else{ 994e8d5648eSdan memset(pChange, 0, sizeof(SessionChange)); 995e8d5648eSdan pChange->aRecord = (u8 *)&pChange[1]; 996e8d5648eSdan } 997e8d5648eSdan 99880fe2d93Sdan /* Populate the change object. None of the preupdate_old(), 99980fe2d93Sdan ** preupdate_new() or SerializeValue() calls below may fail as all 100080fe2d93Sdan ** required values and encodings have already been cached in memory. 100180fe2d93Sdan ** It is not possible for an OOM to occur in this block. */ 1002e8d5648eSdan nByte = 0; 100380fe2d93Sdan for(i=0; i<pTab->nCol; i++){ 1004e8d5648eSdan sqlite3_value *p = 0; 1005e8d5648eSdan if( op!=SQLITE_INSERT ){ 100680fe2d93Sdan sqlite3_preupdate_old(pSession->db, i, &p); 100780fe2d93Sdan }else if( pTab->abPK[i] ){ 100880fe2d93Sdan sqlite3_preupdate_new(pSession->db, i, &p); 1009e8d5648eSdan } 101080fe2d93Sdan sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte); 1011e8d5648eSdan } 101280fe2d93Sdan 101380fe2d93Sdan /* Add the change to the hash-table */ 1014b4480e94Sdan if( pSession->bIndirect || sqlite3_preupdate_depth(pSession->db) ){ 1015b4480e94Sdan pChange->bIndirect = 1; 1016b4480e94Sdan } 101712ca0b56Sdan pChange->nRecord = nByte; 1018798693b2Sdan pChange->op = op; 1019e8d5648eSdan pChange->pNext = pTab->apChange[iHash]; 1020e8d5648eSdan pTab->apChange[iHash] = pChange; 102180fe2d93Sdan 102280fe2d93Sdan }else if( pC->bIndirect ){ 1023b4480e94Sdan /* If the existing change is considered "indirect", but this current 1024b4480e94Sdan ** change is "direct", mark the change object as direct. */ 1025b4480e94Sdan if( sqlite3_preupdate_depth(pSession->db)==0 && pSession->bIndirect==0 ){ 1026b4480e94Sdan pC->bIndirect = 0; 1027b4480e94Sdan } 1028e8d5648eSdan } 10294fccf43aSdan } 103012ca0b56Sdan 103112ca0b56Sdan /* If an error has occurred, mark the session object as failed. */ 103280fe2d93Sdan error_out: 103312ca0b56Sdan if( rc!=SQLITE_OK ){ 103412ca0b56Sdan pSession->rc = rc; 103512ca0b56Sdan } 103627453faeSdan } 10374fccf43aSdan 10384fccf43aSdan /* 10394fccf43aSdan ** The 'pre-update' hook registered by this module with SQLite databases. 10404fccf43aSdan */ 10414fccf43aSdan static void xPreUpdate( 10424fccf43aSdan void *pCtx, /* Copy of third arg to preupdate_hook() */ 10434fccf43aSdan sqlite3 *db, /* Database handle */ 10444fccf43aSdan int op, /* SQLITE_UPDATE, DELETE or INSERT */ 10454fccf43aSdan char const *zDb, /* Database name */ 10464fccf43aSdan char const *zName, /* Table name */ 10474fccf43aSdan sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ 10484fccf43aSdan sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ 10494fccf43aSdan ){ 10504fccf43aSdan sqlite3_session *pSession; 1051cfdbde21Sdrh int nDb = sqlite3Strlen30(zDb); 1052cfdbde21Sdrh int nName = sqlite3Strlen30(zName); 10534fccf43aSdan 10544c220252Sdan assert( sqlite3_mutex_held(db->mutex) ); 10554c220252Sdan 10564fccf43aSdan for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){ 10574fccf43aSdan SessionTable *pTab; 1058296c7658Sdan 1059e8d5648eSdan /* If this session is attached to a different database ("main", "temp" 1060e8d5648eSdan ** etc.), or if it is not currently enabled, there is nothing to do. Skip 1061e8d5648eSdan ** to the next session object attached to this database. */ 1062296c7658Sdan if( pSession->bEnable==0 ) continue; 10634fccf43aSdan if( pSession->rc ) continue; 10644fccf43aSdan if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue; 1065296c7658Sdan 1066ff4d0f41Sdan for(pTab=pSession->pTable; pTab || pSession->bAutoAttach; pTab=pTab->pNext){ 1067ff4d0f41Sdan if( !pTab ){ 1068ff4d0f41Sdan /* This branch is taken if table zName has not yet been attached to 1069ff4d0f41Sdan ** this session and the auto-attach flag is set. */ 1070ff4d0f41Sdan pSession->rc = sqlite3session_attach(pSession,zName); 1071245b49b2Sdan if( pSession->rc ) break; 1072ff4d0f41Sdan pTab = pSession->pTable; 1073ff4d0f41Sdan assert( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ); 1074ff4d0f41Sdan } 1075ff4d0f41Sdan 10764fccf43aSdan if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ){ 1077e8d5648eSdan sessionPreupdateOneChange(op, pSession, pTab); 1078e8d5648eSdan if( op==SQLITE_UPDATE ){ 1079e8d5648eSdan sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab); 10804fccf43aSdan } 10814fccf43aSdan break; 10824fccf43aSdan } 10834fccf43aSdan } 10844fccf43aSdan } 1085296c7658Sdan } 10864fccf43aSdan 10874fccf43aSdan /* 10884fccf43aSdan ** Create a session object. This session object will record changes to 10894fccf43aSdan ** database zDb attached to connection db. 10904fccf43aSdan */ 10914fccf43aSdan int sqlite3session_create( 10924fccf43aSdan sqlite3 *db, /* Database handle */ 10934fccf43aSdan const char *zDb, /* Name of db (e.g. "main") */ 10944fccf43aSdan sqlite3_session **ppSession /* OUT: New session object */ 10954fccf43aSdan ){ 1096296c7658Sdan sqlite3_session *pNew; /* Newly allocated session object */ 1097296c7658Sdan sqlite3_session *pOld; /* Session object already attached to db */ 1098cfdbde21Sdrh int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */ 10994fccf43aSdan 1100296c7658Sdan /* Zero the output value in case an error occurs. */ 11014fccf43aSdan *ppSession = 0; 11024fccf43aSdan 11034fccf43aSdan /* Allocate and populate the new session object. */ 11044fccf43aSdan pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1); 11054fccf43aSdan if( !pNew ) return SQLITE_NOMEM; 11064fccf43aSdan memset(pNew, 0, sizeof(sqlite3_session)); 11074fccf43aSdan pNew->db = db; 11084fccf43aSdan pNew->zDb = (char *)&pNew[1]; 1109296c7658Sdan pNew->bEnable = 1; 11104fccf43aSdan memcpy(pNew->zDb, zDb, nDb+1); 11114fccf43aSdan 11124fccf43aSdan /* Add the new session object to the linked list of session objects 11134fccf43aSdan ** attached to database handle $db. Do this under the cover of the db 11144fccf43aSdan ** handle mutex. */ 11154fccf43aSdan sqlite3_mutex_enter(sqlite3_db_mutex(db)); 11164fccf43aSdan pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew); 11174fccf43aSdan pNew->pNext = pOld; 11184fccf43aSdan sqlite3_mutex_leave(sqlite3_db_mutex(db)); 11194fccf43aSdan 11204fccf43aSdan *ppSession = pNew; 11214fccf43aSdan return SQLITE_OK; 11224fccf43aSdan } 11234fccf43aSdan 112477fc1d5bSdan /* 112577fc1d5bSdan ** Free the list of table objects passed as the first argument. The contents 112677fc1d5bSdan ** of the changed-rows hash tables are also deleted. 112777fc1d5bSdan */ 11285d607a6eSdan void sessionDeleteTable(SessionTable *pList){ 11295d607a6eSdan SessionTable *pNext; 11305d607a6eSdan SessionTable *pTab; 11315d607a6eSdan 11325d607a6eSdan for(pTab=pList; pTab; pTab=pNext){ 11335d607a6eSdan int i; 11345d607a6eSdan pNext = pTab->pNext; 11355d607a6eSdan for(i=0; i<pTab->nChange; i++){ 11365d607a6eSdan SessionChange *p; 11375d607a6eSdan SessionChange *pNext; 11385d607a6eSdan for(p=pTab->apChange[i]; p; p=pNext){ 11395d607a6eSdan pNext = p->pNext; 11405d607a6eSdan sqlite3_free(p); 11415d607a6eSdan } 11425d607a6eSdan } 11435d607a6eSdan sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */ 11445d607a6eSdan sqlite3_free(pTab->apChange); 11455d607a6eSdan sqlite3_free(pTab); 11465d607a6eSdan } 11475d607a6eSdan } 11485d607a6eSdan 11494fccf43aSdan /* 11504fccf43aSdan ** Delete a session object previously allocated using sqlite3session_create(). 11514fccf43aSdan */ 11524fccf43aSdan void sqlite3session_delete(sqlite3_session *pSession){ 11534fccf43aSdan sqlite3 *db = pSession->db; 11544fccf43aSdan sqlite3_session *pHead; 11554fccf43aSdan sqlite3_session **pp; 11564fccf43aSdan 1157296c7658Sdan /* Unlink the session from the linked list of sessions attached to the 1158296c7658Sdan ** database handle. Hold the db mutex while doing so. */ 11594fccf43aSdan sqlite3_mutex_enter(sqlite3_db_mutex(db)); 11604fccf43aSdan pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0); 11614fccf43aSdan for(pp=&pHead; (*pp)!=pSession; pp=&((*pp)->pNext)); 11624fccf43aSdan *pp = (*pp)->pNext; 11634fccf43aSdan if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void *)pHead); 11644fccf43aSdan sqlite3_mutex_leave(sqlite3_db_mutex(db)); 11654fccf43aSdan 1166296c7658Sdan /* Delete all attached table objects. And the contents of their 1167296c7658Sdan ** associated hash-tables. */ 11685d607a6eSdan sessionDeleteTable(pSession->pTable); 11694fccf43aSdan 1170296c7658Sdan /* Free the session object itself. */ 11714fccf43aSdan sqlite3_free(pSession); 11724fccf43aSdan } 11734fccf43aSdan 11744fccf43aSdan /* 11754fccf43aSdan ** Attach a table to a session. All subsequent changes made to the table 11764fccf43aSdan ** while the session object is enabled will be recorded. 11774fccf43aSdan ** 11784fccf43aSdan ** Only tables that have a PRIMARY KEY defined may be attached. It does 11794fccf43aSdan ** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) 11804fccf43aSdan ** or not. 11814fccf43aSdan */ 11824fccf43aSdan int sqlite3session_attach( 11834fccf43aSdan sqlite3_session *pSession, /* Session object */ 11844fccf43aSdan const char *zName /* Table name */ 11854fccf43aSdan ){ 1186ff4d0f41Sdan int rc = SQLITE_OK; 1187ff4d0f41Sdan sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); 1188ff4d0f41Sdan 1189ff4d0f41Sdan if( !zName ){ 1190ff4d0f41Sdan pSession->bAutoAttach = 1; 1191ff4d0f41Sdan }else{ 1192296c7658Sdan SessionTable *pTab; /* New table object (if required) */ 1193296c7658Sdan int nName; /* Number of bytes in string zName */ 11944fccf43aSdan 11954fccf43aSdan /* First search for an existing entry. If one is found, this call is 11964fccf43aSdan ** a no-op. Return early. */ 1197cfdbde21Sdrh nName = sqlite3Strlen30(zName); 11984fccf43aSdan for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){ 11994c220252Sdan if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break; 12004fccf43aSdan } 12014fccf43aSdan 12024c220252Sdan if( !pTab ){ 12034fccf43aSdan /* Allocate new SessionTable object. */ 12044fccf43aSdan pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1); 12054c220252Sdan if( !pTab ){ 12064c220252Sdan rc = SQLITE_NOMEM; 12074c220252Sdan }else{ 12084fccf43aSdan /* Populate the new SessionTable object and link it into the list. */ 12094fccf43aSdan memset(pTab, 0, sizeof(SessionTable)); 12104fccf43aSdan pTab->zName = (char *)&pTab[1]; 12114fccf43aSdan memcpy(pTab->zName, zName, nName+1); 12124fccf43aSdan pTab->pNext = pSession->pTable; 12134fccf43aSdan pSession->pTable = pTab; 12144c220252Sdan } 12154c220252Sdan } 1216ff4d0f41Sdan } 12174fccf43aSdan 12184c220252Sdan sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); 12194c220252Sdan return rc; 12204fccf43aSdan } 12214fccf43aSdan 1222296c7658Sdan /* 1223296c7658Sdan ** Ensure that there is room in the buffer to append nByte bytes of data. 1224296c7658Sdan ** If not, use sqlite3_realloc() to grow the buffer so that there is. 1225296c7658Sdan ** 1226296c7658Sdan ** If successful, return zero. Otherwise, if an OOM condition is encountered, 1227296c7658Sdan ** set *pRc to SQLITE_NOMEM and return non-zero. 1228296c7658Sdan */ 12294fccf43aSdan static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ 123080fe2d93Sdan if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){ 12314fccf43aSdan u8 *aNew; 12324fccf43aSdan int nNew = p->nAlloc ? p->nAlloc : 128; 12334fccf43aSdan do { 12344fccf43aSdan nNew = nNew*2; 12354fccf43aSdan }while( nNew<(p->nAlloc+nByte) ); 12364fccf43aSdan 12374fccf43aSdan aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew); 12384fccf43aSdan if( 0==aNew ){ 12394fccf43aSdan *pRc = SQLITE_NOMEM; 124080fe2d93Sdan }else{ 12414fccf43aSdan p->aBuf = aNew; 12424fccf43aSdan p->nAlloc = nNew; 12434fccf43aSdan } 124480fe2d93Sdan } 124580fe2d93Sdan return (*pRc!=SQLITE_OK); 12464fccf43aSdan } 12474fccf43aSdan 1248296c7658Sdan /* 1249296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is 1250296c7658Sdan ** called. Otherwise, append a single byte to the buffer. 1251296c7658Sdan ** 1252296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before 1253296c7658Sdan ** returning. 1254296c7658Sdan */ 12554fccf43aSdan static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){ 125680fe2d93Sdan if( 0==sessionBufferGrow(p, 1, pRc) ){ 12574fccf43aSdan p->aBuf[p->nBuf++] = v; 12584fccf43aSdan } 12594fccf43aSdan } 12604fccf43aSdan 1261296c7658Sdan /* 1262296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is 1263296c7658Sdan ** called. Otherwise, append a single varint to the buffer. 1264296c7658Sdan ** 1265296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before 1266296c7658Sdan ** returning. 1267296c7658Sdan */ 1268cfdbde21Sdrh static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){ 126980fe2d93Sdan if( 0==sessionBufferGrow(p, 9, pRc) ){ 12704fccf43aSdan p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v); 12714fccf43aSdan } 12724fccf43aSdan } 12734fccf43aSdan 1274296c7658Sdan /* 1275296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is 1276296c7658Sdan ** called. Otherwise, append a blob of data to the buffer. 1277296c7658Sdan ** 1278296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before 1279296c7658Sdan ** returning. 1280296c7658Sdan */ 12814fccf43aSdan static void sessionAppendBlob( 12824fccf43aSdan SessionBuffer *p, 12834fccf43aSdan const u8 *aBlob, 12844fccf43aSdan int nBlob, 12854fccf43aSdan int *pRc 12864fccf43aSdan ){ 128780fe2d93Sdan if( 0==sessionBufferGrow(p, nBlob, pRc) ){ 12884fccf43aSdan memcpy(&p->aBuf[p->nBuf], aBlob, nBlob); 12894fccf43aSdan p->nBuf += nBlob; 12904fccf43aSdan } 12914fccf43aSdan } 12924fccf43aSdan 1293296c7658Sdan /* 1294296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is 1295296c7658Sdan ** called. Otherwise, append a string to the buffer. All bytes in the string 1296296c7658Sdan ** up to (but not including) the nul-terminator are written to the buffer. 1297296c7658Sdan ** 1298296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before 1299296c7658Sdan ** returning. 1300296c7658Sdan */ 1301d5f0767cSdan static void sessionAppendStr( 1302d5f0767cSdan SessionBuffer *p, 1303d5f0767cSdan const char *zStr, 1304d5f0767cSdan int *pRc 1305d5f0767cSdan ){ 1306cfdbde21Sdrh int nStr = sqlite3Strlen30(zStr); 130780fe2d93Sdan if( 0==sessionBufferGrow(p, nStr, pRc) ){ 1308d5f0767cSdan memcpy(&p->aBuf[p->nBuf], zStr, nStr); 1309d5f0767cSdan p->nBuf += nStr; 1310d5f0767cSdan } 1311d5f0767cSdan } 1312d5f0767cSdan 1313296c7658Sdan /* 1314296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is 1315296c7658Sdan ** called. Otherwise, append the string representation of integer iVal 1316296c7658Sdan ** to the buffer. No nul-terminator is written. 1317296c7658Sdan ** 1318296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before 1319296c7658Sdan ** returning. 1320296c7658Sdan */ 1321d5f0767cSdan static void sessionAppendInteger( 1322296c7658Sdan SessionBuffer *p, /* Buffer to append to */ 1323296c7658Sdan int iVal, /* Value to write the string rep. of */ 1324296c7658Sdan int *pRc /* IN/OUT: Error code */ 1325d5f0767cSdan ){ 1326d5f0767cSdan char aBuf[24]; 1327d5f0767cSdan sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal); 1328d5f0767cSdan sessionAppendStr(p, aBuf, pRc); 1329d5f0767cSdan } 1330d5f0767cSdan 1331296c7658Sdan /* 1332296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is 1333296c7658Sdan ** called. Otherwise, append the string zStr enclosed in quotes (") and 1334296c7658Sdan ** with any embedded quote characters escaped to the buffer. No 1335296c7658Sdan ** nul-terminator byte is written. 1336296c7658Sdan ** 1337296c7658Sdan ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before 1338296c7658Sdan ** returning. 1339296c7658Sdan */ 1340d5f0767cSdan static void sessionAppendIdent( 1341296c7658Sdan SessionBuffer *p, /* Buffer to a append to */ 1342296c7658Sdan const char *zStr, /* String to quote, escape and append */ 1343296c7658Sdan int *pRc /* IN/OUT: Error code */ 1344d5f0767cSdan ){ 1345cfdbde21Sdrh int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1; 134680fe2d93Sdan if( 0==sessionBufferGrow(p, nStr, pRc) ){ 1347d5f0767cSdan char *zOut = (char *)&p->aBuf[p->nBuf]; 1348d5f0767cSdan const char *zIn = zStr; 1349d5f0767cSdan *zOut++ = '"'; 1350d5f0767cSdan while( *zIn ){ 1351d5f0767cSdan if( *zIn=='"' ) *zOut++ = '"'; 1352d5f0767cSdan *zOut++ = *(zIn++); 1353d5f0767cSdan } 1354d5f0767cSdan *zOut++ = '"'; 1355cfdbde21Sdrh p->nBuf = (int)((u8 *)zOut - p->aBuf); 1356d5f0767cSdan } 1357d5f0767cSdan } 1358d5f0767cSdan 1359296c7658Sdan /* 1360296c7658Sdan ** This function is a no-op if *pRc is other than SQLITE_OK when it is 1361296c7658Sdan ** called. Otherwse, it appends the serialized version of the value stored 1362296c7658Sdan ** in column iCol of the row that SQL statement pStmt currently points 1363296c7658Sdan ** to to the buffer. 1364296c7658Sdan */ 13654fccf43aSdan static void sessionAppendCol( 1366296c7658Sdan SessionBuffer *p, /* Buffer to append to */ 1367296c7658Sdan sqlite3_stmt *pStmt, /* Handle pointing to row containing value */ 1368296c7658Sdan int iCol, /* Column to read value from */ 1369296c7658Sdan int *pRc /* IN/OUT: Error code */ 13704fccf43aSdan ){ 13714fccf43aSdan if( *pRc==SQLITE_OK ){ 13724fccf43aSdan int eType = sqlite3_column_type(pStmt, iCol); 13734fccf43aSdan sessionAppendByte(p, (u8)eType, pRc); 13744fccf43aSdan if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ 13754fccf43aSdan sqlite3_int64 i; 13764fccf43aSdan u8 aBuf[8]; 13774fccf43aSdan if( eType==SQLITE_INTEGER ){ 13784fccf43aSdan i = sqlite3_column_int64(pStmt, iCol); 13794fccf43aSdan }else{ 13804fccf43aSdan double r = sqlite3_column_double(pStmt, iCol); 13814fccf43aSdan memcpy(&i, &r, 8); 13824fccf43aSdan } 1383296c7658Sdan sessionPutI64(aBuf, i); 13844fccf43aSdan sessionAppendBlob(p, aBuf, 8, pRc); 13854fccf43aSdan } 13864fccf43aSdan if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){ 13876734007dSdan u8 *z; 13886734007dSdan if( eType==SQLITE_BLOB ){ 13896734007dSdan z = (u8 *)sqlite3_column_blob(pStmt, iCol); 13906734007dSdan }else{ 13916734007dSdan z = (u8 *)sqlite3_column_text(pStmt, iCol); 13926734007dSdan } 13936734007dSdan if( z ){ 13944fccf43aSdan int nByte = sqlite3_column_bytes(pStmt, iCol); 13954fccf43aSdan sessionAppendVarint(p, nByte, pRc); 13966734007dSdan sessionAppendBlob(p, z, nByte, pRc); 13976734007dSdan }else{ 13986734007dSdan *pRc = SQLITE_NOMEM; 13996734007dSdan } 14004fccf43aSdan } 14014fccf43aSdan } 14024fccf43aSdan } 14034fccf43aSdan 1404296c7658Sdan /* 1405296c7658Sdan ** 140680fe2d93Sdan ** This function appends an update change to the buffer (see the comments 140780fe2d93Sdan ** under "CHANGESET FORMAT" at the top of the file). An update change 140880fe2d93Sdan ** consists of: 1409296c7658Sdan ** 1410296c7658Sdan ** 1 byte: SQLITE_UPDATE (0x17) 1411296c7658Sdan ** n bytes: old.* record (see RECORD FORMAT) 1412296c7658Sdan ** m bytes: new.* record (see RECORD FORMAT) 1413296c7658Sdan ** 1414296c7658Sdan ** The SessionChange object passed as the third argument contains the 1415296c7658Sdan ** values that were stored in the row when the session began (the old.* 1416296c7658Sdan ** values). The statement handle passed as the second argument points 1417296c7658Sdan ** at the current version of the row (the new.* values). 1418296c7658Sdan ** 1419296c7658Sdan ** If all of the old.* values are equal to their corresponding new.* value 1420296c7658Sdan ** (i.e. nothing has changed), then no data at all is appended to the buffer. 1421296c7658Sdan ** 1422296c7658Sdan ** Otherwise, the old.* record contains all primary key values and the 1423296c7658Sdan ** original values of any fields that have been modified. The new.* record 1424296c7658Sdan ** contains the new values of only those fields that have been modified. 1425296c7658Sdan */ 142680fe2d93Sdan static int sessionAppendUpdate( 1427296c7658Sdan SessionBuffer *pBuf, /* Buffer to append to */ 1428296c7658Sdan sqlite3_stmt *pStmt, /* Statement handle pointing at new row */ 1429296c7658Sdan SessionChange *p, /* Object containing old values */ 143080fe2d93Sdan u8 *abPK /* Boolean array - true for PK columns */ 14314fccf43aSdan ){ 143280fe2d93Sdan int rc = SQLITE_OK; 1433296c7658Sdan SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */ 1434296c7658Sdan int bNoop = 1; /* Set to zero if any values are modified */ 14351f34f8ccSdan int nRewind = pBuf->nBuf; /* Set to zero if any values are modified */ 1436296c7658Sdan int i; /* Used to iterate through columns */ 1437296c7658Sdan u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */ 1438296c7658Sdan 143980fe2d93Sdan sessionAppendByte(pBuf, SQLITE_UPDATE, &rc); 144080fe2d93Sdan sessionAppendByte(pBuf, p->bIndirect, &rc); 14414fccf43aSdan for(i=0; i<sqlite3_column_count(pStmt); i++){ 144237f133ecSdan int bChanged = 0; 14434fccf43aSdan int nAdvance; 14444fccf43aSdan int eType = *pCsr; 14454fccf43aSdan switch( eType ){ 14464fccf43aSdan case SQLITE_NULL: 14474fccf43aSdan nAdvance = 1; 14484fccf43aSdan if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){ 144937f133ecSdan bChanged = 1; 14504fccf43aSdan } 14514fccf43aSdan break; 14524fccf43aSdan 14534fccf43aSdan case SQLITE_FLOAT: 14544fccf43aSdan case SQLITE_INTEGER: { 14554fccf43aSdan nAdvance = 9; 14564fccf43aSdan if( eType==sqlite3_column_type(pStmt, i) ){ 14574fccf43aSdan sqlite3_int64 iVal = sessionGetI64(&pCsr[1]); 14584fccf43aSdan if( eType==SQLITE_INTEGER ){ 14594fccf43aSdan if( iVal==sqlite3_column_int64(pStmt, i) ) break; 14604fccf43aSdan }else{ 14614fccf43aSdan double dVal; 14624fccf43aSdan memcpy(&dVal, &iVal, 8); 14634fccf43aSdan if( dVal==sqlite3_column_double(pStmt, i) ) break; 14644fccf43aSdan } 14654fccf43aSdan } 146637f133ecSdan bChanged = 1; 14674fccf43aSdan break; 14684fccf43aSdan } 14694fccf43aSdan 1470e5754eecSdan default: { 14714fccf43aSdan int nByte; 14724fccf43aSdan int nHdr = 1 + sessionVarintGet(&pCsr[1], &nByte); 1473e5754eecSdan assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); 14744fccf43aSdan nAdvance = nHdr + nByte; 14754fccf43aSdan if( eType==sqlite3_column_type(pStmt, i) 14764fccf43aSdan && nByte==sqlite3_column_bytes(pStmt, i) 14774fccf43aSdan && 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), nByte) 14784fccf43aSdan ){ 14794fccf43aSdan break; 14804fccf43aSdan } 148137f133ecSdan bChanged = 1; 14824fccf43aSdan } 14834fccf43aSdan } 14844fccf43aSdan 148537f133ecSdan if( bChanged || abPK[i] ){ 148680fe2d93Sdan sessionAppendBlob(pBuf, pCsr, nAdvance, &rc); 14874fccf43aSdan }else{ 148880fe2d93Sdan sessionAppendByte(pBuf, 0, &rc); 148937f133ecSdan } 149037f133ecSdan 149137f133ecSdan if( bChanged ){ 149280fe2d93Sdan sessionAppendCol(&buf2, pStmt, i, &rc); 14934fccf43aSdan bNoop = 0; 149437f133ecSdan }else{ 149580fe2d93Sdan sessionAppendByte(&buf2, 0, &rc); 14964fccf43aSdan } 149737f133ecSdan 14984fccf43aSdan pCsr += nAdvance; 14994fccf43aSdan } 15004fccf43aSdan 15014fccf43aSdan if( bNoop ){ 15021f34f8ccSdan pBuf->nBuf = nRewind; 15034fccf43aSdan }else{ 150480fe2d93Sdan sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc); 15054fccf43aSdan } 15061f34f8ccSdan sqlite3_free(buf2.aBuf); 150780fe2d93Sdan 150880fe2d93Sdan return rc; 1509d5f0767cSdan } 15104fccf43aSdan 151177fc1d5bSdan /* 151277fc1d5bSdan ** Formulate and prepare a SELECT statement to retrieve a row from table 151377fc1d5bSdan ** zTab in database zDb based on its primary key. i.e. 151477fc1d5bSdan ** 151577fc1d5bSdan ** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ... 151677fc1d5bSdan */ 1517e8d5648eSdan static int sessionSelectStmt( 1518e8d5648eSdan sqlite3 *db, /* Database handle */ 1519d7fb7d24Sdan const char *zDb, /* Database name */ 1520e8d5648eSdan const char *zTab, /* Table name */ 152177fc1d5bSdan int nCol, /* Number of columns in table */ 152277fc1d5bSdan const char **azCol, /* Names of table columns */ 152377fc1d5bSdan u8 *abPK, /* PRIMARY KEY array */ 152477fc1d5bSdan sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */ 1525d5f0767cSdan ){ 1526e8d5648eSdan int rc = SQLITE_OK; 1527d5f0767cSdan int i; 1528e8d5648eSdan const char *zSep = ""; 1529e8d5648eSdan SessionBuffer buf = {0, 0, 0}; 1530d5f0767cSdan 1531e8d5648eSdan sessionAppendStr(&buf, "SELECT * FROM ", &rc); 1532d7fb7d24Sdan sessionAppendIdent(&buf, zDb, &rc); 1533d7fb7d24Sdan sessionAppendStr(&buf, ".", &rc); 1534e8d5648eSdan sessionAppendIdent(&buf, zTab, &rc); 1535e8d5648eSdan sessionAppendStr(&buf, " WHERE ", &rc); 1536e8d5648eSdan for(i=0; i<nCol; i++){ 1537e8d5648eSdan if( abPK[i] ){ 1538e8d5648eSdan sessionAppendStr(&buf, zSep, &rc); 1539e8d5648eSdan sessionAppendIdent(&buf, azCol[i], &rc); 1540e8d5648eSdan sessionAppendStr(&buf, " = ?", &rc); 1541e8d5648eSdan sessionAppendInteger(&buf, i+1, &rc); 1542e8d5648eSdan zSep = " AND "; 1543d5f0767cSdan } 1544d5f0767cSdan } 1545d5f0767cSdan if( rc==SQLITE_OK ){ 1546e8d5648eSdan rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0); 1547d5f0767cSdan } 1548e8d5648eSdan sqlite3_free(buf.aBuf); 1549e8d5648eSdan return rc; 1550d5f0767cSdan } 1551d5f0767cSdan 155277fc1d5bSdan /* 155377fc1d5bSdan ** Bind the PRIMARY KEY values from the change passed in argument pChange 155477fc1d5bSdan ** to the SELECT statement passed as the first argument. The SELECT statement 155577fc1d5bSdan ** is as prepared by function sessionSelectStmt(). 155677fc1d5bSdan ** 155777fc1d5bSdan ** Return SQLITE_OK if all PK values are successfully bound, or an SQLite 155877fc1d5bSdan ** error code (e.g. SQLITE_NOMEM) otherwise. 155977fc1d5bSdan */ 1560e8d5648eSdan static int sessionSelectBind( 156177fc1d5bSdan sqlite3_stmt *pSelect, /* SELECT from sessionSelectStmt() */ 156277fc1d5bSdan int nCol, /* Number of columns in table */ 156377fc1d5bSdan u8 *abPK, /* PRIMARY KEY array */ 156477fc1d5bSdan SessionChange *pChange /* Change structure */ 1565e8d5648eSdan ){ 1566e8d5648eSdan int i; 1567e8d5648eSdan int rc = SQLITE_OK; 1568e5754eecSdan u8 *a = pChange->aRecord; 1569d5f0767cSdan 1570e8d5648eSdan for(i=0; i<nCol && rc==SQLITE_OK; i++){ 1571e8d5648eSdan int eType = *a++; 1572e8d5648eSdan 1573e8d5648eSdan switch( eType ){ 157480fe2d93Sdan case 0: 1575e8d5648eSdan case SQLITE_NULL: 1576e5754eecSdan assert( abPK[i]==0 ); 1577e8d5648eSdan break; 1578e8d5648eSdan 1579e8d5648eSdan case SQLITE_INTEGER: { 1580e8d5648eSdan if( abPK[i] ){ 1581e8d5648eSdan i64 iVal = sessionGetI64(a); 1582e8d5648eSdan rc = sqlite3_bind_int64(pSelect, i+1, iVal); 1583e8d5648eSdan } 1584e8d5648eSdan a += 8; 1585e8d5648eSdan break; 1586d5f0767cSdan } 1587296c7658Sdan 1588e8d5648eSdan case SQLITE_FLOAT: { 1589e8d5648eSdan if( abPK[i] ){ 1590e8d5648eSdan double rVal; 1591e8d5648eSdan i64 iVal = sessionGetI64(a); 1592e8d5648eSdan memcpy(&rVal, &iVal, 8); 15934e895da1Sdan rc = sqlite3_bind_double(pSelect, i+1, rVal); 1594d5f0767cSdan } 1595e8d5648eSdan a += 8; 1596e8d5648eSdan break; 1597e8d5648eSdan } 1598e8d5648eSdan 1599e8d5648eSdan case SQLITE_TEXT: { 1600e8d5648eSdan int n; 1601e8d5648eSdan a += sessionVarintGet(a, &n); 1602e8d5648eSdan if( abPK[i] ){ 1603e8d5648eSdan rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT); 1604e8d5648eSdan } 1605e8d5648eSdan a += n; 1606e8d5648eSdan break; 1607e8d5648eSdan } 1608e8d5648eSdan 1609e5754eecSdan default: { 1610e8d5648eSdan int n; 1611e5754eecSdan assert( eType==SQLITE_BLOB ); 1612e8d5648eSdan a += sessionVarintGet(a, &n); 1613e8d5648eSdan if( abPK[i] ){ 1614e8d5648eSdan rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT); 1615e8d5648eSdan } 1616e8d5648eSdan a += n; 1617e8d5648eSdan break; 1618e8d5648eSdan } 1619e8d5648eSdan } 1620e8d5648eSdan } 1621e8d5648eSdan 1622d5f0767cSdan return rc; 16234fccf43aSdan } 16244fccf43aSdan 162577fc1d5bSdan /* 162677fc1d5bSdan ** This function is a no-op if *pRc is set to other than SQLITE_OK when it 162777fc1d5bSdan ** is called. Otherwise, append a serialized table header (part of the binary 162877fc1d5bSdan ** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an 162977fc1d5bSdan ** SQLite error code before returning. 163077fc1d5bSdan */ 16315d607a6eSdan static void sessionAppendTableHdr( 16325d607a6eSdan SessionBuffer *pBuf, 16335d607a6eSdan SessionTable *pTab, 16345d607a6eSdan int *pRc 16355d607a6eSdan ){ 16365d607a6eSdan /* Write a table header */ 16375d607a6eSdan sessionAppendByte(pBuf, 'T', pRc); 16385d607a6eSdan sessionAppendVarint(pBuf, pTab->nCol, pRc); 16395d607a6eSdan sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc); 16404f528042Sdan sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc); 16415d607a6eSdan } 16425d607a6eSdan 16434fccf43aSdan /* 16444fccf43aSdan ** Obtain a changeset object containing all changes recorded by the 16454fccf43aSdan ** session object passed as the first argument. 16464fccf43aSdan ** 16474fccf43aSdan ** It is the responsibility of the caller to eventually free the buffer 16484fccf43aSdan ** using sqlite3_free(). 16494fccf43aSdan */ 16504fccf43aSdan int sqlite3session_changeset( 16514fccf43aSdan sqlite3_session *pSession, /* Session object */ 16524fccf43aSdan int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ 16534fccf43aSdan void **ppChangeset /* OUT: Buffer containing changeset */ 16544fccf43aSdan ){ 1655296c7658Sdan sqlite3 *db = pSession->db; /* Source database handle */ 1656296c7658Sdan SessionTable *pTab; /* Used to iterate through attached tables */ 1657296c7658Sdan SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */ 1658296c7658Sdan int rc; /* Return code */ 16594fccf43aSdan 1660296c7658Sdan /* Zero the output variables in case an error occurs. If this session 1661296c7658Sdan ** object is already in the error state (sqlite3_session.rc != SQLITE_OK), 1662296c7658Sdan ** this call will be a no-op. */ 16634fccf43aSdan *pnChangeset = 0; 16644fccf43aSdan *ppChangeset = 0; 1665e5754eecSdan 1666e5754eecSdan if( pSession->rc ) return pSession->rc; 1667e5754eecSdan rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0); 1668e5754eecSdan if( rc!=SQLITE_OK ) return rc; 1669e5754eecSdan 1670e5754eecSdan sqlite3_mutex_enter(sqlite3_db_mutex(db)); 16714fccf43aSdan 16724fccf43aSdan for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ 16734fccf43aSdan if( pTab->nEntry ){ 1674d7fb7d24Sdan const char *zName = pTab->zName; 1675a9605b91Sdan int nCol; /* Number of columns in table */ 1676a9605b91Sdan u8 *abPK; /* Primary key array */ 1677a9605b91Sdan const char **azCol = 0; /* Table columns */ 16781f34f8ccSdan int i; /* Used to iterate through hash buckets */ 16791f34f8ccSdan sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ 16801f34f8ccSdan int nRewind = buf.nBuf; /* Initial size of write buffer */ 16811f34f8ccSdan int nNoop; /* Size of buffer after writing tbl header */ 16824fccf43aSdan 1683a9605b91Sdan /* Check the table schema is still Ok. */ 1684a9605b91Sdan rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK); 1685a9605b91Sdan if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ 1686a9605b91Sdan rc = SQLITE_SCHEMA; 1687a9605b91Sdan } 1688a9605b91Sdan 16894fccf43aSdan /* Write a table header */ 16905d607a6eSdan sessionAppendTableHdr(&buf, pTab, &rc); 16914fccf43aSdan 16924fccf43aSdan /* Build and compile a statement to execute: */ 16934fccf43aSdan if( rc==SQLITE_OK ){ 1694d7fb7d24Sdan rc = sessionSelectStmt( 1695a9605b91Sdan db, pSession->zDb, zName, nCol, azCol, abPK, &pSel); 16964fccf43aSdan } 16974fccf43aSdan 16981f34f8ccSdan nNoop = buf.nBuf; 169912ca0b56Sdan for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){ 1700e8d5648eSdan SessionChange *p; /* Used to iterate through changes */ 1701e8d5648eSdan 17024fccf43aSdan for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){ 1703e5754eecSdan rc = sessionSelectBind(pSel, nCol, abPK, p); 170480fe2d93Sdan if( rc!=SQLITE_OK ) continue; 17051f34f8ccSdan if( sqlite3_step(pSel)==SQLITE_ROW ){ 1706798693b2Sdan if( p->op==SQLITE_INSERT ){ 17074fccf43aSdan int iCol; 17084fccf43aSdan sessionAppendByte(&buf, SQLITE_INSERT, &rc); 1709b4480e94Sdan sessionAppendByte(&buf, p->bIndirect, &rc); 1710e8d5648eSdan for(iCol=0; iCol<nCol; iCol++){ 17111f34f8ccSdan sessionAppendCol(&buf, pSel, iCol, &rc); 17124fccf43aSdan } 1713e8d5648eSdan }else{ 171480fe2d93Sdan rc = sessionAppendUpdate(&buf, pSel, p, abPK); 17154fccf43aSdan } 1716798693b2Sdan }else if( p->op!=SQLITE_INSERT ){ 17174fccf43aSdan /* A DELETE change */ 17184fccf43aSdan sessionAppendByte(&buf, SQLITE_DELETE, &rc); 1719b4480e94Sdan sessionAppendByte(&buf, p->bIndirect, &rc); 17204fccf43aSdan sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); 17214fccf43aSdan } 172212ca0b56Sdan if( rc==SQLITE_OK ){ 17231f34f8ccSdan rc = sqlite3_reset(pSel); 17244fccf43aSdan } 17254fccf43aSdan } 1726e8d5648eSdan } 17274fccf43aSdan 17281f34f8ccSdan sqlite3_finalize(pSel); 17291f34f8ccSdan if( buf.nBuf==nNoop ){ 17304fccf43aSdan buf.nBuf = nRewind; 17314fccf43aSdan } 1732cfdbde21Sdrh sqlite3_free((char*)azCol); /* cast works around VC++ bug */ 17334fccf43aSdan } 17344fccf43aSdan } 17354fccf43aSdan 17364fccf43aSdan if( rc==SQLITE_OK ){ 17374fccf43aSdan *pnChangeset = buf.nBuf; 17384fccf43aSdan *ppChangeset = buf.aBuf; 17394fccf43aSdan }else{ 17404fccf43aSdan sqlite3_free(buf.aBuf); 17414fccf43aSdan } 17424c220252Sdan 1743e5754eecSdan sqlite3_exec(db, "RELEASE changeset", 0, 0, 0); 17444c220252Sdan sqlite3_mutex_leave(sqlite3_db_mutex(db)); 17454fccf43aSdan return rc; 17464fccf43aSdan } 17474fccf43aSdan 1748296c7658Sdan /* 1749296c7658Sdan ** Enable or disable the session object passed as the first argument. 1750296c7658Sdan */ 17514fccf43aSdan int sqlite3session_enable(sqlite3_session *pSession, int bEnable){ 17524c220252Sdan int ret; 17534c220252Sdan sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); 1754296c7658Sdan if( bEnable>=0 ){ 1755296c7658Sdan pSession->bEnable = bEnable; 17564fccf43aSdan } 17574c220252Sdan ret = pSession->bEnable; 17584c220252Sdan sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); 17594c220252Sdan return ret; 1760296c7658Sdan } 17614fccf43aSdan 17624fccf43aSdan /* 1763b4480e94Sdan ** Enable or disable the session object passed as the first argument. 1764b4480e94Sdan */ 1765b4480e94Sdan int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){ 1766b4480e94Sdan int ret; 1767b4480e94Sdan sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); 1768b4480e94Sdan if( bIndirect>=0 ){ 1769b4480e94Sdan pSession->bIndirect = bIndirect; 1770b4480e94Sdan } 1771b4480e94Sdan ret = pSession->bIndirect; 1772b4480e94Sdan sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); 1773b4480e94Sdan return ret; 1774b4480e94Sdan } 1775b4480e94Sdan 1776b4480e94Sdan /* 1777b69ec348Sdan ** Return true if there have been no changes to monitored tables recorded 1778b69ec348Sdan ** by the session object passed as the only argument. 1779b69ec348Sdan */ 1780b69ec348Sdan int sqlite3session_isempty(sqlite3_session *pSession){ 1781b69ec348Sdan int ret = 0; 1782b69ec348Sdan SessionTable *pTab; 1783b69ec348Sdan 1784b69ec348Sdan sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); 1785b69ec348Sdan for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){ 1786b69ec348Sdan ret = (pTab->nEntry>0); 1787b69ec348Sdan } 1788b69ec348Sdan sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); 1789b69ec348Sdan 1790ff530326Sdan return (ret==0); 1791b69ec348Sdan } 1792b69ec348Sdan 1793b69ec348Sdan /* 17944fccf43aSdan ** Create an iterator used to iterate through the contents of a changeset. 17954fccf43aSdan */ 17964fccf43aSdan int sqlite3changeset_start( 1797296c7658Sdan sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ 1798296c7658Sdan int nChangeset, /* Size of buffer pChangeset in bytes */ 1799296c7658Sdan void *pChangeset /* Pointer to buffer containing changeset */ 18004fccf43aSdan ){ 18014fccf43aSdan sqlite3_changeset_iter *pRet; /* Iterator to return */ 18024fccf43aSdan int nByte; /* Number of bytes to allocate for iterator */ 18034fccf43aSdan 1804296c7658Sdan /* Zero the output variable in case an error occurs. */ 1805296c7658Sdan *pp = 0; 18064fccf43aSdan 1807296c7658Sdan /* Allocate and initialize the iterator structure. */ 18084fccf43aSdan nByte = sizeof(sqlite3_changeset_iter); 18094fccf43aSdan pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte); 18104fccf43aSdan if( !pRet ) return SQLITE_NOMEM; 18114fccf43aSdan memset(pRet, 0, sizeof(sqlite3_changeset_iter)); 18124fccf43aSdan pRet->aChangeset = (u8 *)pChangeset; 18134fccf43aSdan pRet->nChangeset = nChangeset; 18144fccf43aSdan pRet->pNext = pRet->aChangeset; 18154fccf43aSdan 1816296c7658Sdan /* Populate the output variable and return success. */ 1817296c7658Sdan *pp = pRet; 18184fccf43aSdan return SQLITE_OK; 18194fccf43aSdan } 18204fccf43aSdan 1821296c7658Sdan /* 1822296c7658Sdan ** Deserialize a single record from a buffer in memory. See "RECORD FORMAT" 1823296c7658Sdan ** for details. 1824296c7658Sdan ** 1825296c7658Sdan ** When this function is called, *paChange points to the start of the record 1826296c7658Sdan ** to deserialize. Assuming no error occurs, *paChange is set to point to 1827296c7658Sdan ** one byte after the end of the same record before this function returns. 1828296c7658Sdan ** 1829296c7658Sdan ** If successful, each element of the apOut[] array (allocated by the caller) 1830296c7658Sdan ** is set to point to an sqlite3_value object containing the value read 1831296c7658Sdan ** from the corresponding position in the record. If that value is not 1832296c7658Sdan ** included in the record (i.e. because the record is part of an UPDATE change 1833296c7658Sdan ** and the field was not modified), the corresponding element of apOut[] is 1834296c7658Sdan ** set to NULL. 1835296c7658Sdan ** 1836296c7658Sdan ** It is the responsibility of the caller to free all sqlite_value structures 1837296c7658Sdan ** using sqlite3_free(). 1838296c7658Sdan ** 1839296c7658Sdan ** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. 1840296c7658Sdan ** The apOut[] array may have been partially populated in this case. 1841296c7658Sdan */ 18424fccf43aSdan static int sessionReadRecord( 18434fccf43aSdan u8 **paChange, /* IN/OUT: Pointer to binary record */ 18444fccf43aSdan int nCol, /* Number of values in record */ 18454fccf43aSdan sqlite3_value **apOut /* Write values to this array */ 18464fccf43aSdan ){ 1847296c7658Sdan int i; /* Used to iterate through columns */ 1848296c7658Sdan u8 *aRec = *paChange; /* Cursor for the serialized record */ 18494fccf43aSdan 18504fccf43aSdan for(i=0; i<nCol; i++){ 1851296c7658Sdan int eType = *aRec++; /* Type of value (SQLITE_NULL, TEXT etc.) */ 185291ddd559Sdan assert( !apOut || apOut[i]==0 ); 18534fccf43aSdan if( eType ){ 185491ddd559Sdan if( apOut ){ 18554fccf43aSdan apOut[i] = sqlite3ValueNew(0); 18564fccf43aSdan if( !apOut[i] ) return SQLITE_NOMEM; 185791ddd559Sdan } 18584fccf43aSdan 18594fccf43aSdan if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ 18604fccf43aSdan int nByte; 18614fccf43aSdan aRec += sessionVarintGet(aRec, &nByte); 186291ddd559Sdan if( apOut ){ 18636734007dSdan u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0); 18646734007dSdan sqlite3ValueSetStr(apOut[i], nByte, (char *)aRec, enc, SQLITE_STATIC); 186591ddd559Sdan } 18664fccf43aSdan aRec += nByte; 18674fccf43aSdan } 18684fccf43aSdan if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ 186991ddd559Sdan if( apOut ){ 18704fccf43aSdan sqlite3_int64 v = sessionGetI64(aRec); 18714fccf43aSdan if( eType==SQLITE_INTEGER ){ 18724fccf43aSdan sqlite3VdbeMemSetInt64(apOut[i], v); 18734fccf43aSdan }else{ 18744fccf43aSdan double d; 18754e895da1Sdan memcpy(&d, &v, 8); 18764fccf43aSdan sqlite3VdbeMemSetDouble(apOut[i], d); 18774fccf43aSdan } 18784fccf43aSdan } 187991ddd559Sdan aRec += 8; 188091ddd559Sdan } 18814fccf43aSdan } 18824fccf43aSdan } 18834fccf43aSdan 18844fccf43aSdan *paChange = aRec; 18854fccf43aSdan return SQLITE_OK; 18864fccf43aSdan } 18874fccf43aSdan 188877fc1d5bSdan /* 188977fc1d5bSdan ** Advance the changeset iterator to the next change. 189077fc1d5bSdan ** 189177fc1d5bSdan ** If both paRec and pnRec are NULL, then this function works like the public 189277fc1d5bSdan ** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the 189377fc1d5bSdan ** sqlite3changeset_new() and old() APIs may be used to query for values. 189477fc1d5bSdan ** 189577fc1d5bSdan ** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change 189677fc1d5bSdan ** record is written to *paRec before returning and the number of bytes in 189777fc1d5bSdan ** the record to *pnRec. 189877fc1d5bSdan ** 189977fc1d5bSdan ** Either way, this function returns SQLITE_ROW if the iterator is 190077fc1d5bSdan ** successfully advanced to the next change in the changeset, an SQLite 190177fc1d5bSdan ** error code if an error occurs, or SQLITE_DONE if there are no further 190277fc1d5bSdan ** changes in the changeset. 190377fc1d5bSdan */ 19045d607a6eSdan static int sessionChangesetNext( 190577fc1d5bSdan sqlite3_changeset_iter *p, /* Changeset iterator */ 190677fc1d5bSdan u8 **paRec, /* If non-NULL, store record pointer here */ 190777fc1d5bSdan int *pnRec /* If non-NULL, store size of record here */ 19085d607a6eSdan ){ 19094fccf43aSdan u8 *aChange; 19104fccf43aSdan int i; 19114fccf43aSdan 19125d607a6eSdan assert( (paRec==0 && pnRec==0) || (paRec && pnRec) ); 19135d607a6eSdan 1914296c7658Sdan /* If the iterator is in the error-state, return immediately. */ 19154fccf43aSdan if( p->rc!=SQLITE_OK ) return p->rc; 19164fccf43aSdan 19175d607a6eSdan /* Free the current contents of p->apValue[], if any. */ 19184fccf43aSdan if( p->apValue ){ 19194fccf43aSdan for(i=0; i<p->nCol*2; i++){ 19204fccf43aSdan sqlite3ValueFree(p->apValue[i]); 19214fccf43aSdan } 19224fccf43aSdan memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2); 19234fccf43aSdan } 19244fccf43aSdan 19254fccf43aSdan /* If the iterator is already at the end of the changeset, return DONE. */ 19264fccf43aSdan if( p->pNext>=&p->aChangeset[p->nChangeset] ){ 19274fccf43aSdan return SQLITE_DONE; 19284fccf43aSdan } 19294fccf43aSdan aChange = p->pNext; 19304fccf43aSdan 19315d607a6eSdan if( aChange[0]=='T' ){ 19324fccf43aSdan int nByte; /* Bytes to allocate for apValue */ 19335d607a6eSdan aChange++; 19344fccf43aSdan aChange += sessionVarintGet(aChange, &p->nCol); 1935244593c8Sdan p->abPK = (u8 *)aChange; 1936244593c8Sdan aChange += p->nCol; 19374fccf43aSdan p->zTab = (char *)aChange; 1938cfdbde21Sdrh aChange += (sqlite3Strlen30((char *)aChange) + 1); 19395d607a6eSdan 19405d607a6eSdan if( paRec==0 ){ 19414fccf43aSdan sqlite3_free(p->apValue); 19424fccf43aSdan nByte = sizeof(sqlite3_value *) * p->nCol * 2; 19434fccf43aSdan p->apValue = (sqlite3_value **)sqlite3_malloc(nByte); 19444fccf43aSdan if( !p->apValue ){ 19454fccf43aSdan return (p->rc = SQLITE_NOMEM); 19464fccf43aSdan } 19474fccf43aSdan memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2); 19484fccf43aSdan } 19495d607a6eSdan } 19505d607a6eSdan 19515d607a6eSdan p->op = *(aChange++); 19525d607a6eSdan p->bIndirect = *(aChange++); 19534fccf43aSdan if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){ 19544fccf43aSdan return (p->rc = SQLITE_CORRUPT); 19554fccf43aSdan } 19564fccf43aSdan 19575d607a6eSdan if( paRec ){ *paRec = aChange; } 19585d607a6eSdan 19594fccf43aSdan /* If this is an UPDATE or DELETE, read the old.* record. */ 19604fccf43aSdan if( p->op!=SQLITE_INSERT ){ 19615d607a6eSdan p->rc = sessionReadRecord(&aChange, p->nCol, paRec?0:p->apValue); 19624fccf43aSdan if( p->rc!=SQLITE_OK ) return p->rc; 19634fccf43aSdan } 19644fccf43aSdan 19654fccf43aSdan /* If this is an INSERT or UPDATE, read the new.* record. */ 19664fccf43aSdan if( p->op!=SQLITE_DELETE ){ 19675d607a6eSdan p->rc = sessionReadRecord(&aChange, p->nCol, paRec?0:&p->apValue[p->nCol]); 19684fccf43aSdan if( p->rc!=SQLITE_OK ) return p->rc; 19694fccf43aSdan } 19704fccf43aSdan 19714f528042Sdan if( pnRec ){ *pnRec = (int)(aChange - *paRec); } 19724fccf43aSdan p->pNext = aChange; 19734fccf43aSdan return SQLITE_ROW; 19744fccf43aSdan } 19754fccf43aSdan 19764fccf43aSdan /* 19775d607a6eSdan ** Advance an iterator created by sqlite3changeset_start() to the next 19785d607a6eSdan ** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE 19795d607a6eSdan ** or SQLITE_CORRUPT. 19805d607a6eSdan ** 19815d607a6eSdan ** This function may not be called on iterators passed to a conflict handler 19825d607a6eSdan ** callback by changeset_apply(). 19835d607a6eSdan */ 19845d607a6eSdan int sqlite3changeset_next(sqlite3_changeset_iter *p){ 19855d607a6eSdan return sessionChangesetNext(p, 0, 0); 19865d607a6eSdan } 19875d607a6eSdan 19885d607a6eSdan /* 1989244593c8Sdan ** The following function extracts information on the current change 199077fc1d5bSdan ** from a changeset iterator. It may only be called after changeset_next() 19914fccf43aSdan ** has returned SQLITE_ROW. 19924fccf43aSdan */ 19934fccf43aSdan int sqlite3changeset_op( 1994296c7658Sdan sqlite3_changeset_iter *pIter, /* Iterator handle */ 19954fccf43aSdan const char **pzTab, /* OUT: Pointer to table name */ 19964fccf43aSdan int *pnCol, /* OUT: Number of columns in table */ 1997b4480e94Sdan int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ 1998b4480e94Sdan int *pbIndirect /* OUT: True if change is indirect */ 19994fccf43aSdan ){ 20004fccf43aSdan *pOp = pIter->op; 20014fccf43aSdan *pnCol = pIter->nCol; 20024fccf43aSdan *pzTab = pIter->zTab; 2003b4480e94Sdan if( pbIndirect ) *pbIndirect = pIter->bIndirect; 20044fccf43aSdan return SQLITE_OK; 20054fccf43aSdan } 20064fccf43aSdan 200777fc1d5bSdan /* 200877fc1d5bSdan ** Return information regarding the PRIMARY KEY and number of columns in 200977fc1d5bSdan ** the database table affected by the change that pIter currently points 201077fc1d5bSdan ** to. This function may only be called after changeset_next() returns 201177fc1d5bSdan ** SQLITE_ROW. 201277fc1d5bSdan */ 2013244593c8Sdan int sqlite3changeset_pk( 2014244593c8Sdan sqlite3_changeset_iter *pIter, /* Iterator object */ 2015244593c8Sdan unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ 2016244593c8Sdan int *pnCol /* OUT: Number of entries in output array */ 2017244593c8Sdan ){ 2018244593c8Sdan *pabPK = pIter->abPK; 2019244593c8Sdan if( pnCol ) *pnCol = pIter->nCol; 2020244593c8Sdan return SQLITE_OK; 2021244593c8Sdan } 2022244593c8Sdan 2023296c7658Sdan /* 2024296c7658Sdan ** This function may only be called while the iterator is pointing to an 2025296c7658Sdan ** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()). 2026296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned. 2027296c7658Sdan ** 2028296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the 2029296c7658Sdan ** iVal'th value in the old.* record. Or, if that particular value is not 2030296c7658Sdan ** included in the record (because the change is an UPDATE and the field 2031296c7658Sdan ** was not modified and is not a PK column), set *ppValue to NULL. 2032296c7658Sdan ** 2033296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is 2034296c7658Sdan ** not modified. Otherwise, SQLITE_OK. 2035296c7658Sdan */ 20364fccf43aSdan int sqlite3changeset_old( 2037296c7658Sdan sqlite3_changeset_iter *pIter, /* Changeset iterator */ 2038296c7658Sdan int iVal, /* Index of old.* value to retrieve */ 20394fccf43aSdan sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ 20404fccf43aSdan ){ 2041d5f0767cSdan if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){ 2042d5f0767cSdan return SQLITE_MISUSE; 2043d5f0767cSdan } 20444fccf43aSdan if( iVal<0 || iVal>=pIter->nCol ){ 20454fccf43aSdan return SQLITE_RANGE; 20464fccf43aSdan } 20474fccf43aSdan *ppValue = pIter->apValue[iVal]; 20484fccf43aSdan return SQLITE_OK; 20494fccf43aSdan } 20504fccf43aSdan 2051296c7658Sdan /* 2052296c7658Sdan ** This function may only be called while the iterator is pointing to an 2053296c7658Sdan ** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()). 2054296c7658Sdan ** Otherwise, SQLITE_MISUSE is returned. 2055296c7658Sdan ** 2056296c7658Sdan ** It sets *ppValue to point to an sqlite3_value structure containing the 2057296c7658Sdan ** iVal'th value in the new.* record. Or, if that particular value is not 2058296c7658Sdan ** included in the record (because the change is an UPDATE and the field 2059296c7658Sdan ** was not modified), set *ppValue to NULL. 2060296c7658Sdan ** 2061296c7658Sdan ** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is 2062296c7658Sdan ** not modified. Otherwise, SQLITE_OK. 2063296c7658Sdan */ 20644fccf43aSdan int sqlite3changeset_new( 2065296c7658Sdan sqlite3_changeset_iter *pIter, /* Changeset iterator */ 2066296c7658Sdan int iVal, /* Index of new.* value to retrieve */ 20674fccf43aSdan sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ 20684fccf43aSdan ){ 2069d5f0767cSdan if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){ 2070d5f0767cSdan return SQLITE_MISUSE; 2071d5f0767cSdan } 20724fccf43aSdan if( iVal<0 || iVal>=pIter->nCol ){ 20734fccf43aSdan return SQLITE_RANGE; 20744fccf43aSdan } 20754fccf43aSdan *ppValue = pIter->apValue[pIter->nCol+iVal]; 20764fccf43aSdan return SQLITE_OK; 20774fccf43aSdan } 20784fccf43aSdan 2079296c7658Sdan /* 20807aa469cdSdan ** The following two macros are used internally. They are similar to the 20817aa469cdSdan ** sqlite3changeset_new() and sqlite3changeset_old() functions, except that 20827aa469cdSdan ** they omit all error checking and return a pointer to the requested value. 20837aa469cdSdan */ 20847aa469cdSdan #define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)] 20857aa469cdSdan #define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)] 20867aa469cdSdan 20877aa469cdSdan /* 2088296c7658Sdan ** This function may only be called with a changeset iterator that has been 2089296c7658Sdan ** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT 2090296c7658Sdan ** conflict-handler function. Otherwise, SQLITE_MISUSE is returned. 2091296c7658Sdan ** 2092296c7658Sdan ** If successful, *ppValue is set to point to an sqlite3_value structure 2093296c7658Sdan ** containing the iVal'th value of the conflicting record. 2094296c7658Sdan ** 2095296c7658Sdan ** If value iVal is out-of-range or some other error occurs, an SQLite error 2096296c7658Sdan ** code is returned. Otherwise, SQLITE_OK. 2097296c7658Sdan */ 2098d5f0767cSdan int sqlite3changeset_conflict( 2099296c7658Sdan sqlite3_changeset_iter *pIter, /* Changeset iterator */ 2100296c7658Sdan int iVal, /* Index of conflict record value to fetch */ 2101d5f0767cSdan sqlite3_value **ppValue /* OUT: Value from conflicting row */ 2102d5f0767cSdan ){ 2103d5f0767cSdan if( !pIter->pConflict ){ 2104d5f0767cSdan return SQLITE_MISUSE; 2105d5f0767cSdan } 2106d5f0767cSdan if( iVal<0 || iVal>=sqlite3_column_count(pIter->pConflict) ){ 2107d5f0767cSdan return SQLITE_RANGE; 2108d5f0767cSdan } 2109d5f0767cSdan *ppValue = sqlite3_column_value(pIter->pConflict, iVal); 2110d5f0767cSdan return SQLITE_OK; 2111d5f0767cSdan } 2112d5f0767cSdan 21134fccf43aSdan /* 21144fccf43aSdan ** Finalize an iterator allocated with sqlite3changeset_start(). 21154fccf43aSdan ** 21164fccf43aSdan ** This function may not be called on iterators passed to a conflict handler 21174fccf43aSdan ** callback by changeset_apply(). 21184fccf43aSdan */ 21194fccf43aSdan int sqlite3changeset_finalize(sqlite3_changeset_iter *p){ 2120296c7658Sdan int i; /* Used to iterate through p->apValue[] */ 2121296c7658Sdan int rc = p->rc; /* Return code */ 212212ca0b56Sdan if( p->apValue ){ 21234fccf43aSdan for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]); 212412ca0b56Sdan } 21254fccf43aSdan sqlite3_free(p->apValue); 21264fccf43aSdan sqlite3_free(p); 21274fccf43aSdan return rc; 21284fccf43aSdan } 21294fccf43aSdan 213091ddd559Sdan /* 213191ddd559Sdan ** Invert a changeset object. 213291ddd559Sdan */ 213391ddd559Sdan int sqlite3changeset_invert( 213491ddd559Sdan int nChangeset, /* Number of bytes in input */ 2135*cfec7eeeSdan const void *pChangeset, /* Input changeset */ 213691ddd559Sdan int *pnInverted, /* OUT: Number of bytes in output changeset */ 213791ddd559Sdan void **ppInverted /* OUT: Inverse of pChangeset */ 213891ddd559Sdan ){ 2139*cfec7eeeSdan int rc = SQLITE_OK; /* Return value */ 214091ddd559Sdan u8 *aOut; 214191ddd559Sdan u8 *aIn; 214291ddd559Sdan int i; 2143*cfec7eeeSdan int nCol = 0; /* Number of cols in current table */ 2144*cfec7eeeSdan u8 *abPK = 0; /* PK array for current table */ 2145*cfec7eeeSdan sqlite3_value **apVal = 0; /* Space for values for UPDATE inversion */ 214691ddd559Sdan 214791ddd559Sdan /* Zero the output variables in case an error occurs. */ 214891ddd559Sdan *ppInverted = 0; 214991ddd559Sdan *pnInverted = 0; 215091ddd559Sdan if( nChangeset==0 ) return SQLITE_OK; 215191ddd559Sdan 215291ddd559Sdan aOut = (u8 *)sqlite3_malloc(nChangeset); 215391ddd559Sdan if( !aOut ) return SQLITE_NOMEM; 215491ddd559Sdan aIn = (u8 *)pChangeset; 215591ddd559Sdan 215691ddd559Sdan i = 0; 215791ddd559Sdan while( i<nChangeset ){ 215891ddd559Sdan u8 eType = aIn[i]; 215991ddd559Sdan switch( eType ){ 216091ddd559Sdan case 'T': { 2161244593c8Sdan /* A 'table' record consists of: 2162244593c8Sdan ** 2163244593c8Sdan ** * A constant 'T' character, 2164244593c8Sdan ** * Number of columns in said table (a varint), 2165244593c8Sdan ** * An array of nCol bytes (abPK), 2166244593c8Sdan ** * A nul-terminated table name. 2167244593c8Sdan */ 216891ddd559Sdan int nByte = 1 + sessionVarintGet(&aIn[i+1], &nCol); 2169*cfec7eeeSdan abPK = &aIn[i+nByte]; 2170244593c8Sdan nByte += nCol; 2171cfdbde21Sdrh nByte += 1 + sqlite3Strlen30((char *)&aIn[i+nByte]); 217291ddd559Sdan memcpy(&aOut[i], &aIn[i], nByte); 217391ddd559Sdan i += nByte; 2174*cfec7eeeSdan sqlite3_free(apVal); 2175*cfec7eeeSdan apVal = 0; 217691ddd559Sdan break; 217791ddd559Sdan } 217891ddd559Sdan 217991ddd559Sdan case SQLITE_INSERT: 218091ddd559Sdan case SQLITE_DELETE: { 218191ddd559Sdan int nByte; 2182b4480e94Sdan u8 *aEnd = &aIn[i+2]; 218391ddd559Sdan 218491ddd559Sdan sessionReadRecord(&aEnd, nCol, 0); 218591ddd559Sdan aOut[i] = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE); 2186b4480e94Sdan aOut[i+1] = aIn[i+1]; 2187cfdbde21Sdrh nByte = (int)(aEnd - &aIn[i+2]); 2188b4480e94Sdan memcpy(&aOut[i+2], &aIn[i+2], nByte); 2189b4480e94Sdan i += 2 + nByte; 219091ddd559Sdan break; 219191ddd559Sdan } 219291ddd559Sdan 219391ddd559Sdan case SQLITE_UPDATE: { 2194*cfec7eeeSdan int iCol; 2195*cfec7eeeSdan int nWrite = 0; 2196b4480e94Sdan u8 *aEnd = &aIn[i+2]; 219791ddd559Sdan 2198*cfec7eeeSdan if( 0==apVal ){ 2199*cfec7eeeSdan apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2); 2200*cfec7eeeSdan if( 0==apVal ){ 2201*cfec7eeeSdan rc = SQLITE_NOMEM; 2202*cfec7eeeSdan goto finished_invert; 2203*cfec7eeeSdan } 2204*cfec7eeeSdan memset(apVal, 0, sizeof(apVal[0])*nCol*2); 2205*cfec7eeeSdan } 220691ddd559Sdan 2207*cfec7eeeSdan /* Read the old.* and new.* records for the update change. */ 2208*cfec7eeeSdan rc = sessionReadRecord(&aEnd, nCol, &apVal[0]); 2209*cfec7eeeSdan if( rc==SQLITE_OK ){ 2210*cfec7eeeSdan rc = sessionReadRecord(&aEnd, nCol, &apVal[nCol]); 2211*cfec7eeeSdan } 2212*cfec7eeeSdan 2213*cfec7eeeSdan /* Write the header for the new UPDATE change. Same as the original. */ 221491ddd559Sdan aOut[i] = SQLITE_UPDATE; 2215b4480e94Sdan aOut[i+1] = aIn[i+1]; 2216*cfec7eeeSdan nWrite = 2; 221791ddd559Sdan 2218*cfec7eeeSdan /* Write the new old.* record. Consists of the PK columns from the 2219*cfec7eeeSdan ** original old.* record, and the other values from the original 2220*cfec7eeeSdan ** new.* record. */ 2221*cfec7eeeSdan for(iCol=0; rc==SQLITE_OK && iCol<nCol; iCol++){ 2222*cfec7eeeSdan sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)]; 2223*cfec7eeeSdan rc = sessionSerializeValue(&aOut[i+nWrite], pVal, &nWrite); 2224*cfec7eeeSdan } 2225*cfec7eeeSdan 2226*cfec7eeeSdan /* Write the new new.* record. Consists of a copy of all values 2227*cfec7eeeSdan ** from the original old.* record, except for the PK columns, which 2228*cfec7eeeSdan ** are set to "undefined". */ 2229*cfec7eeeSdan for(iCol=0; rc==SQLITE_OK && iCol<nCol; iCol++){ 2230*cfec7eeeSdan sqlite3_value *pVal = (abPK[iCol] ? 0 : apVal[iCol]); 2231*cfec7eeeSdan rc = sessionSerializeValue(&aOut[i+nWrite], pVal, &nWrite); 2232*cfec7eeeSdan } 2233*cfec7eeeSdan 2234*cfec7eeeSdan for(iCol=0; iCol<nCol*2; iCol++){ 2235*cfec7eeeSdan sqlite3ValueFree(apVal[iCol]); 2236*cfec7eeeSdan } 2237*cfec7eeeSdan memset(apVal, 0, sizeof(apVal[0])*nCol*2); 2238*cfec7eeeSdan if( rc!=SQLITE_OK ){ 2239*cfec7eeeSdan goto finished_invert; 2240*cfec7eeeSdan } 2241*cfec7eeeSdan 2242*cfec7eeeSdan i += nWrite; 2243*cfec7eeeSdan assert( &aIn[i]==aEnd ); 224491ddd559Sdan break; 224591ddd559Sdan } 224691ddd559Sdan 224791ddd559Sdan default: 2248*cfec7eeeSdan rc = SQLITE_CORRUPT; 2249*cfec7eeeSdan goto finished_invert; 225091ddd559Sdan } 225191ddd559Sdan } 225291ddd559Sdan 2253*cfec7eeeSdan assert( rc==SQLITE_OK ); 225491ddd559Sdan *pnInverted = nChangeset; 225591ddd559Sdan *ppInverted = (void *)aOut; 2256*cfec7eeeSdan 2257*cfec7eeeSdan finished_invert: 2258*cfec7eeeSdan if( rc!=SQLITE_OK ){ 2259*cfec7eeeSdan sqlite3_free(aOut); 2260*cfec7eeeSdan } 2261*cfec7eeeSdan sqlite3_free(apVal); 2262*cfec7eeeSdan return rc; 226391ddd559Sdan } 226491ddd559Sdan 22650c698471Sdan typedef struct SessionApplyCtx SessionApplyCtx; 22660c698471Sdan struct SessionApplyCtx { 22670c698471Sdan sqlite3 *db; 22680c698471Sdan sqlite3_stmt *pDelete; /* DELETE statement */ 2269*cfec7eeeSdan sqlite3_stmt *pUpdate; /* UPDATE statement */ 22700c698471Sdan sqlite3_stmt *pInsert; /* INSERT statement */ 22710c698471Sdan sqlite3_stmt *pSelect; /* SELECT statement */ 22720c698471Sdan int nCol; /* Size of azCol[] and abPK[] arrays */ 22730c698471Sdan const char **azCol; /* Array of column names */ 22740c698471Sdan u8 *abPK; /* Boolean array - true if column is in PK */ 22750c698471Sdan }; 22760c698471Sdan 2277d5f0767cSdan /* 2278d5f0767cSdan ** Formulate a statement to DELETE a row from database db. Assuming a table 2279d5f0767cSdan ** structure like this: 2280d5f0767cSdan ** 2281d5f0767cSdan ** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); 2282d5f0767cSdan ** 2283d5f0767cSdan ** The DELETE statement looks like this: 2284d5f0767cSdan ** 2285db04571cSdan ** DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4) 2286d5f0767cSdan ** 2287d5f0767cSdan ** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require 2288d5f0767cSdan ** matching b and d values, or 1 otherwise. The second case comes up if the 2289d5f0767cSdan ** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE. 2290296c7658Sdan ** 2291296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left 2292296c7658Sdan ** pointing to the prepared version of the SQL statement. 2293d5f0767cSdan */ 2294d5f0767cSdan static int sessionDeleteRow( 2295d5f0767cSdan sqlite3 *db, /* Database handle */ 2296d5f0767cSdan const char *zTab, /* Table name */ 22970c698471Sdan SessionApplyCtx *p /* Session changeset-apply context */ 2298d5f0767cSdan ){ 2299296c7658Sdan int i; 2300296c7658Sdan const char *zSep = ""; 2301d5f0767cSdan int rc = SQLITE_OK; 2302d5f0767cSdan SessionBuffer buf = {0, 0, 0}; 23037cf7df7dSdan int nPk = 0; 2304d5f0767cSdan 2305d5f0767cSdan sessionAppendStr(&buf, "DELETE FROM ", &rc); 2306d5f0767cSdan sessionAppendIdent(&buf, zTab, &rc); 2307296c7658Sdan sessionAppendStr(&buf, " WHERE ", &rc); 2308296c7658Sdan 2309296c7658Sdan for(i=0; i<p->nCol; i++){ 2310296c7658Sdan if( p->abPK[i] ){ 23117cf7df7dSdan nPk++; 2312296c7658Sdan sessionAppendStr(&buf, zSep, &rc); 2313296c7658Sdan sessionAppendIdent(&buf, p->azCol[i], &rc); 2314296c7658Sdan sessionAppendStr(&buf, " = ?", &rc); 2315296c7658Sdan sessionAppendInteger(&buf, i+1, &rc); 2316296c7658Sdan zSep = " AND "; 2317296c7658Sdan } 2318296c7658Sdan } 2319296c7658Sdan 23207cf7df7dSdan if( nPk<p->nCol ){ 2321296c7658Sdan sessionAppendStr(&buf, " AND (?", &rc); 2322296c7658Sdan sessionAppendInteger(&buf, p->nCol+1, &rc); 2323296c7658Sdan sessionAppendStr(&buf, " OR ", &rc); 2324296c7658Sdan 2325296c7658Sdan zSep = ""; 2326296c7658Sdan for(i=0; i<p->nCol; i++){ 2327296c7658Sdan if( !p->abPK[i] ){ 2328296c7658Sdan sessionAppendStr(&buf, zSep, &rc); 2329296c7658Sdan sessionAppendIdent(&buf, p->azCol[i], &rc); 2330296c7658Sdan sessionAppendStr(&buf, " IS ?", &rc); 2331296c7658Sdan sessionAppendInteger(&buf, i+1, &rc); 2332296c7658Sdan zSep = "AND "; 2333296c7658Sdan } 2334296c7658Sdan } 2335296c7658Sdan sessionAppendStr(&buf, ")", &rc); 23367cf7df7dSdan } 2337d5f0767cSdan 2338d5f0767cSdan if( rc==SQLITE_OK ){ 23390c698471Sdan rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0); 2340d5f0767cSdan } 2341d5f0767cSdan sqlite3_free(buf.aBuf); 2342d5f0767cSdan 2343d5f0767cSdan return rc; 2344d5f0767cSdan } 2345d5f0767cSdan 2346d5f0767cSdan /* 2347d5f0767cSdan ** Formulate and prepare a statement to UPDATE a row from database db. 2348d5f0767cSdan ** Assuming a table structure like this: 2349d5f0767cSdan ** 2350d5f0767cSdan ** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); 2351d5f0767cSdan ** 2352d5f0767cSdan ** The UPDATE statement looks like this: 2353d5f0767cSdan ** 2354d5f0767cSdan ** UPDATE x SET 2355d5f0767cSdan ** a = CASE WHEN ?2 THEN ?3 ELSE a END, 2356d5f0767cSdan ** b = CASE WHEN ?5 THEN ?6 ELSE a END, 2357d5f0767cSdan ** c = CASE WHEN ?8 THEN ?9 ELSE a END, 2358d5f0767cSdan ** d = CASE WHEN ?11 THEN ?12 ELSE a END 2359d5f0767cSdan ** WHERE a = ?1 AND c = ?7 AND (?13 OR 2360d5f0767cSdan ** (?5==0 OR b IS ?4) AND (?11==0 OR b IS ?10) AND 2361d5f0767cSdan ** ) 2362d5f0767cSdan ** 2363d5f0767cSdan ** For each column in the table, there are three variables to bind: 2364d5f0767cSdan ** 2365d5f0767cSdan ** ?(i*3+1) The old.* value of the column, if any. 2366d5f0767cSdan ** ?(i*3+2) A boolean flag indicating that the value is being modified. 2367d5f0767cSdan ** ?(i*3+3) The new.* value of the column, if any. 2368d5f0767cSdan ** 2369d5f0767cSdan ** Also, a boolean flag that, if set to true, causes the statement to update 2370d5f0767cSdan ** a row even if the non-PK values do not match. This is required if the 2371d5f0767cSdan ** conflict-handler is invoked with CHANGESET_DATA and returns 2372d5f0767cSdan ** CHANGESET_REPLACE. This is variable "?(nCol*3+1)". 2373d5f0767cSdan ** 2374296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left 2375296c7658Sdan ** pointing to the prepared version of the SQL statement. 2376d5f0767cSdan */ 2377d5f0767cSdan static int sessionUpdateRow( 2378d5f0767cSdan sqlite3 *db, /* Database handle */ 2379d5f0767cSdan const char *zTab, /* Table name */ 23800c698471Sdan SessionApplyCtx *p /* Session changeset-apply context */ 2381d5f0767cSdan ){ 2382d5f0767cSdan int rc = SQLITE_OK; 2383d5f0767cSdan int i; 2384d5f0767cSdan const char *zSep = ""; 2385d5f0767cSdan SessionBuffer buf = {0, 0, 0}; 2386d5f0767cSdan 2387d5f0767cSdan /* Append "UPDATE tbl SET " */ 2388d5f0767cSdan sessionAppendStr(&buf, "UPDATE ", &rc); 2389d5f0767cSdan sessionAppendIdent(&buf, zTab, &rc); 2390d5f0767cSdan sessionAppendStr(&buf, " SET ", &rc); 2391d5f0767cSdan 2392d5f0767cSdan /* Append the assignments */ 23930c698471Sdan for(i=0; i<p->nCol; i++){ 2394d5f0767cSdan sessionAppendStr(&buf, zSep, &rc); 23950c698471Sdan sessionAppendIdent(&buf, p->azCol[i], &rc); 2396d5f0767cSdan sessionAppendStr(&buf, " = CASE WHEN ?", &rc); 2397d5f0767cSdan sessionAppendInteger(&buf, i*3+2, &rc); 2398d5f0767cSdan sessionAppendStr(&buf, " THEN ?", &rc); 2399d5f0767cSdan sessionAppendInteger(&buf, i*3+3, &rc); 2400d5f0767cSdan sessionAppendStr(&buf, " ELSE ", &rc); 24010c698471Sdan sessionAppendIdent(&buf, p->azCol[i], &rc); 2402d5f0767cSdan sessionAppendStr(&buf, " END", &rc); 2403d5f0767cSdan zSep = ", "; 2404d5f0767cSdan } 2405d5f0767cSdan 2406d5f0767cSdan /* Append the PK part of the WHERE clause */ 2407d5f0767cSdan sessionAppendStr(&buf, " WHERE ", &rc); 24080c698471Sdan for(i=0; i<p->nCol; i++){ 24090c698471Sdan if( p->abPK[i] ){ 24100c698471Sdan sessionAppendIdent(&buf, p->azCol[i], &rc); 2411d5f0767cSdan sessionAppendStr(&buf, " = ?", &rc); 2412d5f0767cSdan sessionAppendInteger(&buf, i*3+1, &rc); 2413d5f0767cSdan sessionAppendStr(&buf, " AND ", &rc); 2414d5f0767cSdan } 2415d5f0767cSdan } 2416d5f0767cSdan 2417d5f0767cSdan /* Append the non-PK part of the WHERE clause */ 2418d5f0767cSdan sessionAppendStr(&buf, " (?", &rc); 24190c698471Sdan sessionAppendInteger(&buf, p->nCol*3+1, &rc); 2420d5f0767cSdan sessionAppendStr(&buf, " OR 1", &rc); 24210c698471Sdan for(i=0; i<p->nCol; i++){ 24220c698471Sdan if( !p->abPK[i] ){ 2423d5f0767cSdan sessionAppendStr(&buf, " AND (?", &rc); 2424d5f0767cSdan sessionAppendInteger(&buf, i*3+2, &rc); 2425d5f0767cSdan sessionAppendStr(&buf, "=0 OR ", &rc); 24260c698471Sdan sessionAppendIdent(&buf, p->azCol[i], &rc); 2427d5f0767cSdan sessionAppendStr(&buf, " IS ?", &rc); 2428d5f0767cSdan sessionAppendInteger(&buf, i*3+1, &rc); 2429d5f0767cSdan sessionAppendStr(&buf, ")", &rc); 2430d5f0767cSdan } 2431d5f0767cSdan } 2432d5f0767cSdan sessionAppendStr(&buf, ")", &rc); 2433d5f0767cSdan 2434d5f0767cSdan if( rc==SQLITE_OK ){ 24350c698471Sdan rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0); 2436d5f0767cSdan } 2437d5f0767cSdan sqlite3_free(buf.aBuf); 2438d5f0767cSdan 2439d5f0767cSdan return rc; 2440d5f0767cSdan } 2441d5f0767cSdan 2442296c7658Sdan /* 2443296c7658Sdan ** Formulate and prepare an SQL statement to query table zTab by primary 2444296c7658Sdan ** key. Assuming the following table structure: 2445296c7658Sdan ** 2446296c7658Sdan ** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); 2447296c7658Sdan ** 2448296c7658Sdan ** The SELECT statement looks like this: 2449296c7658Sdan ** 2450296c7658Sdan ** SELECT * FROM x WHERE a = ?1 AND c = ?3 2451296c7658Sdan ** 2452296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left 2453296c7658Sdan ** pointing to the prepared version of the SQL statement. 2454296c7658Sdan */ 2455d5f0767cSdan static int sessionSelectRow( 2456d5f0767cSdan sqlite3 *db, /* Database handle */ 2457d5f0767cSdan const char *zTab, /* Table name */ 24580c698471Sdan SessionApplyCtx *p /* Session changeset-apply context */ 2459d5f0767cSdan ){ 2460d7fb7d24Sdan return sessionSelectStmt( 2461d7fb7d24Sdan db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect); 2462d5f0767cSdan } 2463d5f0767cSdan 2464296c7658Sdan /* 2465296c7658Sdan ** Formulate and prepare an INSERT statement to add a record to table zTab. 2466296c7658Sdan ** For example: 2467296c7658Sdan ** 2468296c7658Sdan ** INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...); 2469296c7658Sdan ** 2470296c7658Sdan ** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left 2471296c7658Sdan ** pointing to the prepared version of the SQL statement. 2472296c7658Sdan */ 24730c698471Sdan static int sessionInsertRow( 24740c698471Sdan sqlite3 *db, /* Database handle */ 24750c698471Sdan const char *zTab, /* Table name */ 24760c698471Sdan SessionApplyCtx *p /* Session changeset-apply context */ 24770c698471Sdan ){ 24780c698471Sdan int rc = SQLITE_OK; 24790c698471Sdan int i; 24800c698471Sdan SessionBuffer buf = {0, 0, 0}; 24810c698471Sdan 24820c698471Sdan sessionAppendStr(&buf, "INSERT INTO main.", &rc); 24830c698471Sdan sessionAppendIdent(&buf, zTab, &rc); 24840c698471Sdan sessionAppendStr(&buf, " VALUES(?", &rc); 24850c698471Sdan for(i=1; i<p->nCol; i++){ 24860c698471Sdan sessionAppendStr(&buf, ", ?", &rc); 24870c698471Sdan } 24880c698471Sdan sessionAppendStr(&buf, ")", &rc); 24890c698471Sdan 24900c698471Sdan if( rc==SQLITE_OK ){ 24910c698471Sdan rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0); 24920c698471Sdan } 24930c698471Sdan sqlite3_free(buf.aBuf); 24940c698471Sdan return rc; 24950c698471Sdan } 24960c698471Sdan 2497296c7658Sdan /* 24987aa469cdSdan ** A wrapper around sqlite3_bind_value() that detects an extra problem. 24997aa469cdSdan ** See comments in the body of this function for details. 25007aa469cdSdan */ 25017aa469cdSdan static int sessionBindValue( 25027aa469cdSdan sqlite3_stmt *pStmt, /* Statement to bind value to */ 25037aa469cdSdan int i, /* Parameter number to bind to */ 25047aa469cdSdan sqlite3_value *pVal /* Value to bind */ 25057aa469cdSdan ){ 25067aa469cdSdan if( (pVal->type==SQLITE_TEXT || pVal->type==SQLITE_BLOB) && pVal->z==0 ){ 25077aa469cdSdan /* This condition occurs when an earlier OOM in a call to 25087aa469cdSdan ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within 25097aa469cdSdan ** a conflict-hanler) has zeroed the pVal->z pointer. Return NOMEM. */ 25107aa469cdSdan return SQLITE_NOMEM; 25117aa469cdSdan } 25127aa469cdSdan return sqlite3_bind_value(pStmt, i, pVal); 25137aa469cdSdan } 25147aa469cdSdan 25157aa469cdSdan /* 2516db04571cSdan ** Iterator pIter must point to an SQLITE_INSERT entry. This function 2517db04571cSdan ** transfers new.* values from the current iterator entry to statement 2518db04571cSdan ** pStmt. The table being inserted into has nCol columns. 2519db04571cSdan ** 2520db04571cSdan ** New.* value $i 0 from the iterator is bound to variable ($i+1) of 2521db04571cSdan ** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1) 2522db04571cSdan ** are transfered to the statement. Otherwise, if abPK is not NULL, it points 2523db04571cSdan ** to an array nCol elements in size. In this case only those values for 2524db04571cSdan ** which abPK[$i] is true are read from the iterator and bound to the 2525db04571cSdan ** statement. 2526db04571cSdan ** 2527db04571cSdan ** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK. 2528db04571cSdan */ 25297aa469cdSdan static int sessionBindRow( 2530db04571cSdan sqlite3_changeset_iter *pIter, /* Iterator to read values from */ 25317aa469cdSdan int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **), 2532db04571cSdan int nCol, /* Number of columns */ 2533db04571cSdan u8 *abPK, /* If not NULL, bind only if true */ 2534db04571cSdan sqlite3_stmt *pStmt /* Bind values to this statement */ 2535db04571cSdan ){ 2536db04571cSdan int i; 2537db04571cSdan int rc = SQLITE_OK; 25387aa469cdSdan 25397aa469cdSdan /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the 25407aa469cdSdan ** argument iterator points to a suitable entry. Make sure that xValue 25417aa469cdSdan ** is one of these to guarantee that it is safe to ignore the return 25427aa469cdSdan ** in the code below. */ 25437aa469cdSdan assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); 25447aa469cdSdan 2545db04571cSdan for(i=0; rc==SQLITE_OK && i<nCol; i++){ 2546db04571cSdan if( !abPK || abPK[i] ){ 2547db04571cSdan sqlite3_value *pVal; 25487aa469cdSdan (void)xValue(pIter, i, &pVal); 25497aa469cdSdan rc = sessionBindValue(pStmt, i+1, pVal); 2550db04571cSdan } 2551db04571cSdan } 2552db04571cSdan return rc; 2553db04571cSdan } 2554db04571cSdan 2555db04571cSdan /* 2556296c7658Sdan ** SQL statement pSelect is as generated by the sessionSelectRow() function. 2557296c7658Sdan ** This function binds the primary key values from the change that changeset 2558296c7658Sdan ** iterator pIter points to to the SELECT and attempts to seek to the table 2559296c7658Sdan ** entry. If a row is found, the SELECT statement left pointing at the row 2560296c7658Sdan ** and SQLITE_ROW is returned. Otherwise, if no row is found and no error 2561296c7658Sdan ** has occured, the statement is reset and SQLITE_OK is returned. If an 25627aa469cdSdan ** error occurs, the statement is reset and an SQLite error code is returned. 25637aa469cdSdan ** 25647aa469cdSdan ** If this function returns SQLITE_ROW, the caller must eventually reset() 25657aa469cdSdan ** statement pSelect. If any other value is returned, the statement does 25667aa469cdSdan ** not require a reset(). 2567296c7658Sdan ** 2568296c7658Sdan ** If the iterator currently points to an INSERT record, bind values from the 2569db04571cSdan ** new.* record to the SELECT statement. Or, if it points to a DELETE or 2570db04571cSdan ** UPDATE, bind values from the old.* record. 2571296c7658Sdan */ 25720c698471Sdan static int sessionSeekToRow( 257337f133ecSdan sqlite3 *db, /* Database handle */ 257437f133ecSdan sqlite3_changeset_iter *pIter, /* Changeset iterator */ 257537f133ecSdan u8 *abPK, /* Primary key flags array */ 25760c698471Sdan sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */ 257737f133ecSdan ){ 25787aa469cdSdan int rc; /* Return code */ 2579296c7658Sdan int nCol; /* Number of columns in table */ 2580296c7658Sdan int op; /* Changset operation (SQLITE_UPDATE etc.) */ 2581296c7658Sdan const char *zDummy; /* Unused */ 258237f133ecSdan 2583b4480e94Sdan sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); 25847aa469cdSdan rc = sessionBindRow(pIter, 2585db04571cSdan op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old, 2586db04571cSdan nCol, abPK, pSelect 2587db04571cSdan ); 25880c698471Sdan 25890c698471Sdan if( rc==SQLITE_OK ){ 25900c698471Sdan rc = sqlite3_step(pSelect); 25910c698471Sdan if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect); 25920c698471Sdan } 25930c698471Sdan 25940c698471Sdan return rc; 25950c698471Sdan } 25960c698471Sdan 2597296c7658Sdan /* 2598296c7658Sdan ** Invoke the conflict handler for the change that the changeset iterator 2599296c7658Sdan ** currently points to. 2600296c7658Sdan ** 2601296c7658Sdan ** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT. 2602296c7658Sdan ** If argument pbReplace is NULL, then the type of conflict handler invoked 2603296c7658Sdan ** depends solely on eType, as follows: 2604296c7658Sdan ** 2605296c7658Sdan ** eType value Value passed to xConflict 2606296c7658Sdan ** ------------------------------------------------- 2607296c7658Sdan ** CHANGESET_DATA CHANGESET_NOTFOUND 2608296c7658Sdan ** CHANGESET_CONFLICT CHANGESET_CONSTRAINT 2609296c7658Sdan ** 2610296c7658Sdan ** Or, if pbReplace is not NULL, then an attempt is made to find an existing 2611296c7658Sdan ** record with the same primary key as the record about to be deleted, updated 2612296c7658Sdan ** or inserted. If such a record can be found, it is available to the conflict 2613296c7658Sdan ** handler as the "conflicting" record. In this case the type of conflict 2614296c7658Sdan ** handler invoked is as follows: 2615296c7658Sdan ** 2616296c7658Sdan ** eType value PK Record found? Value passed to xConflict 2617296c7658Sdan ** ---------------------------------------------------------------- 2618296c7658Sdan ** CHANGESET_DATA Yes CHANGESET_DATA 2619296c7658Sdan ** CHANGESET_DATA No CHANGESET_NOTFOUND 2620296c7658Sdan ** CHANGESET_CONFLICT Yes CHANGESET_CONFLICT 2621296c7658Sdan ** CHANGESET_CONFLICT No CHANGESET_CONSTRAINT 2622296c7658Sdan ** 2623296c7658Sdan ** If pbReplace is not NULL, and a record with a matching PK is found, and 2624296c7658Sdan ** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace 2625296c7658Sdan ** is set to non-zero before returning SQLITE_OK. 2626296c7658Sdan ** 2627296c7658Sdan ** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is 2628296c7658Sdan ** returned. Or, if the conflict handler returns an invalid value, 2629296c7658Sdan ** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT, 2630296c7658Sdan ** this function returns SQLITE_OK. 2631296c7658Sdan */ 26320c698471Sdan static int sessionConflictHandler( 2633296c7658Sdan int eType, /* Either CHANGESET_DATA or CONFLICT */ 2634296c7658Sdan SessionApplyCtx *p, /* changeset_apply() context */ 26350c698471Sdan sqlite3_changeset_iter *pIter, /* Changeset iterator */ 26360c698471Sdan int(*xConflict)(void *, int, sqlite3_changeset_iter*), 2637296c7658Sdan void *pCtx, /* First argument for conflict handler */ 2638296c7658Sdan int *pbReplace /* OUT: Set to true if PK row is found */ 26390c698471Sdan ){ 2640296c7658Sdan int res; /* Value returned by conflict handler */ 26410c698471Sdan int rc; 26420c698471Sdan int nCol; 26430c698471Sdan int op; 26440c698471Sdan const char *zDummy; 26450c698471Sdan 2646b4480e94Sdan sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); 26470c698471Sdan 26480c698471Sdan assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA ); 26490c698471Sdan assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT ); 26500c698471Sdan assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND ); 265137f133ecSdan 265237f133ecSdan /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ 26530c698471Sdan if( pbReplace ){ 26540c698471Sdan rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect); 26550c698471Sdan }else{ 2656db04571cSdan rc = SQLITE_OK; 26570c698471Sdan } 26580c698471Sdan 26590c698471Sdan if( rc==SQLITE_ROW ){ 26600c698471Sdan /* There exists another row with the new.* primary key. */ 26610c698471Sdan pIter->pConflict = p->pSelect; 26620c698471Sdan res = xConflict(pCtx, eType, pIter); 26630c698471Sdan pIter->pConflict = 0; 26640c698471Sdan rc = sqlite3_reset(p->pSelect); 2665db04571cSdan }else if( rc==SQLITE_OK ){ 26660c698471Sdan /* No other row with the new.* primary key. */ 26670c698471Sdan res = xConflict(pCtx, eType+1, pIter); 26680c698471Sdan if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE; 266937f133ecSdan } 267037f133ecSdan 267137f133ecSdan if( rc==SQLITE_OK ){ 26720c698471Sdan switch( res ){ 26730c698471Sdan case SQLITE_CHANGESET_REPLACE: 2674f51e5f6cSdan assert( pbReplace ); 2675f51e5f6cSdan *pbReplace = 1; 26760c698471Sdan break; 26770c698471Sdan 26780c698471Sdan case SQLITE_CHANGESET_OMIT: 26790c698471Sdan break; 26800c698471Sdan 26810c698471Sdan case SQLITE_CHANGESET_ABORT: 26820c698471Sdan rc = SQLITE_ABORT; 26830c698471Sdan break; 26840c698471Sdan 26850c698471Sdan default: 26860c698471Sdan rc = SQLITE_MISUSE; 26870c698471Sdan break; 26880c698471Sdan } 26890c698471Sdan } 26900c698471Sdan 26910c698471Sdan return rc; 26920c698471Sdan } 26930c698471Sdan 2694296c7658Sdan /* 2695296c7658Sdan ** Attempt to apply the change that the iterator passed as the first argument 2696296c7658Sdan ** currently points to to the database. If a conflict is encountered, invoke 2697296c7658Sdan ** the conflict handler callback. 2698296c7658Sdan ** 2699296c7658Sdan ** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If 2700296c7658Sdan ** one is encountered, update or delete the row with the matching primary key 2701296c7658Sdan ** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs, 2702296c7658Sdan ** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry 2703296c7658Sdan ** to true before returning. In this case the caller will invoke this function 2704296c7658Sdan ** again, this time with pbRetry set to NULL. 2705296c7658Sdan ** 2706296c7658Sdan ** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is 2707296c7658Sdan ** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead. 2708296c7658Sdan ** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such 2709296c7658Sdan ** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true 2710296c7658Sdan ** before retrying. In this case the caller attempts to remove the conflicting 2711296c7658Sdan ** row before invoking this function again, this time with pbReplace set 2712296c7658Sdan ** to NULL. 2713296c7658Sdan ** 2714296c7658Sdan ** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function 2715296c7658Sdan ** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is 2716296c7658Sdan ** returned. 2717296c7658Sdan */ 27180c698471Sdan static int sessionApplyOneOp( 2719296c7658Sdan sqlite3_changeset_iter *pIter, /* Changeset iterator */ 2720296c7658Sdan SessionApplyCtx *p, /* changeset_apply() context */ 27210c698471Sdan int(*xConflict)(void *, int, sqlite3_changeset_iter *), 2722296c7658Sdan void *pCtx, /* First argument for the conflict handler */ 2723296c7658Sdan int *pbReplace, /* OUT: True to remove PK row and retry */ 2724296c7658Sdan int *pbRetry /* OUT: True to retry. */ 27250c698471Sdan ){ 27260c698471Sdan const char *zDummy; 27270c698471Sdan int op; 27280c698471Sdan int nCol; 27290c698471Sdan int rc = SQLITE_OK; 27300c698471Sdan 27310c698471Sdan assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect ); 27320c698471Sdan assert( p->azCol && p->abPK ); 27330c698471Sdan assert( !pbReplace || *pbReplace==0 ); 27340c698471Sdan 2735b4480e94Sdan sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); 27360c698471Sdan 27370c698471Sdan if( op==SQLITE_DELETE ){ 27380c698471Sdan 27390c698471Sdan /* Bind values to the DELETE statement. */ 27407aa469cdSdan rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, 0, p->pDelete); 27417cf7df7dSdan if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){ 27427cf7df7dSdan rc = sqlite3_bind_int(p->pDelete, nCol+1, pbRetry==0); 27437cf7df7dSdan } 27440c698471Sdan if( rc!=SQLITE_OK ) return rc; 27450c698471Sdan 27460c698471Sdan sqlite3_step(p->pDelete); 27470c698471Sdan rc = sqlite3_reset(p->pDelete); 27480c698471Sdan if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ 27490c698471Sdan rc = sessionConflictHandler( 27500c698471Sdan SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry 27510c698471Sdan ); 27520c698471Sdan }else if( rc==SQLITE_CONSTRAINT ){ 27530c698471Sdan rc = sessionConflictHandler( 27540c698471Sdan SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 27550c698471Sdan ); 27560c698471Sdan } 27570c698471Sdan 27580c698471Sdan }else if( op==SQLITE_UPDATE ){ 27590c698471Sdan int i; 27600c698471Sdan 27610c698471Sdan /* Bind values to the UPDATE statement. */ 27620c698471Sdan for(i=0; rc==SQLITE_OK && i<nCol; i++){ 27637aa469cdSdan sqlite3_value *pOld = sessionChangesetOld(pIter, i); 27647aa469cdSdan sqlite3_value *pNew = sessionChangesetNew(pIter, i); 27657aa469cdSdan 27660c698471Sdan sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew); 27677aa469cdSdan if( pOld ){ 27687aa469cdSdan rc = sessionBindValue(p->pUpdate, i*3+1, pOld); 27697aa469cdSdan } 27707aa469cdSdan if( rc==SQLITE_OK && pNew ){ 27717aa469cdSdan rc = sessionBindValue(p->pUpdate, i*3+3, pNew); 27720c698471Sdan } 27730c698471Sdan } 27747aa469cdSdan if( rc==SQLITE_OK ) sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0); 27750c698471Sdan if( rc!=SQLITE_OK ) return rc; 27760c698471Sdan 27770c698471Sdan /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict, 27780c698471Sdan ** the result will be SQLITE_OK with 0 rows modified. */ 27790c698471Sdan sqlite3_step(p->pUpdate); 27800c698471Sdan rc = sqlite3_reset(p->pUpdate); 27810c698471Sdan 27820c698471Sdan if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ 27830c698471Sdan /* A NOTFOUND or DATA error. Search the table to see if it contains 27840c698471Sdan ** a row with a matching primary key. If so, this is a DATA conflict. 27850c698471Sdan ** Otherwise, if there is no primary key match, it is a NOTFOUND. */ 27860c698471Sdan 27870c698471Sdan rc = sessionConflictHandler( 27880c698471Sdan SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry 27890c698471Sdan ); 27900c698471Sdan 27910c698471Sdan }else if( rc==SQLITE_CONSTRAINT ){ 2792db04571cSdan /* This is always a CONSTRAINT conflict. */ 2793db04571cSdan rc = sessionConflictHandler( 2794db04571cSdan SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 27950c698471Sdan ); 27960c698471Sdan } 27970c698471Sdan 27980c698471Sdan }else{ 27990c698471Sdan assert( op==SQLITE_INSERT ); 28007aa469cdSdan rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert); 28010c698471Sdan if( rc!=SQLITE_OK ) return rc; 28020c698471Sdan 28030c698471Sdan sqlite3_step(p->pInsert); 28040c698471Sdan rc = sqlite3_reset(p->pInsert); 2805db04571cSdan if( rc==SQLITE_CONSTRAINT ){ 28060c698471Sdan rc = sessionConflictHandler( 28070c698471Sdan SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace 28080c698471Sdan ); 280937f133ecSdan } 281037f133ecSdan } 281137f133ecSdan 281237f133ecSdan return rc; 281337f133ecSdan } 281437f133ecSdan 2815296c7658Sdan /* 2816296c7658Sdan ** Apply the changeset passed via pChangeset/nChangeset to the main database 2817296c7658Sdan ** attached to handle "db". Invoke the supplied conflict handler callback 2818296c7658Sdan ** to resolve any conflicts encountered while applying the change. 2819296c7658Sdan */ 2820d5f0767cSdan int sqlite3changeset_apply( 2821296c7658Sdan sqlite3 *db, /* Apply change to "main" db of this handle */ 2822296c7658Sdan int nChangeset, /* Size of changeset in bytes */ 2823296c7658Sdan void *pChangeset, /* Changeset blob */ 282440368988Sdan int(*xFilter)( 282540368988Sdan void *pCtx, /* Copy of sixth arg to _apply() */ 282640368988Sdan const char *zTab /* Table name */ 282740368988Sdan ), 2828d5f0767cSdan int(*xConflict)( 2829d5f0767cSdan void *pCtx, /* Copy of fifth arg to _apply() */ 2830d5f0767cSdan int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ 2831d5f0767cSdan sqlite3_changeset_iter *p /* Handle describing change and conflict */ 2832d5f0767cSdan ), 2833296c7658Sdan void *pCtx /* First argument passed to xConflict */ 2834d5f0767cSdan ){ 2835ca62ad57Sdan int schemaMismatch = 0; 2836296c7658Sdan sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ 2837296c7658Sdan int rc; /* Return code */ 2838d5f0767cSdan const char *zTab = 0; /* Name of current table */ 2839cfdbde21Sdrh int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ 2840296c7658Sdan SessionApplyCtx sApply; /* changeset_apply() context object */ 2841d5f0767cSdan 28420c698471Sdan memset(&sApply, 0, sizeof(sApply)); 284312ca0b56Sdan rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); 284412ca0b56Sdan if( rc!=SQLITE_OK ) return rc; 28450c698471Sdan 28464c220252Sdan sqlite3_mutex_enter(sqlite3_db_mutex(db)); 28470c698471Sdan rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); 28480c698471Sdan while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){ 28490c698471Sdan int nCol; 2850d5f0767cSdan int op; 28510c698471Sdan int bReplace = 0; 28520c698471Sdan int bRetry = 0; 28530c698471Sdan const char *zNew; 2854ca62ad57Sdan 2855b4480e94Sdan sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0); 2856d5f0767cSdan 28570c698471Sdan if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){ 2858ca62ad57Sdan u8 *abPK; 2859ca62ad57Sdan 2860cfdbde21Sdrh sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ 28610c698471Sdan sqlite3_finalize(sApply.pDelete); 28620c698471Sdan sqlite3_finalize(sApply.pUpdate); 28630c698471Sdan sqlite3_finalize(sApply.pInsert); 28640c698471Sdan sqlite3_finalize(sApply.pSelect); 28650c698471Sdan memset(&sApply, 0, sizeof(sApply)); 28660c698471Sdan sApply.db = db; 286737f133ecSdan 286840368988Sdan /* If an xFilter() callback was specified, invoke it now. If the 286940368988Sdan ** xFilter callback returns zero, skip this table. If it returns 287040368988Sdan ** non-zero, proceed. */ 287140368988Sdan schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew))); 287240368988Sdan if( schemaMismatch ){ 287340368988Sdan zTab = sqlite3_mprintf("%s", zNew); 28744f528042Sdan nTab = (int)strlen(zTab); 287540368988Sdan sApply.azCol = (const char **)zTab; 287640368988Sdan }else{ 2877ca62ad57Sdan sqlite3changeset_pk(pIter, &abPK, 0); 2878296c7658Sdan rc = sessionTableInfo( 2879ca62ad57Sdan db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK 2880ca62ad57Sdan ); 2881ca62ad57Sdan if( rc!=SQLITE_OK ) break; 28820c698471Sdan 2883ca62ad57Sdan if( sApply.nCol==0 ){ 2884ca62ad57Sdan schemaMismatch = 1; 2885ca62ad57Sdan sqlite3_log(SQLITE_SCHEMA, 2886ca62ad57Sdan "sqlite3changeset_apply(): no such table: %s", zTab 2887ca62ad57Sdan ); 2888ca62ad57Sdan } 2889ca62ad57Sdan else if( sApply.nCol!=nCol ){ 2890ca62ad57Sdan schemaMismatch = 1; 2891ca62ad57Sdan sqlite3_log(SQLITE_SCHEMA, 2892ca62ad57Sdan "sqlite3changeset_apply(): table %s has %d columns, expected %d", 2893ca62ad57Sdan zTab, sApply.nCol, nCol 2894ca62ad57Sdan ); 2895ca62ad57Sdan } 2896ca62ad57Sdan else if( memcmp(sApply.abPK, abPK, nCol)!=0 ){ 2897ca62ad57Sdan schemaMismatch = 1; 289840368988Sdan sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): " 289940368988Sdan "primary key mismatch for table %s", zTab 2900ca62ad57Sdan ); 2901ca62ad57Sdan } 2902ca62ad57Sdan else if( 2903ca62ad57Sdan (rc = sessionSelectRow(db, zTab, &sApply)) 29040c698471Sdan || (rc = sessionUpdateRow(db, zTab, &sApply)) 29050c698471Sdan || (rc = sessionDeleteRow(db, zTab, &sApply)) 29060c698471Sdan || (rc = sessionInsertRow(db, zTab, &sApply)) 290737f133ecSdan ){ 290837f133ecSdan break; 290937f133ecSdan } 2910cfdbde21Sdrh nTab = sqlite3Strlen30(zTab); 2911d5f0767cSdan } 291240368988Sdan } 2913d5f0767cSdan 2914ca62ad57Sdan /* If there is a schema mismatch on the current table, proceed to the 2915ca62ad57Sdan ** next change. A log message has already been issued. */ 2916ca62ad57Sdan if( schemaMismatch ) continue; 2917ca62ad57Sdan 29180c698471Sdan rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry); 29190c698471Sdan 29200c698471Sdan if( rc==SQLITE_OK && bRetry ){ 29210c698471Sdan rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, 0); 29220c698471Sdan } 29230c698471Sdan 29240c698471Sdan if( bReplace ){ 2925db04571cSdan assert( pIter->op==SQLITE_INSERT ); 29260c698471Sdan rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0); 29270c698471Sdan if( rc==SQLITE_OK ){ 29287aa469cdSdan rc = sessionBindRow(pIter, 2929db04571cSdan sqlite3changeset_new, sApply.nCol, sApply.abPK, sApply.pDelete); 29300c698471Sdan sqlite3_bind_int(sApply.pDelete, sApply.nCol+1, 1); 29310c698471Sdan } 29320c698471Sdan if( rc==SQLITE_OK ){ 29330c698471Sdan sqlite3_step(sApply.pDelete); 29340c698471Sdan rc = sqlite3_reset(sApply.pDelete); 29350c698471Sdan } 29360c698471Sdan if( rc==SQLITE_OK ){ 29370c698471Sdan rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, 0, 0); 29380c698471Sdan } 29390c698471Sdan if( rc==SQLITE_OK ){ 29400c698471Sdan rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0); 29410c698471Sdan } 29420c698471Sdan } 29430c698471Sdan } 2944d5f0767cSdan 2945296c7658Sdan if( rc==SQLITE_OK ){ 2946296c7658Sdan rc = sqlite3changeset_finalize(pIter); 2947296c7658Sdan }else{ 2948296c7658Sdan sqlite3changeset_finalize(pIter); 2949296c7658Sdan } 2950d5f0767cSdan 2951d5f0767cSdan if( rc==SQLITE_OK ){ 2952d5f0767cSdan rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); 2953d5f0767cSdan }else{ 2954d5f0767cSdan sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0); 2955d5f0767cSdan sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); 2956d5f0767cSdan } 2957d5f0767cSdan 29580c698471Sdan sqlite3_finalize(sApply.pInsert); 29590c698471Sdan sqlite3_finalize(sApply.pDelete); 29600c698471Sdan sqlite3_finalize(sApply.pUpdate); 29610c698471Sdan sqlite3_finalize(sApply.pSelect); 2962cfdbde21Sdrh sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ 29634c220252Sdan sqlite3_mutex_leave(sqlite3_db_mutex(db)); 2964d5f0767cSdan return rc; 2965d5f0767cSdan } 296691ddd559Sdan 296777fc1d5bSdan /* 296877fc1d5bSdan ** This function is called to merge two changes to the same row together as 296977fc1d5bSdan ** part of an sqlite3changeset_concat() operation. A new change object is 297077fc1d5bSdan ** allocated and a pointer to it stored in *ppNew. 297177fc1d5bSdan */ 29725d607a6eSdan static int sessionChangeMerge( 297377fc1d5bSdan SessionTable *pTab, /* Table structure */ 297477fc1d5bSdan SessionChange *pExist, /* Existing change */ 297577fc1d5bSdan int op2, /* Second change operation */ 297677fc1d5bSdan int bIndirect, /* True if second change is indirect */ 297777fc1d5bSdan u8 *aRec, /* Second change record */ 297877fc1d5bSdan int nRec, /* Number of bytes in aRec */ 297977fc1d5bSdan SessionChange **ppNew /* OUT: Merged change */ 29805d607a6eSdan ){ 29815d607a6eSdan SessionChange *pNew = 0; 29825d607a6eSdan 29835d607a6eSdan if( !pExist ){ 29845d607a6eSdan pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange)); 29855d607a6eSdan if( !pNew ){ 29865d607a6eSdan return SQLITE_NOMEM; 29875d607a6eSdan } 29885d607a6eSdan memset(pNew, 0, sizeof(SessionChange)); 2989798693b2Sdan pNew->op = op2; 29905d607a6eSdan pNew->bIndirect = bIndirect; 29915d607a6eSdan pNew->nRecord = nRec; 29925d607a6eSdan pNew->aRecord = aRec; 29935d607a6eSdan }else{ 2994798693b2Sdan int op1 = pExist->op; 29955d607a6eSdan 29965d607a6eSdan /* 29975d607a6eSdan ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2. 29985d607a6eSdan ** op1=INSERT, op2=UPDATE -> INSERT. 29995d607a6eSdan ** op1=INSERT, op2=DELETE -> (none) 30005d607a6eSdan ** 30015d607a6eSdan ** op1=UPDATE, op2=INSERT -> Unsupported. Discard op2. 30025d607a6eSdan ** op1=UPDATE, op2=UPDATE -> UPDATE. 30035d607a6eSdan ** op1=UPDATE, op2=DELETE -> DELETE. 30045d607a6eSdan ** 30055d607a6eSdan ** op1=DELETE, op2=INSERT -> UPDATE. 30065d607a6eSdan ** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2. 30075d607a6eSdan ** op1=DELETE, op2=DELETE -> Unsupported. Discard op2. 30085d607a6eSdan */ 30095d607a6eSdan if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT) 30105d607a6eSdan || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT) 30115d607a6eSdan || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE) 30125d607a6eSdan || (op1==SQLITE_DELETE && op2==SQLITE_DELETE) 30135d607a6eSdan ){ 30145d607a6eSdan pNew = pExist; 30155d607a6eSdan }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){ 30165d607a6eSdan sqlite3_free(pExist); 30175d607a6eSdan assert( pNew==0 ); 30185d607a6eSdan }else{ 30195d607a6eSdan int nByte; 30205d607a6eSdan u8 *aCsr; 30215d607a6eSdan 30225d607a6eSdan nByte = sizeof(SessionChange) + pExist->nRecord + nRec; 30235d607a6eSdan pNew = (SessionChange *)sqlite3_malloc(nByte); 30245d607a6eSdan if( !pNew ){ 30251756ae10Sdan sqlite3_free(pExist); 30265d607a6eSdan return SQLITE_NOMEM; 30275d607a6eSdan } 30285d607a6eSdan memset(pNew, 0, sizeof(SessionChange)); 30295d607a6eSdan pNew->bIndirect = (bIndirect && pExist->bIndirect); 30305d607a6eSdan aCsr = pNew->aRecord = (u8 *)&pNew[1]; 30315d607a6eSdan 3032b08a1efaSdan if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */ 30335d607a6eSdan u8 *a1 = aRec; 3034b08a1efaSdan assert( op2==SQLITE_UPDATE ); 3035798693b2Sdan pNew->op = SQLITE_INSERT; 30365d607a6eSdan sessionReadRecord(&a1, pTab->nCol, 0); 3037798693b2Sdan sessionMergeRecord(&aCsr, pTab->nCol, pExist->aRecord, a1); 3038b08a1efaSdan }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */ 3039b08a1efaSdan assert( op2==SQLITE_INSERT ); 3040798693b2Sdan pNew->op = SQLITE_UPDATE; 3041b08a1efaSdan if( 0==sessionMergeUpdate(&aCsr, pTab, pExist->aRecord, 0, aRec, 0) ){ 3042b08a1efaSdan sqlite3_free(pNew); 3043b08a1efaSdan pNew = 0; 30445d607a6eSdan } 3045b08a1efaSdan }else if( op2==SQLITE_UPDATE ){ /* UPDATE + UPDATE */ 30465d607a6eSdan u8 *a1 = pExist->aRecord; 30475d607a6eSdan u8 *a2 = aRec; 3048*cfec7eeeSdan assert( op1==SQLITE_UPDATE ); 30495d607a6eSdan sessionReadRecord(&a1, pTab->nCol, 0); 30505d607a6eSdan sessionReadRecord(&a2, pTab->nCol, 0); 3051798693b2Sdan pNew->op = SQLITE_UPDATE; 30525d607a6eSdan if( 0==sessionMergeUpdate(&aCsr, pTab, aRec, pExist->aRecord, a1, a2) ){ 30535d607a6eSdan sqlite3_free(pNew); 30545d607a6eSdan pNew = 0; 30555d607a6eSdan } 3056b08a1efaSdan }else{ /* UPDATE + DELETE */ 3057b08a1efaSdan assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE ); 3058798693b2Sdan pNew->op = SQLITE_DELETE; 3059798693b2Sdan sessionMergeRecord(&aCsr, pTab->nCol, aRec, pExist->aRecord); 30605d607a6eSdan } 30615d607a6eSdan 30625d607a6eSdan if( pNew ){ 30634f528042Sdan pNew->nRecord = (int)(aCsr - pNew->aRecord); 30645d607a6eSdan } 30655d607a6eSdan sqlite3_free(pExist); 30665d607a6eSdan } 30675d607a6eSdan } 30685d607a6eSdan 30695d607a6eSdan *ppNew = pNew; 30705d607a6eSdan return SQLITE_OK; 30715d607a6eSdan } 30725d607a6eSdan 307377fc1d5bSdan /* 307477fc1d5bSdan ** Add all changes in the changeset passed via the first two arguments to 307577fc1d5bSdan ** hash tables. 307677fc1d5bSdan */ 30775d607a6eSdan int sessionConcatChangeset( 307877fc1d5bSdan int nChangeset, /* Number of bytes in pChangeset */ 307977fc1d5bSdan void *pChangeset, /* Changeset buffer */ 308077fc1d5bSdan SessionTable **ppTabList /* IN/OUT: List of table objects */ 30815d607a6eSdan ){ 30825d607a6eSdan u8 *aRec; 30835d607a6eSdan int nRec; 30845d607a6eSdan sqlite3_changeset_iter *pIter; 30855d607a6eSdan int rc; 30865d607a6eSdan SessionTable *pTab = 0; 30875d607a6eSdan 30885d607a6eSdan rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); 30895d607a6eSdan if( rc!=SQLITE_OK ) return rc; 30905d607a6eSdan 30915d607a6eSdan while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){ 30925d607a6eSdan const char *zNew; 30935d607a6eSdan int nCol; 30945d607a6eSdan int op; 30955d607a6eSdan int iHash; 30965d607a6eSdan int bIndirect; 30975d607a6eSdan SessionChange *pChange; 30985d607a6eSdan SessionChange *pExist = 0; 30995d607a6eSdan SessionChange **pp; 31005d607a6eSdan 31015d607a6eSdan assert( pIter->apValue==0 ); 31025d607a6eSdan sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect); 31035d607a6eSdan 3104b08a1efaSdan assert( zNew>=(char *)pChangeset && zNew-nChangeset<((char *)pChangeset) ); 3105b08a1efaSdan assert( !pTab || pTab->zName-nChangeset<(char *)pChangeset ); 3106b08a1efaSdan assert( !pTab || zNew>=pTab->zName ); 3107b08a1efaSdan 31085d607a6eSdan if( !pTab || zNew!=pTab->zName ){ 31095d607a6eSdan /* Search the list for a matching table */ 31104f528042Sdan int nNew = (int)strlen(zNew); 3111f29123b5Sdan u8 *abPK; 3112f29123b5Sdan 3113f29123b5Sdan sqlite3changeset_pk(pIter, &abPK, 0); 31145d607a6eSdan for(pTab = *ppTabList; pTab; pTab=pTab->pNext){ 31155d607a6eSdan if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break; 31165d607a6eSdan } 31175d607a6eSdan if( !pTab ){ 31185d607a6eSdan pTab = sqlite3_malloc(sizeof(SessionTable)); 3119f29123b5Sdan if( !pTab ){ 3120f29123b5Sdan rc = SQLITE_NOMEM; 3121f29123b5Sdan break; 3122f29123b5Sdan } 31235d607a6eSdan memset(pTab, 0, sizeof(SessionTable)); 31245d607a6eSdan pTab->pNext = *ppTabList; 3125f29123b5Sdan pTab->abPK = abPK; 3126f29123b5Sdan pTab->nCol = nCol; 31275d607a6eSdan *ppTabList = pTab; 3128f29123b5Sdan }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ 3129f29123b5Sdan rc = SQLITE_SCHEMA; 3130f29123b5Sdan break; 31315d607a6eSdan } 31325d607a6eSdan pTab->zName = (char *)zNew; 31335d607a6eSdan } 31345d607a6eSdan 31351756ae10Sdan if( sessionGrowHash(pTab) ){ 31361756ae10Sdan rc = SQLITE_NOMEM; 31371756ae10Sdan break; 31381756ae10Sdan } 31395d607a6eSdan iHash = sessionChangeHash(pTab, aRec, pTab->nChange); 31405d607a6eSdan 31415d607a6eSdan /* Search for existing entry. If found, remove it from the hash table. 31425d607a6eSdan ** Code below may link it back in. 31435d607a6eSdan */ 31445d607a6eSdan for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){ 31455d607a6eSdan if( sessionChangeEqual(pTab, (*pp)->aRecord, aRec) ){ 31465d607a6eSdan pExist = *pp; 31475d607a6eSdan *pp = (*pp)->pNext; 31485d607a6eSdan pTab->nEntry--; 31495d607a6eSdan break; 31505d607a6eSdan } 31515d607a6eSdan } 31525d607a6eSdan 31535d607a6eSdan rc = sessionChangeMerge(pTab, pExist, op, bIndirect, aRec, nRec, &pChange); 31545d607a6eSdan if( rc ) break; 31555d607a6eSdan if( pChange ){ 31565d607a6eSdan pChange->pNext = pTab->apChange[iHash]; 31575d607a6eSdan pTab->apChange[iHash] = pChange; 31585d607a6eSdan pTab->nEntry++; 31595d607a6eSdan } 31605d607a6eSdan } 31615d607a6eSdan 31625d607a6eSdan if( rc==SQLITE_OK ){ 31635d607a6eSdan rc = sqlite3changeset_finalize(pIter); 31645d607a6eSdan }else{ 31655d607a6eSdan sqlite3changeset_finalize(pIter); 31665d607a6eSdan } 31675d607a6eSdan return rc; 31685d607a6eSdan } 31695d607a6eSdan 31705d607a6eSdan 31715d607a6eSdan /* 31725d607a6eSdan ** 1. Iterate through the left-hand changeset. Add an entry to a table 31735d607a6eSdan ** specific hash table for each change in the changeset. The hash table 31745d607a6eSdan ** key is the PK of the row affected by the change. 31755d607a6eSdan ** 31765d607a6eSdan ** 2. Then interate through the right-hand changeset. Attempt to add an 31775d607a6eSdan ** entry to a hash table for each component change. If a change already 31785d607a6eSdan ** exists with the same PK values, combine the two into a single change. 31795d607a6eSdan ** 31805d607a6eSdan ** 3. Write an output changeset based on the contents of the hash table. 31815d607a6eSdan */ 31825d607a6eSdan int sqlite3changeset_concat( 31835d607a6eSdan int nLeft, /* Number of bytes in lhs input */ 31845d607a6eSdan void *pLeft, /* Lhs input changeset */ 31855d607a6eSdan int nRight /* Number of bytes in rhs input */, 31865d607a6eSdan void *pRight, /* Rhs input changeset */ 31875d607a6eSdan int *pnOut, /* OUT: Number of bytes in output changeset */ 31885d607a6eSdan void **ppOut /* OUT: changeset (left <concat> right) */ 31895d607a6eSdan ){ 31905d607a6eSdan SessionTable *pList = 0; /* List of SessionTable objects */ 31915d607a6eSdan int rc; /* Return code */ 31925d607a6eSdan 31935d607a6eSdan *pnOut = 0; 31945d607a6eSdan *ppOut = 0; 31955d607a6eSdan 31965d607a6eSdan rc = sessionConcatChangeset(nLeft, pLeft, &pList); 31975d607a6eSdan if( rc==SQLITE_OK ){ 31985d607a6eSdan rc = sessionConcatChangeset(nRight, pRight, &pList); 31995d607a6eSdan } 32005d607a6eSdan 32015d607a6eSdan /* Create the serialized output changeset based on the contents of the 32025d607a6eSdan ** hash tables attached to the SessionTable objects in list pList. 32035d607a6eSdan */ 32045d607a6eSdan if( rc==SQLITE_OK ){ 32055d607a6eSdan SessionTable *pTab; 32065d607a6eSdan SessionBuffer buf = {0, 0, 0}; 32075d607a6eSdan for(pTab=pList; pTab; pTab=pTab->pNext){ 32085d607a6eSdan int i; 32095d607a6eSdan if( pTab->nEntry==0 ) continue; 32105d607a6eSdan 32115d607a6eSdan sessionAppendTableHdr(&buf, pTab, &rc); 32125d607a6eSdan for(i=0; i<pTab->nChange; i++){ 32135d607a6eSdan SessionChange *p; 32145d607a6eSdan for(p=pTab->apChange[i]; p; p=p->pNext){ 3215798693b2Sdan sessionAppendByte(&buf, p->op, &rc); 32165d607a6eSdan sessionAppendByte(&buf, p->bIndirect, &rc); 32175d607a6eSdan sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); 32185d607a6eSdan } 32195d607a6eSdan } 32205d607a6eSdan } 32215d607a6eSdan 32225d607a6eSdan if( rc==SQLITE_OK ){ 32235d607a6eSdan *ppOut = buf.aBuf; 32245d607a6eSdan *pnOut = buf.nBuf; 32255d607a6eSdan }else{ 32265d607a6eSdan sqlite3_free(buf.aBuf); 32275d607a6eSdan } 32285d607a6eSdan } 32295d607a6eSdan 32305d607a6eSdan sessionDeleteTable(pList); 32315d607a6eSdan return rc; 32325d607a6eSdan } 32335d607a6eSdan 32349b1c62d4Sdrh #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ 3235