Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_sqlite3BtreeInsert.c245 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6 7/* Helper: open an in-memory DB and get Btree handle */8static int open_memory_db(sqlite3 **ppDb, Btree **ppBt){9  int rc = sqlite3_open(":memory:", ppDb);10  if( rc!=SQLITE_OK ) return rc;11  *ppBt = (*ppDb)->aDb[0].pBt;12  if( *ppBt==0 ) return SQLITE_ERROR;13  return SQLITE_OK;14}15 16/* Helper: create a new intkey+leafdata table and open a write cursor */17static int make_table_and_cursor(Btree *pBt, Pgno *pRoot, BtCursor *pCur){18  int rc;19  int schemaVersion = 0;20  sqlite3BtreeCursorZero(pCur);21  rc = sqlite3BtreeBeginTrans(pBt, 1, &schemaVersion);22  if( rc!=SQLITE_OK ) return rc;23  rc = sqlite3BtreeCreateTable(pBt, pRoot, BTREE_INTKEY|BTREE_LEAFDATA);24  if( rc!=SQLITE_OK ) return rc;25  rc = sqlite3BtreeCursor(pBt, *pRoot, BTREE_WRCSR, NULL, pCur);26  return rc;27}28 29/* Helper: drop table and close cursor, commit and close db */30static void cleanup_all(sqlite3 *db, Btree *pBt, BtCursor *pCur, Pgno root){31  if( pCur && pCur->pBtree ){32    sqlite3BtreeCloseCursor(pCur);33  }34  if( pBt ){35    int moved = 0;36    /* Ignore error from drop if already gone */37    (void)sqlite3BtreeDropTable(pBt, (int)root, &moved);38    (void)sqlite3BtreeCommit(pBt);39  }40  if( db ){41    sqlite3_close(db);42  }43}44 45/* Helper: insert a row (intkey, data) */46static int insert_row(BtCursor *pCur, i64 rowid, const void *pData, int nData,47                      int flags, int seekResult){48  BtreePayload x;49  memset(&x, 0, sizeof(x));50  x.pKey = NULL;51  x.nKey = rowid;52  x.pData = (void*)pData;53  x.nData = nData;54  x.nZero = 0;55  return sqlite3BtreeInsert(pCur, &x, flags, seekResult);56}57 58/* Helper: fetch a row payload into buf, returning payload size (or <0 on err) */59static int fetch_row(BtCursor *pCur, i64 rowid, void *pBuf, int bufCap){60  int rc, res = 0;61  rc = sqlite3BtreeTableMoveto(pCur, rowid, 0, &res);62  if( rc!=SQLITE_OK ) return -1;63  if( res!=0 ) return -2; /* not found */64  {65    u32 sz = sqlite3BtreePayloadSize(pCur);66    if( (int)sz>bufCap ) return -3;67    rc = sqlite3BtreePayload(pCur, 0, (int)sz, pBuf);68    if( rc!=SQLITE_OK ) return -4;69    return (int)sz;70  }71}72 73void setUp(void) {74  /* nothing */75}76void tearDown(void) {77  /* nothing */78}79 80/* Test 1: basic insert and fetch */81void test_sqlite3BtreeInsert_basic_insert_and_fetch(void){82  sqlite3 *db = NULL;83  Btree *pBt = NULL;84  BtCursor cur;85  Pgno root = 0;86 87  TEST_ASSERT_EQUAL_INT(SQLITE_OK, open_memory_db(&db, &pBt));88  TEST_ASSERT_NOT_NULL(pBt);89 90  TEST_ASSERT_EQUAL_INT(SQLITE_OK, make_table_and_cursor(pBt, &root, &cur));91 92  const char *msg = "hello";93  TEST_ASSERT_EQUAL_INT(SQLITE_OK, insert_row(&cur, 1, msg, (int)strlen(msg), 0, 0));94 95  char buf[16] = {0};96  int got = fetch_row(&cur, 1, buf, sizeof(buf));97  TEST_ASSERT_GREATER_OR_EQUAL(0, got);98  TEST_ASSERT_EQUAL_INT((int)strlen(msg), got);99  buf[got] = '\0';100  TEST_ASSERT_EQUAL_STRING(msg, buf);101 102  cleanup_all(db, pBt, &cur, root);103}104 105/* Test 2: overwrite same-size payload on same key */106void test_sqlite3BtreeInsert_overwrite_same_size(void){107  sqlite3 *db = NULL;108  Btree *pBt = NULL;109  BtCursor cur;110  Pgno root = 0;111 112  TEST_ASSERT_EQUAL_INT(SQLITE_OK, open_memory_db(&db, &pBt));113  TEST_ASSERT_EQUAL_INT(SQLITE_OK, make_table_and_cursor(pBt, &root, &cur));114 115  const char *msg1 = "hello";116  const char *msg2 = "HELLO"; /* same length */117  TEST_ASSERT_EQUAL_INT(SQLITE_OK, insert_row(&cur, 5, msg1, (int)strlen(msg1), 0, 0));118 119  /* Overwrite with same size data – should take overwrite optimization path */120  TEST_ASSERT_EQUAL_INT(SQLITE_OK, insert_row(&cur, 5, msg2, (int)strlen(msg2), 0, 0));121 122  char buf[16] = {0};123  int got = fetch_row(&cur, 5, buf, sizeof(buf));124  TEST_ASSERT_GREATER_OR_EQUAL(0, got);125  TEST_ASSERT_EQUAL_INT((int)strlen(msg2), got);126  buf[got] = '\0';127  TEST_ASSERT_EQUAL_STRING(msg2, buf);128 129  cleanup_all(db, pBt, &cur, root);130}131 132/* Test 3: insert large payload to force overflow pages and verify */133void test_sqlite3BtreeInsert_large_payload_overflow(void){134  sqlite3 *db = NULL;135  Btree *pBt = NULL;136  BtCursor cur;137  Pgno root = 0;138 139  TEST_ASSERT_EQUAL_INT(SQLITE_OK, open_memory_db(&db, &pBt));140  TEST_ASSERT_EQUAL_INT(SQLITE_OK, make_table_and_cursor(pBt, &root, &cur));141 142  const int N = 10000; /* large to ensure overflow */143  char *big = (char*)sqlite3_malloc(N);144  TEST_ASSERT_NOT_NULL(big);145  for(int i=0;i<N;i++) big[i] = (char)('a' + (i%26));146 147  TEST_ASSERT_EQUAL_INT(SQLITE_OK, insert_row(&cur, 42, big, N, 0, 0));148 149  /* Fetch back and verify */150  char *back = (char*)sqlite3_malloc(N);151  TEST_ASSERT_NOT_NULL(back);152  int got = fetch_row(&cur, 42, back, N);153  TEST_ASSERT_EQUAL_INT(N, got);154  TEST_ASSERT_EQUAL_INT(0, memcmp(big, back, N));155 156  sqlite3_free(big);157  sqlite3_free(back);158 159  cleanup_all(db, pBt, &cur, root);160}161 162/* Test 4: BTREE_SAVEPOSITION overwrite while positioned on the row */163void test_sqlite3BtreeInsert_saveposition_overwrite(void){164  sqlite3 *db = NULL;165  Btree *pBt = NULL;166  BtCursor cur;167  Pgno root = 0;168 169  TEST_ASSERT_EQUAL_INT(SQLITE_OK, open_memory_db(&db, &pBt));170  TEST_ASSERT_EQUAL_INT(SQLITE_OK, make_table_and_cursor(pBt, &root, &cur));171 172  const char *msg1 = "abcde";173  const char *msg2 = "12345"; /* same length */174 175  /* Insert initial */176  TEST_ASSERT_EQUAL_INT(SQLITE_OK, insert_row(&cur, 7, msg1, (int)strlen(msg1), 0, 0));177 178  /* Position cursor exactly on the rowid 7 */179  int res=0;180  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3BtreeTableMoveto(&cur, 7, 0, &res));181  TEST_ASSERT_EQUAL_INT(0, res);182 183  /* Overwrite using BTREE_SAVEPOSITION: cursor is already at rowid 7 */184  BtreePayload x;185  memset(&x, 0, sizeof(x));186  x.nKey = 7;187  x.pData = (void*)msg2;188  x.nData = (int)strlen(msg2);189  x.nZero = 0;190  int rc = sqlite3BtreeInsert(&cur, &x, BTREE_SAVEPOSITION, 0);191  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);192 193  /* Verify */194  char buf[16]={0};195  int got = fetch_row(&cur, 7, buf, sizeof(buf));196  TEST_ASSERT_EQUAL_INT((int)strlen(msg2), got);197  buf[got] = '\0';198  TEST_ASSERT_EQUAL_STRING(msg2, buf);199 200  cleanup_all(db, pBt, &cur, root);201}202 203/* Test 5: Append hint with ascending keys */204void test_sqlite3BtreeInsert_append_hint(void){205  sqlite3 *db = NULL;206  Btree *pBt = NULL;207  BtCursor cur;208  Pgno root = 0;209 210  TEST_ASSERT_EQUAL_INT(SQLITE_OK, open_memory_db(&db, &pBt));211  TEST_ASSERT_EQUAL_INT(SQLITE_OK, make_table_and_cursor(pBt, &root, &cur));212 213  const char *msg = "x";214  for(int i=1;i<=100;i++){215    TEST_ASSERT_EQUAL_INT(SQLITE_OK, insert_row(&cur, i, msg, 1, BTREE_APPEND, 0));216  }217 218  /* Move to last and verify */219  int pres = 0;220  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3BtreeLast(&cur, &pres));221  TEST_ASSERT_EQUAL_INT(0, pres); /* table not empty */222 223  /* The last row should be key 100 */224  /* Get current key by reading payload after moving to specific key */225  int res = 0;226  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3BtreeTableMoveto(&cur, 100, 0, &res));227  TEST_ASSERT_EQUAL_INT(0, res);228  u32 sz = sqlite3BtreePayloadSize(&cur);229  TEST_ASSERT_EQUAL_UINT32(1, sz);230  char c;231  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3BtreePayload(&cur, 0, 1, &c));232  TEST_ASSERT_EQUAL_INT('x', c);233 234  cleanup_all(db, pBt, &cur, root);235}236 237int main(void){238  UNITY_BEGIN();239  RUN_TEST(test_sqlite3BtreeInsert_basic_insert_and_fetch);240  RUN_TEST(test_sqlite3BtreeInsert_overwrite_same_size);241  RUN_TEST(test_sqlite3BtreeInsert_large_payload_overflow);242  RUN_TEST(test_sqlite3BtreeInsert_saveposition_overwrite);243  RUN_TEST(test_sqlite3BtreeInsert_append_hint);244  return UNITY_END();245}