Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_sqlite3RollbackAll.c203 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6#include <stdio.h>7 8static int g_rb_hook_count = 0;9static void rollback_hook(void *pArg){10  int *pCnt = (int*)pArg;11  (*pCnt)++;12}13 14static void exec_ok(sqlite3 *db, const char *sql){15  char *zErr = 0;16  int rc = sqlite3_exec(db, sql, 0, 0, &zErr);17  if( rc!=SQLITE_OK ){18    const char *msg = zErr ? zErr : "sqlite3_exec failed";19    TEST_FAIL_MESSAGE(msg);20  }21  if( zErr ) sqlite3_free(zErr);22}23 24static int single_int_query(sqlite3 *db, const char *sql, int *pVal){25  sqlite3_stmt *pStmt = 0;26  int rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, 0);27  if( rc!=SQLITE_OK ) return rc;28  rc = sqlite3_step(pStmt);29  if( rc==SQLITE_ROW ){30    *pVal = sqlite3_column_int(pStmt, 0);31    rc = SQLITE_OK;32  }else if( rc==SQLITE_DONE ){33    /* No rows - set 0 */34    *pVal = 0;35    rc = SQLITE_OK;36  }37  sqlite3_finalize(pStmt);38  return rc;39}40 41void setUp(void) {42  /* empty */43}44void tearDown(void) {45  /* empty */46}47 48/* Test 1: No active transaction -> no rollback hook; counters/flags cleared */49static void test_sqlite3RollbackAll_noop_no_callback(void){50  sqlite3 *db = 0;51  int rc = sqlite3_open(":memory:", &db);52  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);53  TEST_ASSERT_NOT_NULL(db);54 55  g_rb_hook_count = 0;56  sqlite3_rollback_hook(db, rollback_hook, &g_rb_hook_count);57 58  /* Seed internal counters/flags to verify clearing */59  sqlite3_mutex_enter(db->mutex);60  db->nDeferredCons = 5;61  db->nDeferredImmCons = 3;62  db->flags |= ((u64)SQLITE_DeferFKs) | ((u64)SQLITE_CorruptRdOnly);63  sqlite3RollbackAll(db, SQLITE_ABORT);64  sqlite3_mutex_leave(db->mutex);65 66  TEST_ASSERT_EQUAL_INT(0, g_rb_hook_count);67  TEST_ASSERT_EQUAL_INT(0, db->nDeferredCons);68  TEST_ASSERT_EQUAL_INT(0, db->nDeferredImmCons);69  TEST_ASSERT_EQUAL_UINT64(0, (db->flags & (((u64)SQLITE_DeferFKs)|((u64)SQLITE_CorruptRdOnly))));70 71  sqlite3_close(db);72}73 74/* Test 2: Write transaction is rolled back and rollback hook is invoked */75static void test_sqlite3RollbackAll_write_txn_rollback_and_callback(void){76  sqlite3 *db = 0;77  int rc = sqlite3_open(":memory:", &db);78  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);79  TEST_ASSERT_NOT_NULL(db);80 81  g_rb_hook_count = 0;82  sqlite3_rollback_hook(db, rollback_hook, &g_rb_hook_count);83 84  exec_ok(db, "BEGIN");85  exec_ok(db, "CREATE TABLE t(a)");86  exec_ok(db, "INSERT INTO t VALUES(1)");87 88  /* Verify table visible inside txn */89  int cnt = -1;90  rc = single_int_query(db, "SELECT count(*) FROM sqlite_master WHERE name='t'", &cnt);91  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);92  TEST_ASSERT_EQUAL_INT(1, cnt);93 94  /* Roll back all with trip code */95  sqlite3_mutex_enter(db->mutex);96  sqlite3RollbackAll(db, SQLITE_ABORT);97  sqlite3_mutex_leave(db->mutex);98 99  /* Rollback hook should have fired exactly once */100  TEST_ASSERT_EQUAL_INT(1, g_rb_hook_count);101 102  /* Table t should no longer exist */103  cnt = -1;104  rc = single_int_query(db, "SELECT count(*) FROM sqlite_master WHERE name='t'", &cnt);105  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);106  TEST_ASSERT_EQUAL_INT(0, cnt);107 108  /* Statement using t should now fail */109  sqlite3_stmt *pStmt = 0;110  rc = sqlite3_prepare_v2(db, "SELECT * FROM t", -1, &pStmt, 0);111  /* Prepare may fail already since schema no longer has 't' */112  if( rc==SQLITE_OK ){113    rc = sqlite3_step(pStmt);114    TEST_ASSERT_TRUE(rc==SQLITE_ERROR || rc==SQLITE_SCHEMA);115  }else{116    TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);117  }118  if( pStmt ) sqlite3_finalize(pStmt);119 120  sqlite3_close(db);121}122 123/* Test 3: Read-only transaction (no write btree) still invokes rollback hook */124static void test_sqlite3RollbackAll_read_only_txn_callback(void){125  sqlite3 *db = 0;126  int rc = sqlite3_open(":memory:", &db);127  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);128  TEST_ASSERT_NOT_NULL(db);129 130  g_rb_hook_count = 0;131  sqlite3_rollback_hook(db, rollback_hook, &g_rb_hook_count);132 133  exec_ok(db, "BEGIN");      /* Start a transaction but do not write */134  exec_ok(db, "SELECT 1");   /* Ensure the connection is active */135 136  sqlite3_mutex_enter(db->mutex);137  sqlite3RollbackAll(db, SQLITE_OK);138  sqlite3_mutex_leave(db->mutex);139 140  /* Even without a write txn, !autoCommit implies the hook is called */141  TEST_ASSERT_EQUAL_INT(1, g_rb_hook_count);142 143  sqlite3_close(db);144}145 146/* Test 4: Schema-change path expires prepared statements */147static void test_sqlite3RollbackAll_expires_prepared_statements_on_schema_change(void){148  sqlite3 *db = 0;149  int rc = sqlite3_open(":memory:", &db);150  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);151  TEST_ASSERT_NOT_NULL(db);152 153  /* Prepare a simple statement */154  sqlite3_stmt *pStmt = 0;155  rc = sqlite3_prepare_v2(db, "SELECT 1", -1, &pStmt, 0);156  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);157  TEST_ASSERT_NOT_NULL(pStmt);158 159  /* Force schemaChange path: set DBFLAG_SchemaChange while init.busy==0 */160  sqlite3_mutex_enter(db->mutex);161  db->mDbFlags |= DBFLAG_SchemaChange;162  /* Call rollback-all to trigger sqlite3ExpirePreparedStatements + schema reset */163  sqlite3RollbackAll(db, SQLITE_OK);164  sqlite3_mutex_leave(db->mutex);165 166  /* The prepared statement should now be expired -> first step returns SQLITE_SCHEMA */167  rc = sqlite3_step(pStmt);168  TEST_ASSERT_EQUAL_INT(SQLITE_SCHEMA, rc);169  sqlite3_finalize(pStmt);170 171  sqlite3_close(db);172}173 174/* Test 5: Counters and flags are reset by sqlite3RollbackAll */175static void test_sqlite3RollbackAll_resets_deferred_counters_and_flags(void){176  sqlite3 *db = 0;177  int rc = sqlite3_open(":memory:", &db);178  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);179  TEST_ASSERT_NOT_NULL(db);180 181  sqlite3_mutex_enter(db->mutex);182  db->nDeferredCons = 42;183  db->nDeferredImmCons = 7;184  db->flags |= ((u64)SQLITE_DeferFKs) | ((u64)SQLITE_CorruptRdOnly);185  sqlite3RollbackAll(db, SQLITE_OK);186  sqlite3_mutex_leave(db->mutex);187 188  TEST_ASSERT_EQUAL_INT(0, db->nDeferredCons);189  TEST_ASSERT_EQUAL_INT(0, db->nDeferredImmCons);190  TEST_ASSERT_EQUAL_UINT64(0, (db->flags & (((u64)SQLITE_DeferFKs)|((u64)SQLITE_CorruptRdOnly))));191 192  sqlite3_close(db);193}194 195int main(void){196  UNITY_BEGIN();197  RUN_TEST(test_sqlite3RollbackAll_noop_no_callback);198  RUN_TEST(test_sqlite3RollbackAll_write_txn_rollback_and_callback);199  RUN_TEST(test_sqlite3RollbackAll_read_only_txn_callback);200  RUN_TEST(test_sqlite3RollbackAll_expires_prepared_statements_on_schema_change);201  RUN_TEST(test_sqlite3RollbackAll_resets_deferred_counters_and_flags);202  return UNITY_END();203}