mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
A reasonably complete implementation of the "changeset" command-line tool
and the ".sessions" command in the command-line shell. FossilOrigin-Name: 7b12f1f9c012f33d376242920583807b014b3287
This commit is contained in:
@ -124,6 +124,58 @@ static void renderValue(sqlite3_value *pVal){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Number of conflicts seen
|
||||
*/
|
||||
static int nConflict = 0;
|
||||
|
||||
/*
|
||||
** The conflict callback
|
||||
*/
|
||||
static int conflictCallback(
|
||||
void *pCtx,
|
||||
int eConflict,
|
||||
sqlite3_changeset_iter *pIter
|
||||
){
|
||||
int op, bIndirect, nCol, i;
|
||||
const char *zTab;
|
||||
unsigned char *abPK;
|
||||
const char *zType = "";
|
||||
const char *zOp = "";
|
||||
const char *zSep = " ";
|
||||
|
||||
nConflict++;
|
||||
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
|
||||
sqlite3changeset_pk(pIter, &abPK, 0);
|
||||
switch( eConflict ){
|
||||
case SQLITE_CHANGESET_DATA: zType = "DATA"; break;
|
||||
case SQLITE_CHANGESET_NOTFOUND: zType = "NOTFOUND"; break;
|
||||
case SQLITE_CHANGESET_CONFLICT: zType = "PRIMARY KEY"; break;
|
||||
case SQLITE_CHANGESET_FOREIGN_KEY: zType = "FOREIGN KEY"; break;
|
||||
case SQLITE_CHANGESET_CONSTRAINT: zType = "CONSTRAINT"; break;
|
||||
}
|
||||
switch( op ){
|
||||
case SQLITE_UPDATE: zOp = "UPDATE of"; break;
|
||||
case SQLITE_INSERT: zOp = "INSERT into"; break;
|
||||
case SQLITE_DELETE: zOp = "DELETE from"; break;
|
||||
}
|
||||
printf("%s conflict on %s table %s with primary key", zType, zOp, zTab);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3_value *pVal;
|
||||
if( abPK[i]==0 ) continue;
|
||||
printf("%s", zSep);
|
||||
if( op==SQLITE_INSERT ){
|
||||
sqlite3changeset_new(pIter, i, &pVal);
|
||||
}else{
|
||||
sqlite3changeset_old(pIter, i, &pVal);
|
||||
}
|
||||
renderValue(pVal);
|
||||
zSep = ",";
|
||||
}
|
||||
printf("\n");
|
||||
return SQLITE_CHANGESET_OMIT;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int sz, rc;
|
||||
void *pBuf = 0;
|
||||
@ -134,7 +186,32 @@ int main(int argc, char **argv){
|
||||
** Apply the changeset in FILENAME to the database file DB
|
||||
*/
|
||||
if( strcmp(argv[2],"apply")==0 ){
|
||||
fprintf(stderr, "not yet implemented\n");
|
||||
sqlite3 *db;
|
||||
if( argc!=4 ) usage(argv[0]);
|
||||
rc = sqlite3_open(argv[3], &db);
|
||||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr, "unable to open database file \"%s\": %s\n",
|
||||
argv[3], sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
sqlite3_exec(db, "BEGIN", 0, 0, 0);
|
||||
nConflict = 0;
|
||||
rc = sqlite3changeset_apply(db, sz, pBuf, 0, conflictCallback, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "sqlite3changeset_apply() returned %d\n", rc);
|
||||
}
|
||||
if( nConflict ){
|
||||
fprintf(stderr, "%d conflicts - no changes applied\n", nConflict);
|
||||
sqlite3_exec(db, "ROLLBACK", 0, 0, 0);
|
||||
}else if( rc ){
|
||||
fprintf(stderr, "sqlite3changeset_apply() returns %d "
|
||||
"- no changes applied\n", rc);
|
||||
sqlite3_exec(db, "ROLLBACK", 0, 0, 0);
|
||||
}else{
|
||||
sqlite3_exec(db, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
sqlite3_close(db);
|
||||
}else
|
||||
|
||||
/* changeset FILENAME concat FILE2 OUT
|
||||
@ -142,7 +219,27 @@ int main(int argc, char **argv){
|
||||
** and write the result into OUT.
|
||||
*/
|
||||
if( strcmp(argv[2],"concat")==0 ){
|
||||
fprintf(stderr, "not yet implemented\n");
|
||||
int szB;
|
||||
void *pB;
|
||||
int szOut;
|
||||
void *pOutBuf;
|
||||
FILE *out;
|
||||
const char *zOut = argv[4];
|
||||
if( argc!=5 ) usage(argv[0]);
|
||||
out = fopen(zOut, "wb");
|
||||
if( out==0 ){
|
||||
fprintf(stderr, "cannot open \"%s\" for writing\n", zOut);
|
||||
exit(1);
|
||||
}
|
||||
readFile(argv[3], &szB, &pB);
|
||||
sqlite3changeset_concat(sz, pBuf, szB, pB, &szOut, &pOutBuf);
|
||||
if( fwrite(pOutBuf, szOut, 1, out)!=1 ){
|
||||
fprintf(stderr, "unable to write all %d bytes of output to \"%s\"\n",
|
||||
szOut, zOut);
|
||||
}
|
||||
fclose(out);
|
||||
sqlite3_free(pOutBuf);
|
||||
sqlite3_free(pB);
|
||||
}else
|
||||
|
||||
/* changeset FILENAME dump
|
||||
@ -196,16 +293,17 @@ int main(int argc, char **argv){
|
||||
FILE *out;
|
||||
int szOut = 0;
|
||||
void *pOutBuf = 0;
|
||||
const char *zOut = argv[3];
|
||||
if( argc!=4 ) usage(argv[0]);
|
||||
out = fopen(argv[3], "wb");
|
||||
out = fopen(zOut, "wb");
|
||||
if( out==0 ){
|
||||
fprintf(stderr, "cannot open \"%s\" for writing\n", argv[3]);
|
||||
fprintf(stderr, "cannot open \"%s\" for writing\n", zOut);
|
||||
exit(1);
|
||||
}
|
||||
sqlite3changeset_invert(sz, pBuf, &szOut, &pOutBuf);
|
||||
if( fwrite(pOutBuf, szOut, 1, out)!=1 ){
|
||||
fprintf(stderr, "unable to write all %d bytes of output to \"%s\"\n",
|
||||
szOut, argv[3]);
|
||||
szOut, zOut);
|
||||
}
|
||||
fclose(out);
|
||||
sqlite3_free(pOutBuf);
|
||||
|
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\s"changeset"\scommand-line\sutility\sfor\sgetting\san\sASCII\sdump\sof\nchange\ssets.
|
||||
D 2014-08-18T17:56:31.306
|
||||
C A\sreasonably\scomplete\simplementation\sof\sthe\s"changeset"\scommand-line\stool\nand\sthe\s".sessions"\scommand\sin\sthe\scommand-line\sshell.
|
||||
D 2014-08-18T20:01:31.177
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 639859a6f81bd15921ccd56ddbd6dfd335278377
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -143,7 +143,7 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/session/changeset.c d46c6467c223717d0e4783115f350c5962d53589
|
||||
F ext/session/changeset.c 9be709cea346d65c6d0cc8bf03569956af125462
|
||||
F ext/session/session1.test 894e3bc9f497c4fa07a2aa3271e3911f3670c3d8
|
||||
F ext/session/session2.test 99ca0da7ddb617d42bafd83adccf99f18ae0384b
|
||||
F ext/session/session3.test a7a9ce59b8d1e49e2cc23d81421ac485be0eea01
|
||||
@ -239,7 +239,7 @@ F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 0ea356d32a5e884add23d1b9b4e8736681dd5697
|
||||
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
|
||||
F src/select.c ea48e891406ccdf748f3eb02893e056d134a0fea
|
||||
F src/shell.c 0845863fc7e813aac148d3303faf9f93f86ad8c3
|
||||
F src/shell.c 1761e117dd58e2383a2d30319c49d0fca00f8bf0
|
||||
F src/sqlite.h.in 021a1f5c50e83060675d994a6014fd409e611d9e
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
@ -1203,7 +1203,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P c2fcf0b9f4bdc48dfc6530bda4f531b94a833207
|
||||
R ef02979994221e0299bd184663702a4d
|
||||
P 55bb3544a6b474c04853270067a35ca4b0079f52
|
||||
R e1146ecf2575392bb0feff21eda4606c
|
||||
U drh
|
||||
Z 24c20f108d2116be16c069d984599c3d
|
||||
Z 0de9dc1123705f1abdab4ea8e245122b
|
||||
|
@ -1 +1 @@
|
||||
55bb3544a6b474c04853270067a35ca4b0079f52
|
||||
7b12f1f9c012f33d376242920583807b014b3287
|
80
src/shell.c
80
src/shell.c
@ -1788,6 +1788,21 @@ static void session_close_all(ShellState *p){
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the xFilter function for an open session. Omit
|
||||
** any tables named by ".session filter" but let all other table through.
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_SESSION)
|
||||
static int session_filter(void *pCtx, const char *zTab){
|
||||
OpenSession *pSession = (OpenSession*)pCtx;
|
||||
int i;
|
||||
for(i=0; i<pSession->nFilter; i++){
|
||||
if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Make sure the database is open. If it is not, then open it. If
|
||||
** the database fails to open, print an error message and exit.
|
||||
@ -3235,12 +3250,75 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
** Close the identified session
|
||||
*/
|
||||
if( strcmp(azCmd[0], "close")==0 ){
|
||||
if( nCmd!=1 ) goto session_syntax_error;
|
||||
if( p->nSession ){
|
||||
session_close(pSession);
|
||||
p->aSession[iSes] = p->aSession[--p->nSession];
|
||||
}
|
||||
}else
|
||||
|
||||
/* .session enable ?BOOLEAN?
|
||||
** Query or set the enable flag
|
||||
*/
|
||||
if( strcmp(azCmd[0], "enable")==0 ){
|
||||
int ii;
|
||||
if( nCmd>2 ) goto session_syntax_error;
|
||||
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
|
||||
if( p->nSession ){
|
||||
ii = sqlite3session_enable(pSession->p, ii);
|
||||
fprintf(p->out, "session %s enable flag = %d\n", pSession->zName, ii);
|
||||
}
|
||||
}else
|
||||
|
||||
/* .session filter GLOB ....
|
||||
** Set a list of GLOB patterns of table names to be excluded.
|
||||
*/
|
||||
if( strcmp(azCmd[0], "filter")==0 ){
|
||||
int ii, nByte;
|
||||
if( nCmd<2 ) goto session_syntax_error;
|
||||
if( p->nSession ){
|
||||
for(ii=0; ii<pSession->nFilter; ii++){
|
||||
sqlite3_free(pSession->azFilter[ii]);
|
||||
}
|
||||
sqlite3_free(pSession->azFilter);
|
||||
nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
|
||||
pSession->azFilter = sqlite3_malloc( nByte );
|
||||
if( pSession->azFilter==0 ){
|
||||
fprintf(stderr, "Error: out or memory\n");
|
||||
exit(1);
|
||||
}
|
||||
for(ii=1; ii<nCmd; ii++){
|
||||
pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
|
||||
}
|
||||
pSession->nFilter = ii-1;
|
||||
}
|
||||
}else
|
||||
|
||||
/* .session indirect ?BOOLEAN?
|
||||
** Query or set the indirect flag
|
||||
*/
|
||||
if( strcmp(azCmd[0], "indirect")==0 ){
|
||||
int ii;
|
||||
if( nCmd>2 ) goto session_syntax_error;
|
||||
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
|
||||
if( p->nSession ){
|
||||
ii = sqlite3session_indirect(pSession->p, ii);
|
||||
fprintf(p->out, "session %s indirect flag = %d\n", pSession->zName,ii);
|
||||
}
|
||||
}else
|
||||
|
||||
/* .session isempty
|
||||
** Determine if the session is empty
|
||||
*/
|
||||
if( strcmp(azCmd[0], "isempty")==0 ){
|
||||
int ii;
|
||||
if( nCmd!=1 ) goto session_syntax_error;
|
||||
if( p->nSession ){
|
||||
ii = sqlite3session_isempty(pSession->p);
|
||||
fprintf(p->out, "session %s isempty flag = %d\n", pSession->zName, ii);
|
||||
}
|
||||
}else
|
||||
|
||||
/* .session list
|
||||
** List all currently open sessions
|
||||
*/
|
||||
@ -3276,6 +3354,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = 0;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
pSession->nFilter = 0;
|
||||
sqlite3session_table_filter(pSession->p, session_filter, pSession);
|
||||
p->nSession++;
|
||||
pSession->zName = sqlite3_mprintf("%s", zName);
|
||||
}else
|
||||
|
Reference in New Issue
Block a user