Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_insertCellFast.c224 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* The test harness provides a global wrapper for the static function. */7extern int test_insertCellFast(MemPage *pPage, int i, u8 *pCell, int sz);8 9/* Helpers: create a new in-memory DB and return it */10static sqlite3* open_memory_db(void){11  sqlite3 *db = 0;12  int rc = sqlite3_open(":memory:", &db);13  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);14  TEST_ASSERT_NOT_NULL(db);15  return db;16}17 18/* Helpers: begin a write transaction and create a new table using Btree API.19** Returns root page number via *pRoot. */20static void begin_and_create(Btree *pBt, Pgno *pRoot){21  int rc;22  sqlite3BtreeEnter(pBt);23  rc = sqlite3BtreeBeginTrans(pBt, 1, 0);24  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);25  rc = sqlite3BtreeCreateTable(pBt, pRoot, BTREE_INTKEY|BTREE_LEAFDATA);26  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);27  sqlite3BtreeLeave(pBt);28}29 30/* Helpers: open a write cursor on a given root page and ensure its MemPage is loaded. */31static BtCursor* open_write_cursor_loaded(Btree *pBt, Pgno root){32  int rc, isEmpty;33  BtCursor *pCur = (BtCursor*)sqlite3Malloc(sqlite3BtreeCursorSize());34  TEST_ASSERT_NOT_NULL(pCur);35  sqlite3BtreeEnter(pBt);36  sqlite3BtreeCursorZero(pCur);37  rc = sqlite3BtreeCursor(pBt, root, BTREE_WRCSR, 0, pCur);38  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);39  /* Force page to be loaded */40  rc = sqlite3BtreeFirst(pCur, &isEmpty);41  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);42  TEST_ASSERT_NOT_NULL(pCur->pPage);43  sqlite3BtreeLeave(pBt);44  return pCur;45}46 47/* cell builder: build a minimal table-leaf cell with 0 payload and 1-byte rowid varint.48** Returns size 4 bytes as per minimum cell size rule. */49static void build_min_table_leaf_cell(u8 rowidByte, u8 *out /* size>=4 */, int *pSz){50  /* Format: [varint payload-size=0x00][varint rowid=rowidByte] plus padding to 4 bytes */51  out[0] = 0x00;        /* nPayload = 0 */52  out[1] = rowidByte;   /* small varint rowid */53  out[2] = 0x00;        /* padding */54  out[3] = 0x00;        /* padding */55  *pSz = 4;56}57 58void setUp(void) {59  /* empty */60}61 62void tearDown(void) {63  /* empty */64}65 66/* Test 1: Basic insertion into an empty leaf page */67void test_insertCellFast_basic_insert_into_empty_leaf(void){68  sqlite3 *db = open_memory_db();69  /* Main database btree handle */70  Btree *pBt = db->aDb[0].pBt;71  TEST_ASSERT_NOT_NULL(pBt);72 73  Pgno root = 0;74  begin_and_create(pBt, &root);75 76  /* Open cursor and load page */77  BtCursor *pCur = open_write_cursor_loaded(pBt, root);78 79  /* Pre-conditions: empty leaf page */80  sqlite3BtreeEnter(pBt);81  MemPage *pPage = pCur->pPage;82  TEST_ASSERT_NOT_NULL(pPage);83  TEST_ASSERT_EQUAL_UINT16(0, pPage->nCell);84  TEST_ASSERT_TRUE(pPage->leaf!=0);85  TEST_ASSERT_TRUE(pPage->intKeyLeaf!=0);86 87  /* Build a minimal valid cell */88  u8 cell[8];89  int sz = 0;90  build_min_table_leaf_cell(0x2A, cell, &sz);91  TEST_ASSERT_EQUAL_INT(4, sz);92 93  /* Call the target wrapper */94  int rc = test_insertCellFast(pPage, 0, cell, sz);95  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);96 97  /* Verify results: one cell inserted */98  TEST_ASSERT_EQUAL_UINT16(1, pPage->nCell);99  TEST_ASSERT_EQUAL_UINT16(0, pPage->nOverflow);100 101  /* Verify the cell-pointer points to data that starts with (0x00, 0x2A) */102  int hdr = pPage->hdrOffset;103  u16 off = get2byte(&pPage->aCellIdx[0]);104  TEST_ASSERT_TRUE(off >= pPage->cellOffset); /* plausible offset */105  TEST_ASSERT_TRUE(off+2 <= pPage->pBt->usableSize);106  TEST_ASSERT_EQUAL_UINT8(0x00, pPage->aData[off+0]);107  TEST_ASSERT_EQUAL_UINT8(0x2A, pPage->aData[off+1]);108 109  sqlite3BtreeLeave(pBt);110 111  /* Cleanup */112  sqlite3BtreeEnter(pBt);113  sqlite3BtreeCloseCursor(pCur);114  sqlite3BtreeCommit(pBt);115  sqlite3BtreeLeave(pBt);116  sqlite3_free(pCur);117  sqlite3_close(db);118}119 120/* Test 2: Force overflow-array path (no space) without touching page body */121void test_insertCellFast_overflow_slot_when_no_free_space(void){122  sqlite3 *db = open_memory_db();123  Btree *pBt = db->aDb[0].pBt;124  TEST_ASSERT_NOT_NULL(pBt);125 126  Pgno root = 0;127  begin_and_create(pBt, &root);128  BtCursor *pCur = open_write_cursor_loaded(pBt, root);129 130  sqlite3BtreeEnter(pBt);131  MemPage *pPage = pCur->pPage;132  TEST_ASSERT_NOT_NULL(pPage);133  TEST_ASSERT_EQUAL_UINT16(0, pPage->nCell);134  TEST_ASSERT_EQUAL_UINT16(0, pPage->nOverflow);135 136  /* Artificially force low free space to trigger overflow-slot path */137  u16 savedFree = pPage->nFree;138  pPage->nFree = 0;139 140  u8 cell[4];141  int sz = 0;142  build_min_table_leaf_cell(0x01, cell, &sz);143 144  int rc = test_insertCellFast(pPage, 0, cell, sz);145  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);146 147  /* Verify overflow queued */148  TEST_ASSERT_EQUAL_UINT16(1, pPage->nOverflow);149  TEST_ASSERT_EQUAL_PTR(cell, pPage->apOvfl[0]);150  TEST_ASSERT_EQUAL_UINT16(0, pPage->aiOvfl[0]);151  TEST_ASSERT_EQUAL_UINT16(0, pPage->nCell);152 153  /* Restore free space to avoid leaving the page inconsistent for subsequent ops */154  pPage->nFree = savedFree;155 156  sqlite3BtreeLeave(pBt);157 158  /* Cleanup */159  sqlite3BtreeEnter(pBt);160  sqlite3BtreeCloseCursor(pCur);161  sqlite3BtreeCommit(pBt);162  sqlite3BtreeLeave(pBt);163  sqlite3_free(pCur);164  sqlite3_close(db);165}166 167/* Test 3: Insert two cells with the second inserted at index 0 (pointer index shift) */168void test_insertCellFast_insert_before_shifts_index(void){169  sqlite3 *db = open_memory_db();170  Btree *pBt = db->aDb[0].pBt;171  TEST_ASSERT_NOT_NULL(pBt);172 173  Pgno root = 0;174  begin_and_create(pBt, &root);175  BtCursor *pCur = open_write_cursor_loaded(pBt, root);176 177  sqlite3BtreeEnter(pBt);178  MemPage *pPage = pCur->pPage;179  TEST_ASSERT_NOT_NULL(pPage);180 181  /* First insert */182  u8 cellA[4], cellB[4];183  int szA=0, szB=0;184  build_min_table_leaf_cell(0x0A, cellA, &szA); /* rowid 10 */185  int rc = test_insertCellFast(pPage, 0, cellA, szA);186  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);187  TEST_ASSERT_EQUAL_UINT16(1, pPage->nCell);188 189  /* Second insert at index 0 (before the first) */190  build_min_table_leaf_cell(0x05, cellB, &szB); /* rowid 5 */191  rc = test_insertCellFast(pPage, 0, cellB, szB);192  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);193  TEST_ASSERT_EQUAL_UINT16(2, pPage->nCell);194 195  /* Check that the first cell-pointer now points to cellB bytes */196  u16 off0 = get2byte(&pPage->aCellIdx[0]);197  TEST_ASSERT_TRUE(off0+2 <= pPage->pBt->usableSize);198  TEST_ASSERT_EQUAL_UINT8(0x00, pPage->aData[off0+0]);199  TEST_ASSERT_EQUAL_UINT8(0x05, pPage->aData[off0+1]);200 201  /* And second pointer should point to cellA bytes */202  u16 off1 = get2byte(&pPage->aCellIdx[2]);203  TEST_ASSERT_TRUE(off1+2 <= pPage->pBt->usableSize);204  TEST_ASSERT_EQUAL_UINT8(0x00, pPage->aData[off1+0]);205  TEST_ASSERT_EQUAL_UINT8(0x0A, pPage->aData[off1+1]);206 207  sqlite3BtreeLeave(pBt);208 209  /* Cleanup */210  sqlite3BtreeEnter(pBt);211  sqlite3BtreeCloseCursor(pCur);212  sqlite3BtreeCommit(pBt);213  sqlite3BtreeLeave(pBt);214  sqlite3_free(pCur);215  sqlite3_close(db);216}217 218int main(void) {219  UNITY_BEGIN();220  RUN_TEST(test_insertCellFast_basic_insert_into_empty_leaf);221  RUN_TEST(test_insertCellFast_overflow_slot_when_no_free_space);222  RUN_TEST(test_insertCellFast_insert_before_shifts_index);223  return UNITY_END();224}