SQLite Forum

Internal schema cache not refreshed after DROP TABLE in different connection
Login
I modified the code to print the schema version before and after each step:

```
#include <stdio.h>
#include <sqlite3.h>
#include <unistd.h>
#include <pthread.h>

static int schema_version(sqlite3 *db) {
  sqlite3_stmt *stmt;
  int version;
  sqlite3_prepare_v2(db, "PRAGMA schema_version", -1, &stmt, NULL);
  sqlite3_step(stmt);
  version = sqlite3_column_int(stmt, 0);
  sqlite3_finalize(stmt);
  return version;
}

static void* thread1(void* arg) {
  sqlite3 *db;
  sqlite3_stmt *stmt;

  sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
  sqlite3_exec(db, "PRAGMA journal_mode=WAL", NULL, NULL, NULL);

  printf("thread 1 - schema %d: creating table\n", schema_version(db));
  sqlite3_prepare_v2(db, "CREATE TABLE test(n INT)", -1, &stmt, NULL);
  sqlite3_step(stmt);
  sqlite3_finalize(stmt);
  printf("thread 1 - schema %d: table created\n", schema_version(db));
  sleep(2);

  printf("thread 1 - schema %d: dropping table\n", schema_version(db));
  sqlite3_prepare_v2(db, "DROP TABLE test", -1, &stmt, NULL);
  sqlite3_step(stmt);
  sqlite3_finalize(stmt);
  printf("thread 1 - schema %d: table dropped\n", schema_version(db));
  sleep(2);

  printf("thread 1: done\n");
  return NULL;
}

static void* thread2(void* arg) {
  sqlite3 *db;
  sqlite3_stmt *stmt;
  int rv;

  sleep(1);

  sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);

  printf("thread 2 - schema %d: trigger schema initialization\n", schema_version(db));
  sqlite3_prepare_v2(db, "SELECT * FROM sqlite_master", -1, &stmt, NULL);
  sqlite3_finalize(stmt);
  printf("thread 2 - schema %d: schema initialized\n", schema_version(db));

  sleep(2);
  printf("thread 2 - schema %d: creating table\n", schema_version(db));
  rv = sqlite3_prepare_v2(db, "CREATE TABLE test(n INT)", -1, &stmt, NULL);
  if (rv != 0) {
    printf("thread 2 - schema %d: err: %s (%d)\n", schema_version(db), sqlite3_errmsg(db), rv);
  }

  printf("thread 2: done\n");
  return NULL;
}

int main() {
  pthread_t t1;
  pthread_t t2;
  void *result;
  unlink("test.db");
  unlink("test.db-shm");
  unlink("test.db-wal");
  pthread_create(&t1, 0, &thread1, NULL);
  pthread_create(&t2, 0, &thread2, NULL);
  pthread_join(t1, &result);
  pthread_join(t2, &result);
}
```

The output is:

```
thread 1 - schema 0: creating table
thread 1 - schema 1: table created
thread 2 - schema 1: trigger schema initialization
thread 2 - schema 1: schema initialized
thread 1 - schema 1: dropping table
thread 1 - schema 2: table dropped
thread 2 - schema 2: creating table
thread 2 - schema 2: err: table test already exists (1)
thread 2: done
thread 1: done
```

Without WAL it's the same.

As far as I can understand from the SQLite code, this might be a case where the internal schema cache of the second connection does not ever get refreshed.

It shouldn't be necessary to force a checkpoint in order for the second connection to become aware of the schema change.