Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_pager_sqlite3PagerCommitPhaseTwo.c140 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6 7/* Unity setup/teardown */8void setUp(void) {9  /* No global setup needed */10}11void tearDown(void) {12  /* No global teardown needed */13}14 15/* Helpers */16static void exec_sql(sqlite3 *db, const char *sql){17  char *zErr = 0;18  int rc = sqlite3_exec(db, sql, 0, 0, &zErr);19  if( rc!=SQLITE_OK ){20    fprintf(stderr, "SQL error (%d): %s\n", rc, zErr ? zErr : "(null)");21  }22  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);23  if( zErr ) sqlite3_free(zErr);24}25 26static Pager* get_main_pager(sqlite3 *db){27  TEST_ASSERT_NOT_NULL(db);28  TEST_ASSERT_TRUE(db->nDb > 0);29  TEST_ASSERT_NOT_NULL(db->aDb);30  Btree *pBt = db->aDb[0].pBt;31  TEST_ASSERT_NOT_NULL(pBt);32  Pager *pPager = sqlite3BtreePager(pBt);33  TEST_ASSERT_NOT_NULL(pPager);34  return pPager;35}36 37/* Test 1: Early return on pre-existing error (NEVER(pPager->errCode)) */38void test_sqlite3PagerCommitPhaseTwo_error_early_return(void){39  /* Allocate a minimal Pager just for this test. It is safe because40     sqlite3PagerCommitPhaseTwo returns immediately when errCode is set,41     before accessing other fields or running asserts. */42  Pager *p = (Pager *)sqlite3_malloc(sizeof(*p));43  TEST_ASSERT_NOT_NULL(p);44  memset(p, 0, sizeof(*p));45 46  /* Set a persistent error and a sentinel iDataVersion. */47  p->errCode = SQLITE_IOERR;   /* trigger early return */48  p->iDataVersion = 123456u;49 50  int rc = sqlite3PagerCommitPhaseTwo(p);51  TEST_ASSERT_EQUAL_INT(SQLITE_IOERR, rc);52  /* iDataVersion must not be incremented on error. */53  TEST_ASSERT_EQUAL_UINT(123456u, p->iDataVersion);54 55  sqlite3_free(p);56}57 58/* Test 2: Optimization no-op path: WRITER_LOCKED + exclusive + PERSIST + no changes */59void test_sqlite3PagerCommitPhaseTwo_optimization_noop_persist_exclusive_writer_locked(void){60  sqlite3 *db = 0;61  int rc = sqlite3_open("test_pager_commit2_opt.db", &db);62  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);63  TEST_ASSERT_NOT_NULL(db);64 65  /* Ensure rollback-journal mode: PERSIST, and exclusive locking mode. */66  exec_sql(db, "PRAGMA journal_mode=PERSIST;");67  exec_sql(db, "PRAGMA locking_mode=EXCLUSIVE;");68  /* Start a RESERVED/WRITE lock without making any changes. */69  exec_sql(db, "BEGIN IMMEDIATE;");70 71  Pager *pPager = get_main_pager(db);72 73  /* Confirm preconditions for optimization branch. We expect:74     - eState == PAGER_WRITER_LOCKED (no page modified)75     - exclusiveMode true76     - journalMode == PAGER_JOURNALMODE_PERSIST77  */78  TEST_ASSERT_EQUAL_INT(PAGER_WRITER_LOCKED, pPager->eState);79  TEST_ASSERT_TRUE(pPager->exclusiveMode!=0);80  TEST_ASSERT_EQUAL_INT(PAGER_JOURNALMODE_PERSIST, pPager->journalMode);81 82  unsigned int beforeDV = pPager->iDataVersion;83 84  rc = sqlite3PagerCommitPhaseTwo(pPager);85  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);86  /* After optimization path, pager moves to READER state and dataVersion increments. */87  TEST_ASSERT_EQUAL_INT(PAGER_READER, pPager->eState);88  TEST_ASSERT_EQUAL_UINT(beforeDV + 1u, pPager->iDataVersion);89 90  /* Connection should now be out of the write-transaction. */91  exec_sql(db, "ROLLBACK;"); /* no-op if already committed, but ensure clean state */92 93  sqlite3_close(db);94}95 96/* Test 3: Normal path after commit-phase-one (DELETE journal mode, with changes) */97void test_sqlite3PagerCommitPhaseTwo_normal_after_phase_one(void){98  sqlite3 *db = 0;99  int rc = sqlite3_open("test_pager_commit2_normal.db", &db);100  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101  TEST_ASSERT_NOT_NULL(db);102 103  /* Ensure rollback journal (not WAL) and normal locking. */104  exec_sql(db, "PRAGMA journal_mode=DELETE;");105  exec_sql(db, "PRAGMA locking_mode=NORMAL;");106 107  exec_sql(db, "BEGIN IMMEDIATE;");108  /* Make a change to ensure there is something to commit. */109  exec_sql(db, "CREATE TABLE IF NOT EXISTS t(x);");110 111  Pager *pPager = get_main_pager(db);112 113  /* Run commit phase one directly on the pager to reach WRITER_FINISHED state. */114  /* Note: sqlite3PagerCommitPhaseOne(Pager*, const char*, int) is an internal API. */115  rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);116  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);117  TEST_ASSERT_EQUAL_INT(PAGER_WRITER_FINISHED, pPager->eState);118 119  unsigned int beforeDV = pPager->iDataVersion;120 121  /* Now run the target function: commit phase two. */122  rc = sqlite3PagerCommitPhaseTwo(pPager);123  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);124  TEST_ASSERT_EQUAL_INT(PAGER_READER, pPager->eState);125  TEST_ASSERT_EQUAL_UINT(beforeDV + 1u, pPager->iDataVersion);126 127  /* Verify the table exists (transaction was committed). */128  exec_sql(db, "SELECT count(*) FROM t;");129 130  sqlite3_close(db);131}132 133/* Unity main runner */134int main(void){135  UNITY_BEGIN();136  RUN_TEST(test_sqlite3PagerCommitPhaseTwo_error_early_return);137  RUN_TEST(test_sqlite3PagerCommitPhaseTwo_optimization_noop_persist_exclusive_writer_locked);138  RUN_TEST(test_sqlite3PagerCommitPhaseTwo_normal_after_phase_one);139  return UNITY_END();140}