Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_sqlite3BtreePutData.c275 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Helper: create an in-memory DB, begin write tx, create intkey table,7   open write cursor positioned to given rowid with given payload. */8static void helper_make_table_and_cursor(9  sqlite3 **pDb,10  Btree **ppBt,11  BtCursor *pCur,12  Pgno *pRoot,13  i64 rowid,14  const unsigned char *pData,15  int nData16){17  int rc;18  sqlite3 *db = 0;19  Btree *pBt = 0;20  Pgno root = 0;21 22  rc = sqlite3_open(":memory:", &db);23  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);24  TEST_ASSERT_NOT_NULL(db);25 26  /* Access the Btree of the main database. */27  pBt = db->aDb[0].pBt;28  TEST_ASSERT_NOT_NULL(pBt);29 30  sqlite3_mutex_enter(db->mutex);31 32  /* Start write transaction */33  rc = sqlite3BtreeBeginTrans(pBt, 1, 0);34  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);35 36  /* Create a new INTKEY table */37  rc = sqlite3BtreeCreateTable(pBt, &root, BTREE_INTKEY | BTREE_LEAFDATA);38  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);39  TEST_ASSERT_TRUE(root>=2);40 41  /* Open a write cursor on that root */42  memset(pCur, 0, sqlite3BtreeCursorSize());43  rc = sqlite3BtreeCursor(pBt, root, BTREE_WRCSR, 0, pCur);44  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);45 46  /* Insert one record with rowid and data */47  {48    BtreePayload x;49    memset(&x, 0, sizeof(x));50    x.nKey = rowid;51    x.pKey = 0;52    x.pData = (void*)pData;53    x.nData = nData;54    x.nZero = 0;55    rc = sqlite3BtreeInsert(pCur, &x, 0, 0);56    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);57  }58 59  /* Move to that row to ensure cursor is positioned */60  {61    int res = 0;62    rc = sqlite3BtreeTableMoveto(pCur, rowid, 0, &res);63    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);64    TEST_ASSERT_EQUAL_INT(0, res);65  }66 67  /* Mark cursor as incrblob */68  sqlite3BtreeIncrblobCursor(pCur);69 70  sqlite3_mutex_leave(db->mutex);71 72  *pDb = db;73  *ppBt = pBt;74  *pRoot = root;75}76 77/* Helper: read back payload of current row into buffer (must be large enough) */78static int helper_read_payload(sqlite3 *db, BtCursor *pCur, unsigned char *outBuf, int *pnOut){79  int rc;80  sqlite3_mutex_enter(db->mutex);81  TEST_ASSERT_EQUAL_INT(1, sqlite3_mutex_held(db->mutex));82 83  /* Ensure positioned on row */84  /* pCur is expected to already be valid on the row */85  {86    u32 n = sqlite3BtreePayloadSize(pCur);87    if( pnOut ) *pnOut = (int)n;88    rc = sqlite3BtreePayload(pCur, 0, n, outBuf);89  }90 91  sqlite3_mutex_leave(db->mutex);92  return rc;93}94 95/* Helper: cleanup cursor and close db, commit transaction */96static void helper_cleanup(sqlite3 *db, Btree *pBt, BtCursor *pCur){97  int rc;98  sqlite3_mutex_enter(db->mutex);99  rc = sqlite3BtreeCloseCursor(pCur);100  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101  rc = sqlite3BtreeCommit(pBt);102  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);103  sqlite3_mutex_leave(db->mutex);104  sqlite3_close(db);105}106 107void setUp(void) { }108void tearDown(void) { }109 110/* Test 1: basic in-place write within local payload, no overflow */111void test_sqlite3BtreePutData_basic_write(void){112  sqlite3 *db = NULL;113  Btree *pBt = NULL;114  BtCursor cur;115  Pgno root = 0;116  const i64 rowid = 1;117  unsigned char initData[16];118  for(int i=0;i<16;i++) initData[i] = (unsigned char)(0x10 + i);119 120  helper_make_table_and_cursor(&db, &pBt, &cur, &root, rowid, initData, 16);121 122  /* Modify 3 bytes starting at offset 5 */123  unsigned char newBytes[3] = { 0xAA, 0xBB, 0xCC };124 125  sqlite3_mutex_enter(db->mutex);126  int rc = sqlite3BtreePutData(&cur, 5, 3, newBytes);127  sqlite3_mutex_leave(db->mutex);128  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);129 130  /* Check result */131  unsigned char got[32]; int n=0;132  rc = helper_read_payload(db, &cur, got, &n);133  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);134  TEST_ASSERT_EQUAL_INT(16, n);135  /* Verify modified segment */136  for(int i=0;i<16;i++){137    unsigned char expect = initData[i];138    if( i>=5 && i<8 ){139      expect = newBytes[i-5];140    }141    TEST_ASSERT_EQUAL_HEX8_MESSAGE(expect, got[i], "Payload byte mismatch");142  }143 144  helper_cleanup(db, pBt, &cur);145}146 147/* Test 2: read-only cursor returns SQLITE_READONLY */148void test_sqlite3BtreePutData_readonly_cursor(void){149  sqlite3 *db = NULL;150  Btree *pBt = NULL;151  BtCursor writeCur;152  Pgno root = 0;153  const i64 rowid = 7;154  unsigned char initData[12];155  for(int i=0;i<12;i++) initData[i] = (unsigned char)(i);156 157  helper_make_table_and_cursor(&db, &pBt, &writeCur, &root, rowid, initData, 12);158 159  /* Open a read-only cursor on the same table and move to the row */160  BtCursor roCur;161  memset(&roCur, 0, sqlite3BtreeCursorSize());162 163  sqlite3_mutex_enter(db->mutex);164  int rc = sqlite3BtreeCursor(pBt, root, 0 /* read-only */, 0, &roCur);165  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);166  int res = 0;167  rc = sqlite3BtreeTableMoveto(&roCur, rowid, 0, &res);168  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);169  TEST_ASSERT_EQUAL_INT(0, res);170  sqlite3BtreeIncrblobCursor(&roCur);171 172  unsigned char bytes[2] = {0x11, 0x22};173  rc = sqlite3BtreePutData(&roCur, 2, 2, bytes);174  sqlite3_mutex_leave(db->mutex);175 176  TEST_ASSERT_EQUAL_INT(SQLITE_READONLY, rc);177 178  /* Cleanup */179  helper_cleanup(db, pBt, &writeCur);180}181 182/* Test 3: writing past end returns SQLITE_CORRUPT (or equivalent) */183void test_sqlite3BtreePutData_past_end_returns_corrupt(void){184  sqlite3 *db = NULL;185  Btree *pBt = NULL;186  BtCursor cur;187  Pgno root = 0;188  const i64 rowid = 2;189  unsigned char initData[8] = {0,1,2,3,4,5,6,7};190  helper_make_table_and_cursor(&db, &pBt, &cur, &root, rowid, initData, 8);191 192  unsigned char two[2] = {0xFE, 0xED};193  sqlite3_mutex_enter(db->mutex);194  int rc = sqlite3BtreePutData(&cur, 7, 2, two); /* 7..8 -> last byte ok, +1 past end */195  sqlite3_mutex_leave(db->mutex);196 197  TEST_ASSERT_NOT_EQUAL_MESSAGE(SQLITE_OK, rc, "Expected corruption error");198 199  helper_cleanup(db, pBt, &cur);200}201 202/* Test 4: invalid (non-restored) cursor returns SQLITE_ABORT */203void test_sqlite3BtreePutData_invalid_cursor_returns_abort(void){204  sqlite3 *db = NULL;205  Btree *pBt = NULL;206  BtCursor cur;207  Pgno root = 0;208  const i64 rowid = 3;209  unsigned char initData[6] = {9,9,9,9,9,9};210  helper_make_table_and_cursor(&db, &pBt, &cur, &root, rowid, initData, 6);211 212  /* Invalidate cursor without making it require-seek */213  sqlite3_mutex_enter(db->mutex);214  sqlite3BtreeClearCursor(&cur); /* sets eState=CURSOR_INVALID */215  unsigned char b = 0xAB;216  int rc = sqlite3BtreePutData(&cur, 0, 1, &b);217  sqlite3_mutex_leave(db->mutex);218 219  TEST_ASSERT_EQUAL_INT(SQLITE_ABORT, rc);220 221  helper_cleanup(db, pBt, &cur);222}223 224/* Test 5: write on large payload crossing overflow pages */225void test_sqlite3BtreePutData_overflow_write(void){226  sqlite3 *db = NULL;227  Btree *pBt = NULL;228  BtCursor cur;229  Pgno root = 0;230  const i64 rowid = 100;231  /* Create a payload large enough to require overflow pages (e.g., 6000 bytes) */232  int nData = 6000;233  unsigned char *big = (unsigned char*)sqlite3_malloc(nData);234  TEST_ASSERT_NOT_NULL(big);235  for(int i=0;i<nData;i++) big[i] = (unsigned char)(i & 0xFF);236 237  helper_make_table_and_cursor(&db, &pBt, &cur, &root, rowid, big, nData);238 239  /* Write 10 bytes starting at offset 4090 (likely crosses local->overflow boundary) */240  unsigned char patch[10];241  for(int i=0;i<10;i++) patch[i] = (unsigned char)(0xF0 + i);242 243  sqlite3_mutex_enter(db->mutex);244  int rc = sqlite3BtreePutData(&cur, 4090, 10, patch);245  sqlite3_mutex_leave(db->mutex);246 247  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);248 249  /* Read back and verify */250  unsigned char *back = (unsigned char*)sqlite3_malloc(nData);251  TEST_ASSERT_NOT_NULL(back);252  int n=0;253  rc = helper_read_payload(db, &cur, back, &n);254  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);255  TEST_ASSERT_EQUAL_INT(nData, n);256  for(int i=0;i<nData;i++){257    unsigned char expect = big[i];258    if( i>=4090 && i<4100 ) expect = patch[i-4090];259    TEST_ASSERT_EQUAL_HEX8(expect, back[i]);260  }261 262  sqlite3_free(back);263  sqlite3_free(big);264  helper_cleanup(db, pBt, &cur);265}266 267int main(void){268  UNITY_BEGIN();269  RUN_TEST(test_sqlite3BtreePutData_basic_write);270  RUN_TEST(test_sqlite3BtreePutData_readonly_cursor);271  RUN_TEST(test_sqlite3BtreePutData_past_end_returns_corrupt);272  RUN_TEST(test_sqlite3BtreePutData_invalid_cursor_returns_abort);273  RUN_TEST(test_sqlite3BtreePutData_overflow_write);274  return UNITY_END();275}