rbu.c 5.9 KB

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