AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Global DB handle for tests */7static sqlite3 *gDb = NULL;8 9/* Helper: create a Parse bound to gDb */10static void initParse(Parse *pParse){11 memset(pParse, 0, sizeof(*pParse));12 pParse->db = gDb;13}14 15/* Helper: allocate an empty SrcList (nSrc=0) using the db allocator */16static SrcList* makeEmptySrcList(sqlite3 *db){17 SrcList *p = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList));18 if( p ){19 p->nSrc = 0;20 }21 return p;22}23 24/* Helper: create an integer literal expression from text (e.g., "1") */25static Expr* makeIntExpr(sqlite3 *db, const char *z){26 Token t;27 t.z = z;28 t.n = (int)strlen(z);29 return sqlite3ExprAlloc(db, TK_INTEGER, &t, 0);30}31 32/* Helper: create an identifier expression (e.g., column or alias name) */33static Expr* makeIdExpr(sqlite3 *db, const char *z){34 Token t;35 t.z = z;36 t.n = (int)strlen(z);37 return sqlite3ExprAlloc(db, TK_ID, &t, 0);38}39 40/* Helper: create sum(1) expression */41static Expr* makeSum1Expr(Parse *pParse){42 Token tName;43 ExprList *pArgs = 0;44 pArgs = sqlite3ExprListAppend(pParse, pArgs, makeIntExpr(pParse->db, "1"));45 tName.z = "sum";46 tName.n = 3;47 return sqlite3ExprFunction(pParse, pArgs, &tName);48}49 50/* Helper: create a simple expanded SELECT with constant result: SELECT 1; */51static Select* makeExpandedConstSelect(Parse *pParse){52 Select *p = (Select*)sqlite3DbMallocZero(pParse->db, sizeof(Select));53 if( p==0 ) return 0;54 p->pSrc = makeEmptySrcList(pParse->db);55 p->pEList = sqlite3ExprListAppend(pParse, 0, makeIntExpr(pParse->db, "1"));56 p->selFlags = SF_Expanded; /* Pretend already expanded */57 return p;58}59 60/* Helper: free a Select */61static void freeSelect(Select *p){62 if( p ) sqlite3SelectDelete(gDb, p);63}64 65void setUp(void) {66 int rc = sqlite3_open(":memory:", &gDb);67 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);68 TEST_ASSERT_NOT_NULL(gDb);69}70 71void tearDown(void) {72 if( gDb ){73 sqlite3_close(gDb);74 gDb = NULL;75 }76}77 78/* Test: If SF_Resolved is already set, resolveSelectStep returns WRC_Prune immediately. */79void test_resolveSelectStep_already_resolved_returns_prune(void){80 Parse parse; initParse(&parse);81 Walker w; memset(&w, 0, sizeof(w)); w.pParse = &parse; w.u.pNC = 0;82 83 Select *p = (Select*)sqlite3DbMallocZero(gDb, sizeof(Select));84 TEST_ASSERT_NOT_NULL(p);85 p->selFlags = SF_Resolved; /* Already resolved */86 87 int rc = test_resolveSelectStep(&w, p);88 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);89 90 freeSelect(p);91}92 93/* Test: Expanded constant-only SELECT resolves successfully and sets SF_Resolved. */94void test_resolveSelectStep_expanded_constant_success(void){95 Parse parse; initParse(&parse);96 Walker w; memset(&w, 0, sizeof(w)); w.pParse = &parse; w.u.pNC = 0;97 98 Select *p = makeExpandedConstSelect(&parse);99 TEST_ASSERT_NOT_NULL(p);100 TEST_ASSERT_NOT_NULL(p->pSrc);101 TEST_ASSERT_NOT_NULL(p->pEList);102 103 int rc = test_resolveSelectStep(&w, p);104 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);105 TEST_ASSERT_TRUE(p->selFlags & SF_Resolved);106 TEST_ASSERT_EQUAL_INT(0, parse.nErr);107 108 freeSelect(p);109}110 111/* Test: Non-expanded SELECT defers to sqlite3SelectPrep and returns WRC_Prune on success. */112void test_resolveSelectStep_not_expanded_calls_select_prep(void){113 Parse parse; initParse(&parse);114 Walker w; memset(&w, 0, sizeof(w)); w.pParse = &parse; w.u.pNC = 0;115 116 Select *p = (Select*)sqlite3DbMallocZero(gDb, sizeof(Select));117 TEST_ASSERT_NOT_NULL(p);118 /* Provide minimal valid components */119 p->pSrc = makeEmptySrcList(gDb);120 p->pEList = sqlite3ExprListAppend(&parse, 0, makeIntExpr(gDb, "1"));121 /* selFlags intentionally does NOT include SF_Expanded */122 123 int rc = test_resolveSelectStep(&w, p);124 TEST_ASSERT_EQUAL_INT_MESSAGE(WRC_Prune, rc, "Expected sqlite3SelectPrep path to succeed");125 /* sqlite3SelectPrep should have run and resolved the SELECT */126 TEST_ASSERT_TRUE(p->selFlags & SF_Resolved);127 TEST_ASSERT_EQUAL_INT(0, parse.nErr);128 129 freeSelect(p);130}131 132/* Test: SELECT with aggregate in the result-set sets SF_Aggregate and resolves. */133void test_resolveSelectStep_result_aggregate_sets_flag(void){134 Parse parse; initParse(&parse);135 Walker w; memset(&w, 0, sizeof(w)); w.pParse = &parse; w.u.pNC = 0;136 137 Select *p = (Select*)sqlite3DbMallocZero(gDb, sizeof(Select));138 TEST_ASSERT_NOT_NULL(p);139 p->pSrc = makeEmptySrcList(gDb);140 p->pEList = 0;141 /* Build sum(1) */142 Expr *pSum = makeSum1Expr(&parse);143 TEST_ASSERT_NOT_NULL(pSum);144 p->pEList = sqlite3ExprListAppend(&parse, p->pEList, pSum);145 TEST_ASSERT_NOT_NULL(p->pEList);146 p->selFlags = SF_Expanded;147 148 int rc = test_resolveSelectStep(&w, p);149 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);150 TEST_ASSERT_TRUE_MESSAGE((p->selFlags & SF_Aggregate)!=0, "SF_Aggregate not set");151 TEST_ASSERT_EQUAL_INT(0, parse.nErr);152 153 freeSelect(p);154}155 156/* Test: HAVING on a non-aggregate query triggers an error and aborts. */157void test_resolveSelectStep_having_on_non_aggregate_aborts(void){158 Parse parse; initParse(&parse);159 Walker w; memset(&w, 0, sizeof(w)); w.pParse = &parse; w.u.pNC = 0;160 161 Select *p = makeExpandedConstSelect(&parse);162 TEST_ASSERT_NOT_NULL(p);163 /* Add HAVING 1 */164 p->pHaving = makeIntExpr(gDb, "1");165 166 int rc = test_resolveSelectStep(&w, p);167 TEST_ASSERT_EQUAL_INT(WRC_Abort, rc);168 TEST_ASSERT_TRUE(parse.nErr>0);169 170 freeSelect(p);171}172 173/* Test: ORDER BY alias resolves to result-set column (iOrderByCol set). */174void test_resolveSelectStep_order_by_alias_resolves(void){175 Parse parse; initParse(&parse);176 Walker w; memset(&w, 0, sizeof(w)); w.pParse = &parse; w.u.pNC = 0;177 178 Select *p = (Select*)sqlite3DbMallocZero(gDb, sizeof(Select));179 TEST_ASSERT_NOT_NULL(p);180 p->pSrc = makeEmptySrcList(gDb);181 /* Build 1+2 AS x */182 Expr *pLeft = makeIntExpr(gDb, "1");183 Expr *pRight = makeIntExpr(gDb, "2");184 Expr *pPlus = sqlite3PExpr(&parse, TK_PLUS, pLeft, pRight);185 TEST_ASSERT_NOT_NULL(pPlus);186 p->pEList = sqlite3ExprListAppend(&parse, 0, pPlus);187 TEST_ASSERT_NOT_NULL(p->pEList);188 Token tX; tX.z = "x"; tX.n = 1;189 sqlite3ExprListSetName(&parse, p->pEList, &tX, 1);190 191 /* ORDER BY x */192 p->pOrderBy = sqlite3ExprListAppend(&parse, 0, makeIdExpr(gDb, "x"));193 194 p->selFlags = SF_Expanded;195 196 int rc = test_resolveSelectStep(&w, p);197 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);198 TEST_ASSERT_NOT_NULL(p->pOrderBy);199 TEST_ASSERT_TRUE(p->pOrderBy->nExpr>=1);200 /* iOrderByCol should indicate it matches the first result column */201 TEST_ASSERT_TRUE_MESSAGE(p->pOrderBy->a[0].u.x.iOrderByCol==1 || p->pOrderBy->a[0].u.x.iOrderByCol>0,202 "ORDER BY alias did not resolve to a result-set column");203 TEST_ASSERT_EQUAL_INT(0, parse.nErr);204 205 freeSelect(p);206}207 208int main(void){209 UNITY_BEGIN();210 RUN_TEST(test_resolveSelectStep_already_resolved_returns_prune);211 RUN_TEST(test_resolveSelectStep_expanded_constant_success);212 RUN_TEST(test_resolveSelectStep_not_expanded_calls_select_prep);213 RUN_TEST(test_resolveSelectStep_result_aggregate_sets_flag);214 RUN_TEST(test_resolveSelectStep_having_on_non_aggregate_aborts);215 RUN_TEST(test_resolveSelectStep_order_by_alias_resolves);216 return UNITY_END();217}