Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_sqlite3BtreeRollback.c191 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3 4#include <string.h>5 6/* Helper: open an in-memory btree */7static Btree* helper_open_btree(sqlite3 **ppDb){8  int rc;9  sqlite3 *db = 0;10  rc = sqlite3_open(":memory:", &db);11  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);12  sqlite3_vfs *pVfs = sqlite3_vfs_find(0);13  TEST_ASSERT_NOT_NULL(pVfs);14 15  Btree *p = 0;16  rc = sqlite3BtreeOpen(pVfs, 0, db, &p, 0,17                        SQLITE_OPEN_MEMORY | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);18  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);19  TEST_ASSERT_NOT_NULL(p);20  *ppDb = db;21  return p;22}23 24/* Helper: close btree and db */25static void helper_close_btree(sqlite3 *db, Btree *p){26  if( p ){27    /* Ensure no cursors left unclosed */28    sqlite3BtreeClose(p);29  }30  if( db ){31    sqlite3_close(db);32  }33}34 35void setUp(void){36  /* nothing */37}38void tearDown(void){39  /* nothing */40}41 42/* Test 1: Basic rollback with tripCode==SQLITE_OK and no cursors. */43void test_sqlite3BtreeRollback_basic_ok(void){44  sqlite3 *db = 0;45  Btree *p = helper_open_btree(&db);46 47  int rc;48  rc = sqlite3BtreeBeginTrans(p, 1, 0);49  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);50 51  /* Verify state before rollback */52  TEST_ASSERT_EQUAL_INT(TRANS_WRITE, p->inTrans);53  TEST_ASSERT_EQUAL_INT(TRANS_WRITE, p->pBt->inTransaction);54 55  rc = sqlite3BtreeRollback(p, SQLITE_OK, 0);56  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);57 58  /* After rollback, both btree and shared should be out of transaction */59  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->inTrans);60  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->pBt->inTransaction);61 62  helper_close_btree(db, p);63}64 65/* Test 2: trip write cursor on non-OK tripCode (writeOnly=1). */66void test_sqlite3BtreeRollback_trips_write_cursor_on_error(void){67  sqlite3 *db = 0;68  Btree *p = helper_open_btree(&db);69  int rc = sqlite3BtreeBeginTrans(p, 1, 0);70  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);71 72  /* Create a table and open a write cursor */73  Pgno root = 0;74  rc = sqlite3BtreeCreateTable(p, &root, BTREE_INTKEY|BTREE_LEAFDATA);75  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);76  TEST_ASSERT_TRUE(root > 0);77 78  BtCursor cur;79  sqlite3BtreeCursorZero(&cur);80  rc = sqlite3BtreeCursor(p, root, BTREE_WRCSR, 0, &cur);81  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);82 83  /* Now rollback with error code -> cursor should be tripped */84  rc = sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 1);85  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); /* Function returns pager rc, trip done internally */86 87  TEST_ASSERT_EQUAL_INT(CURSOR_FAULT, cur.eState);88  TEST_ASSERT_EQUAL_INT(SQLITE_ABORT_ROLLBACK, cur.skipNext);89 90  /* Transaction cleared */91  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->inTrans);92  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->pBt->inTransaction);93 94  sqlite3BtreeCloseCursor(&cur);95  helper_close_btree(db, p);96}97 98/* Test 3: tripCode==SQLITE_OK but saveAllCursors fails due to pinned valid cursor.99** Expect function returns SQLITE_CONSTRAINT_PINNED, trips cursor, and clears txn.100*/101void test_sqlite3BtreeRollback_ok_with_pinned_valid_cursor_returns_constraint_and_trips(void){102  sqlite3 *db = 0;103  Btree *p = helper_open_btree(&db);104  int rc = sqlite3BtreeBeginTrans(p, 1, 0);105  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);106 107  /* Create a table and open a write cursor */108  Pgno root = 0;109  rc = sqlite3BtreeCreateTable(p, &root, BTREE_INTKEY|BTREE_LEAFDATA);110  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);111 112  BtCursor cur;113  sqlite3BtreeCursorZero(&cur);114  rc = sqlite3BtreeCursor(p, root, BTREE_WRCSR, 0, &cur);115  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);116 117  /* Insert a single row so the cursor can be valid */118  BtreePayload x;119  memset(&x, 0, sizeof(x));120  x.nKey = 1;      /* rowid */121  x.pKey = 0;      /* intkey table */122  x.pData = 0;123  x.nData = 0;124  x.nZero = 0;125  rc = sqlite3BtreeInsert(&cur, &x, BTREE_APPEND, 0);126  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);127 128  /* Move to first to force CURSOR_VALID */129  int isEmpty = 0;130  rc = sqlite3BtreeFirst(&cur, &isEmpty);131  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);132  TEST_ASSERT_EQUAL_INT(0, isEmpty);133  TEST_ASSERT_EQUAL_INT(CURSOR_VALID, cur.eState);134 135  /* Pin the cursor so saveCursorPosition() fails with SQLITE_CONSTRAINT_PINNED */136  sqlite3BtreeCursorPin(&cur);137 138  rc = sqlite3BtreeRollback(p, SQLITE_OK, 1);139  TEST_ASSERT_EQUAL_INT(SQLITE_CONSTRAINT_PINNED, rc);140 141  /* Should have tripped cursor (writeOnly forced to 0 on failure) */142  TEST_ASSERT_EQUAL_INT(CURSOR_FAULT, cur.eState);143 144  /* Transaction cleared */145  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->inTrans);146  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->pBt->inTransaction);147 148  sqlite3BtreeCloseCursor(&cur);149  helper_close_btree(db, p);150}151 152/* Test 4: tripCode==SQLITE_OK with an unpinned invalid cursor: no trip occurs. */153void test_sqlite3BtreeRollback_ok_does_not_trip_unpinned_invalid_cursor(void){154  sqlite3 *db = 0;155  Btree *p = helper_open_btree(&db);156  int rc = sqlite3BtreeBeginTrans(p, 1, 0);157  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);158 159  /* Create a table and open a write cursor; table is empty so cursor is invalid */160  Pgno root = 0;161  rc = sqlite3BtreeCreateTable(p, &root, BTREE_INTKEY|BTREE_LEAFDATA);162  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);163 164  BtCursor cur;165  sqlite3BtreeCursorZero(&cur);166  rc = sqlite3BtreeCursor(p, root, BTREE_WRCSR, 0, &cur);167  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);168  TEST_ASSERT_TRUE(cur.eState==CURSOR_INVALID);169 170  rc = sqlite3BtreeRollback(p, SQLITE_OK, 1);171  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);172 173  /* Cursor should not be tripped to FAULT */174  TEST_ASSERT_TRUE(cur.eState!=CURSOR_FAULT);175 176  /* Transaction cleared */177  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->inTrans);178  TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->pBt->inTransaction);179 180  sqlite3BtreeCloseCursor(&cur);181  helper_close_btree(db, p);182}183 184int main(void){185  UNITY_BEGIN();186  RUN_TEST(test_sqlite3BtreeRollback_basic_ok);187  RUN_TEST(test_sqlite3BtreeRollback_trips_write_cursor_on_error);188  RUN_TEST(test_sqlite3BtreeRollback_ok_with_pinned_valid_cursor_returns_constraint_and_trips);189  RUN_TEST(test_sqlite3BtreeRollback_ok_does_not_trip_unpinned_invalid_cursor);190  return UNITY_END();191}