AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Helper: Create a TK_VECTOR expression with N NULL elements */7static Expr* makeVectorOfNulls(Parse *pParse, int n){8 ExprList *pList = 0;9 for(int i=0; i<n; i++){10 Expr *pNull = sqlite3PExpr(pParse, TK_NULL, 0, 0);11 TEST_ASSERT_NOT_NULL_MESSAGE(pNull, "Failed to allocate TK_NULL expression");12 pList = sqlite3ExprListAppend(pParse, pList, pNull);13 TEST_ASSERT_NOT_NULL_MESSAGE(pList, "Failed to append to ExprList");14 }15 Expr *pVec = sqlite3ExprAlloc(pParse->db, TK_VECTOR, 0, 0);16 TEST_ASSERT_NOT_NULL_MESSAGE(pVec, "Failed to allocate TK_VECTOR expression");17 pVec->x.pList = pList; /* Vector uses x.pList */18 return pVec;19}20 21/* Helper: Build a comparison expression pLeft <op> pRight */22static Expr* makeCompareExpr(Parse *pParse, int tkOp, Expr *pLeft, Expr *pRight){23 Expr *pExpr = sqlite3PExpr(pParse, tkOp, pLeft, pRight);24 TEST_ASSERT_NOT_NULL_MESSAGE(pExpr, "Failed to allocate comparison Expr");25 return pExpr;26}27 28/* Helper: Count number of VDBE ops with specific opcode in [start, end) */29static int countOpcode(Vdbe *v, int start, int end, int opcode){30 int n = 0;31 for(int i=start; i<end; i++){32 VdbeOp *op = sqlite3VdbeGetOp(v, i);33 if( op && op->opcode==opcode ) n++;34 }35 return n;36}37 38/* Helper: Find first op with opcode and (optional) p1/p2 match in [start,end). 39 Pass p1Match/p2Match as -1 to ignore. Returns index or -1 if not found. */40static int findOpcodeP1P2(Vdbe *v, int start, int end, int opcode, int p1Match, int p2Match){41 for(int i=start; i<end; i++){42 VdbeOp *op = sqlite3VdbeGetOp(v, i);43 if( op && op->opcode==opcode ){44 if( (p1Match<0 || op->p1==p1Match) && (p2Match<0 || op->p2==p2Match) ){45 return i;46 }47 }48 }49 return -1;50}51 52void setUp(void) {53 /* empty */54}55void tearDown(void) {56 /* empty */57}58 59/* Test: (NULL) = (NULL) with SQLITE_NULLEQ on singleton vector60 Expect: First op OP_Integer 1,dest; and an OP_Integer 0,dest later (due to NULLEQ branch). */61void test_codeVectorCompare_eq_nulleq_singleton(void){62 sqlite3 *db = 0;63 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));64 Parse parse;65 memset(&parse, 0, sizeof(parse));66 parse.db = db;67 parse.pVdbe = sqlite3VdbeCreate(db);68 TEST_ASSERT_NOT_NULL(parse.pVdbe);69 Vdbe *v = parse.pVdbe;70 71 int dest = 10;72 73 Expr *pLeft = makeVectorOfNulls(&parse, 1);74 Expr *pRight = makeVectorOfNulls(&parse, 1);75 Expr *pCmp = makeCompareExpr(&parse, TK_EQ, pLeft, pRight);76 77 int start = sqlite3VdbeCurrentAddr(v);78 test_codeVectorCompare(&parse, pCmp, dest, TK_EQ, SQLITE_NULLEQ);79 int end = sqlite3VdbeCurrentAddr(v);80 81 /* First new op should be OP_Integer 1 -> dest */82 VdbeOp *op0 = sqlite3VdbeGetOp(v, start);83 TEST_ASSERT_NOT_NULL(op0);84 TEST_ASSERT_EQUAL_INT(OP_Integer, op0->opcode);85 TEST_ASSERT_EQUAL_INT(1, op0->p1);86 TEST_ASSERT_EQUAL_INT(dest, op0->p2);87 88 /* Ensure an OP_Integer 0 -> dest exists later (from NULLEQ branch) */89 int idxZero = findOpcodeP1P2(v, start+1, end, OP_Integer, 0, dest);90 TEST_ASSERT_TRUE_MESSAGE(idxZero >= 0, "Did not find OP_Integer 0,dest emitted for NULLEQ");91 92 sqlite3_close(db);93}94 95/* Test: (NULL) <> (NULL) on singleton vector96 Expect the last emitted op is OP_Not dest,dest (the NE invert). */97void test_codeVectorCompare_ne_singleton_has_final_not(void){98 sqlite3 *db = 0;99 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));100 Parse parse;101 memset(&parse, 0, sizeof(parse));102 parse.db = db;103 parse.pVdbe = sqlite3VdbeCreate(db);104 TEST_ASSERT_NOT_NULL(parse.pVdbe);105 Vdbe *v = parse.pVdbe;106 107 int dest = 7;108 109 Expr *pLeft = makeVectorOfNulls(&parse, 1);110 Expr *pRight = makeVectorOfNulls(&parse, 1);111 Expr *pCmp = makeCompareExpr(&parse, TK_NE, pLeft, pRight);112 113 int start = sqlite3VdbeCurrentAddr(v);114 test_codeVectorCompare(&parse, pCmp, dest, TK_NE, 0);115 int end = sqlite3VdbeCurrentAddr(v);116 117 TEST_ASSERT_TRUE_MESSAGE(end > start, "No ops emitted");118 VdbeOp *last = sqlite3VdbeGetOp(v, end-1);119 TEST_ASSERT_NOT_NULL(last);120 TEST_ASSERT_EQUAL_INT(OP_Not, last->opcode);121 TEST_ASSERT_EQUAL_INT(dest, last->p1);122 TEST_ASSERT_EQUAL_INT(dest, last->p2);123 124 sqlite3_close(db);125}126 127/* Test: (NULL,NULL) < (NULL,NULL)128 Expect at least one OP_ElseEq emitted (tie-breaker for vector LT/GT) */129void test_codeVectorCompare_lt_two_elements_has_ElseEq(void){130 sqlite3 *db = 0;131 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));132 Parse parse;133 memset(&parse, 0, sizeof(parse));134 parse.db = db;135 parse.pVdbe = sqlite3VdbeCreate(db);136 TEST_ASSERT_NOT_NULL(parse.pVdbe);137 Vdbe *v = parse.pVdbe;138 139 int dest = 3;140 141 Expr *pLeft = makeVectorOfNulls(&parse, 2);142 Expr *pRight = makeVectorOfNulls(&parse, 2);143 Expr *pCmp = makeCompareExpr(&parse, TK_LT, pLeft, pRight);144 145 int start = sqlite3VdbeCurrentAddr(v);146 test_codeVectorCompare(&parse, pCmp, dest, TK_LT, 0);147 int end = sqlite3VdbeCurrentAddr(v);148 149 int nElseEq = countOpcode(v, start, end, OP_ElseEq);150 TEST_ASSERT_TRUE_MESSAGE(nElseEq >= 1, "Expected OP_ElseEq for vector LT with multiple elements");151 152 /* Sanity: first emitted op is OP_Integer 1->dest */153 VdbeOp *op0 = sqlite3VdbeGetOp(v, start);154 TEST_ASSERT_NOT_NULL(op0);155 TEST_ASSERT_EQUAL_INT(OP_Integer, op0->opcode);156 TEST_ASSERT_EQUAL_INT(1, op0->p1);157 TEST_ASSERT_EQUAL_INT(dest, op0->p2);158 159 sqlite3_close(db);160}161 162/* Test: Mismatched vector sizes -> error and no ops emitted */163void test_codeVectorCompare_mismatched_sizes_sets_error_and_no_ops(void){164 sqlite3 *db = 0;165 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));166 Parse parse;167 memset(&parse, 0, sizeof(parse));168 parse.db = db;169 parse.pVdbe = sqlite3VdbeCreate(db);170 TEST_ASSERT_NOT_NULL(parse.pVdbe);171 Vdbe *v = parse.pVdbe;172 173 int dest = 5;174 175 Expr *pLeft = makeVectorOfNulls(&parse, 1);176 Expr *pRight = makeVectorOfNulls(&parse, 2);177 Expr *pCmp = makeCompareExpr(&parse, TK_EQ, pLeft, pRight);178 179 int start = sqlite3VdbeCurrentAddr(v);180 test_codeVectorCompare(&parse, pCmp, dest, TK_EQ, 0);181 int end = sqlite3VdbeCurrentAddr(v);182 183 TEST_ASSERT_EQUAL_INT_MESSAGE(start, end, "No VDBE ops should be emitted on error");184 TEST_ASSERT_TRUE_MESSAGE(parse.nErr>0, "Expected parse error (row value misused)");185 186 sqlite3_close(db);187}188 189int main(void){190 UNITY_BEGIN();191 RUN_TEST(test_codeVectorCompare_eq_nulleq_singleton);192 RUN_TEST(test_codeVectorCompare_ne_singleton_has_final_not);193 RUN_TEST(test_codeVectorCompare_lt_two_elements_has_ElseEq);194 RUN_TEST(test_codeVectorCompare_mismatched_sizes_sets_error_and_no_ops);195 return UNITY_END();196}