AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6 7#if defined(_WIN32)8# include <io.h>9# define unlink _unlink10#endif11 12/* Forward declaration for internal function to fetch Pager from Btree. */13extern Pager *sqlite3BtreePager(Btree *p);14 15/* Simple helper to remove database and associated WAL/SHM files. */16static void remove_db_files(const char *zPath){17 if( zPath==0 ) return;18 char buf[1024];19 snprintf(buf, sizeof(buf), "%s", zPath);20 remove(buf);21 snprintf(buf, sizeof(buf), "%s-wal", zPath);22 remove(buf);23 snprintf(buf, sizeof(buf), "%s-shm", zPath);24 remove(buf);25}26 27/* Open a database connection at zPath and ensure "main" btree is initialized. */28static sqlite3* open_db_and_init(const char *zPath){29 sqlite3 *db = 0;30 int rc = sqlite3_open(zPath, &db);31 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);32 /* Execute a trivial statement to ensure the main btree is opened/initialized. */33 rc = sqlite3_exec(db, "SELECT 1", 0, 0, 0);34 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);35 return db;36}37 38/* Obtain the Pager* for the "main" database from an open sqlite3* handle. */39static Pager* get_main_pager(sqlite3 *db){40 TEST_ASSERT_NOT_NULL(db);41 /* aDb[0] is "main". Ensure Btree exists. */42 TEST_ASSERT_NOT_NULL(db->aDb);43 TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);44 Pager *pPager = sqlite3BtreePager(db->aDb[0].pBt);45 TEST_ASSERT_NOT_NULL(pPager);46 return pPager;47}48 49/* Execute SQL and assert success. */50static void exec_ok(sqlite3 *db, const char *zSql){51 int rc = sqlite3_exec(db, zSql, 0, 0, 0);52 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, zSql);53}54 55void setUp(void) {56 /* No global setup required */57}58 59void tearDown(void) {60 /* No global teardown required */61}62 63/* Test 1: Not in WAL mode - outputs should remain unchanged and rc==SQLITE_OK. */64void test_sqlite3PagerCheckpoint_no_wal_outputs_unchanged(void){65 const char *zDb = "test_pc_no_wal.sqlite";66 remove_db_files(zDb);67 sqlite3 *db = open_db_and_init(zDb);68 69 Pager *pPager = get_main_pager(db);70 71 int nLog = 1111;72 int nCkpt = 2222;73 int rc = sqlite3PagerCheckpoint(pPager, db, SQLITE_CHECKPOINT_PASSIVE, &nLog, &nCkpt);74 75 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);76 /* Since not in WAL mode (default), pnLog/pnCkpt should be untouched. */77 TEST_ASSERT_EQUAL_INT(1111, nLog);78 TEST_ASSERT_EQUAL_INT(2222, nCkpt);79 80 sqlite3_close(db);81 remove_db_files(zDb);82}83 84/* Helper: create WAL with some frames by performing writes and committing. */85static void create_wal_with_frames(sqlite3 *db){86 exec_ok(db, "PRAGMA journal_mode=WAL;");87 /* Perform multiple writes to ensure WAL frames are generated. */88 exec_ok(db,89 "BEGIN;"90 "CREATE TABLE t1(x);"91 "WITH RECURSIVE c(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM c WHERE i<100) "92 "INSERT INTO t1 SELECT i FROM c;"93 "COMMIT;"94 );95}96 97/* Test 2: In WAL mode with frames, PASSIVE checkpoint should checkpoint everything. */98void test_sqlite3PagerCheckpoint_wal_passive_full_checkpoint(void){99 const char *zDb = "test_pc_wal_passive.sqlite";100 remove_db_files(zDb);101 sqlite3 *db = open_db_and_init(zDb);102 103 create_wal_with_frames(db);104 Pager *pPager = get_main_pager(db);105 106 int nLog = -1;107 int nCkpt = -1;108 int rc = sqlite3PagerCheckpoint(pPager, db, SQLITE_CHECKPOINT_PASSIVE, &nLog, &nCkpt);109 110 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);111 TEST_ASSERT_TRUE(nLog >= 1);112 TEST_ASSERT_EQUAL_INT(nLog, nCkpt);113 114 sqlite3_close(db);115 remove_db_files(zDb);116}117 118/* Test 3: Special-case path: zero-byte db -> set WAL -> checkpoint with no transactions.119 Accept either outputs unchanged (if pWal remains NULL) or zeroed (if initialized). */120void test_sqlite3PagerCheckpoint_wal_specialcase_no_txn(void){121 const char *zDb = "test_pc_wal_special.sqlite";122 remove_db_files(zDb);123 sqlite3 *db = open_db_and_init(zDb);124 125 /* Switch to WAL without any DDL/DML. This can leave pPager->pWal==0. */126 exec_ok(db, "PRAGMA journal_mode=WAL;");127 128 Pager *pPager = get_main_pager(db);129 130 int nLog = -123;131 int nCkpt = -456;132 int rc = sqlite3PagerCheckpoint(pPager, db, SQLITE_CHECKPOINT_PASSIVE, &nLog, &nCkpt);133 134 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);135 /* Either untouched (still -123/-456) or zeroed (no frames to checkpoint). */136 TEST_ASSERT_TRUE((nLog == -123 && nCkpt == -456) || (nLog == 0 && nCkpt == 0));137 138 sqlite3_close(db);139 remove_db_files(zDb);140}141 142/* Test 4: In WAL mode with frames, allow NULL output pointers; must succeed without crashing. */143void test_sqlite3PagerCheckpoint_wal_null_outputs(void){144 const char *zDb = "test_pc_wal_null.sqlite";145 remove_db_files(zDb);146 sqlite3 *db = open_db_and_init(zDb);147 148 create_wal_with_frames(db);149 Pager *pPager = get_main_pager(db);150 151 int rc = sqlite3PagerCheckpoint(pPager, db, SQLITE_CHECKPOINT_FULL, NULL, NULL);152 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);153 154 sqlite3_close(db);155 remove_db_files(zDb);156}157 158int main(void) {159 UNITY_BEGIN();160 RUN_TEST(test_sqlite3PagerCheckpoint_no_wal_outputs_unchanged);161 RUN_TEST(test_sqlite3PagerCheckpoint_wal_passive_full_checkpoint);162 RUN_TEST(test_sqlite3PagerCheckpoint_wal_specialcase_no_txn);163 RUN_TEST(test_sqlite3PagerCheckpoint_wal_null_outputs);164 return UNITY_END();165}