I am aware that the use of SQLITE_UNTESTABLE is discouraged. Still I want to point developers to the fact that SQLITE_UNTESTABLE breaks RBU.

In particular, RBU relies on SQLITE_TESTCTRL_IMPOSTER to be fully working. With SQLITE_UNTESTABLE defined, this is not the case. RBU functions return errors not related to the problem. The target database is not properly updated.

The C code below demonstrates this. It is based on rbusplit.test (https://www.sqlite.org/src/artifact/69271c790732b28b).

To see the problem, compile with the C preprocessor directive SQLITE_UNTESTABLE=1 #defined. Tested with MS Visual Studio 2017.

Ralf

----------

#include <stdio.h>
#include <conio.h>
#include "sqlite3.h"
#include "sqlite3rbu.h"

sqlite3 *db;

static void check(int r, int e) {
  if (r != e) {
    printf("ERROR %d %s\n", e, sqlite3_errmsg(db));
  }
}

static int callback(void *user, int nCol, char **r, char **c) {
  int i;
  for (i = 0; i < nCol; i++) {
    printf("%s ", r[i]);
  }
  printf("\n");
  return 0;
}

#define rbu_db    "rbu.db"
#define target_db "target.db"

int main(void)
{
  int r;
  sqlite3rbu *rbu;
  char *zError;

  // Create rbu_db

  remove(rbu_db);

  check(SQLITE_OK, sqlite3_open_v2(rbu_db, &db,
    SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL));

  check(SQLITE_OK, sqlite3_exec(db,
    "BEGIN;" \

    "CREATE TABLE data0_t1(a, b, c, rbu_control);" \
    "CREATE TABLE data1_t1(a, b, c, rbu_control);" \
    "CREATE TABLE data2_t1(a, b, c, rbu_control);" \
    "CREATE TABLE data3_t1(a, b, c, rbu_control);" \

    "CREATE TABLE data_t2(a, b, c, rbu_control);" \

    "INSERT INTO data0_t1 VALUES(1, 1, 1, 0);" \
    "INSERT INTO data0_t1 VALUES(2, 2, 2, 0);" \
    "INSERT INTO data0_t1 VALUES(3, 3, 3, 0);" \
    "INSERT INTO data0_t1 VALUES(4, 4, 4, 0);" \
    "INSERT INTO data1_t1 VALUES(5, 5, 5, 0);" \
    "INSERT INTO data1_t1 VALUES(6, 6, 6, 0);" \
    "INSERT INTO data1_t1 VALUES(7, 7, 7, 0);" \
    "INSERT INTO data1_t1 VALUES(8, 8, 8, 0);" \
    "INSERT INTO data3_t1 VALUES(9, 9, 9, 0);" \

    "INSERT INTO data_t2 VALUES(1, 1, 1, 0);" \
    "INSERT INTO data_t2 VALUES(2, 2, 2, 0);" \
    "INSERT INTO data_t2 VALUES(3, 3, 3, 0);" \
    "INSERT INTO data_t2 VALUES(4, 4, 4, 0);" \
    "INSERT INTO data_t2 VALUES(5, 5, 5, 0);" \
    "INSERT INTO data_t2 VALUES(6, 6, 6, 0);" \
    "INSERT INTO data_t2 VALUES(7, 7, 7, 0);" \
    "INSERT INTO data_t2 VALUES(8, 8, 8, 0);" \
    "INSERT INTO data_t2 VALUES(9, 9, 9, 0);" \

    "COMMIT;",
    callback, NULL, NULL));

  check(SQLITE_OK, sqlite3_close(db));

  // Create target.db

  remove(target_db);

  check(SQLITE_OK, sqlite3_open_v2(target_db, &db,
    SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL));

  check(SQLITE_OK, sqlite3_exec(db,
    "CREATE TABLE t1(a PRIMARY KEY, b, c);"
    "CREATE TABLE t2(a PRIMARY KEY, b, c);" \

    "CREATE INDEX t1c ON t1(c);",
    callback, NULL, NULL));

  check(SQLITE_OK, sqlite3_close(db));

  // Apply RBU.

  rbu = sqlite3rbu_open(target_db, rbu_db, NULL);
  do
    r = sqlite3rbu_step(rbu);
  while (r == SQLITE_OK);
  check(SQLITE_DONE, r);

  r = sqlite3rbu_close(rbu, &zError);
  check(SQLITE_DONE, r);
  if (zError) {
    printf("%s\n", zError);
    sqlite3_free(zError);
  }

  printf("Done - Press ENTER to exit.");
  _getch();

  return 0;
}
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to