1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Fix some missing comments and other issues with session module code.

FossilOrigin-Name: 20d7c280235201e519f296372f269e7cecda24da
This commit is contained in:
dan
2011-04-18 12:05:03 +00:00
parent 80fe2d9310
commit 798693b2b1
3 changed files with 126 additions and 65 deletions

View File

@ -136,7 +136,7 @@ struct SessionTable {
** this structure stored in a SessionTable.aChange[] hash table. ** this structure stored in a SessionTable.aChange[] hash table.
*/ */
struct SessionChange { 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 bIndirect; /* True if this change is "indirect" */
int nRecord; /* Number of bytes in buffer aRecord[] */ int nRecord; /* Number of bytes in buffer aRecord[] */
u8 *aRecord; /* Buffer containing old.* record */ u8 *aRecord; /* Buffer containing old.* record */
@ -290,29 +290,67 @@ static int sessionSerializeValue(
return SQLITE_OK; 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, <value 1>);
** hash_key_value = HASH_APPEND(hash_key_value, <value 2>);
** hash_key_value = HASH_APPEND(hash_key_value, <value 3>);
**
** 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) #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){ static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
h = HASH_APPEND(h, i & 0xFFFFFFFF); h = HASH_APPEND(h, i & 0xFFFFFFFF);
return HASH_APPEND(h, (i>>32)&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){ static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
int i; int i;
for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]); for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
return h; return h;
} }
/*
** Append the hash of the data type passed as the second argument to the
** hash-key value passed as the first. Return the new hash-key value.
*/
static unsigned int sessionHashAppendType(unsigned int h, int eType){
return HASH_APPEND(h, eType);
}
/* /*
** This function may only be called from within a pre-update callback. ** This function may only be called from within a pre-update callback.
** It calculates a hash based on the primary key values of the old.* or ** It calculates a hash based on the primary key values of the old.* or
** new.* row currently available. The value returned is guaranteed to ** new.* row currently available and, assuming no error occurs, writes it to
** be less than pTab->nBucket. ** *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 */ sqlite3 *db, /* Database handle */
SessionTable *pTab, /* Session table handle */ SessionTable *pTab, /* Session table handle */
int bNew, /* True to hash the new.* PK */ int bNew, /* True to hash the new.* PK */
int *piHash, /* OUT: Hash value */ 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 */ unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */ int i; /* Used to iterate through columns */
@ -333,7 +371,7 @@ static unsigned int sessionPreupdateHash(
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
eType = sqlite3_value_type(pVal); eType = sqlite3_value_type(pVal);
h = HASH_APPEND(h, eType); h = sessionHashAppendType(h, eType);
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
i64 iVal; i64 iVal;
if( eType==SQLITE_INTEGER ){ if( eType==SQLITE_INTEGER ){
@ -356,7 +394,6 @@ static unsigned int sessionPreupdateHash(
}else{ }else{
assert( eType==SQLITE_NULL ); assert( eType==SQLITE_NULL );
*pbNullPK = 1; *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 ** 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 ** calculated by this function are compatible with those calculated by
** sessionPreupdateHash(). ** sessionPreupdateHash().
*/ */
@ -409,7 +446,7 @@ static unsigned int sessionChangeHash(
if( isPK ){ if( isPK ){
a++; a++;
h = HASH_APPEND(h, eType); h = sessionHashAppendType(h, eType);
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
h = sessionHashAppendI64(h, sessionGetI64(a)); h = sessionHashAppendI64(h, sessionGetI64(a));
a += 8; a += 8;
@ -426,20 +463,26 @@ static unsigned int sessionChangeHash(
return (h % nBucket); 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( static int sessionChangeEqual(
SessionTable *pTab, SessionTable *pTab, /* Table used for PK definition */
u8 *aLeft, /* Change record */ u8 *aLeft, /* Change record */
u8 *aRight /* Change record */ u8 *aRight /* Change record */
){ ){
u8 *a1 = aLeft; u8 *a1 = aLeft; /* Cursor to iterate through aLeft */
u8 *a2 = aRight; u8 *a2 = aRight; /* Cursor to iterate through aRight */
int i; int iCol; /* Used to iterate through table columns */
for(i=0; i<pTab->nCol; i++){ for(iCol=0; iCol<pTab->nCol; iCol++){
int n1 = sessionSerialLen(a1); int n1 = sessionSerialLen(a1);
int n2 = sessionSerialLen(a2); 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; return 0;
} }
a1 += n1; a1 += n1;
@ -449,18 +492,31 @@ static int sessionChangeEqual(
return 1; 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( static void sessionMergeRecord(
u8 **paOut, u8 **paOut,
SessionTable *pTab, int nCol,
u8 *aLeft, u8 *aLeft,
u8 *aRight u8 *aRight
){ ){
u8 *a1 = aLeft; u8 *a1 = aLeft; /* Cursor used to iterate through aLeft */
u8 *a2 = aRight; u8 *a2 = aRight; /* Cursor used to iterate through aRight */
u8 *aOut = *paOut; u8 *aOut = *paOut; /* Output cursor */
int i; int iCol; /* Used to iterate from 0 to nCol */
for(i=0; i<pTab->nCol; i++){ for(iCol=0; iCol<nCol; iCol++){
int n1 = sessionSerialLen(a1); int n1 = sessionSerialLen(a1);
int n2 = sessionSerialLen(a2); int n2 = sessionSerialLen(a2);
if( *a2 ){ if( *a2 ){
@ -477,10 +533,24 @@ static void sessionMergeRecord(
*paOut = aOut; *paOut = aOut;
} }
/*
** This is a helper function used by sessionMergeUpdate().
**
** When this function is called, both *paOne and *paTwo point to a value
** within a change record. Before it returns, both have been advanced so
** as to point to the next value in the record.
**
** If, when this function is called, *paTwo points to a valid value (i.e.
** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paOne
** pointer is returned and *pnVal is set to the number of bytes in the
** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
** set to the number of bytes in the value at *paOne. If *paOne points
** to the "no value" placeholder, *pnVal is set to 1.
*/
static u8 *sessionMergeValue( static u8 *sessionMergeValue(
u8 **paOne, u8 **paOne, /* IN/OUT: Left-hand buffer pointer */
u8 **paTwo, u8 **paTwo, /* IN/OUT: Right-hand buffer pointer */
int *pnVal int *pnVal /* OUT: Bytes in returned value */
){ ){
u8 *a1 = *paOne; u8 *a1 = *paOne;
u8 *a2 = *paTwo; u8 *a2 = *paTwo;
@ -507,13 +577,17 @@ static u8 *sessionMergeValue(
return pRet; return pRet;
} }
/*
** This function is used by changeset_concat() to merge two UPDATE changes
** on the same row.
*/
static int sessionMergeUpdate( static int sessionMergeUpdate(
u8 **paOut, u8 **paOut, /* IN/OUT: Pointer to output buffer */
SessionTable *pTab, SessionTable *pTab, /* Table change pertains to */
u8 *aOldRecord1, u8 *aOldRecord1, /* old.* record for first change */
u8 *aOldRecord2, u8 *aOldRecord2, /* old.* record for second change */
u8 *aNewRecord1, u8 *aNewRecord1, /* new.* record for first change */
u8 *aNewRecord2 u8 *aNewRecord2 /* new.* record for second change */
){ ){
u8 *aOld1 = aOldRecord1; u8 *aOld1 = aOldRecord1;
u8 *aOld2 = aOldRecord2; u8 *aOld2 = aOldRecord2;
@ -584,25 +658,12 @@ static void sessionPreupdateEqual(
*pbEqual = 0; *pbEqual = 0;
for(i=0; i<pTab->nCol; i++){ for(i=0; i<pTab->nCol; i++){
int eType = *a++;
if( !pTab->abPK[i] ){ if( !pTab->abPK[i] ){
switch( eType ){ a += sessionSerialLen(a);
case SQLITE_INTEGER:
case SQLITE_FLOAT:
a += 8;
break;
case SQLITE_TEXT:
case SQLITE_BLOB: {
int n;
a += sessionVarintGet(a, &n);
a += n;
break;
}
}
}else{ }else{
sqlite3_value *pVal; /* Value returned by preupdate_new/old */ sqlite3_value *pVal; /* Value returned by preupdate_new/old */
int rc; /* Error code from 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 /* The following calls to preupdate_new() and preupdate_old() can not
** fail. This is because they cache their return values, and by the ** fail. This is because they cache their return values, and by the
@ -942,7 +1003,7 @@ static void sessionPreupdateOneChange(
pChange->bIndirect = 1; pChange->bIndirect = 1;
} }
pChange->nRecord = nByte; pChange->nRecord = nByte;
pChange->bInsert = (op==SQLITE_INSERT); pChange->op = op;
pChange->pNext = pTab->apChange[iHash]; pChange->pNext = pTab->apChange[iHash];
pTab->apChange[iHash] = pChange; pTab->apChange[iHash] = pChange;
@ -1606,8 +1667,8 @@ int sqlite3session_changeset(
rc = sessionSelectBind(pSel, nCol, abPK, p); rc = sessionSelectBind(pSel, nCol, abPK, p);
if( rc!=SQLITE_OK ) continue; if( rc!=SQLITE_OK ) continue;
if( sqlite3_step(pSel)==SQLITE_ROW ){ if( sqlite3_step(pSel)==SQLITE_ROW ){
int iCol; if( p->op==SQLITE_INSERT ){
if( p->bInsert ){ int iCol;
sessionAppendByte(&buf, SQLITE_INSERT, &rc); sessionAppendByte(&buf, SQLITE_INSERT, &rc);
sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendByte(&buf, p->bIndirect, &rc);
for(iCol=0; iCol<nCol; iCol++){ for(iCol=0; iCol<nCol; iCol++){
@ -1616,7 +1677,7 @@ int sqlite3session_changeset(
}else{ }else{
rc = sessionAppendUpdate(&buf, pSel, p, abPK); rc = sessionAppendUpdate(&buf, pSel, p, abPK);
} }
}else if( !p->bInsert ){ }else if( p->op!=SQLITE_INSERT ){
/* A DELETE change */ /* A DELETE change */
sessionAppendByte(&buf, SQLITE_DELETE, &rc); sessionAppendByte(&buf, SQLITE_DELETE, &rc);
sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendByte(&buf, p->bIndirect, &rc);
@ -2784,12 +2845,12 @@ static int sessionChangeMerge(
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
memset(pNew, 0, sizeof(SessionChange)); memset(pNew, 0, sizeof(SessionChange));
pNew->bInsert = op2; pNew->op = op2;
pNew->bIndirect = bIndirect; pNew->bIndirect = bIndirect;
pNew->nRecord = nRec; pNew->nRecord = nRec;
pNew->aRecord = aRec; pNew->aRecord = aRec;
}else{ }else{
int op1 = pExist->bInsert; int op1 = pExist->op;
/* /*
** op1=INSERT, op2=INSERT -> Unsupported. Discard op2. ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2.
@ -2830,12 +2891,12 @@ static int sessionChangeMerge(
if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */ if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */
u8 *a1 = aRec; u8 *a1 = aRec;
assert( op2==SQLITE_UPDATE ); assert( op2==SQLITE_UPDATE );
pNew->bInsert = SQLITE_INSERT; pNew->op = SQLITE_INSERT;
sessionReadRecord(&a1, pTab->nCol, 0); 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 */ }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */
assert( op2==SQLITE_INSERT ); assert( op2==SQLITE_INSERT );
pNew->bInsert = SQLITE_UPDATE; pNew->op = SQLITE_UPDATE;
if( 0==sessionMergeUpdate(&aCsr, pTab, pExist->aRecord, 0, aRec, 0) ){ if( 0==sessionMergeUpdate(&aCsr, pTab, pExist->aRecord, 0, aRec, 0) ){
sqlite3_free(pNew); sqlite3_free(pNew);
pNew = 0; pNew = 0;
@ -2846,15 +2907,15 @@ static int sessionChangeMerge(
u8 *a2 = aRec; u8 *a2 = aRec;
sessionReadRecord(&a1, pTab->nCol, 0); sessionReadRecord(&a1, pTab->nCol, 0);
sessionReadRecord(&a2, 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) ){ if( 0==sessionMergeUpdate(&aCsr, pTab, aRec, pExist->aRecord, a1, a2) ){
sqlite3_free(pNew); sqlite3_free(pNew);
pNew = 0; pNew = 0;
} }
}else{ /* UPDATE + DELETE */ }else{ /* UPDATE + DELETE */
assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE ); assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE );
pNew->bInsert = SQLITE_DELETE; pNew->op = SQLITE_DELETE;
sessionMergeRecord(&aCsr, pTab, aRec, pExist->aRecord); sessionMergeRecord(&aCsr, pTab->nCol, aRec, pExist->aRecord);
} }
if( pNew ){ if( pNew ){
@ -3006,7 +3067,7 @@ int sqlite3changeset_concat(
for(i=0; i<pTab->nChange; i++){ for(i=0; i<pTab->nChange; i++){
SessionChange *p; SessionChange *p;
for(p=pTab->apChange[i]; p; p=p->pNext){ for(p=pTab->apChange[i]; p; p=p->pNext){
sessionAppendByte(&buf, p->bInsert, &rc); sessionAppendByte(&buf, p->op, &rc);
sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendByte(&buf, p->bIndirect, &rc);
sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
} }

View File

@ -1,5 +1,5 @@
C Further\scoverage\stests\sfor\sthe\ssession\smodule. C Fix\ssome\smissing\scomments\sand\sother\sissues\swith\ssession\smodule\scode.
D 2011-04-18T07:36:27.686 D 2011-04-18T12:05:03.122
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -106,7 +106,7 @@ F ext/session/session4.test a6ed685da7a5293c5d6f99855bcf41dbc352ca84
F ext/session/session5.test 8fdfaf9dba28a2f1c6b89b06168bdab1fef2d478 F ext/session/session5.test 8fdfaf9dba28a2f1c6b89b06168bdab1fef2d478
F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5 F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5
F ext/session/sessionfault.test 401045278298a242cbc2e4bc986c102f01ff2180 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/sqlite3session.h 665f5591562e3c71eb3d0da26f1a1efae26f7bcf
F ext/session/test_session.c 311e5b9228374d0b5780448f289847ff1cf7d388 F ext/session/test_session.c 311e5b9228374d0b5780448f289847ff1cf7d388
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
@ -938,7 +938,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P f46d4b641d613c39a80b12106e6a6ac0efc8be83 P 69a01c708bf044eacf21a8951fe9e7d9fb4332c5
R bc07f4a1348864ef3dbdf87527d99ed2 R b92955ca865aafd93c0b967b180f7cc1
U dan U dan
Z fcc600b67a0d6c899a275e81c6cbea0f Z 3095f8afd486ad0b7645eeb6cb4cbdcc

View File

@ -1 +1 @@
69a01c708bf044eacf21a8951fe9e7d9fb4332c5 20d7c280235201e519f296372f269e7cecda24da