Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_expr_sqlite3IndexedExprLookup.c293 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6static sqlite3 *gDb = NULL;7 8/* Unity fixtures */9void setUp(void) {10  /* Initialize a fresh in-memory database for each test */11  int rc = sqlite3_open(":memory:", &gDb);12  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);13}14 15void tearDown(void) {16  if (gDb) {17    sqlite3_close(gDb);18    gDb = NULL;19  }20}21 22/* Helpers to create minimal Expr nodes for testing */23 24static Expr *make_expr_null(void){25  Expr *e = (Expr*)sqlite3DbMallocZero(gDb, sizeof(Expr));26  TEST_ASSERT_NOT_NULL(e);27  e->op = TK_NULL;28  /* Leave other fields zeroed */29  return e;30}31 32static Expr *make_expr_cast_with_aff(const char *affStr){33  /* Create a TK_CAST node with u.zToken=affStr so sqlite3ExprAffinity returns desired affinity */34  Expr *e = (Expr*)sqlite3DbMallocZero(gDb, sizeof(Expr));35  TEST_ASSERT_NOT_NULL(e);36  e->op = TK_CAST;37  e->u.zToken = (char*)affStr; /* constant string; safe for tests */38  return e;39}40 41static IndexedExpr *make_indexed_expr_node(Expr *expr, int iDataCur, int iIdxCur, int iIdxCol, u8 aff, int bMaybeNullRow, const char *zIdxName){42  IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocZero(gDb, sizeof(IndexedExpr));43  TEST_ASSERT_NOT_NULL(p);44  p->pExpr = expr;45  p->iDataCur = iDataCur;46  p->iIdxCur = iIdxCur;47  p->iIdxCol = iIdxCol;48  p->aff = aff;49  p->bMaybeNullRow = bMaybeNullRow ? 1 : 0;50  p->zIdxName = (char*)(zIdxName ? zIdxName : "idx");51  p->pIENext = 0;52  return p;53}54 55/* Helper to initialize a Parse with a Vdbe attached */56static void init_parse(Parse *pParse){57  memset(pParse, 0, sizeof(*pParse));58  pParse->db = gDb;59  pParse->pVdbe = sqlite3VdbeCreate(gDb);60  TEST_ASSERT_NOT_NULL(pParse->pVdbe);61  pParse->nMem = 64; /* provide enough registers for codegen paths */62}63 64/* Cleanup Parse resources created in init_parse */65static void cleanup_parse(Parse *pParse){66  if (pParse->pVdbe) {67    sqlite3VdbeDelete(pParse->pVdbe);68    pParse->pVdbe = NULL;69  }70  /* pIdxEpr memory is from sqlite3DbMallocZero(gDb, ...); it will be71     reclaimed when connection is closed. For tests, it's acceptable. */72}73 74/* Convenience to get current number of ops emitted to Vdbe */75static int vdbe_op_count(Parse *pParse){76  Vdbe *v = pParse->pVdbe;77  TEST_ASSERT_NOT_NULL(v);78  return v->nOp;79}80 81/* TESTS */82 83/* 1) Simple match: expression matches IndexedExpr, affinity TEXT matches, OP_Column emitted, returns target */84void test_sqlite3IndexedExprLookup_simple_match(void){85  Parse parse;86  init_parse(&parse);87 88  Expr *e = make_expr_cast_with_aff("TEXT");89  IndexedExpr *node = make_indexed_expr_node(90    e,              /* pExpr */91    1,              /* iDataCur >= 0 */92    2,              /* iIdxCur */93    0,              /* iIdxCol */94    SQLITE_AFF_TEXT,/* aff matches "TEXT" */95    0,              /* bMaybeNullRow */96    "i1"97  );98  parse.pIdxEpr = node;99 100  int before = vdbe_op_count(&parse);101  int target = 3;102  int rc = test_sqlite3IndexedExprLookup(&parse, e, target);103 104  TEST_ASSERT_EQUAL_INT(target, rc);105  TEST_ASSERT_EQUAL_INT(before + 1, vdbe_op_count(&parse)); /* Expect exactly one OP_Column emitted */106 107  cleanup_parse(&parse);108}109 110/* 2) No match due to affinity mismatch: expression TEXT, node affinity NUMERIC -> returns -1, no ops added */111void test_sqlite3IndexedExprLookup_affinity_mismatch(void){112  Parse parse;113  init_parse(&parse);114 115  Expr *e = make_expr_cast_with_aff("TEXT");116  IndexedExpr *node = make_indexed_expr_node(117    e,118    1,119    2,120    1,121    SQLITE_AFF_NUMERIC, /* mismatch */122    0,123    "i1"124  );125  parse.pIdxEpr = node;126 127  int before = vdbe_op_count(&parse);128  int rc = test_sqlite3IndexedExprLookup(&parse, e, 5);129 130  TEST_ASSERT_EQUAL_INT(-1, rc);131  TEST_ASSERT_EQUAL_INT(before, vdbe_op_count(&parse));132 133  cleanup_parse(&parse);134}135 136/* 3) iSelfTab filtering: only node with iDataCur == iSelfTab-1 is considered */137void test_sqlite3IndexedExprLookup_selftab_filter(void){138  Parse parse;139  init_parse(&parse);140 141  Expr *e = make_expr_cast_with_aff("TEXT");142 143  IndexedExpr *bad = make_indexed_expr_node(144    e,145    3,               /* will be skipped since iSelfTab-1 != 3 */146    2,147    0,148    SQLITE_AFF_TEXT,149    0,150    "bad"151  );152  IndexedExpr *good = make_indexed_expr_node(153    e,154    4,               /* matches iSelfTab-1 when iSelfTab=5 */155    2,156    1,157    SQLITE_AFF_TEXT,158    0,159    "good"160  );161  bad->pIENext = good;162  parse.pIdxEpr = bad;163  parse.iSelfTab = 5; /* only accept iDataCur == 4 */164 165  int before = vdbe_op_count(&parse);166  int rc = test_sqlite3IndexedExprLookup(&parse, e, 7);167 168  TEST_ASSERT_EQUAL_INT(7, rc);169  TEST_ASSERT_EQUAL_INT(before + 1, vdbe_op_count(&parse));170 171  cleanup_parse(&parse);172}173 174/* 4) bMaybeNullRow path: ensures IfNullRow/Column/Goto plus original expr code are emitted */175void test_sqlite3IndexedExprLookup_maybe_null_row_path(void){176  Parse parse;177  init_parse(&parse);178 179  /* Use TK_NULL so sqlite3ExprCode can handle it easily */180  Expr *e = make_expr_null();181  IndexedExpr *node = make_indexed_expr_node(182    e,183    1,                    /* valid iDataCur */184    2,185    0,186    SQLITE_AFF_BLOB,      /* for TK_NULL, affinity test expects BLOB case */187    1,                    /* bMaybeNullRow = true to take special path */188    "i1"189  );190  parse.pIdxEpr = node;191 192  int before = vdbe_op_count(&parse);193  int rc = test_sqlite3IndexedExprLookup(&parse, e, 9);194 195  TEST_ASSERT_EQUAL_INT(9, rc);196  /* Expect multiple ops: IfNullRow, Column, Goto, and code for TK_NULL (Null) at least.197     So nOp should increase by >= 3. */198  TEST_ASSERT_TRUE(vdbe_op_count(&parse) >= before + 3);199 200  cleanup_parse(&parse);201}202 203/* 5) iDataCur < 0 nodes are ignored */204void test_sqlite3IndexedExprLookup_negative_iDataCur_ignored(void){205  Parse parse;206  init_parse(&parse);207 208  Expr *e = make_expr_cast_with_aff("TEXT");209  IndexedExpr *node = make_indexed_expr_node(210    e,211    -1,                 /* invalid: should be skipped */212    2,213    0,214    SQLITE_AFF_TEXT,215    0,216    "i1"217  );218  parse.pIdxEpr = node;219 220  int before = vdbe_op_count(&parse);221  int rc = test_sqlite3IndexedExprLookup(&parse, e, 4);222 223  TEST_ASSERT_EQUAL_INT(-1, rc);224  TEST_ASSERT_EQUAL_INT(before, vdbe_op_count(&parse));225 226  cleanup_parse(&parse);227}228 229/* 6) Multiple nodes: stops at first matching node */230void test_sqlite3IndexedExprLookup_stops_at_first_match(void){231  Parse parse;232  init_parse(&parse);233 234  Expr *e = make_expr_cast_with_aff("TEXT");235 236  IndexedExpr *first = make_indexed_expr_node(237    e, 0, 2, 0, SQLITE_AFF_TEXT, 0, "first"238  );239  IndexedExpr *second = make_indexed_expr_node(240    e, 0, 3, 1, SQLITE_AFF_TEXT, 0, "second"241  );242  first->pIENext = second;243  parse.pIdxEpr = first;244 245  int before = vdbe_op_count(&parse);246  int rc = test_sqlite3IndexedExprLookup(&parse, e, 6);247 248  TEST_ASSERT_EQUAL_INT(6, rc);249  /* Only one OP_Column should be emitted for the first match */250  TEST_ASSERT_EQUAL_INT(before + 1, vdbe_op_count(&parse));251 252  cleanup_parse(&parse);253}254 255/* 7) No match due to expression mismatch */256void test_sqlite3IndexedExprLookup_expression_mismatch(void){257  Parse parse;258  init_parse(&parse);259 260  Expr *want = make_expr_cast_with_aff("TEXT");261  Expr *have = make_expr_cast_with_aff("NUMERIC"); /* different token => different expr */262 263  IndexedExpr *node = make_indexed_expr_node(264    have,265    1,266    2,267    0,268    SQLITE_AFF_NUMERIC, /* matches have; but want != have */269    0,270    "i1"271  );272  parse.pIdxEpr = node;273 274  int before = vdbe_op_count(&parse);275  int rc = test_sqlite3IndexedExprLookup(&parse, want, 8);276 277  TEST_ASSERT_EQUAL_INT(-1, rc);278  TEST_ASSERT_EQUAL_INT(before, vdbe_op_count(&parse));279 280  cleanup_parse(&parse);281}282 283int main(void) {284  UNITY_BEGIN();285  RUN_TEST(test_sqlite3IndexedExprLookup_simple_match);286  RUN_TEST(test_sqlite3IndexedExprLookup_affinity_mismatch);287  RUN_TEST(test_sqlite3IndexedExprLookup_selftab_filter);288  RUN_TEST(test_sqlite3IndexedExprLookup_maybe_null_row_path);289  RUN_TEST(test_sqlite3IndexedExprLookup_negative_iDataCur_ignored);290  RUN_TEST(test_sqlite3IndexedExprLookup_stops_at_first_match);291  RUN_TEST(test_sqlite3IndexedExprLookup_expression_mismatch);292  return UNITY_END();293}