2014-09-03 08:25:09 +00:00
/*
* * 2014 August 30
* *
* * 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 .
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
2015-07-23 20:44:49 +00:00
* * This file contains a command - line application that uses the RBU
2014-09-03 08:25:09 +00:00
* * extension . See the usage ( ) function below for an explanation .
*/
2015-07-23 20:44:49 +00:00
# include "sqlite3rbu.h"
2014-09-03 08:25:09 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
/*
* * Print a usage message and exit .
*/
void usage ( const char * zArgv0 ) {
fprintf ( stderr ,
2016-04-18 09:17:05 +00:00
" Usage: %s ?OPTIONS? TARGET-DB RBU-DB \n "
2014-09-03 08:25:09 +00:00
" \n "
2016-04-18 09:17:05 +00:00
" Where options are: \n "
" \n "
" -step NSTEP \n "
2018-04-20 20:37:25 +00:00
" -statstep NSTATSTEP \n "
2016-04-18 09:17:05 +00:00
" -vacuum \n "
2018-04-20 20:37:25 +00:00
" -presql SQL \n "
2016-04-18 09:17:05 +00:00
" \n "
" If the -vacuum switch is not present, argument RBU-DB must be an RBU \n "
" database containing an update suitable for target database TARGET-DB. \n "
" Or, if -vacuum is specified, then TARGET-DB is a database to vacuum using \n "
" RBU, and RBU-DB is used as the state database for the vacuum (refer to \n "
" API documentation for details). \n "
" \n "
" If NSTEP is set to less than or equal to zero (the default value), this \n "
" program attempts to perform the entire update or vacuum operation before \n "
" exiting \n "
2014-09-03 08:25:09 +00:00
" \n "
" If NSTEP is greater than zero, then a maximum of NSTEP calls are made \n "
2015-07-23 20:44:49 +00:00
" to sqlite3rbu_step(). If the RBU update has not been completely applied \n "
" after the NSTEP'th call is made, the state is saved in the database RBU-DB \n "
" and the program exits. Subsequent invocations of this (or any other RBU) \n "
" application will use this state to resume applying the RBU update to the \n "
2014-09-03 08:25:09 +00:00
" target db. \n "
" \n "
, zArgv0 ) ;
exit ( 1 ) ;
}
2014-09-04 11:03:35 +00:00
void report_default_vfs ( ) {
sqlite3_vfs * pVfs = sqlite3_vfs_find ( 0 ) ;
2021-06-15 15:15:40 +00:00
fprintf ( stdout , " default vfs is \" %s \" \n " , pVfs ? pVfs - > zName : " NULL " ) ;
2015-03-05 16:21:20 +00:00
}
2015-07-23 20:44:49 +00:00
void report_rbu_vfs ( sqlite3rbu * pRbu ) {
sqlite3 * db = sqlite3rbu_db ( pRbu , 0 ) ;
2015-04-23 19:38:20 +00:00
if ( db ) {
2015-03-05 16:21:20 +00:00
char * zName = 0 ;
sqlite3_file_control ( db , " main " , SQLITE_FCNTL_VFSNAME , & zName ) ;
if ( zName ) {
fprintf ( stdout , " using vfs \" %s \" \n " , zName ) ;
} else {
fprintf ( stdout , " vfs name not available \n " ) ;
}
sqlite3_free ( zName ) ;
}
2014-09-04 11:03:35 +00:00
}
2014-09-03 08:25:09 +00:00
int main ( int argc , char * * argv ) {
int i ;
2015-07-23 20:44:49 +00:00
const char * zTarget ; /* Target database to apply RBU to */
const char * zRbu ; /* Database containing RBU */
2015-07-24 21:19:25 +00:00
char zBuf [ 200 ] ; /* Buffer for printf() */
2018-07-22 21:23:19 +00:00
char * zErrmsg = 0 ; /* Error message, if any */
2015-07-23 20:44:49 +00:00
sqlite3rbu * pRbu ; /* RBU handle */
2014-09-03 08:25:09 +00:00
int nStep = 0 ; /* Maximum number of step() calls */
2018-04-20 20:37:25 +00:00
int nStatStep = 0 ; /* Report stats after this many step calls */
2016-04-18 09:17:05 +00:00
int bVacuum = 0 ;
2018-04-20 20:37:25 +00:00
const char * zPreSql = 0 ;
2018-07-22 21:23:19 +00:00
int rc = SQLITE_OK ;
2014-09-18 14:48:38 +00:00
sqlite3_int64 nProgress = 0 ;
2017-04-14 14:50:34 +00:00
int nArgc = argc - 2 ;
2014-09-03 08:25:09 +00:00
2016-04-18 09:17:05 +00:00
if ( argc < 3 ) usage ( argv [ 0 ] ) ;
2017-04-14 14:50:34 +00:00
for ( i = 1 ; i < nArgc ; i + + ) {
2016-04-18 09:17:05 +00:00
const char * zArg = argv [ i ] ;
int nArg = strlen ( zArg ) ;
if ( nArg > 1 & & nArg < = 8 & & 0 = = memcmp ( zArg , " -vacuum " , nArg ) ) {
bVacuum = 1 ;
2018-04-20 20:37:25 +00:00
} else if ( nArg > 1 & & nArg < = 7
& & 0 = = memcmp ( zArg , " -presql " , nArg ) & & i < nArg - 1 ) {
i + + ;
zPreSql = argv [ i ] ;
2016-04-18 09:17:05 +00:00
} else if ( nArg > 1 & & nArg < = 5 & & 0 = = memcmp ( zArg , " -step " , nArg ) & & i < nArg - 1 ) {
i + + ;
nStep = atoi ( argv [ i ] ) ;
2018-04-20 20:37:25 +00:00
} else if ( nArg > 1 & & nArg < = 9
& & 0 = = memcmp ( zArg , " -statstep " , nArg ) & & i < nArg - 1
) {
i + + ;
nStatStep = atoi ( argv [ i ] ) ;
2016-04-18 09:17:05 +00:00
} else {
usage ( argv [ 0 ] ) ;
}
2014-09-03 08:25:09 +00:00
}
2016-04-18 09:17:05 +00:00
2014-09-03 08:25:09 +00:00
zTarget = argv [ argc - 2 ] ;
2015-07-23 20:44:49 +00:00
zRbu = argv [ argc - 1 ] ;
2014-09-03 08:25:09 +00:00
2014-09-04 11:03:35 +00:00
report_default_vfs ( ) ;
2016-04-18 09:17:05 +00:00
/* Open an RBU handle. A vacuum handle if -vacuum was specified, or a
* * regular RBU update handle otherwise . */
if ( bVacuum ) {
pRbu = sqlite3rbu_vacuum ( zTarget , zRbu ) ;
} else {
pRbu = sqlite3rbu_open ( zTarget , zRbu , 0 ) ;
}
report_rbu_vfs ( pRbu ) ;
2018-04-20 20:37:25 +00:00
if ( zPreSql & & pRbu ) {
2018-07-22 21:23:19 +00:00
sqlite3 * dbMain = sqlite3rbu_db ( pRbu , 0 ) ;
rc = sqlite3_exec ( dbMain , zPreSql , 0 , 0 , 0 ) ;
2018-04-20 20:37:25 +00:00
if ( rc = = SQLITE_OK ) {
2018-07-22 21:23:19 +00:00
sqlite3 * dbRbu = sqlite3rbu_db ( pRbu , 1 ) ;
rc = sqlite3_exec ( dbRbu , zPreSql , 0 , 0 , 0 ) ;
2018-04-20 20:37:25 +00:00
}
}
2016-04-18 09:17:05 +00:00
/* If nStep is less than or equal to zero, call
2015-07-23 20:44:49 +00:00
* * sqlite3rbu_step ( ) until either the RBU has been completely applied
2014-09-03 08:25:09 +00:00
* * or an error occurs . Or , if nStep is greater than zero , call
2015-07-23 20:44:49 +00:00
* * sqlite3rbu_step ( ) a maximum of nStep times . */
2018-04-20 20:37:25 +00:00
if ( rc = = SQLITE_OK ) {
for ( i = 0 ; ( nStep < = 0 | | i < nStep ) & & sqlite3rbu_step ( pRbu ) = = SQLITE_OK ; i + + ) {
if ( nStatStep > 0 & & ( i % nStatStep ) = = 0 ) {
sqlite3_int64 nUsed ;
sqlite3_int64 nHighwater ;
sqlite3_status64 ( SQLITE_STATUS_MEMORY_USED , & nUsed , & nHighwater , 0 ) ;
fprintf ( stdout , " memory used=%lld highwater=%lld " , nUsed , nHighwater ) ;
if ( bVacuum = = 0 ) {
int one ;
int two ;
sqlite3rbu_bp_progress ( pRbu , & one , & two ) ;
fprintf ( stdout , " progress=%d/%d \n " , one , two ) ;
} else {
fprintf ( stdout , " \n " ) ;
}
fflush ( stdout ) ;
}
}
nProgress = sqlite3rbu_progress ( pRbu ) ;
rc = sqlite3rbu_close ( pRbu , & zErrmsg ) ;
}
2014-09-03 08:25:09 +00:00
/* Let the user know what happened. */
switch ( rc ) {
case SQLITE_OK :
2015-07-24 21:19:25 +00:00
sqlite3_snprintf ( sizeof ( zBuf ) , zBuf ,
2015-07-23 20:44:49 +00:00
" SQLITE_OK: rbu update incomplete (%lld operations so far) \n " ,
2014-09-18 14:48:38 +00:00
nProgress
) ;
2016-01-14 13:22:24 +00:00
fprintf ( stdout , " %s " , zBuf ) ;
2014-09-03 08:25:09 +00:00
break ;
case SQLITE_DONE :
2015-07-24 21:19:25 +00:00
sqlite3_snprintf ( sizeof ( zBuf ) , zBuf ,
2015-07-23 20:44:49 +00:00
" SQLITE_DONE: rbu update completed (%lld operations) \n " ,
2014-09-18 14:48:38 +00:00
nProgress
) ;
2016-01-14 13:22:24 +00:00
fprintf ( stdout , " %s " , zBuf ) ;
2014-09-03 08:25:09 +00:00
break ;
default :
fprintf ( stderr , " error=%d: %s \n " , rc , zErrmsg ) ;
break ;
}
2020-12-15 16:28:07 +00:00
if ( nStatStep > 0 ) {
sqlite3_int64 nUsed ;
sqlite3_int64 nHighwater ;
sqlite3_status64 ( SQLITE_STATUS_MEMORY_USED , & nUsed , & nHighwater , 0 ) ;
fprintf ( stdout , " memory used=%lld highwater=%lld \n " , nUsed , nHighwater ) ;
}
2014-09-03 08:25:09 +00:00
sqlite3_free ( zErrmsg ) ;
return ( rc = = SQLITE_OK | | rc = = SQLITE_DONE ) ? 0 : 1 ;
}