diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 2232d21938..5a31a204f5 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -136,7 +136,7 @@ struct SessionTable { ** this structure stored in a SessionTable.aChange[] hash table. */ struct SessionChange { - int bInsert; /* True if row was inserted this session */ + int op; /* One of UPDATE, DELETE, INSERT */ int bIndirect; /* True if this change is "indirect" */ int nRecord; /* Number of bytes in buffer aRecord[] */ u8 *aRecord; /* Buffer containing old.* record */ @@ -290,29 +290,67 @@ static int sessionSerializeValue( return SQLITE_OK; } +/* +** This macro is used to calculate hash key values for data structures. In +** order to use this macro, the entire data structure must be represented +** as a series of unsigned integers. In order to calculate a hash-key value +** for a data structure represented as three such integers, the macro may +** then be used as follows: +** +** int hash_key_value; +** hash_key_value = HASH_APPEND(0, ); +** hash_key_value = HASH_APPEND(hash_key_value, ); +** hash_key_value = HASH_APPEND(hash_key_value, ); +** +** In practice, the data structures this macro is used for are the primary +** key values of modified rows. +*/ #define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add) + +/* +** Append the hash of the 64-bit integer passed as the second argument to the +** hash-key value passed as the first. Return the new hash-key value. +*/ static unsigned int sessionHashAppendI64(unsigned int h, i64 i){ h = HASH_APPEND(h, i & 0xFFFFFFFF); return HASH_APPEND(h, (i>>32)&0xFFFFFFFF); } + +/* +** Append the hash of the blob passed via the second and third arguments to +** the hash-key value passed as the first. Return the new hash-key value. +*/ static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){ int i; for(i=0; inBucket. +** new.* row currently available and, assuming no error occurs, writes it to +** *piHash before returning. If the primary key contains one or more NULL +** values, *pbNullPK is set to true before returning. +** +** If an error occurs, an SQLite error code is returned and the final values +** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned +** and the output variables are set as described above. */ -static unsigned int sessionPreupdateHash( +static int sessionPreupdateHash( sqlite3 *db, /* Database handle */ SessionTable *pTab, /* Session table handle */ int bNew, /* True to hash the new.* PK */ int *piHash, /* OUT: Hash value */ - int *pbNullPK + int *pbNullPK /* OUT: True if there are NULL values in PK */ ){ unsigned int h = 0; /* Hash value to return */ int i; /* Used to iterate through columns */ @@ -333,7 +371,7 @@ static unsigned int sessionPreupdateHash( if( rc!=SQLITE_OK ) return rc; eType = sqlite3_value_type(pVal); - h = HASH_APPEND(h, eType); + h = sessionHashAppendType(h, eType); if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ i64 iVal; if( eType==SQLITE_INTEGER ){ @@ -356,7 +394,6 @@ static unsigned int sessionPreupdateHash( }else{ assert( eType==SQLITE_NULL ); *pbNullPK = 1; - return SQLITE_OK; } } } @@ -381,7 +418,7 @@ static int sessionSerialLen(u8 *a){ /* ** Based on the primary key values stored in change aRecord, calculate a -** hash key, assuming the has table has nBucket buckets. The hash keys +** hash key. Assume the has table has nBucket buckets. The hash keys ** calculated by this function are compatible with those calculated by ** sessionPreupdateHash(). */ @@ -409,7 +446,7 @@ static unsigned int sessionChangeHash( if( isPK ){ a++; - h = HASH_APPEND(h, eType); + h = sessionHashAppendType(h, eType); if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ h = sessionHashAppendI64(h, sessionGetI64(a)); a += 8; @@ -426,20 +463,26 @@ static unsigned int sessionChangeHash( return (h % nBucket); } +/* +** Arguments aLeft and aRight are pointers to change records for table pTab. +** This function returns true if the two records apply to the same row (i.e. +** have the same values stored in the primary key columns), or false +** otherwise. +*/ static int sessionChangeEqual( - SessionTable *pTab, + SessionTable *pTab, /* Table used for PK definition */ u8 *aLeft, /* Change record */ u8 *aRight /* Change record */ ){ - u8 *a1 = aLeft; - u8 *a2 = aRight; - int i; + u8 *a1 = aLeft; /* Cursor to iterate through aLeft */ + u8 *a2 = aRight; /* Cursor to iterate through aRight */ + int iCol; /* Used to iterate through table columns */ - for(i=0; inCol; i++){ + for(iCol=0; iColnCol; iCol++){ int n1 = sessionSerialLen(a1); int n2 = sessionSerialLen(a2); - if( pTab->abPK[i] && (n1!=n2 || memcmp(a1, a2, n1)) ){ + if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){ return 0; } a1 += n1; @@ -449,18 +492,31 @@ static int sessionChangeEqual( return 1; } +/* +** Arguments aLeft and aRight both point to buffers containing change +** records with nCol columns. This function "merges" the two records into +** a single records which is written to the buffer at *paOut. *paOut is +** then set to point to one byte after the last byte written before +** returning. +** +** The merging of records is done as follows: For each column, if the +** aRight record contains a value for the column, copy the value from +** their. Otherwise, if aLeft contains a value, copy it. If neither +** record contains a value for a given column, then neither does the +** output record. +*/ static void sessionMergeRecord( u8 **paOut, - SessionTable *pTab, + int nCol, u8 *aLeft, u8 *aRight ){ - u8 *a1 = aLeft; - u8 *a2 = aRight; - u8 *aOut = *paOut; - int i; + u8 *a1 = aLeft; /* Cursor used to iterate through aLeft */ + u8 *a2 = aRight; /* Cursor used to iterate through aRight */ + u8 *aOut = *paOut; /* Output cursor */ + int iCol; /* Used to iterate from 0 to nCol */ - for(i=0; inCol; i++){ + for(iCol=0; iColnCol; i++){ - int eType = *a++; if( !pTab->abPK[i] ){ - switch( eType ){ - case SQLITE_INTEGER: - case SQLITE_FLOAT: - a += 8; - break; - - case SQLITE_TEXT: - case SQLITE_BLOB: { - int n; - a += sessionVarintGet(a, &n); - a += n; - break; - } - } + a += sessionSerialLen(a); }else{ sqlite3_value *pVal; /* Value returned by preupdate_new/old */ int rc; /* Error code from preupdate_new/old */ + int eType = *a++; /* Type of value from change record */ /* The following calls to preupdate_new() and preupdate_old() can not ** fail. This is because they cache their return values, and by the @@ -942,7 +1003,7 @@ static void sessionPreupdateOneChange( pChange->bIndirect = 1; } pChange->nRecord = nByte; - pChange->bInsert = (op==SQLITE_INSERT); + pChange->op = op; pChange->pNext = pTab->apChange[iHash]; pTab->apChange[iHash] = pChange; @@ -1606,8 +1667,8 @@ int sqlite3session_changeset( rc = sessionSelectBind(pSel, nCol, abPK, p); if( rc!=SQLITE_OK ) continue; if( sqlite3_step(pSel)==SQLITE_ROW ){ - int iCol; - if( p->bInsert ){ + if( p->op==SQLITE_INSERT ){ + int iCol; sessionAppendByte(&buf, SQLITE_INSERT, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); for(iCol=0; iColbInsert ){ + }else if( p->op!=SQLITE_INSERT ){ /* A DELETE change */ sessionAppendByte(&buf, SQLITE_DELETE, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); @@ -2784,12 +2845,12 @@ static int sessionChangeMerge( return SQLITE_NOMEM; } memset(pNew, 0, sizeof(SessionChange)); - pNew->bInsert = op2; + pNew->op = op2; pNew->bIndirect = bIndirect; pNew->nRecord = nRec; pNew->aRecord = aRec; }else{ - int op1 = pExist->bInsert; + int op1 = pExist->op; /* ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2. @@ -2830,12 +2891,12 @@ static int sessionChangeMerge( if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */ u8 *a1 = aRec; assert( op2==SQLITE_UPDATE ); - pNew->bInsert = SQLITE_INSERT; + pNew->op = SQLITE_INSERT; sessionReadRecord(&a1, pTab->nCol, 0); - sessionMergeRecord(&aCsr, pTab, pExist->aRecord, a1); + sessionMergeRecord(&aCsr, pTab->nCol, pExist->aRecord, a1); }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */ assert( op2==SQLITE_INSERT ); - pNew->bInsert = SQLITE_UPDATE; + pNew->op = SQLITE_UPDATE; if( 0==sessionMergeUpdate(&aCsr, pTab, pExist->aRecord, 0, aRec, 0) ){ sqlite3_free(pNew); pNew = 0; @@ -2846,15 +2907,15 @@ static int sessionChangeMerge( u8 *a2 = aRec; sessionReadRecord(&a1, pTab->nCol, 0); sessionReadRecord(&a2, pTab->nCol, 0); - pNew->bInsert = SQLITE_UPDATE; + pNew->op = SQLITE_UPDATE; if( 0==sessionMergeUpdate(&aCsr, pTab, aRec, pExist->aRecord, a1, a2) ){ sqlite3_free(pNew); pNew = 0; } }else{ /* UPDATE + DELETE */ assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE ); - pNew->bInsert = SQLITE_DELETE; - sessionMergeRecord(&aCsr, pTab, aRec, pExist->aRecord); + pNew->op = SQLITE_DELETE; + sessionMergeRecord(&aCsr, pTab->nCol, aRec, pExist->aRecord); } if( pNew ){ @@ -3006,7 +3067,7 @@ int sqlite3changeset_concat( for(i=0; inChange; i++){ SessionChange *p; for(p=pTab->apChange[i]; p; p=p->pNext){ - sessionAppendByte(&buf, p->bInsert, &rc); + sessionAppendByte(&buf, p->op, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); } diff --git a/manifest b/manifest index c0ef6b6a13..5d77f78c46 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\scoverage\stests\sfor\sthe\ssession\smodule. -D 2011-04-18T07:36:27.686 +C Fix\ssome\smissing\scomments\sand\sother\sissues\swith\ssession\smodule\scode. +D 2011-04-18T12:05:03.122 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -106,7 +106,7 @@ F ext/session/session4.test a6ed685da7a5293c5d6f99855bcf41dbc352ca84 F ext/session/session5.test 8fdfaf9dba28a2f1c6b89b06168bdab1fef2d478 F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5 F ext/session/sessionfault.test 401045278298a242cbc2e4bc986c102f01ff2180 -F ext/session/sqlite3session.c fd43b8cb35d8112fa77a9e9101f9efe7005e5e23 +F ext/session/sqlite3session.c 04a5065d5b64f43f120113df170e96bb8db8e229 F ext/session/sqlite3session.h 665f5591562e3c71eb3d0da26f1a1efae26f7bcf F ext/session/test_session.c 311e5b9228374d0b5780448f289847ff1cf7d388 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x @@ -938,7 +938,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P f46d4b641d613c39a80b12106e6a6ac0efc8be83 -R bc07f4a1348864ef3dbdf87527d99ed2 +P 69a01c708bf044eacf21a8951fe9e7d9fb4332c5 +R b92955ca865aafd93c0b967b180f7cc1 U dan -Z fcc600b67a0d6c899a275e81c6cbea0f +Z 3095f8afd486ad0b7645eeb6cb4cbdcc diff --git a/manifest.uuid b/manifest.uuid index 4c438b56bb..521c05b9db 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -69a01c708bf044eacf21a8951fe9e7d9fb4332c5 \ No newline at end of file +20d7c280235201e519f296372f269e7cecda24da \ No newline at end of file