mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Fix a problem with handling rebasing UPDATE changes for REPLACE conflict
resolution. FossilOrigin-Name: f7bf71f1d47044e3cbc74018294b8af5ad52c2bb84954e99bbd4e9b8c36fc077
This commit is contained in:
@ -73,6 +73,7 @@ do_apply_v2_test 1.1.1 {
|
|||||||
} {
|
} {
|
||||||
{INSERT t1 0 X. {} {i 1 t {value B}}}
|
{INSERT t1 0 X. {} {i 1 t {value B}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_apply_v2_test 1.1.2 {
|
do_apply_v2_test 1.1.2 {
|
||||||
UPDATE t1 SET b = 'value B' WHERE a=1;
|
UPDATE t1 SET b = 'value B' WHERE a=1;
|
||||||
} {
|
} {
|
||||||
@ -80,7 +81,7 @@ do_apply_v2_test 1.1.2 {
|
|||||||
} {
|
} {
|
||||||
REPLACE
|
REPLACE
|
||||||
} {
|
} {
|
||||||
{DELETE t1 0 X. {i 1 {} {}} {}}
|
{INSERT t1 1 X. {} {i 1 t {value B}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_apply_v2_test 1.2.1 {
|
do_apply_v2_test 1.2.1 {
|
||||||
@ -99,7 +100,7 @@ do_apply_v2_test 1.2.2 {
|
|||||||
} {
|
} {
|
||||||
REPLACE
|
REPLACE
|
||||||
} {
|
} {
|
||||||
{DELETE t1 0 X. {i 2 {} {}} {}}
|
{INSERT t1 1 X. {} {i 2 t first}}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_apply_v2_test 1.3.1 {
|
do_apply_v2_test 1.3.1 {
|
||||||
@ -109,7 +110,7 @@ do_apply_v2_test 1.3.1 {
|
|||||||
} {
|
} {
|
||||||
OMIT
|
OMIT
|
||||||
} {
|
} {
|
||||||
{INSERT t1 1 X. {} {i 1 {} {}}}
|
{DELETE t1 0 X. {i 1 t {value A}} {}}
|
||||||
}
|
}
|
||||||
do_apply_v2_test 1.3.2 {
|
do_apply_v2_test 1.3.2 {
|
||||||
DELETE FROM t1 WHERE a=1;
|
DELETE FROM t1 WHERE a=1;
|
||||||
@ -118,7 +119,7 @@ do_apply_v2_test 1.3.2 {
|
|||||||
} {
|
} {
|
||||||
REPLACE
|
REPLACE
|
||||||
} {
|
} {
|
||||||
{DELETE t1 0 X. {i 1 {} {}} {}}
|
{DELETE t1 1 X. {i 1 t {value A}} {}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
@ -130,6 +131,11 @@ do_apply_v2_test 1.3.2 {
|
|||||||
# 2.1.4 - 1d2u1r
|
# 2.1.4 - 1d2u1r
|
||||||
# 2.1.5 - 1d2u2r !!
|
# 2.1.5 - 1d2u2r !!
|
||||||
# 2.1.6 - 1u2d1r
|
# 2.1.6 - 1u2d1r
|
||||||
|
# 2.1.7 - 1u2d2r
|
||||||
|
#
|
||||||
|
# 2.1.8 - 1i2i2r
|
||||||
|
# 2.1.9 - 1i2i1r
|
||||||
|
#
|
||||||
|
|
||||||
proc xConflictAbort {args} {
|
proc xConflictAbort {args} {
|
||||||
return "ABORT"
|
return "ABORT"
|
||||||
@ -164,13 +170,13 @@ proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} {
|
|||||||
|
|
||||||
set ::lConflict $conflict_handler
|
set ::lConflict $conflict_handler
|
||||||
set rebase [sqlite3changeset_apply_v2 db $c2 xConflict]
|
set rebase [sqlite3changeset_apply_v2 db $c2 xConflict]
|
||||||
#puts [changeset_to_list $rebase]
|
#if {$tn=="2.1.4"} { puts [changeset_to_list $rebase] ; breakpoint }
|
||||||
|
|
||||||
sqlite3rebaser_create R
|
sqlite3rebaser_create R
|
||||||
R configure $rebase
|
R configure $rebase
|
||||||
set c1r [R rebase $c1]
|
set c1r [R rebase $c1]
|
||||||
R delete
|
R delete
|
||||||
#puts [changeset_to_list $c1r]
|
#if {$tn=="2.1.4"} { puts [changeset_to_list $c1r] }
|
||||||
|
|
||||||
sqlite3changeset_apply_v2 db2 $c1r xConflictAbort
|
sqlite3changeset_apply_v2 db2 $c1r xConflictAbort
|
||||||
|
|
||||||
@ -224,11 +230,11 @@ do_rebase_test 2.1.4 {
|
|||||||
} { SELECT * FROM t1 } {2 two 3 three}
|
} { SELECT * FROM t1 } {2 two 3 three}
|
||||||
|
|
||||||
#do_rebase_test 2.1.5 {
|
#do_rebase_test 2.1.5 {
|
||||||
#DELETE FROM t1 WHERE a=1;
|
# DELETE FROM t1 WHERE a=1;
|
||||||
#} {
|
#} {
|
||||||
#UPDATE t1 SET b='one.2' WHERE a=1
|
# UPDATE t1 SET b='one.2' WHERE a=1
|
||||||
#} {
|
#} {
|
||||||
#REPLACE
|
# REPLACE
|
||||||
#} { SELECT * FROM t1 } {2 two 3 three}
|
#} { SELECT * FROM t1 } {2 two 3 three}
|
||||||
|
|
||||||
do_rebase_test 2.1.6 {
|
do_rebase_test 2.1.6 {
|
||||||
@ -247,5 +253,55 @@ do_rebase_test 2.1.7 {
|
|||||||
REPLACE
|
REPLACE
|
||||||
} { SELECT * FROM t1 } {1 one 2 two}
|
} { SELECT * FROM t1 } {1 one 2 two}
|
||||||
|
|
||||||
|
do_rebase_test 2.1.8 {
|
||||||
|
INSERT INTO t1 VALUES(4, 'four.1');
|
||||||
|
} {
|
||||||
|
INSERT INTO t1 VALUES(4, 'four.2');
|
||||||
|
} {
|
||||||
|
REPLACE
|
||||||
|
} { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.2}
|
||||||
|
|
||||||
|
do_rebase_test 2.1.9 {
|
||||||
|
INSERT INTO t1 VALUES(4, 'four.1');
|
||||||
|
} {
|
||||||
|
INSERT INTO t1 VALUES(4, 'four.2');
|
||||||
|
} {
|
||||||
|
OMIT
|
||||||
|
} { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.1}
|
||||||
|
|
||||||
|
do_execsql_test 2.2.0 {
|
||||||
|
CREATE TABLE t2(x, y, z PRIMARY KEY);
|
||||||
|
INSERT INTO t2 VALUES('i', 'a', 'A');
|
||||||
|
INSERT INTO t2 VALUES('ii', 'b', 'B');
|
||||||
|
INSERT INTO t2 VALUES('iii', 'c', 'C');
|
||||||
|
|
||||||
|
CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
|
||||||
|
INSERT INTO t3 VALUES(-1, 'z', 'Z');
|
||||||
|
INSERT INTO t3 VALUES(-2, 'y', 'Y');
|
||||||
|
}
|
||||||
|
|
||||||
|
do_rebase_test 2.2.1 {
|
||||||
|
UPDATE t2 SET x=1 WHERE z='A';
|
||||||
|
} {
|
||||||
|
UPDATE t2 SET y='one' WHERE z='A';
|
||||||
|
} {
|
||||||
|
} { SELECT * FROM t2 WHERE z='A' } { 1 one A }
|
||||||
|
|
||||||
|
do_rebase_test 2.2.2 {
|
||||||
|
UPDATE t2 SET x=1, y='one' WHERE z='B';
|
||||||
|
} {
|
||||||
|
UPDATE t2 SET y='two' WHERE z='B';
|
||||||
|
} {
|
||||||
|
REPLACE
|
||||||
|
} { SELECT * FROM t2 WHERE z='B' } { 1 two B }
|
||||||
|
|
||||||
|
do_rebase_test 2.2.3 {
|
||||||
|
UPDATE t2 SET x=1, y='one' WHERE z='B';
|
||||||
|
} {
|
||||||
|
UPDATE t2 SET y='two' WHERE z='B';
|
||||||
|
} {
|
||||||
|
OMIT
|
||||||
|
} { SELECT * FROM t2 WHERE z='B' } { 1 one B }
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
|
||||||
|
@ -232,8 +232,8 @@ struct SessionTable {
|
|||||||
** statement.
|
** statement.
|
||||||
**
|
**
|
||||||
** For a DELETE change, all fields within the record except those associated
|
** For a DELETE change, all fields within the record except those associated
|
||||||
** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields
|
** with PRIMARY KEY columns are omitted. The PRIMARY KEY fields contain the
|
||||||
** contain the values identifying the row to delete.
|
** values identifying the row to delete.
|
||||||
**
|
**
|
||||||
** For an UPDATE change, all fields except those associated with PRIMARY KEY
|
** For an UPDATE change, all fields except those associated with PRIMARY KEY
|
||||||
** columns and columns that are modified by the UPDATE are set to "undefined".
|
** columns and columns that are modified by the UPDATE are set to "undefined".
|
||||||
@ -3816,35 +3816,19 @@ static int sessionRebaseAdd(
|
|||||||
assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
|
assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
|
||||||
assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
|
assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
|
||||||
|
|
||||||
if( eType==SQLITE_CHANGESET_REPLACE ){
|
sessionAppendByte(&p->rebase,
|
||||||
sessionAppendByte(&p->rebase, SQLITE_DELETE, &rc);
|
(eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc
|
||||||
sessionAppendByte(&p->rebase, 0, &rc);
|
);
|
||||||
for(i=0; i<p->nCol; i++){
|
sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc);
|
||||||
if( p->abPK[i]==0 ){
|
|
||||||
sessionAppendByte(&p->rebase, 0, &rc);
|
|
||||||
}else{
|
|
||||||
sqlite3_value *pVal = 0;
|
|
||||||
if( eOp==SQLITE_INSERT ){
|
|
||||||
sqlite3changeset_new(pIter, i, &pVal);
|
|
||||||
}else{
|
|
||||||
sqlite3changeset_old(pIter, i, &pVal);
|
|
||||||
}
|
|
||||||
sessionAppendValue(&p->rebase, pVal, &rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
sessionAppendByte(&p->rebase, SQLITE_INSERT, &rc);
|
|
||||||
sessionAppendByte(&p->rebase, eOp==SQLITE_DELETE, &rc);
|
|
||||||
for(i=0; i<p->nCol; i++){
|
for(i=0; i<p->nCol; i++){
|
||||||
sqlite3_value *pVal = 0;
|
sqlite3_value *pVal = 0;
|
||||||
if( eOp!=SQLITE_INSERT && p->abPK[i] ){
|
if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){
|
||||||
sqlite3changeset_old(pIter, i, &pVal);
|
sqlite3changeset_old(pIter, i, &pVal);
|
||||||
}else{
|
}else{
|
||||||
sqlite3changeset_new(pIter, i, &pVal);
|
sqlite3changeset_new(pIter, i, &pVal);
|
||||||
}
|
}
|
||||||
sessionAppendValue(&p->rebase, pVal, &rc);
|
sessionAppendValue(&p->rebase, pVal, &rc);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -5026,6 +5010,56 @@ static void sessionAppendRecordMerge(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sessionAppendPartialUpdate(
|
||||||
|
SessionBuffer *pBuf,
|
||||||
|
sqlite3_changeset_iter *pIter,
|
||||||
|
u8 *aRec, int nRec,
|
||||||
|
u8 *aChange, int nChange,
|
||||||
|
int *pRc
|
||||||
|
){
|
||||||
|
sessionBufferGrow(pBuf, 2+nRec+nChange, pRc);
|
||||||
|
if( *pRc==SQLITE_OK ){
|
||||||
|
int bData = 0;
|
||||||
|
u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
|
||||||
|
int i;
|
||||||
|
u8 *a1 = aRec;
|
||||||
|
u8 *a2 = aChange;
|
||||||
|
|
||||||
|
*pOut++ = SQLITE_UPDATE;
|
||||||
|
*pOut++ = pIter->bIndirect;
|
||||||
|
for(i=0; i<pIter->nCol; i++){
|
||||||
|
int n1 = sessionSerialLen(a1);
|
||||||
|
int n2 = sessionSerialLen(a2);
|
||||||
|
if( pIter->abPK[i] || a2[0]==0 ){
|
||||||
|
if( !pIter->abPK[i] ) bData = 1;
|
||||||
|
memcpy(pOut, a1, n1);
|
||||||
|
pOut += n1;
|
||||||
|
}else{
|
||||||
|
*pOut++ = '\0';
|
||||||
|
}
|
||||||
|
a1 += n1;
|
||||||
|
a2 += n2;
|
||||||
|
}
|
||||||
|
if( bData ){
|
||||||
|
a2 = aChange;
|
||||||
|
for(i=0; i<pIter->nCol; i++){
|
||||||
|
int n1 = sessionSerialLen(a1);
|
||||||
|
int n2 = sessionSerialLen(a2);
|
||||||
|
if( pIter->abPK[i] || a2[0]==0 ){
|
||||||
|
memcpy(pOut, a1, n1);
|
||||||
|
pOut += n1;
|
||||||
|
}else{
|
||||||
|
*pOut++ = '\0';
|
||||||
|
}
|
||||||
|
a1 += n1;
|
||||||
|
a2 += n2;
|
||||||
|
}
|
||||||
|
pBuf->nBuf = (pOut - pBuf->aBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int sessionRebase(
|
static int sessionRebase(
|
||||||
sqlite3_rebaser *p, /* Rebaser hash table */
|
sqlite3_rebaser *p, /* Rebaser hash table */
|
||||||
sqlite3_changeset_iter *pIter, /* Input data */
|
sqlite3_changeset_iter *pIter, /* Input data */
|
||||||
@ -5043,6 +5077,7 @@ static int sessionRebase(
|
|||||||
|
|
||||||
while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, &bNew) ){
|
while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, &bNew) ){
|
||||||
SessionChange *pChange = 0;
|
SessionChange *pChange = 0;
|
||||||
|
int bDone = 0;
|
||||||
|
|
||||||
if( bNew ){
|
if( bNew ){
|
||||||
const char *zTab = pIter->zTab;
|
const char *zTab = pIter->zTab;
|
||||||
@ -5071,6 +5106,70 @@ static int sessionRebase(
|
|||||||
|
|
||||||
if( pChange ){
|
if( pChange ){
|
||||||
assert( pChange->op==SQLITE_DELETE || pChange->op==SQLITE_INSERT );
|
assert( pChange->op==SQLITE_DELETE || pChange->op==SQLITE_INSERT );
|
||||||
|
switch( pIter->op ){
|
||||||
|
case SQLITE_INSERT:
|
||||||
|
if( pChange->op==SQLITE_INSERT ){
|
||||||
|
bDone = 1;
|
||||||
|
if( pChange->bIndirect==0 ){
|
||||||
|
sessionAppendByte(&sOut, SQLITE_UPDATE, &rc);
|
||||||
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
|
sessionAppendBlob(&sOut, pChange->aRecord, pChange->nRecord, &rc);
|
||||||
|
sessionAppendBlob(&sOut, aRec, nRec, &rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLITE_UPDATE:
|
||||||
|
bDone = 1;
|
||||||
|
if( pChange->op==SQLITE_DELETE ){
|
||||||
|
if( pChange->bIndirect==0 ){
|
||||||
|
u8 *pCsr = aRec;
|
||||||
|
sessionSkipRecord(&pCsr, pIter->nCol);
|
||||||
|
sessionAppendByte(&sOut, SQLITE_INSERT, &rc);
|
||||||
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
|
sessionAppendRecordMerge(&sOut, pIter->nCol, 1,
|
||||||
|
pCsr, nRec-(pCsr-aRec),
|
||||||
|
pChange->aRecord, pChange->nRecord, &rc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if( pChange->bIndirect==0 ){
|
||||||
|
u8 *pCsr = aRec;
|
||||||
|
sessionAppendByte(&sOut, SQLITE_UPDATE, &rc);
|
||||||
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
|
sessionAppendRecordMerge(&sOut, pIter->nCol, 0,
|
||||||
|
aRec, nRec, pChange->aRecord, pChange->nRecord, &rc
|
||||||
|
);
|
||||||
|
sessionSkipRecord(&pCsr, pIter->nCol);
|
||||||
|
sessionAppendBlob(&sOut, pCsr, nRec - (pCsr-aRec), &rc);
|
||||||
|
}else{
|
||||||
|
sessionAppendPartialUpdate(&sOut, pIter,
|
||||||
|
aRec, nRec, pChange->aRecord, pChange->nRecord, &rc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert( pIter->op==SQLITE_DELETE );
|
||||||
|
bDone = 1;
|
||||||
|
if( pChange->op==SQLITE_INSERT ){
|
||||||
|
sessionAppendByte(&sOut, SQLITE_DELETE, &rc);
|
||||||
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
|
sessionAppendRecordMerge(&sOut, pIter->nCol, 1,
|
||||||
|
pChange->aRecord, pChange->nRecord, aRec, nRec, &rc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bDone==0 ){
|
||||||
|
sessionAppendByte(&sOut, pIter->op, &rc);
|
||||||
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
|
sessionAppendBlob(&sOut, aRec, nRec, &rc);
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
/* If pChange is an INSERT, then rebase the change. If it is a
|
/* If pChange is an INSERT, then rebase the change. If it is a
|
||||||
** DELETE, omit the change from the output altogether. */
|
** DELETE, omit the change from the output altogether. */
|
||||||
if( pChange->op==SQLITE_INSERT ){
|
if( pChange->op==SQLITE_INSERT ){
|
||||||
@ -5097,12 +5196,15 @@ static int sessionRebase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
sessionAppendByte(&sOut, pIter->op, &rc);
|
|
||||||
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
|
||||||
if( pIter->op==SQLITE_INSERT ){
|
if( pIter->op==SQLITE_INSERT ){
|
||||||
|
sessionAppendByte(&sOut, SQLITE_UPDATE, &rc);
|
||||||
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
|
sessionAppendBlob(&sOut, pChange->aRecord, pChange->nRecord, &rc);
|
||||||
sessionAppendBlob(&sOut, aRec, nRec, &rc);
|
sessionAppendBlob(&sOut, aRec, nRec, &rc);
|
||||||
}else{
|
}else{
|
||||||
u8 *pCsr = aRec;
|
u8 *pCsr = aRec;
|
||||||
|
sessionAppendByte(&sOut, pIter->op, &rc);
|
||||||
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
sessionAppendRecordMerge(&sOut, pIter->nCol, 0,
|
sessionAppendRecordMerge(&sOut, pIter->nCol, 0,
|
||||||
aRec, nRec, pChange->aRecord, pChange->nRecord, &rc
|
aRec, nRec, pChange->aRecord, pChange->nRecord, &rc
|
||||||
);
|
);
|
||||||
@ -5118,6 +5220,7 @@ static int sessionRebase(
|
|||||||
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||||
sessionAppendBlob(&sOut, aRec, nRec, &rc);
|
sessionAppendBlob(&sOut, aRec, nRec, &rc);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){
|
if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){
|
||||||
rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
|
rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
|
||||||
|
@ -1216,6 +1216,41 @@ int sqlite3changeset_apply_v2(
|
|||||||
#define SQLITE_CHANGESET_REPLACE 1
|
#define SQLITE_CHANGESET_REPLACE 1
|
||||||
#define SQLITE_CHANGESET_ABORT 2
|
#define SQLITE_CHANGESET_ABORT 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Rebasing changesets
|
||||||
|
**
|
||||||
|
** Changes are rebased as follows:
|
||||||
|
**
|
||||||
|
** <dl>
|
||||||
|
** <dt>INSERT<dd>
|
||||||
|
** This may only conflict with a remote INSERT. If the conflict
|
||||||
|
** resolution was OMIT, then add an UPDATE change to the rebased
|
||||||
|
** changeset. Or, if the conflict resolution was REPLACE, add
|
||||||
|
** nothing to the rebased changeset.
|
||||||
|
**
|
||||||
|
** <dt>DELETE<dd>
|
||||||
|
** This may conflict with a remote UPDATE or DELETE. In both cases the
|
||||||
|
** only possible resolution is OMIT. If the remote operation was a
|
||||||
|
** DELETE, then add no change to the rebased changeset. If the remote
|
||||||
|
** operation was an UPDATE, then the old.* fields of the are updated to
|
||||||
|
** reflect the new.* values in the UPDATE.
|
||||||
|
**
|
||||||
|
** <dt>UPDATE<dd>
|
||||||
|
** This may conflict with a remote UPDATE or DELETE. If it conflicts
|
||||||
|
** with a DELETE, and the conflict resolution was OMIT, then the update
|
||||||
|
** is changed into an INSERT. Any undefined values in the new.* record
|
||||||
|
** from the update change are filled in using hte old.* values from
|
||||||
|
** the conflicting DELETE. Or, if the conflict resolution was REPLACE,
|
||||||
|
** the UPDATE change is simply omitted from the rebased changeset.
|
||||||
|
**
|
||||||
|
** If conflict is with a remote UPDATE and the resolution is OMIT, then
|
||||||
|
** the old.* values are rebased using the new.* values in the remote
|
||||||
|
** change. Or, if the resolution is REPLACE, then the change is copied
|
||||||
|
** into the rebased changeset with updates to columns also updated by
|
||||||
|
** the conflicting UPDATE removed. If this means no columns would be
|
||||||
|
** updated, the change is omitted.
|
||||||
|
** </dl>
|
||||||
|
*/
|
||||||
typedef struct sqlite3_rebaser sqlite3_rebaser;
|
typedef struct sqlite3_rebaser sqlite3_rebaser;
|
||||||
|
|
||||||
/* Create a new rebaser object */
|
/* Create a new rebaser object */
|
||||||
|
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
|||||||
C Add\ssimple\stests\sfor\sthe\ssessions\smodule\srebase\sAPI.
|
C Fix\sa\sproblem\swith\shandling\srebasing\sUPDATE\schanges\sfor\sREPLACE\sconflict\nresolution.
|
||||||
D 2018-03-15T19:25:40.859
|
D 2018-03-16T18:02:47.093
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in 7016fc56c6b9bfe5daac4f34be8be38d8c0b5fab79ccbfb764d3b23bf1c6fff3
|
F Makefile.in 7016fc56c6b9bfe5daac4f34be8be38d8c0b5fab79ccbfb764d3b23bf1c6fff3
|
||||||
@ -400,11 +400,11 @@ F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28
|
|||||||
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
|
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
|
||||||
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
||||||
F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
|
F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
|
||||||
F ext/session/sessionrebase.test d3a33c733e5564afe517252167d8f456a04601b047246d85f1e84bf319c2897f
|
F ext/session/sessionrebase.test 35dede926077b0bbb5c323e278ed575a24fa333b3c2f45f3b6842b532054e463
|
||||||
F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e
|
F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e
|
||||||
F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
|
F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
|
||||||
F ext/session/sqlite3session.c 94b960a94d5e6b2117215a7b1057b3db74ca1222dded2a94588f8ccac5a7d929
|
F ext/session/sqlite3session.c 84f4786c93b12701cf72073064ea70740a7d43508f0bfb96563c49cfd7df644c
|
||||||
F ext/session/sqlite3session.h 8cb9992411344b9e906a394d2213f58da7b3942ae57e7936d1ec3fe26277dfc0
|
F ext/session/sqlite3session.h a1c66a6497c36246d2242223663c2e7c1906bd28099556d7e5148214c2d9902a
|
||||||
F ext/session/test_session.c f253742ea01b089326f189b5ae15a5b55c1c9e97452e4a195ee759ba51b404d5
|
F ext/session/test_session.c f253742ea01b089326f189b5ae15a5b55c1c9e97452e4a195ee759ba51b404d5
|
||||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||||
@ -1713,7 +1713,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 39915b683b3f8d3bf872af1dede96bf2818b488a8638a1d248395023fc4bd0ef
|
P cf0d1abb44cf170d747e9c11f49ec03a29f00ab4821c613ca1e05b883a568211
|
||||||
R 749942968b245595723def17d4b1a08a
|
R 120c1710087879bab403c404357c60c1
|
||||||
U dan
|
U dan
|
||||||
Z 85fdd8cb2cf7c970dbbe7369d1e2a257
|
Z 77da19287ec96a71252949a7a74af667
|
||||||
|
@ -1 +1 @@
|
|||||||
cf0d1abb44cf170d747e9c11f49ec03a29f00ab4821c613ca1e05b883a568211
|
f7bf71f1d47044e3cbc74018294b8af5ad52c2bb84954e99bbd4e9b8c36fc077
|
Reference in New Issue
Block a user