AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Unity setup/teardown */7void setUp(void) {8 /* Nothing to set up globally */9}10void tearDown(void) {11 /* Nothing to clean up globally */12}13 14/* Helper: allocate a zeroed Pager with minimal initialization suitable for15** exercising sqlite3PagerSavepoint without triggering I/O or WAL playback.16*/17static Pager* allocMinimalPager(void){18 Pager *p = (Pager*)sqlite3MallocZero(sizeof(*p));19 TEST_ASSERT_NOT_NULL(p);20 /* Ensure we are not in an error state */21 p->errCode = SQLITE_OK;22 23 /* Avoid entering pagerPlaybackSavepoint path:24 ** - No WAL25 ** - No open journal files26 */27 p->pWal = 0;28 /* jfd/sjfd will remain NULL/0 (isOpen() should evaluate false) */29 30 /* Some reasonable default pageSize for any arithmetic, though we avoid using it */31 p->pageSize = 4096;32 33 /* Initialize other fields used indirectly in surrounding code to benign values */34 p->nSavepoint = 0;35 p->aSavepoint = 0;36 p->nSubRec = 0;37 38 return p;39}40 41/* Helper: allocate array of PagerSavepoint with given count and attach to pPager. */42static void pagerInitSavepoints(Pager *pPager, int nSavepoint){43 PagerSavepoint *a = 0;44 if( nSavepoint>0 ){45 a = (PagerSavepoint*)sqlite3MallocZero(sizeof(PagerSavepoint) * (size_t)nSavepoint);46 TEST_ASSERT_NOT_NULL(a);47 }48 pPager->aSavepoint = a;49 pPager->nSavepoint = nSavepoint;50}51 52/* Test: No-op when iSavepoint >= nSavepoint (release) */53static void test_sqlite3PagerSavepoint_noop_when_index_out_of_range_release(void){54 Pager *p = allocMinimalPager();55 pagerInitSavepoints(p, 2);56 57 /* Ensure pInSavepoint are NULL to avoid any accidental frees */58 /* iSavepoint >= nSavepoint -> no-op */59 int rc = sqlite3PagerSavepoint(p, SAVEPOINT_RELEASE, 2); /* iSavepoint == nSavepoint */60 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);61 TEST_ASSERT_EQUAL_INT(2, p->nSavepoint);62 63 rc = sqlite3PagerSavepoint(p, SAVEPOINT_RELEASE, 5); /* clearly out of range */64 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);65 TEST_ASSERT_EQUAL_INT(2, p->nSavepoint);66 67 sqlite3_free(p->aSavepoint);68 sqlite3_free(p);69}70 71/* Test: No-op when iSavepoint >= nSavepoint (rollback) */72static void test_sqlite3PagerSavepoint_noop_when_index_out_of_range_rollback(void){73 Pager *p = allocMinimalPager();74 pagerInitSavepoints(p, 1);75 76 int rc = sqlite3PagerSavepoint(p, SAVEPOINT_ROLLBACK, 1); /* iSavepoint == nSavepoint */77 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);78 TEST_ASSERT_EQUAL_INT(1, p->nSavepoint);79 80 rc = sqlite3PagerSavepoint(p, SAVEPOINT_ROLLBACK, 99);81 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);82 TEST_ASSERT_EQUAL_INT(1, p->nSavepoint);83 84 sqlite3_free(p->aSavepoint);85 sqlite3_free(p);86}87 88/* Test: SAVEPOINT_RELEASE reduces nSavepoint to iSavepoint, and destroys affected bitvecs.89 Setup nSavepoint=3, release savepoint 1 => remaining nSavepoint=1, elements 1 and 2 destroyed. */90static void test_sqlite3PagerSavepoint_release_shrinks_and_destroys(void){91 Pager *p = allocMinimalPager();92 pagerInitSavepoints(p, 3);93 94 /* Prepare bitvecs that should be destroyed by the operation (indices 1 and 2) */95 p->aSavepoint[0].pInSavepoint = 0; /* remains, do not allocate to avoid freeing it */96 p->aSavepoint[1].pInSavepoint = sqlite3BitvecCreate(32);97 p->aSavepoint[2].pInSavepoint = sqlite3BitvecCreate(64);98 99 /* Mark truncate flag true but sjfd is closed, so truncation path is skipped safely */100 p->aSavepoint[1].bTruncateOnRelease = 1;101 p->aSavepoint[1].iSubRec = 7;102 p->aSavepoint[2].bTruncateOnRelease = 1;103 p->aSavepoint[2].iSubRec = 9;104 105 int rc = sqlite3PagerSavepoint(p, SAVEPOINT_RELEASE, 1);106 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);107 TEST_ASSERT_EQUAL_INT(1, p->nSavepoint);108 109 /* We cannot directly verify that Bitvecs were freed without risking double-free,110 but reaching here without crash and correct nSavepoint indicates expected behavior. */111 112 /* Clean up: the remaining savepoint [0] has NULL Bitvec, safe to free array */113 sqlite3_free(p->aSavepoint);114 sqlite3_free(p);115}116 117/* Test: SAVEPOINT_ROLLBACK reduces nSavepoint to iSavepoint+1, and destroys later bitvecs.118 Setup nSavepoint=3, rollback to 1 => remaining nSavepoint=2, element 2 destroyed. */119static void test_sqlite3PagerSavepoint_rollback_shrinks_and_destroys(void){120 Pager *p = allocMinimalPager();121 pagerInitSavepoints(p, 3);122 123 /* Only index 2 will be destroyed; leave others NULL. */124 p->aSavepoint[2].pInSavepoint = sqlite3BitvecCreate(16);125 126 int rc = sqlite3PagerSavepoint(p, SAVEPOINT_ROLLBACK, 1);127 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);128 TEST_ASSERT_EQUAL_INT(2, p->nSavepoint);129 130 sqlite3_free(p->aSavepoint);131 sqlite3_free(p);132}133 134/* Test: SAVEPOINT_ROLLBACK with negative iSavepoint "rolls back transaction":135 For iSavepoint=-1 and nSavepoint=2 => remaining nSavepoint=0; both are destroyed. */136static void test_sqlite3PagerSavepoint_rollback_negative_rolls_all(void){137 Pager *p = allocMinimalPager();138 pagerInitSavepoints(p, 2);139 140 /* Both entries expected to be destroyed */141 p->aSavepoint[0].pInSavepoint = sqlite3BitvecCreate(8);142 p->aSavepoint[1].pInSavepoint = sqlite3BitvecCreate(8);143 144 int rc = sqlite3PagerSavepoint(p, SAVEPOINT_ROLLBACK, -1);145 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);146 TEST_ASSERT_EQUAL_INT(0, p->nSavepoint);147 148 sqlite3_free(p->aSavepoint);149 sqlite3_free(p);150}151 152/* Test: Error propagation if pPager->errCode is non-OK */153static void test_sqlite3PagerSavepoint_propagates_errcode(void){154 Pager *p = allocMinimalPager();155 pagerInitSavepoints(p, 3);156 157 /* Set a non-OK error state; function should return this and do nothing. */158 p->errCode = SQLITE_IOERR;159 160 int rc = sqlite3PagerSavepoint(p, SAVEPOINT_ROLLBACK, 1);161 TEST_ASSERT_EQUAL_INT(SQLITE_IOERR, rc);162 TEST_ASSERT_EQUAL_INT(3, p->nSavepoint);163 164 rc = sqlite3PagerSavepoint(p, SAVEPOINT_RELEASE, 0);165 TEST_ASSERT_EQUAL_INT(SQLITE_IOERR, rc);166 TEST_ASSERT_EQUAL_INT(3, p->nSavepoint);167 168 sqlite3_free(p->aSavepoint);169 sqlite3_free(p);170}171 172int main(void){173 UNITY_BEGIN();174 175 RUN_TEST(test_sqlite3PagerSavepoint_noop_when_index_out_of_range_release);176 RUN_TEST(test_sqlite3PagerSavepoint_noop_when_index_out_of_range_rollback);177 RUN_TEST(test_sqlite3PagerSavepoint_release_shrinks_and_destroys);178 RUN_TEST(test_sqlite3PagerSavepoint_rollback_shrinks_and_destroys);179 RUN_TEST(test_sqlite3PagerSavepoint_rollback_negative_rolls_all);180 RUN_TEST(test_sqlite3PagerSavepoint_propagates_errcode);181 182 return UNITY_END();183}