AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* A minimal fake sqlite3_file that allows controlling device characteristics6** returned by sqlite3OsDeviceCharacteristics(). This lets us exercise7** SQLITE_ENABLE_BATCH_ATOMIC_WRITE behavior safely.8*/9static int g_fake_devchar = 0;10 11static int fake_xClose(sqlite3_file *id){ (void)id; return SQLITE_OK; }12static int fake_xRead(sqlite3_file *id, void *p, int a, sqlite3_int64 o){ (void)id;(void)p;(void)a;(void)o; return SQLITE_OK; }13static int fake_xWrite(sqlite3_file *id, const void *p, int a, sqlite3_int64 o){ (void)id;(void)p;(void)a;(void)o; return SQLITE_OK; }14static int fake_xTruncate(sqlite3_file *id, sqlite3_int64 s){ (void)id;(void)s; return SQLITE_OK; }15static int fake_xSync(sqlite3_file *id, int f){ (void)id;(void)f; return SQLITE_OK; }16static int fake_xFileSize(sqlite3_file *id, sqlite3_int64 *pSz){ (void)id; if(pSz) *pSz = 0; return SQLITE_OK; }17static int fake_xLock(sqlite3_file *id, int e){ (void)id;(void)e; return SQLITE_OK; }18static int fake_xUnlock(sqlite3_file *id, int e){ (void)id;(void)e; return SQLITE_OK; }19static int fake_xCheckReservedLock(sqlite3_file *id, int *p){ (void)id; if(p) *p = 0; return SQLITE_OK; }20static int fake_xFileControl(sqlite3_file *id, int op, void *arg){ (void)id;(void)op;(void)arg; return SQLITE_OK; }21static int fake_xSectorSize(sqlite3_file *id){ (void)id; return 512; }22static int fake_xDeviceCharacteristics(sqlite3_file *id){ (void)id; return g_fake_devchar; }23 24/* Version 1 sqlite3_io_methods - only xDeviceCharacteristics is actually used */25static const sqlite3_io_methods g_fake_io_methods = {26 1,27 fake_xClose,28 fake_xRead,29 fake_xWrite,30 fake_xTruncate,31 fake_xSync,32 fake_xFileSize,33 fake_xLock,34 fake_xUnlock,35 fake_xCheckReservedLock,36 fake_xFileControl,37 fake_xSectorSize,38 fake_xDeviceCharacteristics39};40 41static sqlite3_file g_fake_file = { &g_fake_io_methods };42 43/* Helper to initialize a Pager for testing this function */44static void initPagerForTest(Pager *p, int isTemp){45 memset(p, 0, sizeof(*p));46 p->tempFile = (u8)isTemp;47 p->fd = &g_fake_file;48 g_fake_devchar = 0;49}50 51void setUp(void) {52 /* Setup code here, or leave empty */53 g_fake_devchar = 0;54}55void tearDown(void) {56 /* Cleanup code here, or leave empty */57}58 59/* Test: Temp file forces noSync and clears others, regardless of sync level */60void test_sqlite3PagerSetFlags_tempFile_forces_noSync(void){61 Pager p;62 initPagerForTest(&p, 1);63 64 unsigned levels[] = {65 (PAGER_SYNCHRONOUS_OFF & PAGER_SYNCHRONOUS_MASK) | 0,66 (2 & PAGER_SYNCHRONOUS_MASK), /* NORMAL */67 (PAGER_SYNCHRONOUS_FULL & PAGER_SYNCHRONOUS_MASK),68 (PAGER_SYNCHRONOUS_EXTRA & PAGER_SYNCHRONOUS_MASK)69 };70 71 for(unsigned i=0;i<sizeof(levels)/sizeof(levels[0]);i++){72 /* Toggle some flags just to ensure they are ignored for temp files */73 unsigned pgFlags = levels[i] | PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL;74 p.noSync = 0; p.fullSync = 1; p.extraSync = 1;75 p.syncFlags = 1234; p.walSyncFlags = 5678;76 p.doNotSpill = 0;77 78 sqlite3PagerSetFlags(&p, pgFlags);79 80 TEST_ASSERT_EQUAL_INT(1, p.noSync);81 TEST_ASSERT_EQUAL_INT(0, p.fullSync);82 TEST_ASSERT_EQUAL_INT(0, p.extraSync);83 TEST_ASSERT_EQUAL_INT(0, p.syncFlags);84 TEST_ASSERT_EQUAL_INT(0, p.walSyncFlags);85 /* With PAGER_CACHESPILL set, SPILLFLAG_OFF must be cleared */86 TEST_ASSERT_EQUAL_INT(0, (p.doNotSpill & SPILLFLAG_OFF));87 }88 89 /* And when PAGER_CACHESPILL not set, SPILLFLAG_OFF must be set */90 p.doNotSpill = 0;91 sqlite3PagerSetFlags(&p, (PAGER_SYNCHRONOUS_NORMAL & PAGER_SYNCHRONOUS_MASK)); /* no CACHESPILL */92 TEST_ASSERT_NOT_EQUAL(0, (p.doNotSpill & SPILLFLAG_OFF));93}94 95/* Test: Level OFF (non-temp) behaves like temp/noSync */96void test_sqlite3PagerSetFlags_level_off_regular_file(void){97 Pager p;98 initPagerForTest(&p, 0);99 p.doNotSpill = SPILLFLAG_OFF; /* Will be cleared if CACHESPILL set */100 unsigned pgFlags = (PAGER_SYNCHRONOUS_OFF & PAGER_SYNCHRONOUS_MASK) | PAGER_CACHESPILL;101 102 sqlite3PagerSetFlags(&p, pgFlags);103 104 TEST_ASSERT_EQUAL_INT(1, p.noSync);105 TEST_ASSERT_EQUAL_INT(0, p.fullSync);106 TEST_ASSERT_EQUAL_INT(0, p.extraSync);107 TEST_ASSERT_EQUAL_INT(0, p.syncFlags);108 TEST_ASSERT_EQUAL_INT(0, p.walSyncFlags);109 TEST_ASSERT_EQUAL_INT(0, (p.doNotSpill & SPILLFLAG_OFF));110}111 112/* Test: NORMAL mode with default sync (no FULLFSYNC) and no CKPT flag */113void test_sqlite3PagerSetFlags_normal_default_syncflags(void){114 Pager p;115 initPagerForTest(&p, 0);116 p.doNotSpill = 0; /* SPILLFLAG_OFF should be set since no CACHESPILL */117 unsigned pgFlags = (PAGER_SYNCHRONOUS_NORMAL & PAGER_SYNCHRONOUS_MASK);118 119 sqlite3PagerSetFlags(&p, pgFlags);120 121 TEST_ASSERT_EQUAL_INT(0, p.noSync);122 TEST_ASSERT_EQUAL_INT(0, p.fullSync);123 TEST_ASSERT_EQUAL_INT(0, p.extraSync);124 TEST_ASSERT_EQUAL_INT(SQLITE_SYNC_NORMAL, p.syncFlags);125 TEST_ASSERT_EQUAL_INT(SQLITE_SYNC_NORMAL<<2, p.walSyncFlags);126 TEST_ASSERT_NOT_EQUAL(0, (p.doNotSpill & SPILLFLAG_OFF));127}128 129/* Test: NORMAL mode with CKPT_FULLFSYNC (but not FULLFSYNC) augments walSyncFlags */130void test_sqlite3PagerSetFlags_normal_ckpt_fullfsync_only(void){131 Pager p;132 initPagerForTest(&p, 0);133 p.doNotSpill = 0;134 unsigned pgFlags = (PAGER_SYNCHRONOUS_NORMAL & PAGER_SYNCHRONOUS_MASK) | PAGER_CKPT_FULLFSYNC;135 136 sqlite3PagerSetFlags(&p, pgFlags);137 138 TEST_ASSERT_EQUAL_INT(SQLITE_SYNC_NORMAL, p.syncFlags);139 /* walSyncFlags should include both (NORMAL<<2) and (FULL<<2) */140 int expectedWal = (SQLITE_SYNC_NORMAL<<2) | (SQLITE_SYNC_FULL<<2);141 TEST_ASSERT_EQUAL_INT(expectedWal, p.walSyncFlags);142}143 144/* Test: FULL mode without FULLFSYNC */145void test_sqlite3PagerSetFlags_full_mode_normal_sync(void){146 Pager p;147 initPagerForTest(&p, 0);148 unsigned pgFlags = (PAGER_SYNCHRONOUS_FULL & PAGER_SYNCHRONOUS_MASK);149 150 sqlite3PagerSetFlags(&p, pgFlags);151 152 TEST_ASSERT_EQUAL_INT(0, p.noSync);153 TEST_ASSERT_EQUAL_INT(1, p.fullSync);154 TEST_ASSERT_EQUAL_INT(0, p.extraSync);155 TEST_ASSERT_EQUAL_INT(SQLITE_SYNC_NORMAL, p.syncFlags);156 int expectedWal = (SQLITE_SYNC_NORMAL<<2) | SQLITE_SYNC_NORMAL;157 TEST_ASSERT_EQUAL_INT(expectedWal, p.walSyncFlags);158}159 160/* Test: FULL mode with FULLFSYNC */161void test_sqlite3PagerSetFlags_full_mode_fullfsync(void){162 Pager p;163 initPagerForTest(&p, 0);164 unsigned pgFlags = (PAGER_SYNCHRONOUS_FULL & PAGER_SYNCHRONOUS_MASK) | PAGER_FULLFSYNC;165 166 sqlite3PagerSetFlags(&p, pgFlags);167 168 TEST_ASSERT_EQUAL_INT(1, p.fullSync);169 TEST_ASSERT_EQUAL_INT(SQLITE_SYNC_FULL, p.syncFlags);170 int expectedWal = (SQLITE_SYNC_FULL<<2) | SQLITE_SYNC_FULL;171 TEST_ASSERT_EQUAL_INT(expectedWal, p.walSyncFlags);172}173 174/* Test: EXTRA mode sets extraSync */175void test_sqlite3PagerSetFlags_extra_mode_sets_extraSync(void){176 Pager p;177 initPagerForTest(&p, 0);178 unsigned pgFlags = (PAGER_SYNCHRONOUS_EXTRA & PAGER_SYNCHRONOUS_MASK);179 180 sqlite3PagerSetFlags(&p, pgFlags);181 182 TEST_ASSERT_EQUAL_INT(0, p.noSync);183 TEST_ASSERT_EQUAL_INT(1, p.fullSync);184 TEST_ASSERT_EQUAL_INT(1, p.extraSync);185 TEST_ASSERT_EQUAL_INT(SQLITE_SYNC_NORMAL, p.syncFlags);186 int expectedWal = (SQLITE_SYNC_NORMAL<<2) | SQLITE_SYNC_NORMAL;187 TEST_ASSERT_EQUAL_INT(expectedWal, p.walSyncFlags);188}189 190/* Test: PAGER_CACHESPILL toggles SPILLFLAG_OFF as specified */191void test_sqlite3PagerSetFlags_cachespill_bit_toggling(void){192 Pager p;193 initPagerForTest(&p, 0);194 195 /* Start with SPILLFLAG_OFF set, ensure it is cleared when CACHESPILL is set */196 p.doNotSpill = SPILLFLAG_OFF | 0xBEEF0000; /* preserve other bits */197 unsigned pgFlags = (PAGER_SYNCHRONOUS_NORMAL & PAGER_SYNCHRONOUS_MASK) | PAGER_CACHESPILL;198 sqlite3PagerSetFlags(&p, pgFlags);199 TEST_ASSERT_EQUAL_INT(0, (p.doNotSpill & SPILLFLAG_OFF));200 TEST_ASSERT_EQUAL_INT(0xBEEF0000, (p.doNotSpill & ~SPILLFLAG_OFF));201 202 /* Now ensure it is set when CACHESPILL is not present */203 p.doNotSpill = 0xCAFE0000; /* SPILLFLAG_OFF currently clear */204 pgFlags = (PAGER_SYNCHRONOUS_NORMAL & PAGER_SYNCHRONOUS_MASK); /* no CACHESPILL */205 sqlite3PagerSetFlags(&p, pgFlags);206 TEST_ASSERT_NOT_EQUAL(0, (p.doNotSpill & SPILLFLAG_OFF));207 TEST_ASSERT_EQUAL_INT(0xCAFE0000, (p.doNotSpill & ~SPILLFLAG_OFF));208}209 210#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE211/* Test: When device reports batch-atomic, extraSync is enabled for non-EXTRA levels */212void test_sqlite3PagerSetFlags_batch_atomic_enables_extraSync(void){213 Pager p;214 initPagerForTest(&p, 0);215 g_fake_devchar = SQLITE_IOCAP_BATCH_ATOMIC;216 217 /* NORMAL level but device supports batch-atomic */218 unsigned pgFlags = (PAGER_SYNCHRONOUS_NORMAL & PAGER_SYNCHRONOUS_MASK);219 sqlite3PagerSetFlags(&p, pgFlags);220 221 TEST_ASSERT_EQUAL_INT(0, p.noSync);222 TEST_ASSERT_EQUAL_INT(0, p.fullSync);223 TEST_ASSERT_EQUAL_INT(1, p.extraSync);224}225#endif226 227int main(void) {228 UNITY_BEGIN();229 RUN_TEST(test_sqlite3PagerSetFlags_tempFile_forces_noSync);230 RUN_TEST(test_sqlite3PagerSetFlags_level_off_regular_file);231 RUN_TEST(test_sqlite3PagerSetFlags_normal_default_syncflags);232 RUN_TEST(test_sqlite3PagerSetFlags_normal_ckpt_fullfsync_only);233 RUN_TEST(test_sqlite3PagerSetFlags_full_mode_normal_sync);234 RUN_TEST(test_sqlite3PagerSetFlags_full_mode_fullfsync);235 RUN_TEST(test_sqlite3PagerSetFlags_extra_mode_sets_extraSync);236 RUN_TEST(test_sqlite3PagerSetFlags_cachespill_bit_toggling);237 #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE238 RUN_TEST(test_sqlite3PagerSetFlags_batch_atomic_enables_extraSync);239 #endif240 return UNITY_END();241}