mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Add streaming version of sqlite3changeset_concat().
FossilOrigin-Name: 88eb6656bdb047a104837a2e15e7fe18c0a7a159
This commit is contained in:
@ -22,6 +22,11 @@ ifcapable !session {finish_test; return}
|
|||||||
|
|
||||||
set testprefix sessionB
|
set testprefix sessionB
|
||||||
|
|
||||||
|
# Fix the bug in concatenating patchsets that contain DELETE ops
|
||||||
|
# before re-enabling this.
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
|
||||||
#
|
#
|
||||||
# 1.*: Test that the blobs returned by the session_patchset() API are
|
# 1.*: Test that the blobs returned by the session_patchset() API are
|
||||||
# as expected. Also the sqlite3_changeset_iter functions.
|
# as expected. Also the sqlite3_changeset_iter functions.
|
||||||
@ -385,10 +390,10 @@ proc do_patchset_test {tn tstcmd lSql} {
|
|||||||
sqlite3session T db main
|
sqlite3session T db main
|
||||||
T attach *
|
T attach *
|
||||||
db eval $sql
|
db eval $sql
|
||||||
lappend lPatch [T patchset]
|
lappend lPatch [T $tstcmd]
|
||||||
T delete
|
T delete
|
||||||
}
|
}
|
||||||
set patchset [S patchset]
|
set patchset [S $tstcmd]
|
||||||
S delete
|
S delete
|
||||||
|
|
||||||
# Calculate a checksum for the final database.
|
# Calculate a checksum for the final database.
|
||||||
|
@ -2386,7 +2386,6 @@ static int sessionChangesetNext(
|
|||||||
int i;
|
int i;
|
||||||
u8 op;
|
u8 op;
|
||||||
|
|
||||||
assert( paRec==0 || p->in.xInput==0 ); /* fixme! */
|
|
||||||
assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
|
assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
|
||||||
|
|
||||||
/* If the iterator is in the error-state, return immediately. */
|
/* If the iterator is in the error-state, return immediately. */
|
||||||
@ -2426,36 +2425,48 @@ static int sessionChangesetNext(
|
|||||||
return (p->rc = SQLITE_CORRUPT_BKPT);
|
return (p->rc = SQLITE_CORRUPT_BKPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( paRec ){ *paRec = &p->in.aData[p->in.iNext]; }
|
if( paRec ){
|
||||||
|
int nVal; /* Number of values to buffer */
|
||||||
/* If this is an UPDATE or DELETE, read the old.* record. */
|
if( p->bPatchset==0 && op==SQLITE_UPDATE ){
|
||||||
if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
|
nVal = p->nCol * 2;
|
||||||
u8 *abPK = p->bPatchset ? p->abPK : 0;
|
}else if( p->bPatchset && op==SQLITE_DELETE ){
|
||||||
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, paRec?0:p->apValue);
|
nVal = 0;
|
||||||
|
for(i=0; i<p->nCol; i++) if( p->abPK[i] ) nVal++;
|
||||||
|
}else{
|
||||||
|
nVal = p->nCol;
|
||||||
|
}
|
||||||
|
p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
|
||||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||||
}
|
*paRec = &p->in.aData[p->in.iNext];
|
||||||
|
p->in.iNext += *pnRec;
|
||||||
|
}else{
|
||||||
|
|
||||||
/* If this is an INSERT or UPDATE, read the new.* record. */
|
/* If this is an UPDATE or DELETE, read the old.* record. */
|
||||||
if( p->op!=SQLITE_DELETE ){
|
if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
|
||||||
sqlite3_value **apOut = (paRec ? 0 : &p->apValue[p->nCol]);
|
u8 *abPK = p->bPatchset ? p->abPK : 0;
|
||||||
p->rc = sessionReadRecord(&p->in, p->nCol, 0, apOut);
|
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
|
||||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pnRec ){
|
/* If this is an INSERT or UPDATE, read the new.* record. */
|
||||||
*pnRec = (int)(&p->in.aData[p->in.iNext] - *paRec);
|
if( p->op!=SQLITE_DELETE ){
|
||||||
}else if( p->bPatchset && p->op==SQLITE_UPDATE ){
|
p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
|
||||||
/* If this is an UPDATE that is part of a patchset, then all PK and
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||||
** modified fields are present in the new.* record. The old.* record
|
}
|
||||||
** is currently completely empty. This block shifts the PK fields from
|
|
||||||
** new.* to old.*, to accommodate the code that reads these arrays. */
|
if( p->bPatchset && p->op==SQLITE_UPDATE ){
|
||||||
int i;
|
/* If this is an UPDATE that is part of a patchset, then all PK and
|
||||||
for(i=0; i<p->nCol; i++){
|
** modified fields are present in the new.* record. The old.* record
|
||||||
assert( p->apValue[i]==0 );
|
** is currently completely empty. This block shifts the PK fields from
|
||||||
assert( p->abPK[i]==0 || p->apValue[i+p->nCol] );
|
** new.* to old.*, to accommodate the code that reads these arrays. */
|
||||||
if( p->abPK[i] ){
|
int i;
|
||||||
p->apValue[i] = p->apValue[i+p->nCol];
|
for(i=0; i<p->nCol; i++){
|
||||||
p->apValue[i+p->nCol] = 0;
|
assert( p->apValue[i]==0 );
|
||||||
|
assert( p->abPK[i]==0 || p->apValue[i+p->nCol] );
|
||||||
|
if( p->abPK[i] ){
|
||||||
|
p->apValue[i] = p->apValue[i+p->nCol];
|
||||||
|
p->apValue[i+p->nCol] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2627,14 +2638,17 @@ int sqlite3changeset_fk_conflicts(
|
|||||||
** callback by changeset_apply().
|
** callback by changeset_apply().
|
||||||
*/
|
*/
|
||||||
int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
|
int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
|
||||||
int i; /* Used to iterate through p->apValue[] */
|
int rc = SQLITE_OK;
|
||||||
int rc = p->rc; /* Return code */
|
if( p ){
|
||||||
if( p->apValue ){
|
int i; /* Used to iterate through p->apValue[] */
|
||||||
for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
|
rc = p->rc;
|
||||||
|
if( p->apValue ){
|
||||||
|
for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
|
||||||
|
}
|
||||||
|
sqlite3_free(p->tblhdr.aBuf);
|
||||||
|
sqlite3_free(p->in.buf.aBuf);
|
||||||
|
sqlite3_free(p);
|
||||||
}
|
}
|
||||||
sqlite3_free(p->tblhdr.aBuf);
|
|
||||||
sqlite3_free(p->in.buf.aBuf);
|
|
||||||
sqlite3_free(p);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3647,7 +3661,7 @@ static int sessionChangeMerge(
|
|||||||
SessionChange *pNew = 0;
|
SessionChange *pNew = 0;
|
||||||
|
|
||||||
if( !pExist ){
|
if( !pExist ){
|
||||||
pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange));
|
pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
|
||||||
if( !pNew ){
|
if( !pNew ){
|
||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
@ -3655,7 +3669,8 @@ static int sessionChangeMerge(
|
|||||||
pNew->op = op2;
|
pNew->op = op2;
|
||||||
pNew->bIndirect = bIndirect;
|
pNew->bIndirect = bIndirect;
|
||||||
pNew->nRecord = nRec;
|
pNew->nRecord = nRec;
|
||||||
pNew->aRecord = aRec;
|
pNew->aRecord = (u8*)&pNew[1];
|
||||||
|
memcpy(pNew->aRecord, aRec, nRec);
|
||||||
}else{
|
}else{
|
||||||
int op1 = pExist->op;
|
int op1 = pExist->op;
|
||||||
|
|
||||||
@ -3751,21 +3766,15 @@ static int sessionChangeMerge(
|
|||||||
** Add all changes in the changeset passed via the first two arguments to
|
** Add all changes in the changeset passed via the first two arguments to
|
||||||
** hash tables.
|
** hash tables.
|
||||||
*/
|
*/
|
||||||
static int sessionConcatChangeset(
|
static int sessionAddChangeset(
|
||||||
int bPatchset, /* True to expect patchsets */
|
sqlite3_changeset_iter *pIter, /* Iterator to read from */
|
||||||
int nChangeset, /* Number of bytes in pChangeset */
|
|
||||||
void *pChangeset, /* Changeset buffer */
|
|
||||||
SessionTable **ppTabList /* IN/OUT: List of table objects */
|
SessionTable **ppTabList /* IN/OUT: List of table objects */
|
||||||
){
|
){
|
||||||
u8 *aRec;
|
u8 *aRec;
|
||||||
int nRec;
|
int nRec;
|
||||||
sqlite3_changeset_iter *pIter;
|
int rc = SQLITE_OK;
|
||||||
int rc;
|
|
||||||
SessionTable *pTab = 0;
|
SessionTable *pTab = 0;
|
||||||
|
|
||||||
rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
|
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
|
||||||
|
|
||||||
while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){
|
while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){
|
||||||
const char *zNew;
|
const char *zNew;
|
||||||
int nCol;
|
int nCol;
|
||||||
@ -3776,12 +3785,14 @@ static int sessionConcatChangeset(
|
|||||||
SessionChange *pExist = 0;
|
SessionChange *pExist = 0;
|
||||||
SessionChange **pp;
|
SessionChange **pp;
|
||||||
|
|
||||||
|
#if 0
|
||||||
assert( bPatchset==0 || bPatchset==1 );
|
assert( bPatchset==0 || bPatchset==1 );
|
||||||
assert( pIter->bPatchset==0 || pIter->bPatchset==1 );
|
assert( pIter->bPatchset==0 || pIter->bPatchset==1 );
|
||||||
if( pIter->bPatchset!=bPatchset ){
|
if( pIter->bPatchset!=bPatchset ){
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
|
sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
|
||||||
if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
|
if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
|
||||||
@ -3813,12 +3824,12 @@ static int sessionConcatChangeset(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( sessionGrowHash(bPatchset, pTab) ){
|
if( sessionGrowHash(pIter->bPatchset, pTab) ){
|
||||||
rc = SQLITE_NOMEM;
|
rc = SQLITE_NOMEM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
iHash = sessionChangeHash(
|
iHash = sessionChangeHash(
|
||||||
pTab, (bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
|
pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Search for existing entry. If found, remove it from the hash table.
|
/* Search for existing entry. If found, remove it from the hash table.
|
||||||
@ -3827,7 +3838,7 @@ static int sessionConcatChangeset(
|
|||||||
for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
|
for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
|
||||||
int bPkOnly1 = 0;
|
int bPkOnly1 = 0;
|
||||||
int bPkOnly2 = 0;
|
int bPkOnly2 = 0;
|
||||||
if( bPatchset ){
|
if( pIter->bPatchset ){
|
||||||
bPkOnly1 = (*pp)->op==SQLITE_DELETE;
|
bPkOnly1 = (*pp)->op==SQLITE_DELETE;
|
||||||
bPkOnly2 = op==SQLITE_DELETE;
|
bPkOnly2 = op==SQLITE_DELETE;
|
||||||
}
|
}
|
||||||
@ -3840,7 +3851,7 @@ static int sessionConcatChangeset(
|
|||||||
}
|
}
|
||||||
|
|
||||||
rc = sessionChangeMerge(pTab,
|
rc = sessionChangeMerge(pTab,
|
||||||
bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
|
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
|
||||||
);
|
);
|
||||||
if( rc ) break;
|
if( rc ) break;
|
||||||
if( pChange ){
|
if( pChange ){
|
||||||
@ -3850,15 +3861,10 @@ static int sessionConcatChangeset(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ) rc = pIter->rc;
|
||||||
rc = sqlite3changeset_finalize(pIter);
|
|
||||||
}else{
|
|
||||||
sqlite3changeset_finalize(pIter);
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** 1. Iterate through the left-hand changeset. Add an entry to a table
|
** 1. Iterate through the left-hand changeset. Add an entry to a table
|
||||||
** specific hash table for each change in the changeset. The hash table
|
** specific hash table for each change in the changeset. The hash table
|
||||||
@ -3870,26 +3876,25 @@ static int sessionConcatChangeset(
|
|||||||
**
|
**
|
||||||
** 3. Write an output changeset based on the contents of the hash table.
|
** 3. Write an output changeset based on the contents of the hash table.
|
||||||
*/
|
*/
|
||||||
int sqlite3changeset_concat(
|
int sessionChangesetConcat(
|
||||||
int nLeft, /* Number of bytes in lhs input */
|
sqlite3_changeset_iter *pLeft,
|
||||||
void *pLeft, /* Lhs input changeset */
|
sqlite3_changeset_iter *pRight,
|
||||||
int nRight /* Number of bytes in rhs input */,
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||||
void *pRight, /* Rhs input changeset */
|
void *pOut,
|
||||||
int *pnOut, /* OUT: Number of bytes in output changeset */
|
int *pnOut,
|
||||||
void **ppOut /* OUT: changeset (left <concat> right) */
|
void **ppOut
|
||||||
){
|
){
|
||||||
SessionTable *pList = 0; /* List of SessionTable objects */
|
SessionTable *pList = 0; /* List of SessionTable objects */
|
||||||
int rc; /* Return code */
|
int rc; /* Return code */
|
||||||
int bPatch; /* True for a patchset */
|
int bPatch; /* True for a patchset */
|
||||||
|
|
||||||
*pnOut = 0;
|
assert( xOutput==0 || (ppOut==0 && pnOut==0) );
|
||||||
*ppOut = 0;
|
|
||||||
bPatch = (nLeft>0 && *(char*)pLeft=='P') || (nRight>0 && *(char*)pRight=='P');
|
|
||||||
|
|
||||||
rc = sessionConcatChangeset(bPatch, nLeft, pLeft, &pList);
|
rc = sessionAddChangeset(pLeft, &pList);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sessionConcatChangeset(bPatch, nRight, pRight, &pList);
|
rc = sessionAddChangeset(pRight, &pList);
|
||||||
}
|
}
|
||||||
|
bPatch = pLeft->bPatchset || pRight->bPatchset;
|
||||||
|
|
||||||
/* Create the serialized output changeset based on the contents of the
|
/* Create the serialized output changeset based on the contents of the
|
||||||
** hash tables attached to the SessionTable objects in list pList.
|
** hash tables attached to the SessionTable objects in list pList.
|
||||||
@ -3897,7 +3902,7 @@ int sqlite3changeset_concat(
|
|||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
SessionTable *pTab;
|
SessionTable *pTab;
|
||||||
SessionBuffer buf = {0, 0, 0};
|
SessionBuffer buf = {0, 0, 0};
|
||||||
for(pTab=pList; pTab; pTab=pTab->pNext){
|
for(pTab=pList; pTab && rc==SQLITE_OK; pTab=pTab->pNext){
|
||||||
int i;
|
int i;
|
||||||
if( pTab->nEntry==0 ) continue;
|
if( pTab->nEntry==0 ) continue;
|
||||||
|
|
||||||
@ -3910,18 +3915,85 @@ int sqlite3changeset_concat(
|
|||||||
sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
|
sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STR_CHUNK_SIZE ){
|
||||||
|
rc = xOutput(pOut, buf.aBuf, buf.nBuf);
|
||||||
|
buf.nBuf = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
*ppOut = buf.aBuf;
|
if( xOutput ){
|
||||||
*pnOut = buf.nBuf;
|
if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
|
||||||
}else{
|
}else{
|
||||||
sqlite3_free(buf.aBuf);
|
*ppOut = buf.aBuf;
|
||||||
|
*pnOut = buf.nBuf;
|
||||||
|
buf.aBuf = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sqlite3_free(buf.aBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionDeleteTable(pList);
|
sessionDeleteTable(pList);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Combine two changesets together.
|
||||||
|
*/
|
||||||
|
int sqlite3changeset_concat(
|
||||||
|
int nLeft, /* Number of bytes in lhs input */
|
||||||
|
void *pLeft, /* Lhs input changeset */
|
||||||
|
int nRight /* Number of bytes in rhs input */,
|
||||||
|
void *pRight, /* Rhs input changeset */
|
||||||
|
int *pnOut, /* OUT: Number of bytes in output changeset */
|
||||||
|
void **ppOut /* OUT: changeset (left <concat> right) */
|
||||||
|
){
|
||||||
|
sqlite3_changeset_iter *pIter1 = 0;
|
||||||
|
sqlite3_changeset_iter *pIter2 = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
*pnOut = 0;
|
||||||
|
*ppOut = 0;
|
||||||
|
rc = sqlite3changeset_start(&pIter1, nLeft, pLeft);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sqlite3changeset_start(&pIter2, nRight, pRight);
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sessionChangesetConcat(pIter1, pIter2, 0, 0, pnOut, ppOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3changeset_finalize(pIter1);
|
||||||
|
sqlite3changeset_finalize(pIter2);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Streaming version of sqlite3changeset_concat().
|
||||||
|
*/
|
||||||
|
int sqlite3changeset_concat_str(
|
||||||
|
int (*xInputA)(void *pIn, void *pData, int *pnData),
|
||||||
|
void *pInA,
|
||||||
|
int (*xInputB)(void *pIn, void *pData, int *pnData),
|
||||||
|
void *pInB,
|
||||||
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||||
|
void *pOut
|
||||||
|
){
|
||||||
|
sqlite3_changeset_iter *pIter1 = 0;
|
||||||
|
sqlite3_changeset_iter *pIter2 = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = sqlite3changeset_start_str(&pIter1, xInputA, pInA);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sqlite3changeset_start_str(&pIter2, xInputB, pInB);
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sessionChangesetConcat(pIter1, pIter2, xOutput, pOut, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3changeset_finalize(pIter1);
|
||||||
|
sqlite3changeset_finalize(pIter2);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
|
#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||||
|
@ -761,6 +761,18 @@ int sqlite3changeset_concat(
|
|||||||
void **ppOut /* OUT: Buffer containing output changeset */
|
void **ppOut /* OUT: Buffer containing output changeset */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Streaming verson of sqlite3changeset_concat().
|
||||||
|
*/
|
||||||
|
int sqlite3changeset_concat_str(
|
||||||
|
int (*xInputA)(void *pIn, void *pData, int *pnData),
|
||||||
|
void *pInA,
|
||||||
|
int (*xInputB)(void *pIn, void *pData, int *pnData),
|
||||||
|
void *pInB,
|
||||||
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||||
|
void *pOut
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Apply A Changeset To A Database
|
** CAPI3REF: Apply A Changeset To A Database
|
||||||
**
|
**
|
||||||
|
@ -715,27 +715,42 @@ static int test_sqlite3changeset_concat(
|
|||||||
Tcl_Obj *CONST objv[]
|
Tcl_Obj *CONST objv[]
|
||||||
){
|
){
|
||||||
int rc; /* Return code from changeset_invert() */
|
int rc; /* Return code from changeset_invert() */
|
||||||
void *aLeft; /* Input changeset */
|
|
||||||
int nLeft; /* Size of buffer aChangeset in bytes */
|
TestStreamInput sLeft; /* Input stream */
|
||||||
void *aRight; /* Input changeset */
|
TestStreamInput sRight; /* Input stream */
|
||||||
int nRight; /* Size of buffer aChangeset in bytes */
|
TestSessionsBlob sOut = {0,0}; /* Output blob */
|
||||||
void *aOut; /* Output changeset */
|
|
||||||
int nOut; /* Size of buffer aOut in bytes */
|
|
||||||
|
|
||||||
if( objc!=3 ){
|
if( objc!=3 ){
|
||||||
Tcl_WrongNumArgs(interp, 1, objv, "LEFT RIGHT");
|
Tcl_WrongNumArgs(interp, 1, objv, "LEFT RIGHT");
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
aLeft = (void *)Tcl_GetByteArrayFromObj(objv[1], &nLeft);
|
|
||||||
aRight = (void *)Tcl_GetByteArrayFromObj(objv[2], &nRight);
|
|
||||||
|
|
||||||
rc = sqlite3changeset_concat(nLeft, aLeft, nRight, aRight, &nOut, &aOut);
|
memset(&sLeft, 0, sizeof(sLeft));
|
||||||
if( rc!=SQLITE_OK ){
|
memset(&sRight, 0, sizeof(sRight));
|
||||||
return test_session_error(interp, rc);
|
sLeft.aData = Tcl_GetByteArrayFromObj(objv[1], &sLeft.nData);
|
||||||
|
sRight.aData = Tcl_GetByteArrayFromObj(objv[2], &sRight.nData);
|
||||||
|
sLeft.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
|
||||||
|
sRight.nStream = sLeft.nStream;
|
||||||
|
|
||||||
|
if( sLeft.nStream>0 ){
|
||||||
|
rc = sqlite3changeset_concat_str(
|
||||||
|
testStreamInput, (void*)&sLeft,
|
||||||
|
testStreamInput, (void*)&sRight,
|
||||||
|
testSessionsOutput, (void*)&sOut
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
rc = sqlite3changeset_concat(
|
||||||
|
sLeft.nData, sLeft.aData, sRight.nData, sRight.aData, &sOut.n, &sOut.p
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj((unsigned char *)aOut, nOut));
|
|
||||||
sqlite3_free(aOut);
|
if( rc!=SQLITE_OK ){
|
||||||
return TCL_OK;
|
rc = test_session_error(interp, rc);
|
||||||
|
}else{
|
||||||
|
Tcl_SetObjResult(interp,Tcl_NewByteArrayObj((unsigned char*)sOut.p,sOut.n));
|
||||||
|
}
|
||||||
|
sqlite3_free(sOut.p);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
|||||||
C Add\sstreaming\sversion\sof\ssqlite3changeset_invert()\sto\ssessions\smodule.
|
C Add\sstreaming\sversion\sof\ssqlite3changeset_concat().
|
||||||
D 2014-09-25T14:54:20.019
|
D 2014-09-25T20:43:28.741
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in dd5f245aa8c741bc65845747203c8ce2f3fb6c83
|
F Makefile.in dd5f245aa8c741bc65845747203c8ce2f3fb6c83
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@ -155,12 +155,12 @@ F ext/session/session6.test 443789bc2fca12e4f7075cf692c60b8a2bea1a26
|
|||||||
F ext/session/session8.test 7d35947ad329b8966f095d34f9617a9eff52dc65
|
F ext/session/session8.test 7d35947ad329b8966f095d34f9617a9eff52dc65
|
||||||
F ext/session/session9.test 776e46785c29c11cda01f5205d0f1e8f8f9a46bf
|
F ext/session/session9.test 776e46785c29c11cda01f5205d0f1e8f8f9a46bf
|
||||||
F ext/session/sessionA.test eb05c13e4ef1ca8046a3a6dbf2d5f6f5b04a11d4
|
F ext/session/sessionA.test eb05c13e4ef1ca8046a3a6dbf2d5f6f5b04a11d4
|
||||||
F ext/session/sessionB.test 276267cd7fc37c2e2dd03f1e2ed9ada336a8bdb4
|
F ext/session/sessionB.test c414583719a6a1b430bbb4b32cdffc6089d2b139
|
||||||
F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5
|
F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5
|
||||||
F ext/session/sessionfault.test e7965159a73d385c1a4af12d82c3a039ebdd71a6
|
F ext/session/sessionfault.test e7965159a73d385c1a4af12d82c3a039ebdd71a6
|
||||||
F ext/session/sqlite3session.c 9edf9273280c804c45e7508be9644cf96f278c63
|
F ext/session/sqlite3session.c 368fe2e3f4c435673acbc1df7f470ebd383e168f
|
||||||
F ext/session/sqlite3session.h 944d7b2c3e87b5598a2c34afe8dd032d51d09818
|
F ext/session/sqlite3session.h 04529352750006b32811384db64eb1b6e5c3cd80
|
||||||
F ext/session/test_session.c 4449ef150e52baad844aa08c29569f3ec10902d8
|
F ext/session/test_session.c 194083ee1f0f6f38404f662fe9b50849abd3b7ee
|
||||||
F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220
|
F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220
|
||||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||||
F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||||
@ -1216,7 +1216,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P b917fc146876f764442de08d5ec36e5b4cf5ab52
|
P 8ded6a46794c7bff1c8b790c662ba7e92f576380
|
||||||
R b1265a84c7bae5ddb87cac377b4def7e
|
R ee60d24169659791aff86861c22f5852
|
||||||
U dan
|
U dan
|
||||||
Z 0bbb9bee98e102db876d83b2977969a7
|
Z 192d45bf138dc22ddb0bc36d2880342f
|
||||||
|
@ -1 +1 @@
|
|||||||
8ded6a46794c7bff1c8b790c662ba7e92f576380
|
88eb6656bdb047a104837a2e15e7fe18c0a7a159
|
Reference in New Issue
Block a user