mirror of https://github.com/sqlite/sqlite
Progress on the sqlite3-rsync utility. This is an incremental check-in. It
does compile, but it does not work. FossilOrigin-Name: fa06977b6db7fa745720561ec0b10570cf7e71598dc7a7c5ee650640e5bdf6f5
This commit is contained in:
parent
79254dc363
commit
dc3bec34a6
14
Makefile.in
14
Makefile.in
|
@ -700,8 +700,18 @@ sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h
|
|||
dbhash$(TEXE): $(TOP)/tool/dbhash.c sqlite3.lo sqlite3.h
|
||||
$(LTLINK) -o $@ $(TOP)/tool/dbhash.c sqlite3.lo $(TLIBS)
|
||||
|
||||
sqlite3-rsync$(TEXE): $(TOP)/tool/sqlite3-rsync.c sqlite3.lo sqlite3.h
|
||||
$(LTLINK) -o $@ $(TOP)/tool/sqlite3-rsync.c sqlite3.lo $(TLIBS)
|
||||
RSYNC_SRC = \
|
||||
$(TOP)/tool/sqlite3-rsync.c \
|
||||
$(TOP)/ext/misc/sha1.c \
|
||||
sqlite3.c
|
||||
|
||||
RSYNC_OPT = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_OMIT_DEPRECATED
|
||||
|
||||
sqlite3-rsync$(TEXE): $(RSYNC_SRC)
|
||||
$(TCC) -o $@ $(RSYNC_SRC) $(TLIBS)
|
||||
|
||||
scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.lo
|
||||
$(LTLINK) -o $@ -I. -DSCRUB_STANDALONE \
|
||||
|
|
14
Makefile.msc
14
Makefile.msc
|
@ -1867,8 +1867,18 @@ sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\consio\console_io.h $(TOP)\ext\con
|
|||
dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
sqlite3-rsync.exe: $(TOP)\tool\sqlite3-rsync.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\sqlite3-rsync.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
|
||||
RSYNC_SRC = \
|
||||
$(TOP)\tool\sqlite3-rsync.c \
|
||||
$(TOP)\ext\misc\sha1.c \
|
||||
$(SQLITE3C)
|
||||
|
||||
RSYNC_OPT = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_OMIT_DEPRECATED
|
||||
|
||||
sqlite3-rsync.exe: $(RSYNC_SRC) $(LIBRESOBJS)
|
||||
$(LTLINK) $(RSYNC_OPT) $(NO_WARN) $(RSYNC_SRC) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
|
||||
|
||||
scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSCRUB_STANDALONE=1 $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
|
|
@ -196,7 +196,8 @@ static void hash_step_vformat(
|
|||
** zOut[]. zOut[] must be at least 41 bytes long. */
|
||||
static void hash_finish(
|
||||
SHA1Context *p, /* The SHA1 context to finish and render */
|
||||
char *zOut /* Store hexadecimal hash here */
|
||||
char *zOut, /* Store hex or binary hash here */
|
||||
int bAsBinary /* 1 for binary hash, 0 for hex hash */
|
||||
){
|
||||
unsigned int i;
|
||||
unsigned char finalcount[8];
|
||||
|
@ -251,7 +252,7 @@ static void sha1Func(
|
|||
}else{
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
hash_finish(&cx, zOut, sqlite3_user_data(context)!=0);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
@ -365,7 +366,7 @@ static void sha1QueryFunc(
|
|||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
hash_finish(&cx, zOut, 0);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
@ -379,11 +380,17 @@ int sqlite3_sha_init(
|
|||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
static int one = 1;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sha1", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, sha1Func, 0, 0);
|
||||
0, sha1Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1b", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
(void*)&one, sha1Func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
|
|
15
main.mk
15
main.mk
|
@ -568,9 +568,18 @@ dbhash$(EXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h
|
|||
$(TCCX) -o dbhash$(EXE) -DSQLITE_THREADSAFE=0 \
|
||||
$(TOP)/tool/dbhash.c sqlite3.c $(TLIBS) $(THREADLIB)
|
||||
|
||||
sqlite3-rsync$(EXE): $(TOP)/tool/sqlite3-rsync.c sqlite3.o
|
||||
$(TCCX) -o sqlite3-rsync$(EXE) -DSQLITE_THREADSAFE=0 \
|
||||
$(TOP)/tool/sqlite3-rsync.c sqlite3.o $(TLIBS) $(THREADLIB)
|
||||
RSYNC_SRC = \
|
||||
$(TOP)/tool/sqlite3-rsync.c \
|
||||
$(TOP)/ext/misc/sha1.c \
|
||||
sqlite3.c
|
||||
|
||||
RSYNC_OPT = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_OMIT_DEPRECATED
|
||||
|
||||
sqlite3-rsync$(EXE): $(RSYNC_SRC)
|
||||
$(TCC) -o $@ $(RSYNC_OPT) $(RSYNC_SRC) $(TLIBS)
|
||||
|
||||
scrub$(EXE): $(TOP)/ext/misc/scrub.c sqlite3.o
|
||||
$(TCC) -I. -DSCRUB_STANDALONE -o scrub$(EXE) $(TOP)/ext/misc/scrub.c sqlite3.o $(THREADLIB)
|
||||
|
|
20
manifest
20
manifest
|
@ -1,11 +1,11 @@
|
|||
C Improved\sSSH\sinfrastructure.\s\sThe\sfoundation\sis\snow\sin\splace\sto\sbegin\sworking\non\sthe\sactual\ssync\sprotocol.\s\sStill\sexperimental.\s\sStill\sa\swork\sin\sprogress.
|
||||
D 2024-09-10T22:14:18.799
|
||||
C Progress\son\sthe\ssqlite3-rsync\sutility.\s\sThis\sis\san\sincremental\scheck-in.\s\sIt\ndoes\scompile,\sbut\sit\sdoes\snot\swork.
|
||||
D 2024-09-11T17:02:44.010
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in c9a51ee844a471c950881748f21699fdbf42ef540bf5e78d269f99003f510256
|
||||
F Makefile.in 54e80b016b0e58db383c0f08d340ef795b8b709ffb6f53a51a8ba7bf0c5e288f
|
||||
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
|
||||
F Makefile.msc 4ecdd8ec6bb3264cc2f6c4b154cf9ddd2647e4c6fcb2a294c9725a1483cb2862
|
||||
F Makefile.msc a86e0f3fe5f807daa82d44b5056e3dbc311e569bd4748646a776a994124ec58b
|
||||
F README.md c3c0f19532ce28f6297a71870f3c7b424729f0e6d9ab889616d3587dd2332159
|
||||
F VERSION 0db40f92c04378404eb45bff93e9e42c148c7e54fd3da99469ed21e22411f5a6
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
|
@ -420,7 +420,7 @@ F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6
|
|||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
F ext/misc/series.c a6089b5e8e3002bd1e5d9877cee6aead0b9a6426e406c09a399817db9e9ae823
|
||||
F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d
|
||||
F ext/misc/sha1.c dfd26eb3437a88fe7349d1fe080b761549c456ae17cb11242441bf66031942bf
|
||||
F ext/misc/shathree.c 1821d90a0040c9accdbe3e3527d378d30569475d758aa70f6848924c0b430e8c
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c c0aa7b80d6df45f7da59d912b38752bcac1af53a5766966160e6c5cdd397dbea
|
||||
|
@ -687,7 +687,7 @@ F ext/wasm/wasmfs.make 8a4955882aaa0783b3f60a9484a1f0f3d8b6f775c0fcd17c082f31966
|
|||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk 936f535d99e70cf7c1f51c485a3fad7c7c858abad34d41ce100729befc2b2afe
|
||||
F main.mk 9ffe4a14bdb4a0b856217a5465ca6b1ef4bef66a3c45e2da3fdb6d9bfc8d583e
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
|
||||
|
@ -2174,7 +2174,7 @@ F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
|
|||
F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x
|
||||
F tool/split-sqlite3c.tcl 5aa60643afca558bc732b1444ae81a522326f91e1dc5665b369c54f09e20de60
|
||||
F tool/sqldiff.c 847fc8fcfddf5ce4797b7394cad6372f2f5dc17d8186e2ef8fb44d50fae4f44a
|
||||
F tool/sqlite3-rsync.c d9fd25997c34d9a63e7afdd99b467aaa69440e3ce4d4f85cf47da3e182f4c7e9
|
||||
F tool/sqlite3-rsync.c eb75a24e3a47fe7b5a4d5cbd2eadd4f4b6b6d6038ec7c94eb98a879ccd1bf8c5
|
||||
F tool/sqlite3_analyzer.c.in 8da2b08f56eeac331a715036cf707cc20f879f231362be0c22efd682e2b89b4f
|
||||
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
|
||||
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
|
||||
|
@ -2213,8 +2213,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
|
|||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 397b2d37b7a6619b0c1eee201065585d03496f94786b21540f613e4716d56612
|
||||
R 721e909ab77c2cd7295ba63619aaa44c
|
||||
P 9a1a95f523a96303aad57e2422c2b51ea7e125f5490f32f7a2929d49b6c69ef8
|
||||
R f1d49deccd29ff432816ec80f04a6271
|
||||
U drh
|
||||
Z 2e6a3a2b31db87fda5c83fa80a99e1a6
|
||||
Z f5a21c2123f254d15ff8790517b1651d
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
|
|
@ -1 +1 @@
|
|||
9a1a95f523a96303aad57e2422c2b51ea7e125f5490f32f7a2929d49b6c69ef8
|
||||
fa06977b6db7fa745720561ec0b10570cf7e71598dc7a7c5ee650640e5bdf6f5
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
static const char zUsage[] =
|
||||
|
@ -37,10 +38,29 @@ struct SQLiteRsync {
|
|||
FILE *pIn; /* Receive from the other side */
|
||||
sqlite3_uint64 nOut; /* Bytes transmitted */
|
||||
sqlite3_uint64 nIn; /* Bytes received */
|
||||
sqlite3 *db; /* Database connection */
|
||||
int nErr; /* Number of errors encountered */
|
||||
int eVerbose; /* Bigger for more output. 0 means none. */
|
||||
int bCommCheck; /* True to debug the communication protocol */
|
||||
int isRemote; /* On the remote side of a connection */
|
||||
};
|
||||
|
||||
|
||||
/* Magic numbers to identify particular messages sent over the wire.
|
||||
*/
|
||||
#define ORIGIN_BEGIN 0x41 /* Initial message */
|
||||
#define ORIGIN_END 0x42 /* Time to quit */
|
||||
#define ORIGIN_ERROR 0x43 /* Error message from the remote */
|
||||
#define ORIGIN_PAGE 0x44 /* New page data */
|
||||
#define ORIGIN_TXN 0x45 /* Transaction commit */
|
||||
|
||||
#define REPLICA_BEGIN 0x61 /* Welcome message */
|
||||
#define REPLICA_ERROR 0x62 /* Error. Report and quit. */
|
||||
#define REPLICA_END 0x63 /* Replica wants to stop */
|
||||
#define REPLICA_HASH 0x64 /* One or more pages hashes to report */
|
||||
#define REPLICA_READY 0x65 /* Read to receive page content */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
** Beginning of the popen2() implementation copied from Fossil *************
|
||||
****************************************************************************/
|
||||
|
@ -87,6 +107,12 @@ static void win32_fatal_error(const char *zMsg){
|
|||
# define PTR_TO_INT(X) ((int)(X))
|
||||
#endif
|
||||
|
||||
/* Register SQL functions provided by ext/misc/sha1.c */
|
||||
extern int sqlite3_sha_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
);
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
|
@ -471,6 +497,238 @@ static void echoOneLine(SQLiteRsync *p){
|
|||
}
|
||||
}
|
||||
|
||||
/* Read a single big-endian 32-bit unsigned integer from the input
|
||||
** stream. Return 0 on success and 1 if there are any errors.
|
||||
*/
|
||||
static int readUint32(SQLiteRsync *p, unsigned int *pU){
|
||||
unsigned char buf[4];
|
||||
if( fread(buf, sizeof(buf), 1, p->pIn)==1 ){
|
||||
*pU = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
return 0;
|
||||
}else{
|
||||
p->nErr++;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a single big-endian 32-bit unsigned integer to the output stream.
|
||||
** Return 0 on success and 1 if there are any errors.
|
||||
*/
|
||||
static int writeUint32(SQLiteRsync *p, unsigned int x){
|
||||
unsigned char buf[4];
|
||||
buf[3] = x & 0xff;
|
||||
x >>= 8;
|
||||
buf[2] = x & 0xff;
|
||||
x >>= 8;
|
||||
buf[1] = x & 0xff;
|
||||
x >>= 8;
|
||||
buf[0] = x;
|
||||
if( fwrite(buf, sizeof(buf), 1, p->pOut)!=1 ){
|
||||
p->nErr++;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Report an error.
|
||||
**
|
||||
** If this happens on the remote side, we send back a REMOTE_ERROR
|
||||
** message. On the local side, the error message goes to stderr.
|
||||
*/
|
||||
static void reportError(SQLiteRsync *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *zMsg;
|
||||
unsigned int nMsg;
|
||||
va_start(ap, zFormat);
|
||||
zMsg = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
nMsg = zMsg ? (unsigned int)strlen(zMsg) : 0;
|
||||
if( p->isRemote ){
|
||||
if( p->zReplica ){
|
||||
putc(REPLICA_ERROR, p->pOut);
|
||||
}else{
|
||||
putc(ORIGIN_ERROR, p->pOut);
|
||||
}
|
||||
writeUint32(p, nMsg);
|
||||
fwrite(zMsg, nMsg, 1, p->pOut);
|
||||
fflush(p->pOut);
|
||||
}else{
|
||||
fprintf(stderr, "%s\n", zMsg);
|
||||
}
|
||||
sqlite3_free(zMsg);
|
||||
p->nErr++;
|
||||
}
|
||||
|
||||
/* Receive and report an error message coming from the other side.
|
||||
*/
|
||||
static void readAndDisplayError(SQLiteRsync *p){
|
||||
unsigned int n = 0;
|
||||
char *zMsg;
|
||||
(void)readUint32(p, &n);
|
||||
if( n==0 ){
|
||||
fprintf(stderr,"ERROR: unknown (possibly out-of-memory)\n");
|
||||
}else{
|
||||
zMsg = sqlite3_malloc64( n+1 );
|
||||
if( zMsg==0 ){
|
||||
fprintf(stderr, "ERROR: out-of-memory\n");
|
||||
return;
|
||||
}
|
||||
memset(zMsg, 0, n+1);
|
||||
fread(zMsg, 1, n, p->pIn);
|
||||
fprintf(stderr,"ERROR: %s\n", zMsg);
|
||||
sqlite3_free(zMsg);
|
||||
}
|
||||
p->nErr++;
|
||||
}
|
||||
|
||||
/* Construct a new prepared statement. Report an error and return NULL
|
||||
** if anything goes wrong.
|
||||
*/
|
||||
static sqlite3_stmt *prepareStmtVA(
|
||||
SQLiteRsync *p,
|
||||
char *zFormat,
|
||||
va_list ap
|
||||
){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *zSql;
|
||||
char *zToFree = 0;
|
||||
int rc;
|
||||
|
||||
if( strchr(zFormat,'%') ){
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
if( zSql==0 ){
|
||||
reportError(p, "out-of-memory");
|
||||
return 0;
|
||||
}else{
|
||||
zToFree = zSql;
|
||||
}
|
||||
}else{
|
||||
zSql = zFormat;
|
||||
}
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc || pStmt==0 ){
|
||||
reportError(p, "unable to prepare SQL [%s]: %s", zSql,
|
||||
sqlite3_errmsg(p->db));
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
}
|
||||
if( zToFree ) sqlite3_free(zToFree);
|
||||
return pStmt;
|
||||
}
|
||||
static sqlite3_stmt *prepareStmt(
|
||||
SQLiteRsync *p,
|
||||
char *zFormat,
|
||||
...
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = prepareStmtVA(p, zFormat, ap);
|
||||
va_end(ap);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/* Run a single SQL statement
|
||||
*/
|
||||
static void runSql(SQLiteRsync *p, char *zSql, ...){
|
||||
sqlite3_stmt *pStmt;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zSql);
|
||||
pStmt = prepareStmtVA(p, zSql, ap);
|
||||
va_end(ap);
|
||||
if( pStmt ){
|
||||
int rc = sqlite3_step(pStmt);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){
|
||||
reportError(p, "SQL statement [%s] failed: %s", zSql,
|
||||
sqlite3_errmsg(p->db));
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run an SQL statement that returns a single unsigned 32-bit integer result
|
||||
*/
|
||||
static int runSqlReturnUInt(
|
||||
SQLiteRsync *p,
|
||||
unsigned int *pRes,
|
||||
char *zSql,
|
||||
...
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int res = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zSql);
|
||||
pStmt = prepareStmtVA(p, zSql, ap);
|
||||
va_end(ap);
|
||||
if( pStmt==0 ){
|
||||
res = 1;
|
||||
}else{
|
||||
int rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
*pRes = (unsigned int)(sqlite3_column_int64(pStmt, 0)&0xffffffff);
|
||||
}else{
|
||||
reportError(p, "SQL statement [%s] failed: %s", zSql,
|
||||
sqlite3_errmsg(p->db));
|
||||
res = 1;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Run an SQL statement that returns a single TEXT value that is no more
|
||||
** than 99 bytes in length.
|
||||
*/
|
||||
static int runSqlReturnText(
|
||||
SQLiteRsync *p,
|
||||
char *pRes,
|
||||
char *zSql,
|
||||
...
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int res = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zSql);
|
||||
pStmt = prepareStmtVA(p, zSql, ap);
|
||||
va_end(ap);
|
||||
pRes[0] = 0;
|
||||
if( pStmt==0 ){
|
||||
res = 1;
|
||||
}else{
|
||||
int rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
const unsigned char *a = sqlite3_column_text(pStmt, 0);
|
||||
int n;
|
||||
if( a==0 ){
|
||||
pRes[0] = 0;
|
||||
}else{
|
||||
n = sqlite3_column_bytes(pStmt, 0);
|
||||
if( n>99 ) n = 99;
|
||||
memcpy(pRes, a, n);
|
||||
pRes[n] = 0;
|
||||
}
|
||||
}else{
|
||||
reportError(p, "SQL statement [%s] failed: %s", zSql,
|
||||
sqlite3_errmsg(p->db));
|
||||
res = 1;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Close the database connection associated with p
|
||||
*/
|
||||
static void closeDb(SQLiteRsync *p){
|
||||
if( p->db ){
|
||||
sqlite3_close(p->db);
|
||||
p->db = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run the origin-side protocol.
|
||||
**
|
||||
|
@ -484,6 +742,12 @@ static void echoOneLine(SQLiteRsync *p){
|
|||
** 7. Send origin-end message
|
||||
*/
|
||||
static void originSide(SQLiteRsync *p){
|
||||
int rc = 0;
|
||||
int c = 0;
|
||||
unsigned int nPage = 0;
|
||||
unsigned int szPg = 0;
|
||||
char buf[100];
|
||||
|
||||
if( p->bCommCheck ){
|
||||
fprintf(p->pOut, "sqlite3-rsync origin-begin %s\n", p->zOrigin);
|
||||
fflush(p->pOut);
|
||||
|
@ -493,6 +757,59 @@ static void originSide(SQLiteRsync *p){
|
|||
echoOneLine(p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Open the ORIGIN database. */
|
||||
rc = sqlite3_open_v2(p->zOrigin, &p->db, SQLITE_OPEN_READONLY, 0);
|
||||
if( rc ){
|
||||
reportError(p, "unable to open origin database file \"%s\": %s",
|
||||
sqlite3_errmsg(p->db));
|
||||
closeDb(p);
|
||||
return;
|
||||
}
|
||||
sqlite3_sha_init(p->db, 0, 0);
|
||||
runSql(p, "BEGIN");
|
||||
runSqlReturnText(p, buf, "PRAGMA journal_mode");
|
||||
if( sqlite3_stricmp(buf,"wal")!=0 ){
|
||||
reportError(p, "Origin database is not in WAL mode");
|
||||
}
|
||||
runSqlReturnUInt(p, &nPage, "PRAGMA page_count");
|
||||
runSqlReturnUInt(p, &szPg, "PRAGMA page_size");
|
||||
|
||||
if( p->nErr==0 ){
|
||||
/* Send the ORIGIN_BEGIN message */
|
||||
fputc(ORIGIN_BEGIN, p->pOut);
|
||||
writeUint32(p, nPage);
|
||||
writeUint32(p, szPg);
|
||||
fflush(p->pOut);
|
||||
}
|
||||
|
||||
/* Respond to message from the replica */
|
||||
while( p->nErr==0 && (c = fgetc(p->pIn))!=EOF ){
|
||||
switch( c ){
|
||||
case REPLICA_ERROR: {
|
||||
readAndDisplayError(p);
|
||||
break;
|
||||
}
|
||||
case REPLICA_BEGIN: {
|
||||
break;
|
||||
}
|
||||
case REPLICA_END: {
|
||||
break;
|
||||
}
|
||||
case REPLICA_HASH: {
|
||||
break;
|
||||
}
|
||||
case REPLICA_READY: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
reportError(p, "Origin side received unknown message: 0x%02x", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeDb(p);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -508,6 +825,8 @@ static void originSide(SQLiteRsync *p){
|
|||
** 7. COMMIT
|
||||
*/
|
||||
static void replicaSide(SQLiteRsync *p){
|
||||
int c;
|
||||
char buf[100];
|
||||
if( p->bCommCheck ){
|
||||
echoOneLine(p);
|
||||
fprintf(p->pOut, "replica-begin %s\n", p->zReplica);
|
||||
|
@ -517,6 +836,74 @@ static void replicaSide(SQLiteRsync *p){
|
|||
fflush(p->pOut);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Respond to message from the origin. The origin will initiate the
|
||||
** the conversation with an ORIGIN_BEGIN message.
|
||||
*/
|
||||
while( p->nErr==0 && (c = fgetc(p->pIn))!=EOF ){
|
||||
switch( c ){
|
||||
case ORIGIN_ERROR: {
|
||||
readAndDisplayError(p);
|
||||
break;
|
||||
}
|
||||
case ORIGIN_BEGIN: {
|
||||
unsigned int nOPage = 0, szOPage = 0;
|
||||
unsigned int nRPage = 0, szRPage = 0;
|
||||
int rc = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
|
||||
closeDb(p);
|
||||
readUint32(p, &nOPage);
|
||||
readUint32(p, &szOPage);
|
||||
if( p->nErr ) break;
|
||||
rc = sqlite3_open(p->zReplica, &p->db);
|
||||
if( rc ){
|
||||
reportError(p, "cannot open replica database \"%s\": %s",
|
||||
p->zReplica, sqlite3_errmsg(p->db));
|
||||
closeDb(p);
|
||||
break;
|
||||
}
|
||||
sqlite3_sha_init(p->db, 0, 0);
|
||||
if( runSqlReturnUInt(p, &nRPage, "PRAGMA page_count") ){
|
||||
break;
|
||||
}
|
||||
if( nRPage==0 ){
|
||||
runSql(p, "PRAGMA page_size=%u", szOPage);
|
||||
runSql(p, "PRAGMA journal_mode=WAL");
|
||||
}
|
||||
runSql(p, "BEGIN IMMEDIATE");
|
||||
runSqlReturnText(p, buf, "PRAGMA journal_mode");
|
||||
if( strcmp(buf, "wal")!=0 ){
|
||||
reportError(p, "replica is not in WAL mode");
|
||||
break;
|
||||
}
|
||||
runSqlReturnUInt(p, &nRPage, "PRAGMA page_count");
|
||||
runSqlReturnUInt(p, &szRPage, "PRAGMA page_size");
|
||||
if( szRPage!=szOPage ){
|
||||
reportError(p, "page size mismatch; origin is %d bytes and "
|
||||
"replica is %d bytes", szOPage, szRPage);
|
||||
break;
|
||||
}
|
||||
pStmt = prepareStmt(p,
|
||||
"SELECT pgno, sha1(data) FROM sqlite_dbpage"
|
||||
" WHERE pgno<=min(%d,%d)", nRPage, nOPage);
|
||||
sqlite3_finalize(pStmt);
|
||||
break;
|
||||
}
|
||||
case ORIGIN_END: {
|
||||
break;
|
||||
}
|
||||
case ORIGIN_PAGE: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
reportError(p, "Replica side received unknown message: 0x%02x", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeDb(p);
|
||||
}
|
||||
|
||||
|
||||
|
@ -544,7 +931,7 @@ static void replicaSide(SQLiteRsync *p){
|
|||
**
|
||||
** If (3) is seen, call originSide() on stdin and stdout.
|
||||
**
|
||||
** If (4) is seen, call replicaSide() on stdin and stdout.
|
||||
q** If (4) is seen, call replicaSide() on stdin and stdout.
|
||||
*/
|
||||
int main(int argc, char **argv){
|
||||
int isOrigin = 0;
|
||||
|
@ -635,6 +1022,7 @@ int main(int argc, char **argv){
|
|||
if( isOrigin ){
|
||||
ctx.pIn = stdin;
|
||||
ctx.pOut = stdout;
|
||||
ctx.isRemote = 1;
|
||||
originSide(&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
@ -643,6 +1031,7 @@ int main(int argc, char **argv){
|
|||
ctx.zOrigin = 0;
|
||||
ctx.pIn = stdin;
|
||||
ctx.pOut = stdout;
|
||||
ctx.isRemote = 1;
|
||||
replicaSide(&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue