AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdio.h>5 6/* The wrapper for the static function under test */7int test_exprCodeInlineFunction(Parse *pParse, ExprList *pFarg, int iFuncId, int target);8 9static Expr* makeIntegerExpr(sqlite3 *db, int val){10 char buf[64];11 sqlite3_snprintf(sizeof(buf), buf, "%d", val);12 Token t; t.z = buf; t.n = (int)strlen(buf);13 return sqlite3ExprAlloc(db, TK_INTEGER, &t, 0);14}15 16static Expr* makeNullExpr(sqlite3 *db){17 (void)db; /* db not used for TK_NULL token */18 return sqlite3ExprAlloc(db, TK_NULL, 0, 0);19}20 21static ExprList* makeExprList(Parse *pParse, Expr **apExpr, int n){22 ExprList *pList = 0;23 for(int i=0;i<n;i++){24 pList = sqlite3ExprListAppend(pParse, pList, apExpr[i]);25 }26 return pList;27}28 29static void initParseWithVdbe(sqlite3 *db, Parse *pParse, Vdbe **ppVdbe, int nMem){30 memset(pParse, 0, sizeof(*pParse));31 pParse->db = db;32 Vdbe *v = sqlite3VdbeCreate(db);33 TEST_ASSERT_NOT_NULL(v);34 pParse->pVdbe = v;35 pParse->nMem = nMem; /* ensure target registers are valid */36 *ppVdbe = v;37}38 39static int countOpcode(Vdbe *v, u8 opcode){40 int n = 0;41 for(int i=0;i<v->nOp;i++) if( v->aOp[i].opcode==opcode ) n++;42 return n;43}44 45static int containsIntegerLiteral(Vdbe *v, int val){46 for(int i=0;i<v->nOp;i++){47 if( v->aOp[i].opcode==OP_Integer && v->aOp[i].p1==val ) return 1;48 }49 return 0;50}51 52void setUp(void) {53 /* empty */54}55 56void tearDown(void) {57 /* empty */58}59 60/* Test that COALESCE(NULL, 99, 123) generates short-circuit structure:61 OP_Null, OP_NotNull, OP_Integer(99), OP_NotNull, OP_Integer(123) */62void test_exprCodeInlineFunction_coalesce_short_circuit(void){63 sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));64 Parse parse; Vdbe *v = 0;65 initParseWithVdbe(db, &parse, &v, 8);66 67 Expr *args[3];68 args[0] = makeNullExpr(db);69 args[1] = makeIntegerExpr(db, 99);70 args[2] = makeIntegerExpr(db, 123);71 ExprList *pFarg = makeExprList(&parse, args, 3);72 73 int target = 1;74 int rcTarget = test_exprCodeInlineFunction(&parse, pFarg, INLINEFUNC_coalesce, target);75 TEST_ASSERT_EQUAL_INT(target, rcTarget);76 77 /* Basic structure checks */78 TEST_ASSERT_TRUE(v->nOp >= 5); /* expect at least: Null, NotNull, Integer, NotNull, Integer */79 TEST_ASSERT_EQUAL_INT(OP_Null, v->aOp[0].opcode);80 81 /* Find first OP_NotNull and verify following OP_Integer(99) */82 int idx = 1;83 TEST_ASSERT_EQUAL_INT(OP_NotNull, v->aOp[idx].opcode);84 TEST_ASSERT_EQUAL_INT(target, v->aOp[idx].p1);85 idx++;86 TEST_ASSERT_EQUAL_INT(OP_Integer, v->aOp[idx].opcode);87 TEST_ASSERT_EQUAL_INT(99, v->aOp[idx].p1);88 idx++;89 TEST_ASSERT_EQUAL_INT(OP_NotNull, v->aOp[idx].opcode);90 TEST_ASSERT_EQUAL_INT(target, v->aOp[idx].p1);91 idx++;92 TEST_ASSERT_EQUAL_INT(OP_Integer, v->aOp[idx].opcode);93 TEST_ASSERT_EQUAL_INT(123, v->aOp[idx].p1);94 95 /* Count of OP_NotNull should be exactly 2 for 3 args */96 TEST_ASSERT_EQUAL_INT(2, countOpcode(v, OP_NotNull));97 98 sqlite3ExprListDelete(db, pFarg); /* Frees contained Expr objects */99 sqlite3VdbeDelete(v);100 sqlite3_close(db);101}102 103/* Test that default inline path only evaluates/codes the first argument */104void test_exprCodeInlineFunction_default_uses_first_argument_only(void){105 sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));106 Parse parse; Vdbe *v = 0;107 initParseWithVdbe(db, &parse, &v, 8);108 109 Expr *args[2];110 args[0] = makeIntegerExpr(db, 7);111 args[1] = makeIntegerExpr(db, 9);112 ExprList *pFarg = makeExprList(&parse, args, 2);113 114 int target = 2;115 /* Use an unknown/invalid iFuncId to trigger the default case. */116 int rcTarget = test_exprCodeInlineFunction(&parse, pFarg, -9999, target);117 TEST_ASSERT_EQUAL_INT(target, rcTarget);118 119 /* Expect only one OP_Integer for the first arg, and no evidence of the second arg (9). */120 TEST_ASSERT_TRUE(v->nOp >= 1);121 TEST_ASSERT_EQUAL_INT(OP_Integer, v->aOp[0].opcode);122 TEST_ASSERT_EQUAL_INT(7, v->aOp[0].p1);123 TEST_ASSERT_FALSE(containsIntegerLiteral(v, 9));124 125 sqlite3ExprListDelete(db, pFarg);126 sqlite3VdbeDelete(v);127 sqlite3_close(db);128}129 130/* Test that IIF(false, 55) (2-arg form) expands to CASE-like structure131 with an implicit ELSE NULL. We verify that:132 - An OP_Goto exists (from the THEN jump to end).133 - The last opcode is OP_Null (implicit ELSE NULL when condition is false).134 - The THEN expression literal (55) is present in the program. */135void test_exprCodeInlineFunction_iif_two_args_false_condition(void){136 sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));137 Parse parse; Vdbe *v = 0;138 initParseWithVdbe(db, &parse, &v, 16);139 140 Expr *args[2];141 args[0] = makeIntegerExpr(db, 0); /* condition: false */142 args[1] = makeIntegerExpr(db, 55); /* then-result */143 ExprList *pFarg = makeExprList(&parse, args, 2);144 145 int target = 3;146 int rcTarget = test_exprCodeInlineFunction(&parse, pFarg, INLINEFUNC_iif, target);147 TEST_ASSERT_EQUAL_INT(target, rcTarget);148 149 TEST_ASSERT_TRUE(v->nOp > 0);150 /* Expect at least one OP_Goto in CASE code generation */151 TEST_ASSERT_TRUE(countOpcode(v, OP_Goto) >= 1);152 /* The THEN literal should be present in the bytecode */153 TEST_ASSERT_TRUE(containsIntegerLiteral(v, 55));154 /* When condition is false and there's no explicit ELSE, last op should be OP_Null. */155 TEST_ASSERT_EQUAL_INT(OP_Null, v->aOp[v->nOp - 1].opcode);156 TEST_ASSERT_EQUAL_INT(target, v->aOp[v->nOp - 1].p2);157 158 sqlite3ExprListDelete(db, pFarg);159 sqlite3VdbeDelete(v);160 sqlite3_close(db);161}162 163int main(void){164 UNITY_BEGIN();165 RUN_TEST(test_exprCodeInlineFunction_coalesce_short_circuit);166 RUN_TEST(test_exprCodeInlineFunction_default_uses_first_argument_only);167 RUN_TEST(test_exprCodeInlineFunction_iif_two_args_false_condition);168 return UNITY_END();169}