Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_expr_sqlite3ExprCodeIN.c189 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* Wrapper declared in module */8void test_sqlite3ExprCodeIN(Parse *pParse, Expr *pExpr, int destIfFalse, int destIfNull);9 10/* Helpers to build expressions */11static Expr* makeIntExpr(sqlite3 *db, int val){12  char buf[40];13  Token t;14  sqlite3_snprintf(sizeof(buf), buf, "%d", val);15  t.z = buf;16  t.n = (int)strlen(buf);17  return sqlite3ExprAlloc(db, TK_INTEGER, &t, 0);18}19 20static Expr* makeInExprList(Parse *pParse, int lhsVal, const int *rhsVals, int nRhs){21  sqlite3 *db = pParse->db;22  Expr *pLhs = makeIntExpr(db, lhsVal);23  ExprList *pList = 0;24  for(int i=0; i<nRhs; i++){25    Expr *pItem = makeIntExpr(db, rhsVals[i]);26    pList = sqlite3ExprListAppend(pParse, pList, pItem);27  }28  Expr *pIn = sqlite3PExpr(pParse, TK_IN, pLhs, 0);29  /* Attach the RHS exprlist and mark union as list */30  pIn->x.pList = pList;31  ExprSetProperty(pIn, EP_xIsList);32  return pIn;33}34 35static void destroyExpr(sqlite3 *db, Expr *p){36  if(p) sqlite3ExprDelete(db, p);37}38 39static void initParse(sqlite3 *db, Parse *p){40  memset(p, 0, sizeof(*p));41  p->db = db;42  /* Create a VDBE for code generation */43  sqlite3VdbeCreate(p);44}45 46/* Scan helpers */47static int countOpcode(Vdbe *v, int op){48  int n = 0;49  int nOp = v->nOp;50  for(int i=0; i<nOp; i++){51    const VdbeOp *pOp = sqlite3VdbeGetOp(v, i);52    if(pOp->opcode==op) n++;53  }54  return n;55}56 57static int existsOpcodeWithP2(Vdbe *v, int op, int p2){58  int nOp = v->nOp;59  for(int i=0; i<nOp; i++){60    const VdbeOp *pOp = sqlite3VdbeGetOp(v, i);61    if(pOp->opcode==op && pOp->p2==p2) return 1;62  }63  return 0;64}65 66static int existsOpcode(Vdbe *v, int op){67  return countOpcode(v, op)>0;68}69 70void setUp(void) {71  /* empty */72}73 74void tearDown(void) {75  /* empty */76}77 78/* Test 1: RHS list with >2 constants -> ephemeral table path (Step 6 loop), distinct false/null labels */79void test_sqlite3ExprCodeIN_eph_step6_distinct_labels(void){80  sqlite3 *db = 0;81  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));82 83  Parse sParse; initParse(db, &sParse);84  Vdbe *v = sParse.pVdbe; TEST_ASSERT_NOT_NULL(v);85 86  /* Build expression: 1 IN (1,2,3) */87  int rhsVals[] = {1,2,3};88  Expr *pIn = makeInExprList(&sParse, 1, rhsVals, 3);89 90  /* Distinct labels for false and null */91  int destIfFalse = sqlite3VdbeMakeLabel(&sParse);92  int destIfNull  = sqlite3VdbeMakeLabel(&sParse);93 94  test_sqlite3ExprCodeIN(&sParse, pIn, destIfFalse, destIfNull);95 96  /* Resolve our labels to known addresses: first null, then false */97  int aNull = sqlite3VdbeAddOp0(v, OP_Noop);98  sqlite3VdbeResolveLabel(&sParse, destIfNull);99  int aFalse = sqlite3VdbeAddOp0(v, OP_Noop);100  sqlite3VdbeResolveLabel(&sParse, destIfFalse);101 102  /* Validate generated opcodes */103  /* Expect Step 6 scan: OP_Rewind present, OP_Column and OP_Ne present, and a OP_Goto to destIfNull */104  TEST_ASSERT_TRUE_MESSAGE(existsOpcode(v, OP_Rewind), "Expected OP_Rewind for RHS scan");105  TEST_ASSERT_TRUE_MESSAGE(existsOpcode(v, OP_Column), "Expected OP_Column to read RHS row");106  TEST_ASSERT_TRUE_MESSAGE(existsOpcode(v, OP_Ne),     "Expected OP_Ne to compare LHS/RHS");107  TEST_ASSERT_TRUE_MESSAGE(existsOpcodeWithP2(v, OP_Goto, aNull), "Expected OP_Goto -> destIfNull");108  /* Also expect there is some branch to destIfFalse */109  TEST_ASSERT_TRUE_MESSAGE(existsOpcodeWithP2(v, OP_Goto, aFalse) || existsOpcodeWithP2(v, OP_Rewind, aFalse),110                           "Expected a path to destIfFalse");111 112  destroyExpr(db, pIn);113  sqlite3VdbeDelete(v);114  sqlite3_close(db);115}116 117/* Test 2: RHS list with 2 constants -> NOOP path (sequence of comparisons), distinct false/null labels */118void test_sqlite3ExprCodeIN_noop_list_two_terms(void){119  sqlite3 *db = 0;120  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));121 122  Parse sParse; initParse(db, &sParse);123  Vdbe *v = sParse.pVdbe; TEST_ASSERT_NOT_NULL(v);124 125  /* Build expression: 5 IN (1,2) */126  int rhsVals[] = {1,2};127  Expr *pIn = makeInExprList(&sParse, 5, rhsVals, 2);128 129  int destIfFalse = sqlite3VdbeMakeLabel(&sParse);130  int destIfNull  = sqlite3VdbeMakeLabel(&sParse);131 132  test_sqlite3ExprCodeIN(&sParse, pIn, destIfFalse, destIfNull);133 134  /* Resolve labels: null first, then false, to distinct addresses */135  int aNull  = sqlite3VdbeAddOp0(v, OP_Noop);136  sqlite3VdbeResolveLabel(&sParse, destIfNull);137  int aFalse = sqlite3VdbeAddOp0(v, OP_Noop);138  sqlite3VdbeResolveLabel(&sParse, destIfFalse);139 140  /* NOOP path should not use OP_Rewind */141  TEST_ASSERT_EQUAL_INT_MESSAGE(0, countOpcode(v, OP_Rewind), "Did not expect OP_Rewind in NOOP path");142 143  /* Should use OP_Eq comparisons and an OP_IsNull on the regCkNull when dests differ */144  TEST_ASSERT_TRUE_MESSAGE(existsOpcode(v, OP_Eq), "Expected OP_Eq comparisons in NOOP path");145  TEST_ASSERT_TRUE_MESSAGE(existsOpcodeWithP2(v, OP_IsNull, aNull), "Expected OP_IsNull -> destIfNull");146  TEST_ASSERT_TRUE_MESSAGE(existsOpcodeWithP2(v, OP_Goto, aFalse),  "Expected OP_Goto -> destIfFalse");147 148  destroyExpr(db, pIn);149  sqlite3VdbeDelete(v);150  sqlite3_close(db);151}152 153/* Test 3: RHS list with >2 constants but destIfFalse==destIfNull -> combined NotFound */154void test_sqlite3ExprCodeIN_eph_equal_labels_notfound(void){155  sqlite3 *db = 0;156  TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));157 158  Parse sParse; initParse(db, &sParse);159  Vdbe *v = sParse.pVdbe; TEST_ASSERT_NOT_NULL(v);160 161  /* Build expression: 7 IN (1,2,3,4) */162  int rhsVals[] = {1,2,3,4};163  Expr *pIn = makeInExprList(&sParse, 7, rhsVals, 4);164 165  int destBoth = sqlite3VdbeMakeLabel(&sParse);166 167  test_sqlite3ExprCodeIN(&sParse, pIn, destBoth, destBoth);168 169  /* Resolve the shared label to a known address */170  int aDest = sqlite3VdbeAddOp0(v, OP_Noop);171  sqlite3VdbeResolveLabel(&sParse, destBoth);172 173  /* Expect OP_NotFound directly to destBoth and no OP_Rewind (since it should short-circuit) */174  TEST_ASSERT_TRUE_MESSAGE(existsOpcodeWithP2(v, OP_NotFound, aDest), "Expected OP_NotFound -> destBoth");175  /* In this combined path, Step 6 should be skipped entirely */176  TEST_ASSERT_EQUAL_INT_MESSAGE(0, countOpcode(v, OP_Rewind), "Did not expect OP_Rewind when dests are equal");177 178  destroyExpr(db, pIn);179  sqlite3VdbeDelete(v);180  sqlite3_close(db);181}182 183int main(void){184  UNITY_BEGIN();185  RUN_TEST(test_sqlite3ExprCodeIN_eph_step6_distinct_labels);186  RUN_TEST(test_sqlite3ExprCodeIN_noop_list_two_terms);187  RUN_TEST(test_sqlite3ExprCodeIN_eph_equal_labels_notfound);188  return UNITY_END();189}