Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_insert_sqlite3OpenTableAndIndices.c258 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdbool.h>6 7/* Unity fixtures */8void setUp(void) {9  /* No global setup */10}11void tearDown(void) {12  /* No global teardown */13}14 15/* Helper: exec SQL, assert success */16static void exec_sql_ok(sqlite3 *db, const char *sql){17  char *errmsg = 0;18  int rc = sqlite3_exec(db, sql, 0, 0, &errmsg);19  if( rc!=SQLITE_OK ){20    const char *em = errmsg ? errmsg : "unknown";21    TEST_FAIL_MESSAGE(em);22  }23  if( errmsg ) sqlite3_free(errmsg);24}25 26/* Helper: initialize a Parse+Vdbe */27static void init_parse(sqlite3 *db, Parse *pParse, Vdbe **ppVdbe){28  memset(pParse, 0, sizeof(Parse));29  pParse->db = db;30  Vdbe *v = sqlite3VdbeCreate(db);31  TEST_ASSERT_NOT_NULL(v);32  pParse->pVdbe = v;33  if( ppVdbe ) *ppVdbe = v;34}35 36/* Helper: cleanup Vdbe */37static void cleanup_vdbe(Vdbe *v){38  if( v ) sqlite3VdbeDelete(v);39}40 41/* Helper: find Table* by name in "main" */42static Table* find_table(sqlite3 *db, const char *zName){43  Table *pTab = sqlite3FindTable(db, zName, "main");44  TEST_ASSERT_NOT_NULL_MESSAGE(pTab, "Table not found in schema");45  return pTab;46}47 48/* Helper: collect Index tnums into array; returns count */49static int collect_index_tnums(Table *pTab, int *aTnum, int nAlloc){50  int n = 0;51  for(Index *pIdx = pTab->pIndex; pIdx && n<nAlloc; pIdx = pIdx->pNext){52    aTnum[n++] = pIdx->tnum;53  }54  return n;55}56 57/* Helper: check if value in array */58static bool int_in_array(int v, const int *a, int n){59  for(int i=0;i<n;i++) if( a[i]==v ) return true;60  return false;61}62 63/* Helper: find OP_OpenWrite with given cursor (p1) in ops[start..end) */64static const VdbeOp* find_openwrite_by_cursor(const Vdbe *v, int start, int cursor){65  for(int i=start; i<v->nOp; i++){66    const VdbeOp *op = &v->aOp[i];67    if( op->opcode==OP_OpenWrite && op->p1==cursor ){68      return op;69    }70  }71  return NULL;72}73 74/* Helper: find OP_OpenWrite with given tnum in P2 (index/table rootpage) */75static const VdbeOp* find_openwrite_by_tnum(const Vdbe *v, int start, int tnum){76  for(int i=start; i<v->nOp; i++){77    const VdbeOp *op = &v->aOp[i];78    if( op->opcode==OP_OpenWrite && op->p2==tnum ){79      return op;80    }81  }82  return NULL;83}84 85/* Test 1: Rowid table, full open (table + all indexes), base iBase=0 */86static void test_sqlite3OpenTableAndIndices_rowid_full_open(void){87  sqlite3 *db = NULL;88  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));89  exec_sql_ok(db,90    "CREATE TABLE t1(a, b, c);\n"91    "CREATE INDEX t1_a ON t1(a);\n"92    "CREATE INDEX t1_b ON t1(b);\n"93  );94  Table *pTab = find_table(db, "t1");95 96  Parse p;97  Vdbe *v = NULL;98  init_parse(db, &p, &v);99 100  int dataCur = -1, idxCur = -1;101  int nOp0 = v->nOp;102  int p5 = 7;103  int rc = sqlite3OpenTableAndIndices(&p, pTab, OP_OpenWrite, (u8)p5,104                                      0, NULL, &dataCur, &idxCur);105  TEST_ASSERT_EQUAL_INT(0, nOp0); /* Fresh Vdbe has no ops */106  TEST_ASSERT_EQUAL_INT(2, rc);   /* two indexes */107  TEST_ASSERT_EQUAL_INT(0, dataCur);108  TEST_ASSERT_EQUAL_INT(1, idxCur);109 110  /* Verify table open at cursor 0 */111  const VdbeOp *opTbl = find_openwrite_by_cursor(v, nOp0, 0);112  TEST_ASSERT_NOT_NULL(opTbl);113  TEST_ASSERT_EQUAL_INT(OP_OpenWrite, opTbl->opcode);114  TEST_ASSERT_EQUAL_INT(pTab->tnum, opTbl->p2);115 116  /* Verify index opens at cursors 1 and 2 with provided p5 */117  int idxTnums[8]; /* plenty */118  int nIdx = collect_index_tnums(pTab, idxTnums, 8);119  TEST_ASSERT_EQUAL_INT(2, nIdx);120 121  const VdbeOp *opIdx1 = find_openwrite_by_cursor(v, nOp0, 1);122  const VdbeOp *opIdx2 = find_openwrite_by_cursor(v, nOp0, 2);123  TEST_ASSERT_NOT_NULL(opIdx1);124  TEST_ASSERT_NOT_NULL(opIdx2);125  TEST_ASSERT_TRUE(int_in_array(opIdx1->p2, idxTnums, nIdx));126  TEST_ASSERT_TRUE(int_in_array(opIdx2->p2, idxTnums, nIdx));127  TEST_ASSERT(opIdx1->p2 != opIdx2->p2);128 129  /* p5 applies only to index opens on rowid tables */130  TEST_ASSERT_EQUAL_UINT16(p5, opIdx1->p5);131  TEST_ASSERT_EQUAL_UINT16(p5, opIdx2->p5);132 133  cleanup_vdbe(v);134  sqlite3_close(db);135}136 137/* Test 2: Rowid table with selective aToOpen: open only the second index */138static void test_sqlite3OpenTableAndIndices_rowid_selective_aToOpen(void){139  sqlite3 *db = NULL;140  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));141  exec_sql_ok(db,142    "CREATE TABLE t2(x, y, z);\n"143    "CREATE INDEX t2_x ON t2(x);\n"144    "CREATE INDEX t2_y ON t2(y);\n"145  );146  Table *pTab = find_table(db, "t2");147 148  Parse p;149  Vdbe *v = NULL;150  init_parse(db, &p, &v);151 152  int dataCur=-1, idxCur=-1;153  int iBase = 5;154  unsigned char aToOpen[3] = {0, 0, 1}; /* skip table, skip first index, open second index only */155  int rc = sqlite3OpenTableAndIndices(&p, pTab, OP_OpenWrite, (u8)9,156                                      iBase, aToOpen, &dataCur, &idxCur);157  TEST_ASSERT_EQUAL_INT(2, rc);158  TEST_ASSERT_EQUAL_INT(iBase, dataCur);159  TEST_ASSERT_EQUAL_INT(iBase+1, idxCur);160 161  /* Expect only one OP_OpenWrite: for cursor 7 (second index), and none for 5 or 6 */162  const VdbeOp *op5 = find_openwrite_by_cursor(v, 0, 5);163  const VdbeOp *op6 = find_openwrite_by_cursor(v, 0, 6);164  const VdbeOp *op7 = find_openwrite_by_cursor(v, 0, 7);165 166  TEST_ASSERT_NULL(op5);167  TEST_ASSERT_NULL(op6);168  TEST_ASSERT_NOT_NULL(op7);169 170  /* The opened thing must be one of the table's indexes (not the table, since table was skipped) */171  int idxTnums[8];172  int nIdx = collect_index_tnums(pTab, idxTnums, 8);173  TEST_ASSERT_TRUE(int_in_array(op7->p2, idxTnums, nIdx));174 175  cleanup_vdbe(v);176  sqlite3_close(db);177}178 179/* Test 3: Rowid table with iBase < 0 uses pParse->nTab and updates nTab */180static void test_sqlite3OpenTableAndIndices_rowid_negative_iBase_and_nTab(void){181  sqlite3 *db = NULL;182  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));183  exec_sql_ok(db,184    "CREATE TABLE t3(p, q);\n"185    "CREATE INDEX t3_p ON t3(p);\n"186    "CREATE INDEX t3_q ON t3(q);\n"187  );188  Table *pTab = find_table(db, "t3");189 190  Parse p;191  Vdbe *v = NULL;192  init_parse(db, &p, &v);193  p.nTab = 8; /* Preexisting temp cursor space */194 195  int dataCur=-1, idxCur=-1;196  int rc = sqlite3OpenTableAndIndices(&p, pTab, OP_OpenWrite, (u8)5,197                                      -1, NULL, &dataCur, &idxCur);198  TEST_ASSERT_EQUAL_INT(2, rc);199  TEST_ASSERT_EQUAL_INT(8, dataCur);200  TEST_ASSERT_EQUAL_INT(9, idxCur);201  /* Should allocate data + 2 indexes => next free is 11 */202  TEST_ASSERT_EQUAL_INT(11, p.nTab);203 204  /* Verify there are opens for cursors 8, 9, 10 */205  TEST_ASSERT_NOT_NULL(find_openwrite_by_cursor(v, 0, 8));206  TEST_ASSERT_NOT_NULL(find_openwrite_by_cursor(v, 0, 9));207  TEST_ASSERT_NOT_NULL(find_openwrite_by_cursor(v, 0, 10));208 209  cleanup_vdbe(v);210  sqlite3_close(db);211}212 213/* Test 4: WITHOUT ROWID table: data cursor is PK index, and p5 forced to 0 for PK open */214static void test_sqlite3OpenTableAndIndices_without_rowid_pk_p5_zero_and_dataCur(void){215  sqlite3 *db = NULL;216  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));217  exec_sql_ok(db,218    "CREATE TABLE w(a INTEGER, b INTEGER, PRIMARY KEY(a)) WITHOUT ROWID;\n"219    "CREATE INDEX w_b ON w(b);\n"220  );221  Table *pTab = find_table(db, "w");222  Index *pPk = sqlite3PrimaryKeyIndex(pTab);223  TEST_ASSERT_NOT_NULL_MESSAGE(pPk, "Primary key index not found");224  int pkTnum = pPk->tnum;225 226  Parse p;227  Vdbe *v = NULL;228  init_parse(db, &p, &v);229 230  int dataCur=-1, idxCur=-1;231  int iBase = 2;232  int p5in = 99;233  int rc = sqlite3OpenTableAndIndices(&p, pTab, OP_OpenWrite, (u8)p5in,234                                      iBase, NULL, &dataCur, &idxCur);235  TEST_ASSERT_EQUAL_INT(2, rc);236  /* First index cursor number always equals iBase */237  TEST_ASSERT_EQUAL_INT(iBase, idxCur);238 239  /* Find OpenWrite for the PK index tnum */240  const VdbeOp *opPk = find_openwrite_by_tnum(v, 0, pkTnum);241  TEST_ASSERT_NOT_NULL_MESSAGE(opPk, "No OP_OpenWrite for PK index");242  /* Data cursor must be the cursor used for opening the PK index */243  TEST_ASSERT_EQUAL_INT(opPk->p1, dataCur);244  /* p5 forced to 0 for WITHOUT ROWID PK open */245  TEST_ASSERT_EQUAL_UINT16(0, opPk->p5);246 247  cleanup_vdbe(v);248  sqlite3_close(db);249}250 251int main(void){252  UNITY_BEGIN();253  RUN_TEST(test_sqlite3OpenTableAndIndices_rowid_full_open);254  RUN_TEST(test_sqlite3OpenTableAndIndices_rowid_selective_aToOpen);255  RUN_TEST(test_sqlite3OpenTableAndIndices_rowid_negative_iBase_and_nTab);256  RUN_TEST(test_sqlite3OpenTableAndIndices_without_rowid_pk_p5_zero_and_dataCur);257  return UNITY_END();258}