AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Global state for tests */7static sqlite3 *gDb = NULL;8static Parse gParse; /* zeroed in setUp */9static Vdbe *gVdbe = NULL;10 11/* Helper: create a TK_INTEGER expression with EP_IntValue */12static Expr *makeIntExpr(sqlite3 *db, i64 val){13 Expr *e = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));14 TEST_ASSERT_NOT_NULL(e);15 e->op = TK_INTEGER;16 e->flags = EP_IntValue | EP_Leaf | EP_TokenOnly;17 e->u.iValue = val;18 ExprClearVVAProperties(e);19 return e;20}21 22/* Helper: free a single expression allocated with sqlite3DbMallocZero */23static void freeExpr(sqlite3 *db, Expr *e){24 /* Use internal destructor when available */25 if( e ) sqlite3ExprDelete(db, e);26}27 28/* Helper: free pIdxPartExpr list */29static void freeIdxPartExprList(Parse *pParse){30 IndexedExpr *p = pParse->pIdxPartExpr;31 while( p ){32 IndexedExpr *pNext = p->pIENext;33 if( p->pExpr ) freeExpr(pParse->db, p->pExpr);34 sqlite3DbFree(pParse->db, p);35 p = pNext;36 }37 pParse->pIdxPartExpr = NULL;38}39 40void setUp(void) {41 int rc = sqlite3_open(":memory:", &gDb);42 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);43 memset(&gParse, 0, sizeof(gParse));44 gParse.db = gDb;45 gParse.nMem = 100; /* plenty of registers */46 gVdbe = sqlite3VdbeCreate(&gParse);47 TEST_ASSERT_NOT_NULL(gVdbe);48 /* Ensure parse points to vdbe */49 gParse.pVdbe = gVdbe;50 gParse.pIdxPartExpr = NULL;51}52 53void tearDown(void) {54 freeIdxPartExprList(&gParse);55 if( gVdbe ){56 sqlite3VdbeDelete(gVdbe);57 gVdbe = NULL;58 gParse.pVdbe = NULL;59 }60 if( gDb ){61 sqlite3_close(gDb);62 gDb = NULL;63 }64 memset(&gParse, 0, sizeof(gParse));65}66 67/* Utility: fetch op at index */68static VdbeOp *opAt(int i){69 return sqlite3VdbeGetOp(gVdbe, i);70}71 72/* Test: No matching IndexedExpr - should return 0 and emit no ops */73void test_exprPartidxExprLookup_no_match_returns_zero_and_no_ops(void){74 Expr col;75 memset(&col, 0, sizeof(col));76 col.op = TK_COLUMN;77 col.iColumn = 1;78 col.iTable = 2;79 80 int startOps = gVdbe->nOp;81 int ret = test_exprPartidxExprLookup(&gParse, &col, 5);82 TEST_ASSERT_EQUAL_INT(0, ret);83 TEST_ASSERT_EQUAL_INT(startOps, gVdbe->nOp);84}85 86/* Test: Basic match without bMaybeNullRow -> OP_Integer then OP_Affinity */87void test_exprPartidxExprLookup_basic_match_generates_integer_and_affinity(void){88 /* Build matching IndexedExpr */89 IndexedExpr *ie = (IndexedExpr*)sqlite3DbMallocZero(gDb, sizeof(IndexedExpr));90 TEST_ASSERT_NOT_NULL(ie);91 ie->iIdxCol = 1;92 ie->iDataCur = 2;93 ie->iIdxCur = 17; /* arbitrary */94 ie->bMaybeNullRow = 0;95 ie->aff = 'B'; /* TEXT affinity for testing */96 ie->pExpr = makeIntExpr(gDb, 123);97 gParse.pIdxPartExpr = ie;98 99 Expr col;100 memset(&col, 0, sizeof(col));101 col.op = TK_COLUMN;102 col.iColumn = 1;103 col.iTable = 2;104 105 int target = 7;106 int ret = test_exprPartidxExprLookup(&gParse, &col, target);107 TEST_ASSERT_EQUAL_INT(target, ret);108 109 TEST_ASSERT_EQUAL_INT(2, gVdbe->nOp); /* OP_Integer + OP_Affinity */110 111 VdbeOp *op0 = opAt(0);112 VdbeOp *op1 = opAt(1);113 TEST_ASSERT_NOT_NULL(op0);114 TEST_ASSERT_NOT_NULL(op1);115 116 TEST_ASSERT_EQUAL_INT(OP_Integer, op0->opcode);117 TEST_ASSERT_EQUAL_INT(123, op0->p1);118 TEST_ASSERT_EQUAL_INT(target, op0->p2);119 120 TEST_ASSERT_EQUAL_INT(OP_Affinity, op1->opcode);121 TEST_ASSERT_EQUAL_INT(ret, op1->p1);122 TEST_ASSERT_EQUAL_INT(1, op1->p2);123 TEST_ASSERT_EQUAL_INT(0, op1->p3);124 TEST_ASSERT_NOT_NULL(op1->p4.z);125 TEST_ASSERT_EQUAL_INT(ie->aff, (int)(unsigned char)op1->p4.z[0]);126}127 128/* Test: bMaybeNullRow true -> OP_IfNullRow inserted and patched */129void test_exprPartidxExprLookup_maybeNullRow_inserts_and_patches_IfNullRow(void){130 IndexedExpr *ie = (IndexedExpr*)sqlite3DbMallocZero(gDb, sizeof(IndexedExpr));131 TEST_ASSERT_NOT_NULL(ie);132 ie->iIdxCol = 3;133 ie->iDataCur = 4;134 ie->iIdxCur = 5; /* cursor used by IfNullRow */135 ie->bMaybeNullRow = 1;136 ie->aff = 'D'; /* INTEGER affinity */137 ie->pExpr = makeIntExpr(gDb, 77);138 gParse.pIdxPartExpr = ie;139 140 Expr col;141 memset(&col, 0, sizeof(col));142 col.op = TK_COLUMN;143 col.iColumn = 3;144 col.iTable = 4;145 146 int target = 9;147 int ret = test_exprPartidxExprLookup(&gParse, &col, target);148 TEST_ASSERT_EQUAL_INT(target, ret);149 150 TEST_ASSERT_EQUAL_INT(3, gVdbe->nOp); /* IfNullRow + Integer + Affinity */151 152 VdbeOp *op0 = opAt(0);153 VdbeOp *op1 = opAt(1);154 VdbeOp *op2 = opAt(2);155 TEST_ASSERT_NOT_NULL(op0);156 TEST_ASSERT_NOT_NULL(op1);157 TEST_ASSERT_NOT_NULL(op2);158 159 TEST_ASSERT_EQUAL_INT(OP_IfNullRow, op0->opcode);160 TEST_ASSERT_EQUAL_INT(ie->iIdxCur, op0->p1);161 /* p2 is jump destination patched by sqlite3VdbeJumpHere - ensure non-zero */162 TEST_ASSERT(op0->p2 > 0);163 /* p3 patched to ret by sqlite3VdbeChangeP3 */164 TEST_ASSERT_EQUAL_INT(ret, op0->p3);165 166 TEST_ASSERT_EQUAL_INT(OP_Integer, op1->opcode);167 TEST_ASSERT_EQUAL_INT(77, op1->p1);168 TEST_ASSERT_EQUAL_INT(target, op1->p2);169 170 TEST_ASSERT_EQUAL_INT(OP_Affinity, op2->opcode);171 TEST_ASSERT_EQUAL_INT(ret, op2->p1);172 TEST_ASSERT_EQUAL_INT(1, op2->p2);173 TEST_ASSERT_EQUAL_INT(0, op2->p3);174 TEST_ASSERT_NOT_NULL(op2->p4.z);175 TEST_ASSERT_EQUAL_INT(ie->aff, (int)(unsigned char)op2->p4.z[0]);176}177 178/* Test: Multiple nodes - ensure it skips non-matching and uses the matching one */179void test_exprPartidxExprLookup_skips_nonmatching_uses_matching_node(void){180 IndexedExpr *head = (IndexedExpr*)sqlite3DbMallocZero(gDb, sizeof(IndexedExpr));181 IndexedExpr *match = (IndexedExpr*)sqlite3DbMallocZero(gDb, sizeof(IndexedExpr));182 TEST_ASSERT_NOT_NULL(head);183 TEST_ASSERT_NOT_NULL(match);184 185 /* First node - non-matching */186 head->iIdxCol = 10;187 head->iDataCur = 20;188 head->iIdxCur = 30;189 head->bMaybeNullRow = 0;190 head->aff = 'C';191 head->pExpr = makeIntExpr(gDb, 111);192 193 /* Second node - matching */194 match->iIdxCol = 1;195 match->iDataCur = 2;196 match->iIdxCur = 40;197 match->bMaybeNullRow = 0;198 match->aff = 'E'; /* REAL affinity */199 match->pExpr = makeIntExpr(gDb, 222);200 201 head->pIENext = match;202 gParse.pIdxPartExpr = head;203 204 Expr col;205 memset(&col, 0, sizeof(col));206 col.op = TK_COLUMN;207 col.iColumn = 1;208 col.iTable = 2;209 210 int target = 12;211 int ret = test_exprPartidxExprLookup(&gParse, &col, target);212 TEST_ASSERT_EQUAL_INT(target, ret);213 214 TEST_ASSERT_EQUAL_INT(2, gVdbe->nOp);215 VdbeOp *op0 = opAt(0);216 VdbeOp *op1 = opAt(1);217 TEST_ASSERT_EQUAL_INT(OP_Integer, op0->opcode);218 TEST_ASSERT_EQUAL_INT(222, op0->p1);219 TEST_ASSERT_EQUAL_INT(target, op0->p2);220 221 TEST_ASSERT_EQUAL_INT(OP_Affinity, op1->opcode);222 TEST_ASSERT_EQUAL_INT(ret, op1->p1);223 TEST_ASSERT_NOT_NULL(op1->p4.z);224 TEST_ASSERT_EQUAL_INT(match->aff, (int)(unsigned char)op1->p4.z[0]);225}226 227/* Test: Return value is the target register when coding a simple integer expr */228void test_exprPartidxExprLookup_returns_target_register(void){229 IndexedExpr *ie = (IndexedExpr*)sqlite3DbMallocZero(gDb, sizeof(IndexedExpr));230 TEST_ASSERT_NOT_NULL(ie);231 ie->iIdxCol = 7;232 ie->iDataCur = 8;233 ie->iIdxCur = 9;234 ie->bMaybeNullRow = 0;235 ie->aff = 'B';236 ie->pExpr = makeIntExpr(gDb, 5);237 gParse.pIdxPartExpr = ie;238 239 Expr col;240 memset(&col, 0, sizeof(col));241 col.op = TK_COLUMN;242 col.iColumn = 7;243 col.iTable = 8;244 245 int target = 25;246 int ret = test_exprPartidxExprLookup(&gParse, &col, target);247 TEST_ASSERT_EQUAL_INT(target, ret);248}249 250int main(void) {251 UNITY_BEGIN();252 RUN_TEST(test_exprPartidxExprLookup_no_match_returns_zero_and_no_ops);253 RUN_TEST(test_exprPartidxExprLookup_basic_match_generates_integer_and_affinity);254 RUN_TEST(test_exprPartidxExprLookup_maybeNullRow_inserts_and_patches_IfNullRow);255 RUN_TEST(test_exprPartidxExprLookup_skips_nonmatching_uses_matching_node);256 RUN_TEST(test_exprPartidxExprLookup_returns_target_register);257 return UNITY_END();258}