AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Globals for tests */7static sqlite3 *gDb = NULL;8static Btree *gBt = NULL;9 10/* Unity setUp and tearDown */11void setUp(void) {12 int rc = sqlite3_open(":memory:", &gDb);13 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);14 TEST_ASSERT_NOT_NULL(gDb);15 16 /* Main database btree */17 TEST_ASSERT_NOT_NULL(gDb->aDb);18 TEST_ASSERT_NOT_NULL(gDb->aDb[0].pBt);19 gBt = gDb->aDb[0].pBt;20}21 22void tearDown(void) {23 if (gDb) {24 /* Ensure db->mutex not held here */25 sqlite3_close(gDb);26 gDb = NULL;27 gBt = NULL;28 }29}30 31/* Helper: begin a write transaction, returning schema version if requested */32static int begin_write_txn(int *pSchemaVersion){33 int rc;34 sqlite3_mutex_enter(gDb->mutex);35 rc = sqlite3BtreeBeginTrans(gBt, 1, pSchemaVersion);36 sqlite3_mutex_leave(gDb->mutex);37 return rc;38}39 40/* Helper: release a statement savepoint at index iSavepoint */41static int release_stmt_sp(int iSavepoint){42 int rc;43 sqlite3_mutex_enter(gDb->mutex);44 rc = sqlite3BtreeSavepoint(gBt, SAVEPOINT_RELEASE, iSavepoint);45 sqlite3_mutex_leave(gDb->mutex);46 return rc;47}48 49/* Helper: rollback a statement savepoint at index iSavepoint */50static int rollback_stmt_sp(int iSavepoint){51 int rc;52 sqlite3_mutex_enter(gDb->mutex);53 rc = sqlite3BtreeSavepoint(gBt, SAVEPOINT_ROLLBACK, iSavepoint);54 sqlite3_mutex_leave(gDb->mutex);55 return rc;56}57 58/* Helper: commit the current write transaction */59static int commit_txn(void){60 int rc;61 sqlite3_mutex_enter(gDb->mutex);62 rc = sqlite3BtreeCommit(gBt);63 sqlite3_mutex_leave(gDb->mutex);64 return rc;65}66 67/* Helper: start a fresh write transaction (after commit) */68static int restart_write_txn(void){69 int rc;70 int schema = 0;71 sqlite3_mutex_enter(gDb->mutex);72 rc = sqlite3BtreeBeginTrans(gBt, 1, &schema);73 sqlite3_mutex_leave(gDb->mutex);74 return rc;75}76 77/* Test 1: Basic success path: begin write txn, begin stmt, release */78void test_sqlite3BtreeBeginStmt_basic_ok(void){79 int rc;80 int schema = 0;81 82 rc = begin_write_txn(&schema);83 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);84 85 /* db->nSavepoint should be 0 initially; iStatement must be > nSavepoint */86 sqlite3_mutex_enter(gDb->mutex);87 TEST_ASSERT_EQUAL_INT(0, gDb->nSavepoint);88 sqlite3_mutex_leave(gDb->mutex);89 90 sqlite3_mutex_enter(gDb->mutex);91 rc = sqlite3BtreeBeginStmt(gBt, 1);92 sqlite3_mutex_leave(gDb->mutex);93 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);94 95 rc = release_stmt_sp(1);96 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);97 98 /* Clean up transaction */99 rc = commit_txn();100 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101}102 103/* Test 2: Multiple statement-level savepoints can be opened and released */104void test_sqlite3BtreeBeginStmt_multiple_levels(void){105 int rc;106 rc = begin_write_txn(NULL);107 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);108 109 sqlite3_mutex_enter(gDb->mutex);110 rc = sqlite3BtreeBeginStmt(gBt, 1);111 sqlite3_mutex_leave(gDb->mutex);112 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);113 114 sqlite3_mutex_enter(gDb->mutex);115 rc = sqlite3BtreeBeginStmt(gBt, 2);116 sqlite3_mutex_leave(gDb->mutex);117 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);118 119 rc = release_stmt_sp(2);120 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);121 rc = release_stmt_sp(1);122 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);123 124 rc = commit_txn();125 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);126}127 128/* Test 3: Rollback a statement savepoint created by sqlite3BtreeBeginStmt */129void test_sqlite3BtreeBeginStmt_rollback_savepoint(void){130 int rc;131 rc = begin_write_txn(NULL);132 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);133 134 sqlite3_mutex_enter(gDb->mutex);135 rc = sqlite3BtreeBeginStmt(gBt, 1);136 sqlite3_mutex_leave(gDb->mutex);137 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);138 139 rc = rollback_stmt_sp(1);140 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);141 142 rc = commit_txn();143 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);144}145 146/* Test 4: Begin stmt savepoint, commit transaction (auto-closes), then restart */147void test_sqlite3BtreeBeginStmt_after_commit_restart(void){148 int rc;149 150 rc = begin_write_txn(NULL);151 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);152 153 sqlite3_mutex_enter(gDb->mutex);154 rc = sqlite3BtreeBeginStmt(gBt, 1);155 sqlite3_mutex_leave(gDb->mutex);156 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);157 158 /* Commit the write transaction; statement-level savepoint is auto-closed */159 rc = commit_txn();160 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);161 162 /* Start a new write transaction and begin a new statement-level savepoint */163 rc = restart_write_txn();164 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);165 166 sqlite3_mutex_enter(gDb->mutex);167 rc = sqlite3BtreeBeginStmt(gBt, 1);168 sqlite3_mutex_leave(gDb->mutex);169 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);170 171 rc = release_stmt_sp(1);172 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);173 174 rc = commit_txn();175 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);176}177 178int main(void){179 UNITY_BEGIN();180 RUN_TEST(test_sqlite3BtreeBeginStmt_basic_ok);181 RUN_TEST(test_sqlite3BtreeBeginStmt_multiple_levels);182 RUN_TEST(test_sqlite3BtreeBeginStmt_rollback_savepoint);183 RUN_TEST(test_sqlite3BtreeBeginStmt_after_commit_restart);184 return UNITY_END();185}