Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_sqlite3BtreeLast.c196 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdio.h>5 6/* Helper: execute SQL and assert SQLITE_OK */7static void exec_or_fail(sqlite3 *db, const char *sql){8  char *zErr = 0;9  int rc = sqlite3_exec(db, sql, 0, 0, &zErr);10  if( rc!=SQLITE_OK ){11    const char *msg = zErr ? zErr : sqlite3_errmsg(db);12    printf("SQL error: %s\n", msg);13  }14  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);15  sqlite3_free(zErr);16}17 18/* Helper: get rootpage of a table from sqlite_master */19static Pgno get_rootpage(sqlite3 *db, const char *zName){20  Pgno root = 0;21  sqlite3_stmt *pStmt = 0;22  const char *sql = "SELECT rootpage FROM sqlite_master WHERE name=?1";23  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_prepare_v2(db, sql, -1, &pStmt, 0));24  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC));25  if( sqlite3_step(pStmt)==SQLITE_ROW ){26    root = (Pgno)sqlite3_column_int(pStmt, 0);27  }28  sqlite3_finalize(pStmt);29  TEST_ASSERT_MESSAGE(root!=0, "Failed to fetch rootpage");30  return root;31}32 33/* Helper: open a read-only BtCursor on given root page */34static void open_read_cursor(sqlite3 *db, Pgno root, BtCursor **ppCur){35  Btree *pBt = db->aDb[0].pBt;36  int n = sqlite3BtreeCursorSize();37  BtCursor *pCur = (BtCursor*)sqlite3_malloc(n);38  TEST_ASSERT_NOT_NULL(pCur);39  memset(pCur, 0, n);40  sqlite3BtreeCursorZero(pCur);41 42  /* Start a read transaction to satisfy assertions in sqlite3BtreeCursor */43  sqlite3_mutex_enter(db->mutex);44  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3BtreeBeginTrans(pBt, 0, 0));45  sqlite3_mutex_leave(db->mutex);46 47  /* Use API wrapper that manages BtShared mutex internally */48  TEST_ASSERT_EQUAL_INT(SQLITE_OK,49    sqlite3BtreeCursor(pBt, root, 0 /* read-only */, 0, pCur)50  );51  *ppCur = pCur;52}53 54/* Helper: close cursor and free memory */55static void close_cursor(BtCursor *pCur){56  if( pCur ){57    sqlite3BtreeCloseCursor(pCur);58    sqlite3_free(pCur);59  }60}61 62/* setUp/tearDown */63void setUp(void) { }64void tearDown(void) { }65 66/* Test 1: Empty table -> sqlite3BtreeLast returns *pRes==1, SQLITE_OK */67void test_sqlite3BtreeLast_empty_table(void){68  sqlite3 *db = 0;69  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));70  exec_or_fail(db, "PRAGMA auto_vacuum=0");71  exec_or_fail(db, "CREATE TABLE t1(x)");72 73  Pgno root = get_rootpage(db, "t1");74 75  BtCursor *pCur = 0;76  open_read_cursor(db, root, &pCur);77 78  int res = -1;79  /* Hold db mutex and BtShared mutex as required by implementation asserts */80  sqlite3_mutex_enter(db->mutex);81  sqlite3BtreeEnter(db->aDb[0].pBt);82  int rc = sqlite3BtreeLast(pCur, &res);83  sqlite3BtreeLeave(db->aDb[0].pBt);84  sqlite3_mutex_leave(db->mutex);85 86  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);87  TEST_ASSERT_EQUAL_INT(1, res);88 89  close_cursor(pCur);90  sqlite3_close(db);91}92 93/* Test 2: Non-empty table -> *pRes==0, cursor at last row, AtLast flag set */94void test_sqlite3BtreeLast_nonempty_table_simple(void){95  sqlite3 *db = 0;96  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));97  exec_or_fail(db, "PRAGMA auto_vacuum=0");98  exec_or_fail(db, "CREATE TABLE t2(x)");99  exec_or_fail(db, "INSERT INTO t2 VALUES('a'),('b'),('c'),('d'),('e')");100 101  Pgno root = get_rootpage(db, "t2");102 103  BtCursor *pCur = 0;104  open_read_cursor(db, root, &pCur);105 106  int res = -1;107  sqlite3_mutex_enter(db->mutex);108  sqlite3BtreeEnter(db->aDb[0].pBt);109  int rc = sqlite3BtreeLast(pCur, &res);110  sqlite3BtreeLeave(db->aDb[0].pBt);111  sqlite3_mutex_leave(db->mutex);112 113  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);114  TEST_ASSERT_EQUAL_INT(0, res);115 116  /* Verify last rowid == 5 and BTCF_AtLast flag set */117  sqlite3BtreeEnter(db->aDb[0].pBt);118  i64 lastRowid = sqlite3BtreeIntegerKey(pCur);119  sqlite3BtreeLeave(db->aDb[0].pBt);120  TEST_ASSERT_EQUAL_INT64(5, lastRowid);121  TEST_ASSERT_TRUE((pCur->curFlags & BTCF_AtLast)!=0);122 123  /* Call again to exercise the fast-path; still *pRes==0 and AtLast flag */124  sqlite3_mutex_enter(db->mutex);125  sqlite3BtreeEnter(db->aDb[0].pBt);126  res = -1;127  rc = sqlite3BtreeLast(pCur, &res);128  sqlite3BtreeLeave(db->aDb[0].pBt);129  sqlite3_mutex_leave(db->mutex);130 131  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);132  TEST_ASSERT_EQUAL_INT(0, res);133  TEST_ASSERT_TRUE((pCur->curFlags & BTCF_AtLast)!=0);134 135  close_cursor(pCur);136  sqlite3_close(db);137}138 139/* Test 3: Deep btree (force internal nodes) -> last row correct */140void test_sqlite3BtreeLast_deep_tree(void){141  sqlite3 *db = 0;142  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));143  /* Force small page size to get internal nodes quickly */144  exec_or_fail(db, "PRAGMA page_size=512");145  exec_or_fail(db, "PRAGMA auto_vacuum=0");146  exec_or_fail(db, "CREATE TABLE t3(x)");147  /* Insert many rows with large payload to split pages and create height>1 */148  {149    sqlite3_stmt *pIns = 0;150    TEST_ASSERT_EQUAL_INT(SQLITE_OK,151      sqlite3_prepare_v2(db, "INSERT INTO t3(rowid,x) VALUES(?,?)", -1, &pIns, 0)152    );153    char big[1000];154    memset(big, 'x', sizeof(big));155    int N = 200;156    for(int i=1; i<=N; i++){157      TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_bind_int64(pIns, 1, (sqlite3_int64)i));158      TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_bind_text(pIns, 2, big, (int)sizeof(big), SQLITE_STATIC));159      TEST_ASSERT_EQUAL_INT(SQLITE_DONE, sqlite3_step(pIns));160      TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_reset(pIns));161      TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_clear_bindings(pIns));162    }163    sqlite3_finalize(pIns);164  }165 166  Pgno root = get_rootpage(db, "t3");167 168  BtCursor *pCur = 0;169  open_read_cursor(db, root, &pCur);170 171  int res = -1;172  sqlite3_mutex_enter(db->mutex);173  sqlite3BtreeEnter(db->aDb[0].pBt);174  int rc = sqlite3BtreeLast(pCur, &res);175  sqlite3BtreeLeave(db->aDb[0].pBt);176  sqlite3_mutex_leave(db->mutex);177 178  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);179  TEST_ASSERT_EQUAL_INT(0, res);180 181  sqlite3BtreeEnter(db->aDb[0].pBt);182  i64 lastRowid = sqlite3BtreeIntegerKey(pCur);183  sqlite3BtreeLeave(db->aDb[0].pBt);184  TEST_ASSERT_EQUAL_INT64(200, lastRowid);185 186  close_cursor(pCur);187  sqlite3_close(db);188}189 190int main(void){191  UNITY_BEGIN();192  RUN_TEST(test_sqlite3BtreeLast_empty_table);193  RUN_TEST(test_sqlite3BtreeLast_nonempty_table_simple);194  RUN_TEST(test_sqlite3BtreeLast_deep_tree);195  return UNITY_END();196}