xref: /sqlite-3.40.0/ext/rbu/rbu.c (revision a959bf53)
1 /*
2 ** 2014 August 30
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 **
13 ** This file contains a command-line application that uses the RBU
14 ** extension. See the usage() function below for an explanation.
15 */
16 
17 #include "sqlite3rbu.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 /*
23 ** Print a usage message and exit.
24 */
usage(const char * zArgv0)25 void usage(const char *zArgv0){
26   fprintf(stderr,
27 "Usage: %s ?OPTIONS? TARGET-DB RBU-DB\n"
28 "\n"
29 "Where options are:\n"
30 "\n"
31 "    -step NSTEP\n"
32 "    -statstep NSTATSTEP\n"
33 "    -vacuum\n"
34 "    -presql SQL\n"
35 "\n"
36 "  If the -vacuum switch is not present, argument RBU-DB must be an RBU\n"
37 "  database containing an update suitable for target database TARGET-DB.\n"
38 "  Or, if -vacuum is specified, then TARGET-DB is a database to vacuum using\n"
39 "  RBU, and RBU-DB is used as the state database for the vacuum (refer to\n"
40 "  API documentation for details).\n"
41 "\n"
42 "  If NSTEP is set to less than or equal to zero (the default value), this \n"
43 "  program attempts to perform the entire update or vacuum operation before\n"
44 "  exiting\n"
45 "\n"
46 "  If NSTEP is greater than zero, then a maximum of NSTEP calls are made\n"
47 "  to sqlite3rbu_step(). If the RBU update has not been completely applied\n"
48 "  after the NSTEP'th call is made, the state is saved in the database RBU-DB\n"
49 "  and the program exits. Subsequent invocations of this (or any other RBU)\n"
50 "  application will use this state to resume applying the RBU update to the\n"
51 "  target db.\n"
52 "\n"
53 , zArgv0);
54   exit(1);
55 }
56 
report_default_vfs()57 void report_default_vfs(){
58   sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
59   fprintf(stdout, "default vfs is \"%s\"\n", pVfs ? pVfs->zName : "NULL");
60 }
61 
report_rbu_vfs(sqlite3rbu * pRbu)62 void report_rbu_vfs(sqlite3rbu *pRbu){
63   sqlite3 *db = sqlite3rbu_db(pRbu, 0);
64   if( db ){
65     char *zName = 0;
66     sqlite3_file_control(db, "main", SQLITE_FCNTL_VFSNAME, &zName);
67     if( zName ){
68       fprintf(stdout, "using vfs \"%s\"\n", zName);
69     }else{
70       fprintf(stdout, "vfs name not available\n");
71     }
72     sqlite3_free(zName);
73   }
74 }
75 
main(int argc,char ** argv)76 int main(int argc, char **argv){
77   int i;
78   const char *zTarget;            /* Target database to apply RBU to */
79   const char *zRbu;               /* Database containing RBU */
80   char zBuf[200];                 /* Buffer for printf() */
81   char *zErrmsg = 0;              /* Error message, if any */
82   sqlite3rbu *pRbu;               /* RBU handle */
83   int nStep = 0;                  /* Maximum number of step() calls */
84   int nStatStep = 0;              /* Report stats after this many step calls */
85   int bVacuum = 0;
86   const char *zPreSql = 0;
87   int rc = SQLITE_OK;
88   sqlite3_int64 nProgress = 0;
89   int nArgc = argc-2;
90 
91   if( argc<3 ) usage(argv[0]);
92   for(i=1; i<nArgc; i++){
93     const char *zArg = argv[i];
94     int nArg = strlen(zArg);
95     if( nArg>1 && nArg<=8 && 0==memcmp(zArg, "-vacuum", nArg) ){
96       bVacuum = 1;
97     }else if( nArg>1 && nArg<=7
98            && 0==memcmp(zArg, "-presql", nArg) && i<nArg-1 ){
99       i++;
100       zPreSql = argv[i];
101     }else if( nArg>1 && nArg<=5 && 0==memcmp(zArg, "-step", nArg) && i<nArg-1 ){
102       i++;
103       nStep = atoi(argv[i]);
104     }else if( nArg>1 && nArg<=9
105            && 0==memcmp(zArg, "-statstep", nArg) && i<nArg-1
106     ){
107       i++;
108       nStatStep = atoi(argv[i]);
109     }else{
110       usage(argv[0]);
111     }
112   }
113 
114   zTarget = argv[argc-2];
115   zRbu = argv[argc-1];
116 
117   report_default_vfs();
118 
119   /* Open an RBU handle. A vacuum handle if -vacuum was specified, or a
120   ** regular RBU update handle otherwise.  */
121   if( bVacuum ){
122     pRbu = sqlite3rbu_vacuum(zTarget, zRbu);
123   }else{
124     pRbu = sqlite3rbu_open(zTarget, zRbu, 0);
125   }
126   report_rbu_vfs(pRbu);
127 
128   if( zPreSql && pRbu ){
129     sqlite3 *dbMain = sqlite3rbu_db(pRbu, 0);
130     rc = sqlite3_exec(dbMain, zPreSql, 0, 0, 0);
131     if( rc==SQLITE_OK ){
132       sqlite3 *dbRbu = sqlite3rbu_db(pRbu, 1);
133       rc = sqlite3_exec(dbRbu, zPreSql, 0, 0, 0);
134     }
135   }
136 
137   /* If nStep is less than or equal to zero, call
138   ** sqlite3rbu_step() until either the RBU has been completely applied
139   ** or an error occurs. Or, if nStep is greater than zero, call
140   ** sqlite3rbu_step() a maximum of nStep times.  */
141   if( rc==SQLITE_OK ){
142     for(i=0; (nStep<=0 || i<nStep) && sqlite3rbu_step(pRbu)==SQLITE_OK; i++){
143       if( nStatStep>0 && (i % nStatStep)==0 ){
144         sqlite3_int64 nUsed;
145         sqlite3_int64 nHighwater;
146         sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &nUsed, &nHighwater, 0);
147         fprintf(stdout, "memory used=%lld highwater=%lld", nUsed, nHighwater);
148         if( bVacuum==0 ){
149           int one;
150           int two;
151           sqlite3rbu_bp_progress(pRbu, &one, &two);
152           fprintf(stdout, "  progress=%d/%d\n", one, two);
153         }else{
154           fprintf(stdout, "\n");
155         }
156         fflush(stdout);
157       }
158     }
159     nProgress = sqlite3rbu_progress(pRbu);
160     rc = sqlite3rbu_close(pRbu, &zErrmsg);
161   }
162 
163   /* Let the user know what happened. */
164   switch( rc ){
165     case SQLITE_OK:
166       sqlite3_snprintf(sizeof(zBuf), zBuf,
167           "SQLITE_OK: rbu update incomplete (%lld operations so far)\n",
168           nProgress
169       );
170       fprintf(stdout, "%s", zBuf);
171       break;
172 
173     case SQLITE_DONE:
174       sqlite3_snprintf(sizeof(zBuf), zBuf,
175           "SQLITE_DONE: rbu update completed (%lld operations)\n",
176           nProgress
177       );
178       fprintf(stdout, "%s", zBuf);
179       break;
180 
181     default:
182       fprintf(stderr, "error=%d: %s\n", rc, zErrmsg);
183       break;
184   }
185 
186   if( nStatStep>0 ){
187     sqlite3_int64 nUsed;
188     sqlite3_int64 nHighwater;
189     sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &nUsed, &nHighwater, 0);
190     fprintf(stdout, "memory used=%lld highwater=%lld\n", nUsed, nHighwater);
191   }
192 
193   sqlite3_free(zErrmsg);
194   return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1;
195 }
196