Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_sqlite3_db_cacheflush.c211 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <stdlib.h>6#include <string.h>7 8/* Unity setup/teardown */9void setUp(void) {10  /* No-op */11}12void tearDown(void) {13  /* No-op */14}15 16/* Helper: build a temporary database filename. Caller must sqlite3_free(). */17static char *make_temp_db_filename(const char *tag){18  char tmp[L_tmpnam];19  if( tmpnam(tmp)==NULL ){20    /* Fallback */21    return sqlite3_mprintf("test_%s_%ld.db", tag?tag:"db", (long)sqlite3OsRandomness(0,0));22  }23  return sqlite3_mprintf("%s_%s.db", tmp, tag?tag:"db");24}25 26/* Helper: execute SQL and assert success */27static void exec_ok(sqlite3 *db, const char *sql){28  char *err = 0;29  int rc = sqlite3_exec(db, sql, 0, 0, &err);30  if( err ){31    /* If rc not OK, include message in assertion output */32    TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err);33  }else{34    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);35  }36  if( err ) sqlite3_free(err);37}38 39/* Helper: prepare/step/finalize and return single int result */40static int query_int(sqlite3 *db, const char *sql){41  sqlite3_stmt *stmt = 0;42  int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);43  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");44  rc = sqlite3_step(stmt);45  TEST_ASSERT_MESSAGE(rc==SQLITE_ROW || rc==SQLITE_DONE, "step not ROW/DONE");46  int val = 0;47  if( rc==SQLITE_ROW ){48    val = sqlite3_column_int(stmt, 0);49    rc = sqlite3_step(stmt);50    TEST_ASSERT_MESSAGE(rc==SQLITE_DONE, "expected single-row result");51  }52  rc = sqlite3_finalize(stmt);53  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "finalize failed");54  return val;55}56 57/* Helper: open database and set pragmas for predictable behavior */58static void open_db_with_pragmas(const char *filename, sqlite3 **pDb){59  int rc = sqlite3_open(filename, pDb);60  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);61  /* Use rollback journal mode for predictable uncommitted visibility semantics */62  exec_ok(*pDb, "PRAGMA journal_mode=DELETE;");63  /* Avoid long waits in case of lock contentions */64  exec_ok(*pDb, "PRAGMA busy_timeout=0;");65  exec_ok(*pDb, "PRAGMA synchronous=OFF;");66}67 68/* Test 1: No transaction, expect SQLITE_OK. */69static void test_sqlite3_db_cacheflush_no_txn_ok(void){70  char *fname = make_temp_db_filename("no_txn");71  sqlite3 *db = 0;72 73  open_db_with_pragmas(fname, &db);74  /* Create a simple schema, but no active write transaction */75  exec_ok(db, "CREATE TABLE IF NOT EXISTS t(x);");76 77  int rc = sqlite3_db_cacheflush(db);78  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);79 80  sqlite3_close(db);81  remove(fname);82  sqlite3_free(fname);83}84 85/* Test 2: Write transaction with uncommitted change; flush returns OK and does not commit. */86static void test_sqlite3_db_cacheflush_uncommitted_changes_not_visible(void){87  char *fname = make_temp_db_filename("txn");88  sqlite3 *db1 = 0;89  sqlite3 *db2 = 0;90 91  open_db_with_pragmas(fname, &db1);92  open_db_with_pragmas(fname, &db2);93 94  /* Setup schema and baseline committed row */95  exec_ok(db1, "DROP TABLE IF EXISTS t;");96  exec_ok(db1, "CREATE TABLE t(x);");97  exec_ok(db1, "INSERT INTO t VALUES(1);");98  exec_ok(db1, "COMMIT;"); /* ensure autocommit */99  /* Ensure db2 sees baseline */100  TEST_ASSERT_EQUAL_INT(1, query_int(db2, "SELECT count(*) FROM t;"));101 102  /* Start write transaction and add uncommitted row */103  exec_ok(db1, "BEGIN;");104  exec_ok(db1, "INSERT INTO t VALUES(2);");105 106  /* Flush caches */107  int rc = sqlite3_db_cacheflush(db1);108  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);109 110  /* Within same connection, uncommitted row is visible */111  TEST_ASSERT_EQUAL_INT(2, query_int(db1, "SELECT count(*) FROM t;"));112  /* From another connection, uncommitted row must NOT be visible */113  TEST_ASSERT_EQUAL_INT(1, query_int(db2, "SELECT count(*) FROM t;"));114 115  /* Rollback and ensure row 2 is gone on both */116  exec_ok(db1, "ROLLBACK;");117  TEST_ASSERT_EQUAL_INT(1, query_int(db1, "SELECT count(*) FROM t;"));118  TEST_ASSERT_EQUAL_INT(1, query_int(db2, "SELECT count(*) FROM t;"));119 120  /* Now try again, but commit after flush to verify normal visibility */121  exec_ok(db1, "BEGIN;");122  exec_ok(db1, "INSERT INTO t VALUES(2);");123  rc = sqlite3_db_cacheflush(db1);124  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);125  exec_ok(db1, "COMMIT;");126 127  /* After commit, both connections should see both rows */128  TEST_ASSERT_EQUAL_INT(2, query_int(db1, "SELECT count(*) FROM t;"));129  TEST_ASSERT_EQUAL_INT(2, query_int(db2, "SELECT count(*) FROM t;"));130 131  sqlite3_close(db1);132  sqlite3_close(db2);133  remove(fname);134  sqlite3_free(fname);135}136 137/* Test 3: Attached database: uncommitted changes in both schemas; flush OK; not visible elsewhere until commit. */138static void test_sqlite3_db_cacheflush_with_attached_db(void){139  char *fname_main = make_temp_db_filename("main");140  char *fname_aux  = make_temp_db_filename("aux");141  sqlite3 *dbA = 0;142  sqlite3 *dbB = 0;143 144  open_db_with_pragmas(fname_main, &dbA);145  open_db_with_pragmas(fname_main, &dbB);146 147  /* Attach auxiliary db to both connections */148  {149    char *sqlAttachA = sqlite3_mprintf("ATTACH '%q' AS aux;", fname_aux);150    char *sqlAttachB = sqlite3_mprintf("ATTACH '%q' AS aux;", fname_aux);151    exec_ok(dbA, sqlAttachA);152    exec_ok(dbB, sqlAttachB);153    sqlite3_free(sqlAttachA);154    sqlite3_free(sqlAttachB);155  }156  /* Ensure aux uses DELETE journal mode as well */157  exec_ok(dbA, "PRAGMA aux.journal_mode=DELETE;");158  exec_ok(dbB, "PRAGMA aux.journal_mode=DELETE;");159 160  /* Create schemas and baseline committed rows in both dbs */161  exec_ok(dbA, "DROP TABLE IF EXISTS main.m;");162  exec_ok(dbA, "DROP TABLE IF EXISTS aux.a;");163  exec_ok(dbA, "CREATE TABLE main.m(x);");164  exec_ok(dbA, "CREATE TABLE aux.a(y);");165  exec_ok(dbA, "INSERT INTO main.m VALUES(10);");166  exec_ok(dbA, "INSERT INTO aux.a  VALUES(20);");167  exec_ok(dbA, "COMMIT;"); /* ensure autocommit */168 169  /* Confirm baselines visible from dbB */170  TEST_ASSERT_EQUAL_INT(1, query_int(dbB, "SELECT count(*) FROM main.m;"));171  TEST_ASSERT_EQUAL_INT(1, query_int(dbB, "SELECT count(*) FROM aux.a;"));172 173  /* Start a write transaction and insert into both schemas without commit */174  exec_ok(dbA, "BEGIN;");175  exec_ok(dbA, "INSERT INTO main.m VALUES(11);");176  exec_ok(dbA, "INSERT INTO aux.a  VALUES(21);");177 178  /* Flush caches */179  int rc = sqlite3_db_cacheflush(dbA);180  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);181 182  /* dbA sees uncommitted rows */183  TEST_ASSERT_EQUAL_INT(2, query_int(dbA, "SELECT count(*) FROM main.m;"));184  TEST_ASSERT_EQUAL_INT(2, query_int(dbA, "SELECT count(*) FROM aux.a;"));185  /* dbB must NOT see uncommitted rows from either schema */186  TEST_ASSERT_EQUAL_INT(1, query_int(dbB, "SELECT count(*) FROM main.m;"));187  TEST_ASSERT_EQUAL_INT(1, query_int(dbB, "SELECT count(*) FROM aux.a;"));188 189  /* Rollback and verify baseline remains */190  exec_ok(dbA, "ROLLBACK;");191  TEST_ASSERT_EQUAL_INT(1, query_int(dbA, "SELECT count(*) FROM main.m;"));192  TEST_ASSERT_EQUAL_INT(1, query_int(dbA, "SELECT count(*) FROM aux.a;"));193  TEST_ASSERT_EQUAL_INT(1, query_int(dbB, "SELECT count(*) FROM main.m;"));194  TEST_ASSERT_EQUAL_INT(1, query_int(dbB, "SELECT count(*) FROM aux.a;"));195 196  sqlite3_close(dbA);197  sqlite3_close(dbB);198  /* Cleanup files */199  remove(fname_main);200  remove(fname_aux);201  sqlite3_free(fname_main);202  sqlite3_free(fname_aux);203}204 205int main(void){206  UNITY_BEGIN();207  RUN_TEST(test_sqlite3_db_cacheflush_no_txn_ok);208  RUN_TEST(test_sqlite3_db_cacheflush_uncommitted_changes_not_visible);209  RUN_TEST(test_sqlite3_db_cacheflush_with_attached_db);210  return UNITY_END();211}