mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Add new sessions API sqlite3changegroup_add_change().
FossilOrigin-Name: 5eaab43ce48bb8d710f784ecd6aa9a4b3e708b44b0f7e49daf66a3f8bc2b9873
This commit is contained in:
101
ext/session/sessionchange.test
Normal file
101
ext/session/sessionchange.test
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# 2011 March 07
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library.
|
||||||
|
#
|
||||||
|
|
||||||
|
if {![info exists testdir]} {
|
||||||
|
set testdir [file join [file dirname [info script]] .. .. test]
|
||||||
|
}
|
||||||
|
source [file join [file dirname [info script]] session_common.tcl]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
ifcapable !session {finish_test; return}
|
||||||
|
|
||||||
|
set testprefix sessionchange
|
||||||
|
|
||||||
|
do_execsql_test 1.0 {
|
||||||
|
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test 1.1 {
|
||||||
|
set C [changeset_from_sql {
|
||||||
|
INSERT INTO t1 VALUES(1, 2, 3);
|
||||||
|
INSERT INTO t1 VALUES(10, 20, 30);
|
||||||
|
}]
|
||||||
|
|
||||||
|
set res [list]
|
||||||
|
set iter [sqlite3changeset_start $C]
|
||||||
|
while {[$iter next]=="SQLITE_ROW"} {
|
||||||
|
lappend res [$iter data]
|
||||||
|
}
|
||||||
|
$iter finalize
|
||||||
|
|
||||||
|
set res
|
||||||
|
} [list \
|
||||||
|
{INSERT t1 0 X.. {} {i 10 i 20 i 30}} \
|
||||||
|
{INSERT t1 0 X.. {} {i 1 i 2 i 3}} \
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
do_test 1.2 {
|
||||||
|
sqlite3changegroup grp
|
||||||
|
set iter [sqlite3changeset_start $C]
|
||||||
|
while {[$iter next]=="SQLITE_ROW"} {
|
||||||
|
grp add_change $iter
|
||||||
|
}
|
||||||
|
$iter finalize
|
||||||
|
|
||||||
|
set res [list]
|
||||||
|
grp output
|
||||||
|
sqlite3session_foreach c [grp output] { lappend res $c }
|
||||||
|
grp delete
|
||||||
|
set res
|
||||||
|
} [list \
|
||||||
|
{INSERT t1 0 X.. {} {i 10 i 20 i 30}} \
|
||||||
|
{INSERT t1 0 X.. {} {i 1 i 2 i 3}} \
|
||||||
|
]
|
||||||
|
|
||||||
|
do_test 1.3.1 {
|
||||||
|
set iter [sqlite3changeset_start $C]
|
||||||
|
sqlite3changegroup grp
|
||||||
|
list [catch { grp add_change $iter } msg] $msg
|
||||||
|
} {1 SQLITE_ERROR}
|
||||||
|
do_test 1.3.2 {
|
||||||
|
while {[$iter next]=="SQLITE_ROW"} { }
|
||||||
|
list [catch { grp add_change $iter } msg] $msg
|
||||||
|
} {1 SQLITE_ERROR}
|
||||||
|
grp delete
|
||||||
|
$iter finalize
|
||||||
|
|
||||||
|
do_test 1.4 {
|
||||||
|
set res [list]
|
||||||
|
set iter [sqlite3changeset_start -invert $C]
|
||||||
|
while {[$iter next]=="SQLITE_ROW"} {
|
||||||
|
lappend res [$iter data]
|
||||||
|
}
|
||||||
|
$iter finalize
|
||||||
|
set res
|
||||||
|
} [list \
|
||||||
|
{DELETE t1 0 X.. {i 10 i 20 i 30} {}} \
|
||||||
|
{DELETE t1 0 X.. {i 1 i 2 i 3} {}} \
|
||||||
|
]
|
||||||
|
|
||||||
|
do_test 1.5 {
|
||||||
|
sqlite3changegroup grp
|
||||||
|
set iter [sqlite3changeset_start -invert $C]
|
||||||
|
$iter next
|
||||||
|
list [catch { grp add_change $iter } msg] $msg
|
||||||
|
} {1 SQLITE_ERROR}
|
||||||
|
$iter finalize
|
||||||
|
grp delete
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
@@ -3685,14 +3685,14 @@ static int sessionChangesetNextOne(
|
|||||||
p->rc = sessionInputBuffer(&p->in, 2);
|
p->rc = sessionInputBuffer(&p->in, 2);
|
||||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||||
|
|
||||||
|
sessionDiscardData(&p->in);
|
||||||
|
p->in.iCurrent = p->in.iNext;
|
||||||
|
|
||||||
/* If the iterator is already at the end of the changeset, return DONE. */
|
/* If the iterator is already at the end of the changeset, return DONE. */
|
||||||
if( p->in.iNext>=p->in.nData ){
|
if( p->in.iNext>=p->in.nData ){
|
||||||
return SQLITE_DONE;
|
return SQLITE_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionDiscardData(&p->in);
|
|
||||||
p->in.iCurrent = p->in.iNext;
|
|
||||||
|
|
||||||
op = p->in.aData[p->in.iNext++];
|
op = p->in.aData[p->in.iNext++];
|
||||||
while( op=='T' || op=='P' ){
|
while( op=='T' || op=='P' ){
|
||||||
if( pbNew ) *pbNew = 1;
|
if( pbNew ) *pbNew = 1;
|
||||||
@@ -5427,6 +5427,7 @@ struct sqlite3_changegroup {
|
|||||||
int rc; /* Error code */
|
int rc; /* Error code */
|
||||||
int bPatch; /* True to accumulate patchsets */
|
int bPatch; /* True to accumulate patchsets */
|
||||||
SessionTable *pList; /* List of tables in current patch */
|
SessionTable *pList; /* List of tables in current patch */
|
||||||
|
SessionBuffer rec;
|
||||||
|
|
||||||
sqlite3 *db; /* Configured by changegroup_schema() */
|
sqlite3 *db; /* Configured by changegroup_schema() */
|
||||||
char *zDb; /* Configured by changegroup_schema() */
|
char *zDb; /* Configured by changegroup_schema() */
|
||||||
@@ -5725,29 +5726,94 @@ static int sessionChangesetExtendRecord(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Add all changes in the changeset traversed by the iterator passed as
|
** Locate or create a SessionTable object that may be used to add the
|
||||||
** the first argument to the changegroup hash tables.
|
** change currently pointed to by iterator pIter to changegroup pGrp.
|
||||||
|
** If successful, set output variable (*ppTab) to point to the table
|
||||||
|
** object and return SQLITE_OK. Otherwise, if some error occurs, return
|
||||||
|
** an SQLite error code and leave (*ppTab) set to NULL.
|
||||||
*/
|
*/
|
||||||
static int sessionChangesetToHash(
|
static int sessionChangesetFindTable(
|
||||||
sqlite3_changeset_iter *pIter, /* Iterator to read from */
|
sqlite3_changegroup *pGrp,
|
||||||
sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */
|
const char *zTab,
|
||||||
int bRebase /* True if hash table is for rebasing */
|
sqlite3_changeset_iter *pIter,
|
||||||
|
SessionTable **ppTab
|
||||||
){
|
){
|
||||||
u8 *aRec;
|
|
||||||
int nRec;
|
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
SessionTable *pTab = 0;
|
SessionTable *pTab = 0;
|
||||||
SessionBuffer rec = {0, 0, 0};
|
int nTab = (int)strlen(zTab);
|
||||||
|
u8 *abPK = 0;
|
||||||
|
int nCol = 0;
|
||||||
|
|
||||||
while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
|
*ppTab = 0;
|
||||||
const char *zNew;
|
sqlite3changeset_pk(pIter, &abPK, &nCol);
|
||||||
int nCol;
|
|
||||||
int op;
|
/* Search the list for an existing table */
|
||||||
int iHash;
|
for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
|
||||||
int bIndirect;
|
if( 0==sqlite3_strnicmp(pTab->zName, zTab, nTab+1) ) break;
|
||||||
SessionChange *pChange;
|
}
|
||||||
|
|
||||||
|
/* If one was not found above, create a new table now */
|
||||||
|
if( !pTab ){
|
||||||
|
SessionTable **ppNew;
|
||||||
|
|
||||||
|
pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nTab+1);
|
||||||
|
if( !pTab ){
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
memset(pTab, 0, sizeof(SessionTable));
|
||||||
|
pTab->nCol = nCol;
|
||||||
|
pTab->abPK = (u8*)&pTab[1];
|
||||||
|
memcpy(pTab->abPK, abPK, nCol);
|
||||||
|
pTab->zName = (char*)&pTab->abPK[nCol];
|
||||||
|
memcpy(pTab->zName, zTab, nTab+1);
|
||||||
|
|
||||||
|
if( pGrp->db ){
|
||||||
|
pTab->nCol = 0;
|
||||||
|
rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb);
|
||||||
|
if( rc ){
|
||||||
|
assert( pTab->azCol==0 );
|
||||||
|
sqlite3_free(pTab);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The new object must be linked on to the end of the list, not
|
||||||
|
** simply added to the start of it. This is to ensure that the
|
||||||
|
** tables within the output of sqlite3changegroup_output() are in
|
||||||
|
** the right order. */
|
||||||
|
for(ppNew=&pGrp->pList; *ppNew; ppNew=&(*ppNew)->pNext);
|
||||||
|
*ppNew = pTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the table is compatible. */
|
||||||
|
if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
|
||||||
|
rc = SQLITE_SCHEMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppTab = pTab;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Add the change currently indicated by iterator pIter to the hash table
|
||||||
|
** belonging to changegroup pGrp.
|
||||||
|
*/
|
||||||
|
static int sessionOneChangeToHash(
|
||||||
|
sqlite3_changegroup *pGrp,
|
||||||
|
sqlite3_changeset_iter *pIter,
|
||||||
|
int bRebase
|
||||||
|
){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
int nCol = 0;
|
||||||
|
int op = 0;
|
||||||
|
int iHash = 0;
|
||||||
|
int bIndirect = 0;
|
||||||
|
SessionChange *pChange = 0;
|
||||||
SessionChange *pExist = 0;
|
SessionChange *pExist = 0;
|
||||||
SessionChange **pp;
|
SessionChange **pp = 0;
|
||||||
|
SessionTable *pTab = 0;
|
||||||
|
u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
|
||||||
|
int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
|
||||||
|
|
||||||
/* Ensure that only changesets, or only patchsets, but not a mixture
|
/* Ensure that only changesets, or only patchsets, but not a mixture
|
||||||
** of both, are being combined. It is an error to try to combine a
|
** of both, are being combined. It is an error to try to combine a
|
||||||
@@ -5756,77 +5822,32 @@ static int sessionChangesetToHash(
|
|||||||
pGrp->bPatch = pIter->bPatchset;
|
pGrp->bPatch = pIter->bPatchset;
|
||||||
}else if( pIter->bPatchset!=pGrp->bPatch ){
|
}else if( pIter->bPatchset!=pGrp->bPatch ){
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
|
if( rc==SQLITE_OK ){
|
||||||
if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
|
const char *zTab = 0;
|
||||||
/* Search the list for a matching table */
|
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
|
||||||
int nNew = (int)strlen(zNew);
|
rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab);
|
||||||
u8 *abPK;
|
|
||||||
|
|
||||||
sqlite3changeset_pk(pIter, &abPK, 0);
|
|
||||||
for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
|
|
||||||
if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
|
|
||||||
}
|
|
||||||
if( !pTab ){
|
|
||||||
SessionTable **ppTab;
|
|
||||||
|
|
||||||
pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1);
|
|
||||||
if( !pTab ){
|
|
||||||
rc = SQLITE_NOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
memset(pTab, 0, sizeof(SessionTable));
|
|
||||||
pTab->nCol = nCol;
|
|
||||||
pTab->abPK = (u8*)&pTab[1];
|
|
||||||
memcpy(pTab->abPK, abPK, nCol);
|
|
||||||
pTab->zName = (char*)&pTab->abPK[nCol];
|
|
||||||
memcpy(pTab->zName, zNew, nNew+1);
|
|
||||||
|
|
||||||
if( pGrp->db ){
|
|
||||||
pTab->nCol = 0;
|
|
||||||
rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb);
|
|
||||||
if( rc ){
|
|
||||||
assert( pTab->azCol==0 );
|
|
||||||
sqlite3_free(pTab);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The new object must be linked on to the end of the list, not
|
if( rc==SQLITE_OK && nCol<pTab->nCol ){
|
||||||
** simply added to the start of it. This is to ensure that the
|
SessionBuffer *pBuf = &pGrp->rec;
|
||||||
** tables within the output of sqlite3changegroup_output() are in
|
rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, pBuf);
|
||||||
** the right order. */
|
aRec = pBuf->aBuf;
|
||||||
for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
|
nRec = pBuf->nBuf;
|
||||||
*ppTab = pTab;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
|
|
||||||
rc = SQLITE_SCHEMA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( nCol<pTab->nCol ){
|
|
||||||
assert( pGrp->db );
|
assert( pGrp->db );
|
||||||
rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, &rec);
|
|
||||||
if( rc ) break;
|
|
||||||
aRec = rec.aBuf;
|
|
||||||
nRec = rec.nBuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
|
if( rc==SQLITE_OK && sessionGrowHash(0, pIter->bPatchset, pTab) ){
|
||||||
rc = SQLITE_NOMEM;
|
rc = SQLITE_NOMEM;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
/* Search for existing entry. If found, remove it from the hash table.
|
||||||
|
** Code below may link it back in. */
|
||||||
iHash = sessionChangeHash(
|
iHash = sessionChangeHash(
|
||||||
pTab, (pIter->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.
|
|
||||||
** Code below may link it back in.
|
|
||||||
*/
|
|
||||||
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;
|
||||||
@@ -5841,19 +5862,41 @@ static int sessionChangesetToHash(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
rc = sessionChangeMerge(pTab, bRebase,
|
rc = sessionChangeMerge(pTab, bRebase,
|
||||||
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
|
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
|
||||||
);
|
);
|
||||||
if( rc ) break;
|
}
|
||||||
if( pChange ){
|
if( rc==SQLITE_OK && pChange ){
|
||||||
pChange->pNext = pTab->apChange[iHash];
|
pChange->pNext = pTab->apChange[iHash];
|
||||||
pTab->apChange[iHash] = pChange;
|
pTab->apChange[iHash] = pChange;
|
||||||
pTab->nEntry++;
|
pTab->nEntry++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ) rc = pIter->rc;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Add all changes in the changeset traversed by the iterator passed as
|
||||||
|
** the first argument to the changegroup hash tables.
|
||||||
|
*/
|
||||||
|
static int sessionChangesetToHash(
|
||||||
|
sqlite3_changeset_iter *pIter, /* Iterator to read from */
|
||||||
|
sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */
|
||||||
|
int bRebase /* True if hash table is for rebasing */
|
||||||
|
){
|
||||||
|
u8 *aRec;
|
||||||
|
int nRec;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
|
||||||
|
while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
|
||||||
|
rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
|
||||||
|
if( rc!=SQLITE_OK ) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_free(rec.aBuf);
|
|
||||||
if( rc==SQLITE_OK ) rc = pIter->rc;
|
if( rc==SQLITE_OK ) rc = pIter->rc;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -5981,6 +6024,23 @@ int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Add a single change to a changeset-group.
|
||||||
|
*/
|
||||||
|
int sqlite3changegroup_add_change(
|
||||||
|
sqlite3_changegroup *pGrp,
|
||||||
|
sqlite3_changeset_iter *pIter
|
||||||
|
){
|
||||||
|
if( pIter->in.iCurrent==pIter->in.iNext
|
||||||
|
|| pIter->rc!=SQLITE_OK
|
||||||
|
|| pIter->bInvert
|
||||||
|
){
|
||||||
|
/* Iterator does not point to any valid entry or is an INVERT iterator. */
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
return sessionOneChangeToHash(pGrp, pIter, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Obtain a buffer containing a changeset representing the concatenation
|
** Obtain a buffer containing a changeset representing the concatenation
|
||||||
** of all changesets added to the group so far.
|
** of all changesets added to the group so far.
|
||||||
@@ -6030,6 +6090,7 @@ void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
|
|||||||
if( pGrp ){
|
if( pGrp ){
|
||||||
sqlite3_free(pGrp->zDb);
|
sqlite3_free(pGrp->zDb);
|
||||||
sessionDeleteTable(0, pGrp->pList);
|
sessionDeleteTable(0, pGrp->pList);
|
||||||
|
sqlite3_free(pGrp->rec.aBuf);
|
||||||
sqlite3_free(pGrp);
|
sqlite3_free(pGrp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6431,6 +6492,7 @@ int sqlite3rebaser_rebase_strm(
|
|||||||
void sqlite3rebaser_delete(sqlite3_rebaser *p){
|
void sqlite3rebaser_delete(sqlite3_rebaser *p){
|
||||||
if( p ){
|
if( p ){
|
||||||
sessionDeleteTable(0, p->grp.pList);
|
sessionDeleteTable(0, p->grp.pList);
|
||||||
|
sqlite3_free(p->grp.rec.aBuf);
|
||||||
sqlite3_free(p);
|
sqlite3_free(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1057,6 +1057,30 @@ int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb);
|
|||||||
*/
|
*/
|
||||||
int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
|
int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Add A Single Change To A Changegroup
|
||||||
|
** METHOD: sqlite3_changegroup
|
||||||
|
**
|
||||||
|
** This function adds the single change currently indicated by the iterator
|
||||||
|
** passed as the second argument to the changegroup object. The rules for
|
||||||
|
** adding the change are just as described for [sqlite3_changegroup_add()].
|
||||||
|
**
|
||||||
|
** If the change is successfully added to the changegroup, SQLITE_OK is
|
||||||
|
** returned. Otherwise, an SQLite error code is returned.
|
||||||
|
**
|
||||||
|
** The iterator must point to a valid entry when this function is called.
|
||||||
|
** If it does not, SQLITE_ERROR is returned and no change is added to the
|
||||||
|
** changegroup. Additionally, the iterator must not have been opened with
|
||||||
|
** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
|
||||||
|
** returned.
|
||||||
|
*/
|
||||||
|
int sqlite3changegroup_add_change(
|
||||||
|
sqlite3_changegroup*,
|
||||||
|
sqlite3_changeset_iter*
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
|
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
|
||||||
** METHOD: sqlite3_changegroup
|
** METHOD: sqlite3_changegroup
|
||||||
|
@@ -1038,6 +1038,64 @@ static int SQLITE_TCLAPI test_sqlite3changeset_concat(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Tcl_Obj *testIterData(sqlite3_changeset_iter *pIter){
|
||||||
|
Tcl_Obj *pVar = 0;
|
||||||
|
int nCol; /* Number of columns in table */
|
||||||
|
int nCol2; /* Number of columns in table */
|
||||||
|
int op; /* SQLITE_INSERT, UPDATE or DELETE */
|
||||||
|
const char *zTab; /* Name of table change applies to */
|
||||||
|
Tcl_Obj *pOld; /* Vector of old.* values */
|
||||||
|
Tcl_Obj *pNew; /* Vector of new.* values */
|
||||||
|
int bIndirect;
|
||||||
|
|
||||||
|
char *zPK;
|
||||||
|
unsigned char *abPK;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
|
||||||
|
pVar = Tcl_NewObj();
|
||||||
|
|
||||||
|
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(
|
||||||
|
op==SQLITE_INSERT ? "INSERT" :
|
||||||
|
op==SQLITE_UPDATE ? "UPDATE" :
|
||||||
|
"DELETE", -1
|
||||||
|
));
|
||||||
|
|
||||||
|
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zTab, -1));
|
||||||
|
Tcl_ListObjAppendElement(0, pVar, Tcl_NewBooleanObj(bIndirect));
|
||||||
|
|
||||||
|
zPK = ckalloc(nCol+1);
|
||||||
|
memset(zPK, 0, nCol+1);
|
||||||
|
sqlite3changeset_pk(pIter, &abPK, &nCol2);
|
||||||
|
assert( nCol==nCol2 );
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
zPK[i] = (abPK[i] ? 'X' : '.');
|
||||||
|
}
|
||||||
|
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zPK, -1));
|
||||||
|
ckfree(zPK);
|
||||||
|
|
||||||
|
pOld = Tcl_NewObj();
|
||||||
|
if( op!=SQLITE_INSERT ){
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
sqlite3_value *pVal;
|
||||||
|
sqlite3changeset_old(pIter, i, &pVal);
|
||||||
|
test_append_value(pOld, pVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pNew = Tcl_NewObj();
|
||||||
|
if( op!=SQLITE_DELETE ){
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
sqlite3_value *pVal;
|
||||||
|
sqlite3changeset_new(pIter, i, &pVal);
|
||||||
|
test_append_value(pNew, pVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tcl_ListObjAppendElement(0, pVar, pOld);
|
||||||
|
Tcl_ListObjAppendElement(0, pVar, pNew);
|
||||||
|
|
||||||
|
return pVar;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** sqlite3session_foreach VARNAME CHANGESET SCRIPT
|
** sqlite3session_foreach VARNAME CHANGESET SCRIPT
|
||||||
*/
|
*/
|
||||||
@@ -1111,67 +1169,8 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
|
|||||||
}
|
}
|
||||||
|
|
||||||
while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
|
while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
|
||||||
int nCol; /* Number of columns in table */
|
Tcl_Obj *pVar = 0; /* Tcl value to set $VARNAME to */
|
||||||
int nCol2; /* Number of columns in table */
|
pVar = testIterData(pIter);
|
||||||
int op; /* SQLITE_INSERT, UPDATE or DELETE */
|
|
||||||
const char *zTab; /* Name of table change applies to */
|
|
||||||
Tcl_Obj *pVar; /* Tcl value to set $VARNAME to */
|
|
||||||
Tcl_Obj *pOld; /* Vector of old.* values */
|
|
||||||
Tcl_Obj *pNew; /* Vector of new.* values */
|
|
||||||
int bIndirect;
|
|
||||||
|
|
||||||
char *zPK;
|
|
||||||
unsigned char *abPK;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Test that _fk_conflicts() returns SQLITE_MISUSE if called on this
|
|
||||||
** iterator. */
|
|
||||||
int nDummy;
|
|
||||||
if( SQLITE_MISUSE!=sqlite3changeset_fk_conflicts(pIter, &nDummy) ){
|
|
||||||
sqlite3changeset_finalize(pIter);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
|
|
||||||
pVar = Tcl_NewObj();
|
|
||||||
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(
|
|
||||||
op==SQLITE_INSERT ? "INSERT" :
|
|
||||||
op==SQLITE_UPDATE ? "UPDATE" :
|
|
||||||
"DELETE", -1
|
|
||||||
));
|
|
||||||
|
|
||||||
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zTab, -1));
|
|
||||||
Tcl_ListObjAppendElement(0, pVar, Tcl_NewBooleanObj(bIndirect));
|
|
||||||
|
|
||||||
zPK = ckalloc(nCol+1);
|
|
||||||
memset(zPK, 0, nCol+1);
|
|
||||||
sqlite3changeset_pk(pIter, &abPK, &nCol2);
|
|
||||||
assert( nCol==nCol2 );
|
|
||||||
for(i=0; i<nCol; i++){
|
|
||||||
zPK[i] = (abPK[i] ? 'X' : '.');
|
|
||||||
}
|
|
||||||
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zPK, -1));
|
|
||||||
ckfree(zPK);
|
|
||||||
|
|
||||||
pOld = Tcl_NewObj();
|
|
||||||
if( op!=SQLITE_INSERT ){
|
|
||||||
for(i=0; i<nCol; i++){
|
|
||||||
sqlite3_value *pVal;
|
|
||||||
sqlite3changeset_old(pIter, i, &pVal);
|
|
||||||
test_append_value(pOld, pVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pNew = Tcl_NewObj();
|
|
||||||
if( op!=SQLITE_DELETE ){
|
|
||||||
for(i=0; i<nCol; i++){
|
|
||||||
sqlite3_value *pVal;
|
|
||||||
sqlite3changeset_new(pIter, i, &pVal);
|
|
||||||
test_append_value(pNew, pVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tcl_ListObjAppendElement(0, pVar, pOld);
|
|
||||||
Tcl_ListObjAppendElement(0, pVar, pNew);
|
|
||||||
|
|
||||||
Tcl_ObjSetVar2(interp, pVarname, 0, pVar, 0);
|
Tcl_ObjSetVar2(interp, pVarname, 0, pVar, 0);
|
||||||
rc = Tcl_EvalObjEx(interp, pScript, 0);
|
rc = Tcl_EvalObjEx(interp, pScript, 0);
|
||||||
if( rc!=TCL_OK && rc!=TCL_CONTINUE ){
|
if( rc!=TCL_OK && rc!=TCL_CONTINUE ){
|
||||||
@@ -1459,6 +1458,12 @@ struct TestChangegroup {
|
|||||||
sqlite3_changegroup *pGrp;
|
sqlite3_changegroup *pGrp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct TestChangeIter TestChangeIter;
|
||||||
|
struct TestChangeIter {
|
||||||
|
sqlite3_changeset_iter *pIter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Destructor for Tcl changegroup command object.
|
** Destructor for Tcl changegroup command object.
|
||||||
*/
|
*/
|
||||||
@@ -1491,6 +1496,7 @@ static int SQLITE_TCLAPI test_changegroup_cmd(
|
|||||||
{ "add", 1, "CHANGESET", }, /* 1 */
|
{ "add", 1, "CHANGESET", }, /* 1 */
|
||||||
{ "output", 0, "", }, /* 2 */
|
{ "output", 0, "", }, /* 2 */
|
||||||
{ "delete", 0, "", }, /* 3 */
|
{ "delete", 0, "", }, /* 3 */
|
||||||
|
{ "add_change", 1, "ITERATOR", }, /* 4 */
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
int rc = TCL_OK;
|
int rc = TCL_OK;
|
||||||
@@ -1542,6 +1548,24 @@ static int SQLITE_TCLAPI test_changegroup_cmd(
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case 4: { /* add_change */
|
||||||
|
Tcl_CmdInfo cmdInfo; /* Database Tcl command (objv[2]) info */
|
||||||
|
TestChangeIter *pIter = 0;
|
||||||
|
const char *zIter = Tcl_GetString(objv[2]);
|
||||||
|
if( 0==Tcl_GetCommandInfo(interp, zIter, &cmdInfo) ){
|
||||||
|
Tcl_AppendResult(interp, "no such iter: ", Tcl_GetString(objv[2]), 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pIter = (struct TestChangeIter*)cmdInfo.objClientData;
|
||||||
|
|
||||||
|
rc = sqlite3changegroup_add_change(p->pGrp, pIter->pIter);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
rc = test_session_error(interp, rc, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
default: { /* delete */
|
default: { /* delete */
|
||||||
assert( iSub==3 );
|
assert( iSub==3 );
|
||||||
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
|
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
|
||||||
@@ -1585,6 +1609,115 @@ static int SQLITE_TCLAPI test_sqlite3changegroup(
|
|||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const char *sqlite3ErrName(int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Destructor for Tcl iterator command object.
|
||||||
|
*/
|
||||||
|
static void test_iter_del(void *clientData){
|
||||||
|
TestChangeIter *p = (TestChangeIter*)clientData;
|
||||||
|
sqlite3changeset_finalize(p->pIter);
|
||||||
|
ckfree(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SQLITE_TCLAPI test_iter_cmd(
|
||||||
|
void * clientData,
|
||||||
|
Tcl_Interp *interp,
|
||||||
|
int objc,
|
||||||
|
Tcl_Obj *CONST objv[]
|
||||||
|
){
|
||||||
|
static const char *aSub[] = {
|
||||||
|
"next", /* 0 */
|
||||||
|
"data", /* 1 */
|
||||||
|
"finalize", /* 2 */
|
||||||
|
0
|
||||||
|
};
|
||||||
|
int iSub = 0;
|
||||||
|
|
||||||
|
TestChangeIter *p = (TestChangeIter*)clientData;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
|
||||||
|
if( objc<2 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 1, objv, "CMD");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Tcl_GetIndexFromObj(interp, objv[1], aSub, "sub-command", 0, &iSub) ){
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
switch( iSub ){
|
||||||
|
case 0:
|
||||||
|
rc = sqlite3changeset_next(p->pIter);
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Tcl_SetObjResult(interp, testIterData(p->pIter));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rc = sqlite3changeset_finalize(p->pIter);
|
||||||
|
p->pIter = 0;
|
||||||
|
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert( 0 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Tclcmd: sqlite3changeset_start ?-invert? CHANGESET
|
||||||
|
*/
|
||||||
|
static int SQLITE_TCLAPI test_sqlite3changeset_start(
|
||||||
|
void * clientData,
|
||||||
|
Tcl_Interp *interp,
|
||||||
|
int objc,
|
||||||
|
Tcl_Obj *CONST objv[]
|
||||||
|
){
|
||||||
|
int isInvert = 0;
|
||||||
|
void *pChangeset = 0; /* Buffer containing changeset */
|
||||||
|
int nChangeset = 0; /* Size of buffer aChangeset in bytes */
|
||||||
|
TestChangeIter *pNew = 0;
|
||||||
|
sqlite3_changeset_iter *pIter = 0;
|
||||||
|
int flags = 0;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
|
||||||
|
static int iCmd = 1;
|
||||||
|
char zCmd[64];
|
||||||
|
|
||||||
|
if( objc==3 ){
|
||||||
|
int n = 0;
|
||||||
|
const char *z = Tcl_GetStringFromObj(objv[1], &n);
|
||||||
|
isInvert = (n>=2 && sqlite3_strnicmp(z, "-invert", n)==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( objc!=2 && (objc!=3 || !isInvert) ){
|
||||||
|
Tcl_WrongNumArgs(interp, 1, objv, "?-invert? CHANGESET");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = isInvert ? SQLITE_CHANGESETSTART_INVERT : 0;
|
||||||
|
pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[objc-1], &nChangeset);
|
||||||
|
rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, flags);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
char *zErr = sqlite3_mprintf(
|
||||||
|
"error in sqlite3changeset_start_v2() - %d", rc
|
||||||
|
);
|
||||||
|
Tcl_AppendResult(interp, zErr, (char*)0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNew = (TestChangeIter*)ckalloc(sizeof(TestChangeIter));
|
||||||
|
pNew->pIter = pIter;
|
||||||
|
|
||||||
|
sprintf(zCmd, "csiter%d", iCmd++);
|
||||||
|
Tcl_CreateObjCommand(interp, zCmd, test_iter_cmd, (void*)pNew, test_iter_del);
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewStringObj(zCmd, -1));
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int TestSession_Init(Tcl_Interp *interp){
|
int TestSession_Init(Tcl_Interp *interp){
|
||||||
struct Cmd {
|
struct Cmd {
|
||||||
const char *zCmd;
|
const char *zCmd;
|
||||||
@@ -1592,6 +1725,7 @@ int TestSession_Init(Tcl_Interp *interp){
|
|||||||
} aCmd[] = {
|
} aCmd[] = {
|
||||||
{ "sqlite3session", test_sqlite3session },
|
{ "sqlite3session", test_sqlite3session },
|
||||||
{ "sqlite3changegroup", test_sqlite3changegroup },
|
{ "sqlite3changegroup", test_sqlite3changegroup },
|
||||||
|
{ "sqlite3changeset_start", test_sqlite3changeset_start },
|
||||||
{ "sqlite3session_foreach", test_sqlite3session_foreach },
|
{ "sqlite3session_foreach", test_sqlite3session_foreach },
|
||||||
{ "sqlite3changeset_invert", test_sqlite3changeset_invert },
|
{ "sqlite3changeset_invert", test_sqlite3changeset_invert },
|
||||||
{ "sqlite3changeset_concat", test_sqlite3changeset_concat },
|
{ "sqlite3changeset_concat", test_sqlite3changeset_concat },
|
||||||
|
18
manifest
18
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sproblem\sin\ssqlar_uncompress()\swhen\sbeing\sused\sto\sextract\ssymbolic\slinks.
|
C Add\snew\ssessions\sAPI\ssqlite3changegroup_add_change().
|
||||||
D 2024-05-06T11:27:47.649
|
D 2024-05-06T17:55:19.315
|
||||||
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 LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@@ -567,6 +567,7 @@ F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8
|
|||||||
F ext/session/sessionalter.test 460bdac2832a550519f6bc32e5db2c0cee94f335870aaf25a3a403a81ab20e17
|
F ext/session/sessionalter.test 460bdac2832a550519f6bc32e5db2c0cee94f335870aaf25a3a403a81ab20e17
|
||||||
F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee
|
F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee
|
||||||
F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
|
F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
|
||||||
|
F ext/session/sessionchange.test 77c4702050f24270b58070e2cf01c95c3d232a3ef164b70f31974b386ce69903
|
||||||
F ext/session/sessionconflict.test 28890457bb90457be772d3067cdb5f78db9b51d997e4f3d09f22cddc9be80a38
|
F ext/session/sessionconflict.test 28890457bb90457be772d3067cdb5f78db9b51d997e4f3d09f22cddc9be80a38
|
||||||
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
|
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
|
||||||
F ext/session/sessionfault.test 573bf027fb870d57bd4e7cf50822a3e4b17b2b923407438747aaa918dec57a09
|
F ext/session/sessionfault.test 573bf027fb870d57bd4e7cf50822a3e4b17b2b923407438747aaa918dec57a09
|
||||||
@@ -582,9 +583,9 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a
|
|||||||
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
|
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
|
||||||
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
|
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
|
||||||
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
||||||
F ext/session/sqlite3session.c 829d468f0f3d2710aace56b0116a7ca3f414683ce78e3125ae5e21547a895078
|
F ext/session/sqlite3session.c c7473aafbd88f796391a8c25aa90975a8f3729ab7f4f8cf74ab9d3b014e10abe
|
||||||
F ext/session/sqlite3session.h 4cf19a51975746d7cff2fdd74db8b769c570958e1c3639ac150d824ac1553b3e
|
F ext/session/sqlite3session.h c02e7bbeb38647436fa7d6f364ffe90ac61b8ba5a28f0c04b22a23887baab6cb
|
||||||
F ext/session/test_session.c 7b94ad945cd4afe6c73ee935aeb3d44b4446186e1729362af616c7695a5283d9
|
F ext/session/test_session.c 8bcc857125372e640f75ab63b4188080f9bbab92b65f86dfd160721c574b2044
|
||||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||||
F ext/userauth/user-auth.txt ca7e9ee82ca4e1c1744295f8184dd70edfae1992865d26c64303f539eb6c084c
|
F ext/userauth/user-auth.txt ca7e9ee82ca4e1c1744295f8184dd70edfae1992865d26c64303f539eb6c084c
|
||||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||||
@@ -2188,8 +2189,9 @@ 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 9bdf73a8d4a3b4a72f2882252f9ed29a6f1a26d3f50c071f27455bcf10458c4b
|
P 4d90c3f179a3d7355b6b0202faf56f0be4be56986920576e528208cb84daa4af 49f84878e21f85d44d8429cdc2908f87383e59737e1af3fdbccf0c276d883567
|
||||||
R c4e317266c51f659c5ce93f052688c23
|
R 17b8f244002104b13ac86f24d06a1235
|
||||||
|
T +closed 49f84878e21f85d44d8429cdc2908f87383e59737e1af3fdbccf0c276d883567
|
||||||
U dan
|
U dan
|
||||||
Z d759657d9ef1cadf5eb299f7ac2ab3b0
|
Z ea504d9f33b8a329c60b503f8918f722
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@@ -1 +1 @@
|
|||||||
4d90c3f179a3d7355b6b0202faf56f0be4be56986920576e528208cb84daa4af
|
5eaab43ce48bb8d710f784ecd6aa9a4b3e708b44b0f7e49daf66a3f8bc2b9873
|
Reference in New Issue
Block a user