AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* The wrapper made available by the module for the static function */7extern int test_pager_write(PgHdr *pPg);8 9/* Minimal stubbed IO methods so that isOpen(jfd) is true and writes succeed */10static int stub_xClose(sqlite3_file* p){ (void)p; return SQLITE_OK; }11static int stub_xRead(sqlite3_file* p, void* b, int a, sqlite3_int64 o){ (void)p;(void)b;(void)a;(void)o; return SQLITE_OK; }12static int stub_xWrite(sqlite3_file* p, const void* b, int a, sqlite3_int64 o){ (void)p;(void)b;(void)a;(void)o; return SQLITE_OK; }13static int stub_xTruncate(sqlite3_file* p, sqlite3_int64 s){ (void)p;(void)s; return SQLITE_OK; }14static int stub_xSync(sqlite3_file* p, int f){ (void)p;(void)f; return SQLITE_OK; }15static int stub_xFileSize(sqlite3_file* p, sqlite3_int64* sz){ (void)p; if(sz)*sz=0; return SQLITE_OK; }16static int stub_xLock(sqlite3_file* p, int l){ (void)p;(void)l; return SQLITE_OK; }17static int stub_xUnlock(sqlite3_file* p, int l){ (void)p;(void)l; return SQLITE_OK; }18static int stub_xCheckReservedLock(sqlite3_file* p, int* r){ (void)p; if(r)*r=0; return SQLITE_OK; }19static int stub_xFileControl(sqlite3_file* p, int op, void* a){ (void)p;(void)op;(void)a; return SQLITE_OK; }20static int stub_xSectorSize(sqlite3_file* p){ (void)p; return 512; }21static int stub_xDeviceCharacteristics(sqlite3_file* p){ (void)p; return 0; }22static int stub_xShmMap(sqlite3_file* p, int a, int b, int c, void volatile** d){ (void)p;(void)a;(void)b;(void)c;(void)d; return SQLITE_OK; }23static int stub_xShmLock(sqlite3_file* p, int a, int b, int c){ (void)p;(void)a;(void)b;(void)c; return SQLITE_OK; }24static void stub_xShmBarrier(sqlite3_file* p){ (void)p; }25static int stub_xShmUnmap(sqlite3_file* p, int d){ (void)p;(void)d; return SQLITE_OK; }26static int stub_xFetch(sqlite3_file* p, sqlite3_int64 o, int a, void** pp){ (void)p;(void)o;(void)a; if(pp)*pp=0; return SQLITE_OK; }27static int stub_xUnfetch(sqlite3_file* p, sqlite3_int64 o, void* q){ (void)p;(void)o;(void)q; return SQLITE_OK; }28 29static const sqlite3_io_methods gStubIoMethods = {30 3, /* iVersion */31 stub_xClose,32 stub_xRead,33 stub_xWrite,34 stub_xTruncate,35 stub_xSync,36 stub_xFileSize,37 stub_xLock,38 stub_xUnlock,39 stub_xCheckReservedLock,40 stub_xFileControl,41 stub_xSectorSize,42 stub_xDeviceCharacteristics,43 stub_xShmMap,44 stub_xShmLock,45 stub_xShmBarrier,46 stub_xShmUnmap,47 stub_xFetch,48 stub_xUnfetch49};50 51static void setup_pcache_and_page(int pageSize, Pgno pgno, PCache **ppCache, PgHdr **ppPg){52 PCache *pCache = 0;53 PgHdr *pPg = 0;54 55 sqlite3PcacheOpen(pageSize, 0, 0, 0, 0, &pCache);56 TEST_ASSERT_NOT_NULL(pCache);57 58 /* createFlag=1 to create if not exists */59 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3PcacheFetch(pCache, pgno, 1, &pPg));60 TEST_ASSERT_NOT_NULL(pPg);61 /* Ensure pgno is set */62 pPg->pgno = pgno;63 64 *ppCache = pCache;65 *ppPg = pPg;66}67 68static Pager* alloc_clear_pager(void){69 Pager *pPager = (Pager*)sqlite3MallocZero(sizeof(Pager));70 TEST_ASSERT_NOT_NULL(pPager);71 return pPager;72}73 74static sqlite3_file* alloc_closed_filehandle(void){75 sqlite3_file *f = (sqlite3_file*)sqlite3MallocZero(sizeof(sqlite3_file));76 TEST_ASSERT_NOT_NULL(f);77 /* pMethods left NULL => isOpen() is false */78 return f;79}80 81static sqlite3_file* alloc_open_stub_filehandle(void){82 sqlite3_file *f = (sqlite3_file*)sqlite3MallocZero(sizeof(sqlite3_file));83 TEST_ASSERT_NOT_NULL(f);84 f->pMethods = &gStubIoMethods; /* isOpen() true, operations succeed */85 return f;86}87 88static void release_pcache_and_page(PCache *pCache, PgHdr *pPg){89 if( pPg ) sqlite3PcacheRelease(pPg);90 if( pCache ) sqlite3PcacheClose(pCache);91}92 93void setUp(void) {94 /* Initialize SQLite global state to ensure pcache/mem are ready */95 sqlite3_initialize();96}97 98void tearDown(void) {99 /* No global teardown necessary here */100}101 102/* Test 1: From WRITER_LOCKED with journal OFF -> transitions to CACHEMOD,103 marks WRITEABLE, updates dbSize, and returns OK. */104void test_pager_write_locked_off_transitions_and_writable(void){105 const int pageSize = 1024;106 const Pgno pgno = 7;107 108 PCache *pCache = 0; PgHdr *pPg = 0;109 setup_pcache_and_page(pageSize, pgno, &pCache, &pPg);110 111 Pager *pPager = alloc_clear_pager();112 pPager->pPCache = pCache;113 pPager->pageSize = pageSize;114 pPager->eState = PAGER_WRITER_LOCKED;115 pPager->errCode = SQLITE_OK;116 pPager->readOnly = 0;117 pPager->tempFile = 0;118 pPager->eLock = RESERVED_LOCK;119 pPager->journalMode = PAGER_JOURNALMODE_OFF;120 pPager->useJournal = 0;121 pPager->pInJournal = 0;122 pPager->setSuper = 0;123 pPager->dbSize = 3;124 pPager->dbOrigSize = 3;125 pPager->dbFileSize = 3;126 pPager->dbHintSize = 3;127 pPager->changeCountDone = 0;128 pPager->jfd = alloc_closed_filehandle(); /* isOpen=false to match pInJournal==0 */129 pPager->nSavepoint = 0;130 131 pPg->pPager = pPager;132 pPg->flags = 0;133 134 int rc = test_pager_write(pPg);135 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);136 TEST_ASSERT_EQUAL_INT(PAGER_WRITER_CACHEMOD, pPager->eState);137 TEST_ASSERT_TRUE(pPg->flags & PGHDR_WRITEABLE);138 TEST_ASSERT_EQUAL_UINT(pgno, pPager->dbSize); /* dbSize grows to pgno */139 140 /* Cleanup */141 sqlite3_free(pPager->jfd);142 sqlite3_free(pPager);143 release_pcache_and_page(pCache, pPg);144}145 146/* Test 2: With pInJournal set and open jfd, pgno>dbOrigSize in CACHEMOD:147 NEED_SYNC is set; WRITEABLE set; dbSize updated; returns OK. */148void test_pager_write_sets_need_sync_on_append_with_journal_cachemod(void){149 const int pageSize = 1024;150 const Pgno pgno = 10;151 152 PCache *pCache = 0; PgHdr *pPg = 0;153 setup_pcache_and_page(pageSize, pgno, &pCache, &pPg);154 155 Pager *pPager = alloc_clear_pager();156 pPager->pPCache = pCache;157 pPager->pageSize = pageSize;158 pPager->eState = PAGER_WRITER_CACHEMOD;159 pPager->errCode = SQLITE_OK;160 pPager->readOnly = 0;161 pPager->tempFile = 0;162 pPager->eLock = RESERVED_LOCK;163 pPager->journalMode = PAGER_JOURNALMODE_MEMORY; /* not OFF -> require useJournal=1 */164 pPager->useJournal = 1;165 pPager->pInJournal = sqlite3BitvecCreate(100);166 TEST_ASSERT_NOT_NULL(pPager->pInJournal);167 pPager->setSuper = 0;168 pPager->dbSize = 2;169 pPager->dbOrigSize = 5;170 pPager->dbFileSize = 5;171 pPager->dbHintSize = 5;172 pPager->changeCountDone = 0;173 pPager->jfd = alloc_open_stub_filehandle(); /* isOpen=true to match pInJournal!=0 */174 pPager->nSavepoint = 0;175 176 pPg->pPager = pPager;177 pPg->flags = 0;178 179 /* Sanity: page not in journal bitvec yet */180 TEST_ASSERT_EQUAL_INT(0, sqlite3BitvecTestNotNull(pPager->pInJournal, pgno));181 182 int rc = test_pager_write(pPg);183 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);184 TEST_ASSERT_TRUE(pPg->flags & PGHDR_WRITEABLE);185 TEST_ASSERT_TRUE(pPg->flags & PGHDR_NEED_SYNC);186 TEST_ASSERT_EQUAL_UINT(pgno, pPager->dbSize);187 188 /* Cleanup */189 sqlite3BitvecDestroy(pPager->pInJournal);190 sqlite3_free(pPager->jfd);191 sqlite3_free(pPager);192 release_pcache_and_page(pCache, pPg);193}194 195/* Test 3: In DBMOD state with journal and pgno>dbOrigSize:196 NEED_SYNC is NOT set (because eState==PAGER_WRITER_DBMOD), but WRITEABLE is set. */197void test_pager_write_no_need_sync_in_dbmod_on_append(void){198 const int pageSize = 1024;199 const Pgno pgno = 12;200 201 PCache *pCache = 0; PgHdr *pPg = 0;202 setup_pcache_and_page(pageSize, pgno, &pCache, &pPg);203 204 Pager *pPager = alloc_clear_pager();205 pPager->pPCache = pCache;206 pPager->pageSize = pageSize;207 pPager->eState = PAGER_WRITER_DBMOD;208 pPager->errCode = SQLITE_OK;209 pPager->readOnly = 0;210 pPager->tempFile = 0;211 pPager->eLock = EXCLUSIVE_LOCK; /* Required for DBMOD */212 pPager->journalMode = PAGER_JOURNALMODE_MEMORY;213 pPager->useJournal = 1;214 pPager->pInJournal = sqlite3BitvecCreate(200);215 TEST_ASSERT_NOT_NULL(pPager->pInJournal);216 pPager->setSuper = 0;217 pPager->dbSize = 4;218 pPager->dbOrigSize = 6;219 pPager->dbFileSize = 6;220 pPager->dbHintSize = 6;221 pPager->changeCountDone = 0;222 pPager->jfd = alloc_open_stub_filehandle();223 pPager->nSavepoint = 0;224 225 pPg->pPager = pPager;226 pPg->flags = 0;227 228 int rc = test_pager_write(pPg);229 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);230 TEST_ASSERT_TRUE(pPg->flags & PGHDR_WRITEABLE);231 TEST_ASSERT_FALSE((pPg->flags & PGHDR_NEED_SYNC) != 0);232 TEST_ASSERT_EQUAL_UINT(pgno, pPager->dbSize);233 234 sqlite3BitvecDestroy(pPager->pInJournal);235 sqlite3_free(pPager->jfd);236 sqlite3_free(pPager);237 release_pcache_and_page(pCache, pPg);238}239 240/* Test 4: With journal and pgno<=dbOrigSize -> page added to rollback journal.241 Verify journal bit set, nRec incremented, journalOff advanced, NEED_SYNC set, and WRITEABLE set. */242void test_pager_write_journals_existing_page_and_sets_bit(void){243 const int pageSize = 1024;244 const Pgno pgno = 5;245 246 PCache *pCache = 0; PgHdr *pPg = 0;247 setup_pcache_and_page(pageSize, pgno, &pCache, &pPg);248 249 Pager *pPager = alloc_clear_pager();250 pPager->pPCache = pCache;251 pPager->pageSize = pageSize;252 pPager->eState = PAGER_WRITER_CACHEMOD;253 pPager->errCode = SQLITE_OK;254 pPager->readOnly = 0;255 pPager->tempFile = 0;256 pPager->eLock = RESERVED_LOCK;257 pPager->journalMode = PAGER_JOURNALMODE_MEMORY;258 pPager->useJournal = 1;259 pPager->pInJournal = sqlite3BitvecCreate(100);260 TEST_ASSERT_NOT_NULL(pPager->pInJournal);261 pPager->setSuper = 0;262 pPager->dbSize = 20; /* dbSize can exceed dbOrigSize */263 pPager->dbOrigSize = 10; /* existing page */264 pPager->dbFileSize = 10;265 pPager->dbHintSize = 10;266 pPager->changeCountDone = 0;267 pPager->jfd = alloc_open_stub_filehandle();268 pPager->nSavepoint = 0;269 pPager->journalOff = 0;270 pPager->nRec = 0;271 272 pPg->pPager = pPager;273 pPg->flags = 0;274 275 /* Pre-conditions */276 TEST_ASSERT_EQUAL_INT(0, sqlite3BitvecTestNotNull(pPager->pInJournal, pgno));277 TEST_ASSERT_EQUAL_INT(0, pPager->nRec);278 TEST_ASSERT_EQUAL_INT(0, pPager->journalOff);279 280 int rc = test_pager_write(pPg);281 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);282 TEST_ASSERT_TRUE(pPg->flags & PGHDR_WRITEABLE);283 TEST_ASSERT_TRUE(pPg->flags & PGHDR_NEED_SYNC);284 TEST_ASSERT_EQUAL_INT(1, pPager->nRec);285 TEST_ASSERT_EQUAL_INT(8 + pageSize, (int)pPager->journalOff);286 TEST_ASSERT_NOT_EQUAL(0, sqlite3BitvecTestNotNull(pPager->pInJournal, pgno));287 288 sqlite3BitvecDestroy(pPager->pInJournal);289 sqlite3_free(pPager->jfd);290 sqlite3_free(pPager);291 release_pcache_and_page(pCache, pPg);292}293 294int main(void){295 UNITY_BEGIN();296 RUN_TEST(test_pager_write_locked_off_transitions_and_writable);297 RUN_TEST(test_pager_write_sets_need_sync_on_append_with_journal_cachemod);298 RUN_TEST(test_pager_write_no_need_sync_in_dbmod_on_append);299 RUN_TEST(test_pager_write_journals_existing_page_and_sets_bit);300 return UNITY_END();301}