AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <string.h>6 7/* Unity setUp/tearDown */8void setUp(void) {9 /* No global setup required */10}11void tearDown(void) {12 /* No global teardown required */13}14 15/* Helper to open an in-memory database and return Pager* for main db */16static int open_memdb_and_get_pager(sqlite3 **ppDb, Pager **ppPager){17 int rc = sqlite3_open(":memory:", ppDb);18 if( rc!=SQLITE_OK ) return rc;19 20 /* Ensure the main database/pager is initialized by creating a table. */21 rc = sqlite3_exec(*ppDb, "CREATE TABLE IF NOT EXISTS t_init(x);", 0, 0, 0);22 if( rc!=SQLITE_OK ){23 sqlite3_close(*ppDb);24 *ppDb = 0;25 return rc;26 }27 28 /* Obtain the Pager* from the main database Btree */29 if( (*ppDb)->aDb==0 || (*ppDb)->aDb[0].pBt==0 ){30 /* Force initialization if somehow not yet done */31 rc = sqlite3_exec(*ppDb, "SELECT name FROM sqlite_master LIMIT 1;", 0, 0, 0);32 if( rc!=SQLITE_OK ){33 sqlite3_close(*ppDb);34 *ppDb = 0;35 return rc;36 }37 }38 39 *ppPager = sqlite3BtreePager((*ppDb)->aDb[0].pBt);40 return SQLITE_OK;41}42 43/* Convenience wrapper around sqlite3PagerCacheStat */44static u64 pager_stat_value(Pager *pPager, int eStat, int reset){45 u64 v = 0;46 sqlite3PagerCacheStat(pPager, eStat, reset, &v);47 return v;48}49 50static void reset_stat(Pager *pPager, int eStat){51 (void)pager_stat_value(pPager, eStat, 1);52}53 54/* Test: HIT accumulates into pnVal and resets correctly */55void test_sqlite3PagerCacheStat_hit_accumulates_and_resets(void){56 sqlite3 *db = 0;57 Pager *pPager = 0;58 int rc = open_memdb_and_get_pager(&db, &pPager);59 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);60 TEST_ASSERT_NOT_NULL(pPager);61 62 /* Reset HIT counter */63 reset_stat(pPager, SQLITE_DBSTATUS_CACHE_HIT);64 65 /* Run a query twice to create at least one cache hit on the second run */66 rc = sqlite3_exec(db, "SELECT name FROM sqlite_master WHERE type='table' LIMIT 10;", 0, 0, 0);67 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);68 rc = sqlite3_exec(db, "SELECT name FROM sqlite_master WHERE type='table' LIMIT 10;", 0, 0, 0);69 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);70 71 u64 v1 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_HIT, 0);72 TEST_ASSERT_TRUE(v1 >= 1); /* Expect at least one hit */73 74 /* Calling again with reset=1 should report same number and then clear */75 u64 v2 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_HIT, 1);76 TEST_ASSERT_TRUE(v2 >= 1);77 TEST_ASSERT_EQUAL_UINT64(v1, v2);78 79 /* Now the counter should be zero */80 u64 v3 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_HIT, 0);81 TEST_ASSERT_EQUAL_UINT64(0, v3);82 83 sqlite3_close(db);84}85 86/* Test: MISS counter increases after first access to schema */87void test_sqlite3PagerCacheStat_miss_counter_increases_after_first_access(void){88 sqlite3 *db = 0;89 Pager *pPager = 0;90 int rc = open_memdb_and_get_pager(&db, &pPager);91 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);92 TEST_ASSERT_NOT_NULL(pPager);93 94 /* Reset MISS counter */95 reset_stat(pPager, SQLITE_DBSTATUS_CACHE_MISS);96 97 /* First access to schema should cause at least one miss */98 rc = sqlite3_exec(db, "SELECT name FROM sqlite_master LIMIT 5;", 0, 0, 0);99 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);100 101 u64 miss = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_MISS, 0);102 TEST_ASSERT_TRUE(miss >= 1);103 104 /* Reset and verify zero */105 u64 beforeReset = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_MISS, 1);106 TEST_ASSERT_TRUE(beforeReset >= 1);107 u64 afterReset = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_MISS, 0);108 TEST_ASSERT_EQUAL_UINT64(0, afterReset);109 110 sqlite3_close(db);111}112 113/* Test: WRITE counter increases after DDL/INSERT and accumulation works */114void test_sqlite3PagerCacheStat_write_counter_increases_after_ddl(void){115 sqlite3 *db = 0;116 Pager *pPager = 0;117 int rc = open_memdb_and_get_pager(&db, &pPager);118 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);119 TEST_ASSERT_NOT_NULL(pPager);120 121 /* Reset WRITE counter */122 reset_stat(pPager, SQLITE_DBSTATUS_CACHE_WRITE);123 124 /* Perform writes: create a table and insert rows */125 rc = sqlite3_exec(db,126 "CREATE TABLE t1(a);"127 "INSERT INTO t1(a) VALUES(1),(2),(3),(4),(5);", 0, 0, 0);128 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);129 130 /* Get current write count */131 u64 w1 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE, 0);132 TEST_ASSERT_TRUE(w1 >= 1);133 134 /* Verify accumulation into a non-zero pnVal */135 u64 pn = 5;136 sqlite3PagerCacheStat(pPager, SQLITE_DBSTATUS_CACHE_WRITE, 0, &pn);137 TEST_ASSERT_EQUAL_UINT64(5 + w1, pn);138 139 /* Reset and verify cleared */140 u64 w2 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE, 1);141 TEST_ASSERT_TRUE(w2 >= 1);142 u64 w3 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE, 0);143 TEST_ASSERT_EQUAL_UINT64(0, w3);144 145 sqlite3_close(db);146}147 148/* Test: Resetting one stat does not affect others (HIT vs WRITE) */149void test_sqlite3PagerCacheStat_reset_is_per_statistic(void){150 sqlite3 *db = 0;151 Pager *pPager = 0;152 int rc = open_memdb_and_get_pager(&db, &pPager);153 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);154 TEST_ASSERT_NOT_NULL(pPager);155 156 /* Reset both counters first */157 reset_stat(pPager, SQLITE_DBSTATUS_CACHE_HIT);158 reset_stat(pPager, SQLITE_DBSTATUS_CACHE_WRITE);159 160 /* Generate some writes and hits */161 rc = sqlite3_exec(db,162 "CREATE TABLE t2(x);"163 "INSERT INTO t2 VALUES(10),(20);", 0, 0, 0);164 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);165 rc = sqlite3_exec(db, "SELECT name FROM sqlite_master WHERE type='table' LIMIT 10;", 0, 0, 0);166 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);167 rc = sqlite3_exec(db, "SELECT name FROM sqlite_master WHERE type='table' LIMIT 10;", 0, 0, 0);168 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);169 170 u64 w_before = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE, 0);171 TEST_ASSERT_TRUE(w_before >= 1);172 173 /* Reset HIT only */174 (void)pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_HIT, 1);175 176 /* WRITE should be unaffected */177 u64 w_after = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE, 0);178 TEST_ASSERT_EQUAL_UINT64(w_before, w_after);179 180 sqlite3_close(db);181}182 183/* Test: SPILL stat can be queried/reset without error */184void test_sqlite3PagerCacheStat_spill_stat_access_and_reset(void){185 sqlite3 *db = 0;186 Pager *pPager = 0;187 int rc = open_memdb_and_get_pager(&db, &pPager);188 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);189 TEST_ASSERT_NOT_NULL(pPager);190 191 /* Read current SPILL count (may be 0) */192 u64 s0 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE + 1, 0);193 TEST_ASSERT_TRUE(s0 >= 0);194 195 /* Reset SPILL count */196 u64 sReset = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE + 1, 1);197 TEST_ASSERT_TRUE(sReset >= 0);198 199 /* Now it should be zero */200 u64 s1 = pager_stat_value(pPager, SQLITE_DBSTATUS_CACHE_WRITE + 1, 0);201 TEST_ASSERT_EQUAL_UINT64(0, s1);202 203 sqlite3_close(db);204}205 206int main(void){207 UNITY_BEGIN();208 RUN_TEST(test_sqlite3PagerCacheStat_hit_accumulates_and_resets);209 RUN_TEST(test_sqlite3PagerCacheStat_miss_counter_increases_after_first_access);210 RUN_TEST(test_sqlite3PagerCacheStat_write_counter_increases_after_ddl);211 RUN_TEST(test_sqlite3PagerCacheStat_reset_is_per_statistic);212 RUN_TEST(test_sqlite3PagerCacheStat_spill_stat_access_and_reset);213 return UNITY_END();214}