SQLiteBackup.mod 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. MODULE SQLiteBackup;
  2. (* Online backup API:
  3. backup_init/step/finish/remaining/pagecount. *)
  4. FROM SYSTEM IMPORT ADDRESS;
  5. FROM SQLite IMPORT
  6. SQLiteOk, SQLiteRow, SQLiteDone,
  7. sqlite3_open, sqlite3_close, sqlite3_exec,
  8. sqlite3_prepare_v2, sqlite3_step, sqlite3_column_int,
  9. sqlite3_finalize,
  10. sqlite3_backup_init, sqlite3_backup_step, sqlite3_backup_finish,
  11. sqlite3_backup_remaining, sqlite3_backup_pagecount,
  12. sqlite3_free;
  13. VAR
  14. ExitCode : INTEGER;
  15. src, dst, dst2, bk : ADDRESS;
  16. rc, pages : INTEGER;
  17. ok : BOOLEAN;
  18. PROCEDURE ExecSQL (h : ADDRESS; sql : ARRAY OF CHAR) : BOOLEAN;
  19. VAR
  20. errmsg : ADDRESS;
  21. good : BOOLEAN;
  22. BEGIN
  23. errmsg := NIL;
  24. good := sqlite3_exec(h, sql, NIL, NIL, errmsg) = SQLiteOk;
  25. IF errmsg # NIL THEN
  26. sqlite3_free(errmsg)
  27. END;
  28. RETURN good
  29. END ExecSQL;
  30. PROCEDURE CountRows (h : ADDRESS; want : INTEGER) : BOOLEAN;
  31. VAR
  32. s : ADDRESS;
  33. code, got : INTEGER;
  34. good : BOOLEAN;
  35. BEGIN
  36. s := NIL; got := -1; good := FALSE;
  37. code := sqlite3_prepare_v2(h, "SELECT count(*) FROM t;",
  38. -1, s, NIL);
  39. IF (code = SQLiteOk) AND (s # NIL) THEN
  40. IF sqlite3_step(s) = SQLiteRow THEN
  41. got := sqlite3_column_int(s, 0);
  42. IF sqlite3_step(s) = SQLiteDone THEN good := TRUE END
  43. END;
  44. IF sqlite3_finalize(s) # SQLiteOk THEN good := FALSE END
  45. END;
  46. RETURN good AND (got = want)
  47. END CountRows;
  48. BEGIN
  49. ExitCode := 1;
  50. src := NIL; dst := NIL; dst2 := NIL; bk := NIL;
  51. ok := FALSE;
  52. IF (sqlite3_open(":memory:", src) = SQLiteOk) AND (src # NIL)
  53. AND (sqlite3_open(":memory:", dst) = SQLiteOk) AND (dst # NIL)
  54. AND (sqlite3_open(":memory:", dst2) = SQLiteOk) AND (dst2 # NIL) THEN
  55. ok := ExecSQL(src, "CREATE TABLE t(x INTEGER);")
  56. AND ExecSQL(src, "INSERT INTO t VALUES(1);")
  57. AND ExecSQL(src, "INSERT INTO t VALUES(2);")
  58. END;
  59. (* Full backup into another in-memory database. *)
  60. IF ok THEN
  61. bk := sqlite3_backup_init(dst, "main", src, "main");
  62. ok := bk # NIL;
  63. IF ok THEN
  64. ok := sqlite3_backup_step(bk, -1) = SQLiteDone
  65. END;
  66. IF ok THEN
  67. pages := sqlite3_backup_pagecount(bk);
  68. ok := (pages > 0) AND (sqlite3_backup_remaining(bk) = 0)
  69. END;
  70. IF sqlite3_backup_finish(bk) # SQLiteOk THEN ok := FALSE END;
  71. bk := NIL
  72. END;
  73. IF ok THEN ok := CountRows(dst, 2) END;
  74. (* Incremental backup, one page at a time. *)
  75. IF ok THEN
  76. bk := sqlite3_backup_init(dst2, "main", src, "main");
  77. ok := bk # NIL;
  78. IF ok THEN
  79. rc := sqlite3_backup_step(bk, 1);
  80. WHILE (rc = SQLiteOk) DO
  81. rc := sqlite3_backup_step(bk, 1)
  82. END;
  83. ok := (rc = SQLiteDone) AND (sqlite3_backup_remaining(bk) = 0);
  84. IF sqlite3_backup_finish(bk) # SQLiteOk THEN ok := FALSE END;
  85. bk := NIL
  86. END
  87. END;
  88. IF ok THEN ok := CountRows(dst2, 2) END;
  89. IF bk # NIL THEN
  90. IF sqlite3_backup_finish(bk) # SQLiteOk THEN ok := FALSE END
  91. END;
  92. IF src # NIL THEN
  93. IF sqlite3_close(src) # SQLiteOk THEN ok := FALSE END
  94. END;
  95. IF dst # NIL THEN
  96. IF sqlite3_close(dst) # SQLiteOk THEN ok := FALSE END
  97. END;
  98. IF dst2 # NIL THEN
  99. IF sqlite3_close(dst2) # SQLiteOk THEN ok := FALSE END
  100. END;
  101. IF ok THEN ExitCode := 42 END
  102. END SQLiteBackup.