Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_pager_sqlite3PagerRollback.c203 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/* Helper: execute SQL and assert success */9static void exec_sql_ok(sqlite3 *db, const char *sql){10  char *errmsg = 0;11  int rc = sqlite3_exec(db, sql, 0, 0, &errmsg);12  if( rc!=SQLITE_OK ){13    const char *msg = errmsg ? errmsg : "(null)";14    /* Use Unity to report the error and fail */15    char buf[512];16    snprintf(buf, sizeof(buf), "SQL error %d: %s while executing: %s", rc, msg, sql);17    if( errmsg ) sqlite3_free(errmsg);18    TEST_FAIL_MESSAGE(buf);19  }20  if( errmsg ) sqlite3_free(errmsg);21}22 23/* Helper: Execute a scalar int query and return the first column of first row (or 0 if no row) */24static int query_int(sqlite3 *db, const char *sql){25  sqlite3_stmt *stmt = 0;26  int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);27  if( rc!=SQLITE_OK ){28    char buf[512];29    snprintf(buf, sizeof(buf), "prepare failed %d for: %s", rc, sql);30    TEST_FAIL_MESSAGE(buf);31  }32  int val = 0;33  rc = sqlite3_step(stmt);34  if( rc==SQLITE_ROW ){35    val = sqlite3_column_int(stmt, 0);36  }else if( rc==SQLITE_DONE ){37    val = 0;38  }else{39    char buf[512];40    snprintf(buf, sizeof(buf), "step failed %d for: %s", rc, sql);41    sqlite3_finalize(stmt);42    TEST_FAIL_MESSAGE(buf);43  }44  sqlite3_finalize(stmt);45  return val;46}47 48/* Helper: open a new database connection to a given filename */49static sqlite3* open_db(const char *filename){50  sqlite3 *db = 0;51  int rc = sqlite3_open(filename, &db);52  if( rc!=SQLITE_OK ){53    char buf[256];54    snprintf(buf, sizeof(buf), "sqlite3_open failed %d for %s", rc, filename);55    TEST_FAIL_MESSAGE(buf);56  }57  return db;58}59 60/* Helper: close DB and assert success */61static void close_db(sqlite3 *db){62  int rc = sqlite3_close(db);63  if( rc!=SQLITE_OK ){64    char buf[256];65    snprintf(buf, sizeof(buf), "sqlite3_close failed %d", rc);66    TEST_FAIL_MESSAGE(buf);67  }68}69 70/* Helper: get Pager* from sqlite3* connection */71static Pager* getPager(sqlite3 *db){72  TEST_ASSERT_NOT_NULL(db);73  TEST_ASSERT_NOT_NULL(db->aDb);74  TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);75  Pager *pPager = sqlite3BtreePager(db->aDb[0].pBt);76  TEST_ASSERT_NOT_NULL(pPager);77  return pPager;78}79 80void setUp(void) {81  /* No global setup required */82}83 84void tearDown(void) {85  /* No global teardown required */86}87 88/* Test: calling sqlite3PagerRollback on a freshly opened connection (no txn) is a no-op and returns SQLITE_OK. */89void test_sqlite3PagerRollback_noop_when_open(void){90  const char *fname = "test_pager_rb_open.db";91  sqlite3 *db = open_db(fname);92 93  Pager *pPager = getPager(db);94  int rc = sqlite3PagerRollback(pPager);95  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);96 97  /* Sanity: database usable after call */98  exec_sql_ok(db, "CREATE TABLE IF NOT EXISTS s(x);");99 100  close_db(db);101  remove(fname);102}103 104/* Test: rollback of uncommitted changes using rollback-journal (DELETE mode) */105void test_sqlite3PagerRollback_undo_changes_with_rollback_journal(void){106  const char *fname = "test_pager_rb_delete.db";107  sqlite3 *db = open_db(fname);108 109  /* Ensure rollback journal mode */110  exec_sql_ok(db, "PRAGMA journal_mode=DELETE;");111 112  /* Begin a write transaction and make changes, but do not commit */113  exec_sql_ok(db, "BEGIN IMMEDIATE;");114  exec_sql_ok(db, "CREATE TABLE t(x);");115  exec_sql_ok(db, "INSERT INTO t VALUES(1);");116 117  /* Directly rollback via pager */118  Pager *pPager = getPager(db);119  int rc = sqlite3PagerRollback(pPager);120  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);121 122  /* Bring the connection back to a consistent high-level state */123  exec_sql_ok(db, "ROLLBACK;");124 125  /* Verify that changes were not persisted */126  int n = query_int(db, "SELECT count(*) FROM sqlite_master WHERE name='t';");127  TEST_ASSERT_EQUAL_INT(0, n);128 129  /* Connection still usable */130  exec_sql_ok(db, "CREATE TABLE t2(y);");131  n = query_int(db, "SELECT count(*) FROM sqlite_master WHERE name='t2';");132  TEST_ASSERT_EQUAL_INT(1, n);133 134  close_db(db);135  remove(fname);136  /* Clean up possible -wal/-shm if created by VFS */137  remove("test_pager_rb_delete.db-journal");138}139 140/* Test: rollback of uncommitted changes in WAL mode */141void test_sqlite3PagerRollback_undo_changes_with_wal_mode(void){142  const char *fname = "test_pager_rb_wal.db";143  sqlite3 *db = open_db(fname);144 145  /* Switch to WAL mode */146  exec_sql_ok(db, "PRAGMA journal_mode=WAL;");147 148  /* Begin a write transaction and make changes, but do not commit */149  exec_sql_ok(db, "BEGIN;");150  exec_sql_ok(db, "CREATE TABLE w(x);");151  exec_sql_ok(db, "INSERT INTO w VALUES(10);");152 153  /* Directly rollback via pager */154  Pager *pPager = getPager(db);155  int rc = sqlite3PagerRollback(pPager);156  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);157 158  /* Synchronize high-level transaction state */159  exec_sql_ok(db, "ROLLBACK;");160 161  /* Verify that changes were not persisted */162  int n = query_int(db, "SELECT count(*) FROM sqlite_master WHERE name='w';");163  TEST_ASSERT_EQUAL_INT(0, n);164 165  /* Connection still usable */166  exec_sql_ok(db, "CREATE TABLE w2(y);");167  n = query_int(db, "SELECT count(*) FROM sqlite_master WHERE name='w2';");168  TEST_ASSERT_EQUAL_INT(1, n);169 170  close_db(db);171  remove(fname);172  remove("test_pager_rb_wal.db-wal");173  remove("test_pager_rb_wal.db-shm");174}175 176/* Test: sqlite3PagerRollback returns OK when in a read transaction (no write). */177void test_sqlite3PagerRollback_noop_in_reader_state(void){178  const char *fname = "test_pager_rb_reader.db";179  sqlite3 *db = open_db(fname);180 181  /* Start a deferred transaction and perform a read to ensure a read lock */182  exec_sql_ok(db, "BEGIN;");183  (void)query_int(db, "SELECT count(*) FROM sqlite_master;");184 185  Pager *pPager = getPager(db);186  int rc = sqlite3PagerRollback(pPager);187  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);188 189  /* Rollback at SQL level to clean up */190  exec_sql_ok(db, "ROLLBACK;");191 192  close_db(db);193  remove(fname);194}195 196int main(void){197  UNITY_BEGIN();198  RUN_TEST(test_sqlite3PagerRollback_noop_when_open);199  RUN_TEST(test_sqlite3PagerRollback_undo_changes_with_rollback_journal);200  RUN_TEST(test_sqlite3PagerRollback_undo_changes_with_wal_mode);201  RUN_TEST(test_sqlite3PagerRollback_noop_in_reader_state);202  return UNITY_END();203}