AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Unity setUp/tearDown */7void setUp(void) {8 /* Setup code here, or leave empty */9}10void tearDown(void) {11 /* Cleanup code here, or leave empty */12}13 14/* Helper: Create a Parse with an open in-memory DB. Returns 0 on success. */15static int open_db_and_init_parse(sqlite3 **ppDb, Parse *pParse){16 sqlite3 *db = 0;17 int rc = sqlite3_open(":memory:", &db);18 if( rc!=SQLITE_OK ){19 return rc;20 }21 memset(pParse, 0, sizeof(Parse));22 pParse->db = db;23 *ppDb = db;24 return SQLITE_OK;25}26 27/* Helper: Create a simple TK_NULL expression */28static Expr* make_null_expr(sqlite3 *db){29 return sqlite3ExprAlloc(db, TK_NULL, 0, 0);30}31 32/* Helper: Create a TK_INTEGER expression from a literal "1" */33static Expr* make_int1_expr(sqlite3 *db){34 static const char oneStr[] = "1";35 Token tOne;36 tOne.z = (char*)oneStr;37 tOne.n = (int)strlen(oneStr);38 return sqlite3ExprAlloc(db, TK_INTEGER, &tOne, 0);39}40 41/* Helper: Create an aggregate function expression COUNT(1) */42static Expr* make_count1_expr(Parse *pParse){43 sqlite3 *db = pParse->db;44 45 /* Build argument list: (1) */46 Expr *arg = make_int1_expr(db);47 if( arg==0 ) return 0;48 49 ExprList *pList = sqlite3ExprListAppend(pParse, 0, arg);50 if( pList==0 ){51 sqlite3ExprDelete(db, arg);52 return 0;53 }54 55 /* Build function token: "count" */56 static const char cntStr[] = "count";57 Token tFunc;58 tFunc.z = (char*)cntStr;59 tFunc.n = (int)strlen(cntStr);60 61 /* Allocate the function Expr node with TK_FUNCTION and attach the arg list */62 Expr *pFunc = sqlite3ExprAlloc(db, TK_FUNCTION, &tFunc, 0);63 if( pFunc==0 ){64 sqlite3ExprListDelete(db, pList);65 return 0;66 }67 pFunc->x.pList = pList;68 69 return pFunc;70}71 72/* Test 1: NULL expression returns SQLITE_OK and preserves NameContext flags */73void test_sqlite3ResolveExprNames_null_expr_returns_ok_and_preserves_flags(void){74 sqlite3 *db = 0;75 Parse parse;76 int rc;77 78 rc = open_db_and_init_parse(&db, &parse);79 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);80 81 NameContext nc;82 memset(&nc, 0, sizeof(nc));83 nc.pParse = &parse;84 85 /* Seed ncFlags with the flags that the function saves/restores */86 nc.ncFlags = NC_HasAgg | NC_MinMaxAgg | NC_HasWin | NC_OrderAgg;87 88 rc = sqlite3ResolveExprNames(&nc, 0);89 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);90 91 /* Ensure flags are preserved */92 TEST_ASSERT_TRUE((nc.ncFlags & NC_HasAgg) != 0);93 TEST_ASSERT_TRUE((nc.ncFlags & NC_MinMaxAgg) != 0);94 TEST_ASSERT_TRUE((nc.ncFlags & NC_HasWin) != 0);95 TEST_ASSERT_TRUE((nc.ncFlags & NC_OrderAgg) != 0);96 97 sqlite3_close(db);98}99 100/* Test 2: Simple literal expression (TK_NULL) does not set EP_Agg or EP_Win on the expr.101 Pre-existing NC flags are preserved on NameContext but not propagated to expr. */102void test_sqlite3ResolveExprNames_literal_expr_no_agg_no_win_sets_no_flags(void){103 sqlite3 *db = 0;104 Parse parse;105 int rc;106 107 rc = open_db_and_init_parse(&db, &parse);108 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);109 110 Expr *pExpr = make_null_expr(db);111 TEST_ASSERT_NOT_NULL(pExpr);112 113 NameContext nc;114 memset(&nc, 0, sizeof(nc));115 nc.pParse = &parse;116 117 /* Pre-set NC_HasAgg and NC_HasWin to ensure they are not copied to Expr flags */118 nc.ncFlags = NC_HasAgg | NC_HasWin | NC_MinMaxAgg | NC_OrderAgg;119 120 rc = sqlite3ResolveExprNames(&nc, pExpr);121 TEST_ASSERT_EQUAL_INT(0, rc); /* 0 means no errors */122 123 /* The expression should not have aggregate or window properties set */124 TEST_ASSERT_EQUAL_INT(0, (pExpr->flags & EP_Agg));125 TEST_ASSERT_EQUAL_INT(0, (pExpr->flags & EP_Win));126 127 /* NameContext flags should still include the pre-existing ones */128 TEST_ASSERT_TRUE((nc.ncFlags & NC_HasAgg) != 0);129 TEST_ASSERT_TRUE((nc.ncFlags & NC_HasWin) != 0);130 TEST_ASSERT_TRUE((nc.ncFlags & NC_MinMaxAgg) != 0);131 TEST_ASSERT_TRUE((nc.ncFlags & NC_OrderAgg) != 0);132 133 sqlite3ExprDelete(db, pExpr);134 sqlite3_close(db);135}136 137/* Test 3: Aggregate function COUNT(1) sets NC_HasAgg and EP_Agg on the root expression */138void test_sqlite3ResolveExprNames_aggregate_function_sets_flags(void){139 sqlite3 *db = 0;140 Parse parse;141 int rc;142 143 rc = open_db_and_init_parse(&db, &parse);144 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);145 146 Expr *pFunc = make_count1_expr(&parse);147 TEST_ASSERT_NOT_NULL(pFunc);148 149 NameContext nc;150 memset(&nc, 0, sizeof(nc));151 nc.pParse = &parse;152 153 /* Allow aggregates in this context */154 nc.ncFlags = NC_AllowAgg;155 156 rc = sqlite3ResolveExprNames(&nc, pFunc);157 TEST_ASSERT_EQUAL_INT(0, rc); /* success (no errors) */158 159 /* The NameContext should indicate an aggregate was encountered */160 TEST_ASSERT_TRUE((nc.ncFlags & NC_HasAgg) != 0);161 162 /* The root expression should be marked as aggregate */163 TEST_ASSERT_TRUE((pFunc->flags & EP_Agg) != 0);164 165 /* It should not be marked as a window function just from COUNT(1) */166 TEST_ASSERT_EQUAL_INT(0, (pFunc->flags & EP_Win));167 168 sqlite3ExprDelete(db, pFunc);169 sqlite3_close(db);170}171 172int main(void) {173 UNITY_BEGIN();174 RUN_TEST(test_sqlite3ResolveExprNames_null_expr_returns_ok_and_preserves_flags);175 RUN_TEST(test_sqlite3ResolveExprNames_literal_expr_no_agg_no_win_sets_no_flags);176 RUN_TEST(test_sqlite3ResolveExprNames_aggregate_function_sets_flags);177 return UNITY_END();178}