AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <string.h>5 6/* Global database handle for tests */7static sqlite3 *gDb = NULL;8 9/* Helper to initialize a Parse object */10static void initParse(Parse *p, sqlite3 *db){11 memset(p, 0, sizeof(*p));12 p->db = db;13}14 15/* Helper: create an integer literal expression */16static Expr* makeIntLiteral(Parse *pParse, const char *z){17 return sqlite3Expr(pParse->db, TK_INTEGER, z);18}19 20/* Helper: create a single-arg function expression, e.g., name(arglit) */21static Expr* makeFunc1(Parse *pParse, const char *zName, const char *arglit){22 Expr *pArg = makeIntLiteral(pParse, arglit);23 ExprList *pArgs = sqlite3ExprListAppend(pParse, 0, pArg);24 Token t;25 t.z = (char*)zName;26 t.n = (int)strlen(zName);27 return sqlite3ExprFunction(pParse, pArgs, &t);28}29 30/* Helper: append an expression to a new or existing list */31static ExprList* listAppend(Parse *pParse, ExprList *pList, Expr *pExpr){32 return sqlite3ExprListAppend(pParse, pList, pExpr);33}34 35void setUp(void) {36 int rc = sqlite3_open(":memory:", &gDb);37 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);38}39 40void tearDown(void) {41 if( gDb ){42 sqlite3_close(gDb);43 gDb = NULL;44 }45}46 47/* Test: pList == NULL should return SQLITE_OK and not modify ncFlags */48void test_sqlite3ResolveExprListNames_null_list(void){49 Parse p;50 initParse(&p, gDb);51 52 NameContext nc;53 memset(&nc, 0, sizeof(nc));54 nc.pParse = &p;55 nc.ncFlags = (u16)(NC_HasAgg | NC_MinMaxAgg | NC_HasWin | NC_OrderAgg);56 57 u16 before = nc.ncFlags;58 int rc = sqlite3ResolveExprListNames(&nc, NULL);59 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);60 TEST_ASSERT_EQUAL_UINT16(before, nc.ncFlags);61}62 63/* Test: simple literal expression should not set EP_Agg/EP_Win and ncFlags remain 0 */64void test_sqlite3ResolveExprListNames_plain_literal(void){65 Parse p;66 initParse(&p, gDb);67 68 NameContext nc;69 memset(&nc, 0, sizeof(nc));70 nc.pParse = &p;71 72 Expr *pOne = makeIntLiteral(&p, "1");73 ExprList *pList = listAppend(&p, NULL, pOne);74 75 int rc = sqlite3ResolveExprListNames(&nc, pList);76 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);77 78 /* First and only expression */79 Expr *pExpr0 = pList->a[0].pExpr;80 TEST_ASSERT_NOT_NULL(pExpr0);81 TEST_ASSERT_EQUAL_INT(0, (pExpr0->flags & (EP_Agg|EP_Win)));82 TEST_ASSERT_EQUAL_UINT16(0, (nc.ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg)));83 84 sqlite3ExprListDelete(p.db, pList);85}86 87/* Test: aggregate function count(1) sets EP_Agg and NC_HasAgg */88void test_sqlite3ResolveExprListNames_simple_agg_count(void){89 Parse p;90 initParse(&p, gDb);91 92 NameContext nc;93 memset(&nc, 0, sizeof(nc));94 nc.pParse = &p;95 96 Expr *pCnt = makeFunc1(&p, "count", "1");97 ExprList *pList = listAppend(&p, NULL, pCnt);98 99 int rc = sqlite3ResolveExprListNames(&nc, pList);100 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101 102 Expr *pExpr0 = pList->a[0].pExpr;103 TEST_ASSERT_NOT_NULL(pExpr0);104 TEST_ASSERT_NOT_EQUAL(0, (pExpr0->flags & EP_Agg));105 TEST_ASSERT_EQUAL_INT(0, (pExpr0->flags & EP_Win));106 TEST_ASSERT_NOT_EQUAL(0, (nc.ncFlags & NC_HasAgg));107 108 sqlite3ExprListDelete(p.db, pList);109}110 111/* Test: savedHasAgg behavior across multiple expressions: [1, count(1)] */112void test_sqlite3ResolveExprListNames_two_exprs_savedHasAgg(void){113 Parse p;114 initParse(&p, gDb);115 116 NameContext nc;117 memset(&nc, 0, sizeof(nc));118 nc.pParse = &p;119 120 Expr *pOne = makeIntLiteral(&p, "1");121 Expr *pCnt = makeFunc1(&p, "count", "1");122 ExprList *pList = NULL;123 pList = listAppend(&p, pList, pOne);124 pList = listAppend(&p, pList, pCnt);125 126 int rc = sqlite3ResolveExprListNames(&nc, pList);127 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);128 129 Expr *pExpr0 = pList->a[0].pExpr;130 Expr *pExpr1 = pList->a[1].pExpr;131 TEST_ASSERT_NOT_NULL(pExpr0);132 TEST_ASSERT_NOT_NULL(pExpr1);133 TEST_ASSERT_EQUAL_INT(0, (pExpr0->flags & (EP_Agg|EP_Win)));134 TEST_ASSERT_NOT_EQUAL(0, (pExpr1->flags & EP_Agg));135 TEST_ASSERT_NOT_EQUAL(0, (nc.ncFlags & NC_HasAgg));136 137 sqlite3ExprListDelete(p.db, pList);138}139 140/* Test: min(1) should set EP_Agg on expr and NC_MinMaxAgg in ncFlags (and NC_HasAgg) */141void test_sqlite3ResolveExprListNames_minmax_flags(void){142 Parse p;143 initParse(&p, gDb);144 145 NameContext nc;146 memset(&nc, 0, sizeof(nc));147 nc.pParse = &p;148 149 Expr *pMin = makeFunc1(&p, "min", "1");150 ExprList *pList = listAppend(&p, NULL, pMin);151 152 int rc = sqlite3ResolveExprListNames(&nc, pList);153 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);154 155 Expr *pExpr0 = pList->a[0].pExpr;156 TEST_ASSERT_NOT_NULL(pExpr0);157 TEST_ASSERT_NOT_EQUAL(0, (pExpr0->flags & EP_Agg));158 TEST_ASSERT_NOT_EQUAL(0, (nc.ncFlags & NC_HasAgg));159 TEST_ASSERT_NOT_EQUAL(0, (nc.ncFlags & NC_MinMaxAgg));160 161 sqlite3ExprListDelete(p.db, pList);162}163 164/* Test: initial flags (e.g., NC_OrderAgg) are preserved and unioned with found flags */165void test_sqlite3ResolveExprListNames_preserves_initial_flags(void){166 Parse p;167 initParse(&p, gDb);168 169 NameContext nc;170 memset(&nc, 0, sizeof(nc));171 nc.pParse = &p;172 nc.ncFlags = NC_OrderAgg; /* Pretend we enter with this flag already set */173 174 u16 initial = nc.ncFlags;175 176 Expr *pSum = makeFunc1(&p, "sum", "1");177 ExprList *pList = listAppend(&p, NULL, pSum);178 179 int rc = sqlite3ResolveExprListNames(&nc, pList);180 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);181 182 /* Should keep NC_OrderAgg and also set NC_HasAgg due to sum() */183 TEST_ASSERT_NOT_EQUAL(0, (nc.ncFlags & NC_OrderAgg));184 TEST_ASSERT_NOT_EQUAL(0, (nc.ncFlags & NC_HasAgg));185 /* Initial must still be present */186 TEST_ASSERT_EQUAL_UINT16(NC_OrderAgg, (nc.ncFlags & NC_OrderAgg));187 188 sqlite3ExprListDelete(p.db, pList);189}190 191/* Test: NULL entry in list is skipped and does not crash; non-NULL still processed */192void test_sqlite3ResolveExprListNames_skips_null_entries(void){193 Parse p;194 initParse(&p, gDb);195 196 NameContext nc;197 memset(&nc, 0, sizeof(nc));198 nc.pParse = &p;199 200 Expr *pOne = makeIntLiteral(&p, "1");201 Expr *pCnt = makeFunc1(&p, "count", "1");202 ExprList *pList = NULL;203 pList = listAppend(&p, pList, pOne);204 pList = listAppend(&p, pList, pCnt);205 206 /* Manually null-out first expression to exercise skip path */207 pList->a[0].pExpr = NULL;208 209 int rc = sqlite3ResolveExprListNames(&nc, pList);210 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);211 212 /* The second expression should still be marked as aggregate */213 Expr *pExpr1 = pList->a[1].pExpr;214 TEST_ASSERT_NOT_NULL(pExpr1);215 TEST_ASSERT_NOT_EQUAL(0, (pExpr1->flags & EP_Agg));216 TEST_ASSERT_NOT_EQUAL(0, (nc.ncFlags & NC_HasAgg));217 218 sqlite3ExprListDelete(p.db, pList);219}220 221/* Test: if pParse->nErr > 0, function returns SQLITE_ERROR */222void test_sqlite3ResolveExprListNames_returns_error_on_parse_error(void){223 Parse p;224 initParse(&p, gDb);225 226 NameContext nc;227 memset(&nc, 0, sizeof(nc));228 nc.pParse = &p;229 230 Expr *pOne = makeIntLiteral(&p, "1");231 ExprList *pList = listAppend(&p, NULL, pOne);232 233 p.nErr = 1; /* Simulate prior parse/resolve error */234 235 int rc = sqlite3ResolveExprListNames(&nc, pList);236 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);237 238 /* Cleanup */239 sqlite3ExprListDelete(p.db, pList);240}241 242int main(void){243 UNITY_BEGIN();244 RUN_TEST(test_sqlite3ResolveExprListNames_null_list);245 RUN_TEST(test_sqlite3ResolveExprListNames_plain_literal);246 RUN_TEST(test_sqlite3ResolveExprListNames_simple_agg_count);247 RUN_TEST(test_sqlite3ResolveExprListNames_two_exprs_savedHasAgg);248 RUN_TEST(test_sqlite3ResolveExprListNames_minmax_flags);249 RUN_TEST(test_sqlite3ResolveExprListNames_preserves_initial_flags);250 RUN_TEST(test_sqlite3ResolveExprListNames_skips_null_entries);251 RUN_TEST(test_sqlite3ResolveExprListNames_returns_error_on_parse_error);252 return UNITY_END();253}