Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_expr_exprCodeTargetAndOr.c209 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Global db handle for tests */7static sqlite3 *gDb = NULL;8 9/* Unity hooks */10void setUp(void) {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/* Helper: create a minimal Parse with Vdbe and enough registers */23static void initParse(Parse *pParse, Vdbe **ppVdbe){24  memset(pParse, 0, sizeof(*pParse));25  pParse->db = gDb;26  Vdbe *v = sqlite3VdbeCreate(gDb);27  TEST_ASSERT_NOT_NULL(v);28  pParse->pVdbe = v;29  pParse->nMem = 200; /* big enough for target/temp regs */30  if (ppVdbe) *ppVdbe = v;31}32 33/* Helper: build a TK_VARIABLE Expr. Uses string literals for tokens. */34static void makeVarExpr(Expr *p, int varIndex, int setSubqueryFlag){35  memset(p, 0, sizeof(*p));36  p->op = TK_VARIABLE;37  p->iColumn = varIndex; /* used as P1 by OP_Variable */38  p->u.zToken = (varIndex==1)?"?1":(varIndex==2?"?2":"?9");39  if (setSubqueryFlag) p->flags |= EP_Subquery;40}41 42/* Helper: build top-level AND/OR Expr with given children */43static void makeAndOrExpr(Expr *p, int op, Expr *pLeft, Expr *pRight){44  memset(p, 0, sizeof(*p));45  p->op = op; /* TK_AND or TK_OR */46  p->pLeft = pLeft;47  p->pRight = pRight;48}49 50/* Helper: find first opcode index matching 'opcode', or -1 if not found */51static int findFirstOpcode(Vdbe *v, int opcode){52  int nOp = sqlite3VdbeCurrentAddr(v);53  for(int i=0;i<nOp;i++){54    Op *pOp = sqlite3VdbeGetOp(v, i);55    if( pOp && pOp->opcode==opcode ) return i;56  }57  return -1;58}59 60/* Test 1: AND with right-first evaluation (left has EP_Subquery). Expect OP_IfNot and trailing short-circuit OP_Or. */61void test_exprCodeTargetAndOr_AND_right_first_shortcircuit_structure(void){62  Parse parse; Vdbe *v; initParse(&parse, &v);63 64  Expr left, right, top;65  makeVarExpr(&left, 1, /*EP_Subquery*/1);66  makeVarExpr(&right, 2, /*EP_Subquery*/0);67  makeAndOrExpr(&top, TK_AND, &left, &right);68 69  int tmpReg = 0;70  int target = 5;71  int retReg = test_exprCodeTargetAndOr(&parse, &top, target, &tmpReg);72 73  /* Returned register equals target */74  TEST_ASSERT_EQUAL_INT(target, retReg);75  /* A temp register should be used for the non-target operand */76  TEST_ASSERT_TRUE_MESSAGE(tmpReg>0, "Expected non-zero temp register");77 78  int nOp = sqlite3VdbeCurrentAddr(v);79  TEST_ASSERT_TRUE(nOp >= 5);80 81  int idxIfNot = findFirstOpcode(v, OP_IfNot);82  TEST_ASSERT_TRUE_MESSAGE(idxIfNot >= 0, "Expected OP_IfNot for TK_AND short-circuit");83 84  /* The last opcode should be the short-circuit OP_Or(regSS,regSS,target) */85  Op *pLast = sqlite3VdbeGetOp(v, nOp-1);86  TEST_ASSERT_NOT_NULL(pLast);87  TEST_ASSERT_EQUAL_INT(OP_Or, pLast->opcode);88  TEST_ASSERT_EQUAL_INT(target, pLast->p3);89 90  /* There should be an OP_And that combines both operands */91  int idxAnd = findFirstOpcode(v, OP_And);92  TEST_ASSERT_TRUE_MESSAGE(idxAnd >= 0, "Expected OP_And combining operands");93 94  /* There should be a OP_Goto before the final OP_Or (skip to end on no-short-circuit path) */95  int idxGoto = findFirstOpcode(v, OP_Goto);96  TEST_ASSERT_TRUE_MESSAGE(idxGoto >= 0, "Expected OP_Goto before jump target patching");97 98  sqlite3VdbeDelete(v);99}100 101/* Test 2: OR with left-first evaluation and right has EP_Subquery. Expect OP_If (not IfNot) and trailing OP_Or. */102void test_exprCodeTargetAndOr_OR_left_first_right_is_subquery(void){103  Parse parse; Vdbe *v; initParse(&parse, &v);104 105  Expr left, right, top;106  makeVarExpr(&left, 1, /*EP_Subquery*/0);107  makeVarExpr(&right, 2, /*EP_Subquery*/1); /* right is subquery -> may skip */108  makeAndOrExpr(&top, TK_OR, &left, &right);109 110  int tmpReg = 0;111  int target = 7;112  int retReg = test_exprCodeTargetAndOr(&parse, &top, target, &tmpReg);113 114  TEST_ASSERT_EQUAL_INT(target, retReg);115  TEST_ASSERT_TRUE_MESSAGE(tmpReg>0, "Expected non-zero temp register");116 117  int nOp = sqlite3VdbeCurrentAddr(v);118  TEST_ASSERT_TRUE(nOp >= 5);119 120  int idxIf = findFirstOpcode(v, OP_If);121  TEST_ASSERT_TRUE_MESSAGE(idxIf >= 0, "Expected OP_If for TK_OR short-circuit");122  TEST_ASSERT_EQUAL_INT(-1, findFirstOpcode(v, OP_IfNot)); /* Ensure no OP_IfNot in this path */123 124  Op *pLast = sqlite3VdbeGetOp(v, nOp-1);125  TEST_ASSERT_NOT_NULL(pLast);126  TEST_ASSERT_EQUAL_INT(OP_Or, pLast->opcode);127  TEST_ASSERT_EQUAL_INT(target, pLast->p3);128 129  /* There should be at least one OP_Or combining the two operands before the trailing OP_Or */130  /* The trailing OP_Or is the last op; ensure we also have another OP_Or before it or OP_Variable/OP_Goto exist */131  int idxOr = findFirstOpcode(v, OP_Or);132  TEST_ASSERT_TRUE_MESSAGE(idxOr >= 0, "Expected OP_Or combining operands");133 134  int idxGoto = findFirstOpcode(v, OP_Goto);135  TEST_ASSERT_TRUE_MESSAGE(idxGoto >= 0, "Expected OP_Goto before final short-circuit OP_Or");136 137  sqlite3VdbeDelete(v);138}139 140/* Test 3: AND without any EP_Subquery flags (no skip branch). Expect no trailing OP_Goto/extra OP_Or; last opcode is OP_And. */141void test_exprCodeTargetAndOr_AND_no_skip_branch_last_is_And(void){142  Parse parse; Vdbe *v; initParse(&parse, &v);143 144  Expr left, right, top;145  makeVarExpr(&left, 1, /*EP_Subquery*/0);146  makeVarExpr(&right, 2, /*EP_Subquery*/0);147  makeAndOrExpr(&top, TK_AND, &left, &right);148 149  int tmpReg = 0;150  int target = 11;151  int retReg = test_exprCodeTargetAndOr(&parse, &top, target, &tmpReg);152 153  TEST_ASSERT_EQUAL_INT(target, retReg);154  TEST_ASSERT_TRUE_MESSAGE(tmpReg>0, "Expected non-zero temp register");155 156  /* No skip branch expected */157  TEST_ASSERT_EQUAL_INT(-1, findFirstOpcode(v, OP_If));158  TEST_ASSERT_EQUAL_INT(-1, findFirstOpcode(v, OP_IfNot));159 160  int nOp = sqlite3VdbeCurrentAddr(v);161  TEST_ASSERT_TRUE(nOp >= 3);162 163  Op *pLast = sqlite3VdbeGetOp(v, nOp-1);164  TEST_ASSERT_NOT_NULL(pLast);165  TEST_ASSERT_EQUAL_INT(OP_And, pLast->opcode);166 167  /* Ensure no OP_Goto exists in this no-skip path */168  TEST_ASSERT_EQUAL_INT(-1, findFirstOpcode(v, OP_Goto));169  /* Ensure no trailing OP_Or exists */170  /* There could be no OP_Or at all in this path */171  sqlite3VdbeDelete(v);172}173 174/* Test 4: OR with right-first evaluation (left has EP_Subquery). Expect OP_If and trailing OP_Or. */175void test_exprCodeTargetAndOr_OR_right_first_shortcircuit_structure(void){176  Parse parse; Vdbe *v; initParse(&parse, &v);177 178  Expr left, right, top;179  makeVarExpr(&left, 1, /*EP_Subquery*/1);  /* left is marked subquery -> compute right first */180  makeVarExpr(&right, 2, /*EP_Subquery*/0);181  makeAndOrExpr(&top, TK_OR, &left, &right);182 183  int tmpReg = 0;184  int target = 13;185  int retReg = test_exprCodeTargetAndOr(&parse, &top, target, &tmpReg);186 187  TEST_ASSERT_EQUAL_INT(target, retReg);188  TEST_ASSERT_TRUE_MESSAGE(tmpReg>0, "Expected non-zero temp register");189 190  int idxIf = findFirstOpcode(v, OP_If);191  TEST_ASSERT_TRUE_MESSAGE(idxIf >= 0, "Expected OP_If for TK_OR skip branch");192 193  int nOp = sqlite3VdbeCurrentAddr(v);194  Op *pLast = sqlite3VdbeGetOp(v, nOp-1);195  TEST_ASSERT_NOT_NULL(pLast);196  TEST_ASSERT_EQUAL_INT(OP_Or, pLast->opcode);197  TEST_ASSERT_EQUAL_INT(target, pLast->p3);198 199  sqlite3VdbeDelete(v);200}201 202int main(void) {203  UNITY_BEGIN();204  RUN_TEST(test_exprCodeTargetAndOr_AND_right_first_shortcircuit_structure);205  RUN_TEST(test_exprCodeTargetAndOr_OR_left_first_right_is_subquery);206  RUN_TEST(test_exprCodeTargetAndOr_AND_no_skip_branch_last_is_And);207  RUN_TEST(test_exprCodeTargetAndOr_OR_right_first_shortcircuit_structure);208  return UNITY_END();209}