AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Globals for tests */7static sqlite3 *gDb = NULL;8 9/* Unity setup/teardown */10void setUp(void) {11 int rc = sqlite3_open(":memory:", &gDb);12 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);13 /* Create simple schema used by tests */14 rc = sqlite3_exec(gDb, "CREATE TABLE t1(a INTEGER, b TEXT);", 0, 0, 0);15 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);16}17 18void tearDown(void) {19 if (gDb) {20 sqlite3_close(gDb);21 gDb = NULL;22 }23}24 25/* Helpers to build tokens safely */26static Token makeToken(const char *z){27 Token t;28 t.z = z;29 t.n = (int)strlen(z);30 return t;31}32 33/* Helper: build SELECT <col> FROM <table> */34static Select* buildSelect_Col_From_Table(Parse *pParse, const char *zCol, const char *zTable){35 Token tCol = makeToken(zCol);36 Token tTable = makeToken(zTable);37 38 SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0, &tTable, 0);39 TEST_ASSERT_NOT_NULL(pSrc);40 41 Expr *pE = sqlite3ExprAlloc(pParse->db, TK_ID, &tCol, 0);42 TEST_ASSERT_NOT_NULL(pE);43 44 ExprList *pEList = sqlite3ExprListAppend(pParse, 0, pE);45 TEST_ASSERT_NOT_NULL(pEList);46 47 Select *pSel = sqlite3SelectNew(pParse, pEList, pSrc, 0, 0, 0, 0, 0, 0, 0);48 TEST_ASSERT_NOT_NULL(pSel);49 return pSel;50}51 52/* Helper: build SELECT <const> (no FROM) */53static Select* buildSelect_Const(Parse *pParse, const char *zConst){54 Token tConst = makeToken(zConst);55 Expr *pE = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &tConst, 0);56 TEST_ASSERT_NOT_NULL(pE);57 ExprList *pEList = sqlite3ExprListAppend(pParse, 0, pE);58 TEST_ASSERT_NOT_NULL(pEList);59 Select *pSel = sqlite3SelectNew(pParse, pEList, 0, 0, 0, 0, 0, 0, 0, 0);60 TEST_ASSERT_NOT_NULL(pSel);61 return pSel;62}63 64/* Helper: free Select safely */65static void freeSelect(Select *pSel){66 if( pSel ){67 sqlite3SelectDelete(gDb, pSel);68 }69}70 71/* Test 1: Basic resolution of columns in a simple SELECT ... FROM ... */72void test_sqlite3ResolveSelectNames_basic_select_from_table(void){73 Parse parse;74 memset(&parse, 0, sizeof(parse));75 parse.db = gDb;76 77 Select *pSel = buildSelect_Col_From_Table(&parse, "a", "t1");78 79 /* Expand then resolve */80 sqlite3SelectExpand(&parse, pSel);81 sqlite3ResolveSelectNames(&parse, pSel, NULL);82 83 /* No errors */84 TEST_ASSERT_EQUAL_INT(0, parse.nErr);85 86 /* SF_Resolved should be set */87 TEST_ASSERT_TRUE((pSel->selFlags & SF_Resolved)!=0);88 89 /* The result expression should have been resolved to TK_COLUMN */90 TEST_ASSERT_NOT_NULL(pSel->pEList);91 TEST_ASSERT_EQUAL_INT(1, pSel->pEList->nExpr);92 Expr *pExpr = pSel->pEList->a[0].pExpr;93 TEST_ASSERT_NOT_NULL(pExpr);94 TEST_ASSERT_EQUAL_INT(TK_COLUMN, pExpr->op);95 96 freeSelect(pSel);97}98 99/* Test 2: Unresolved column should yield an error */100void test_sqlite3ResolveSelectNames_unresolved_column_error(void){101 Parse parse;102 memset(&parse, 0, sizeof(parse));103 parse.db = gDb;104 105 /* Column "c" does not exist in t1 */106 Select *pSel = buildSelect_Col_From_Table(&parse, "c", "t1");107 108 sqlite3SelectExpand(&parse, pSel);109 sqlite3ResolveSelectNames(&parse, pSel, NULL);110 111 TEST_ASSERT_TRUE(parse.nErr > 0);112 113 freeSelect(pSel);114}115 116/* Test 3: Subquery in FROM should be resolved by the walker */117void test_sqlite3ResolveSelectNames_subquery_in_from_is_resolved(void){118 Parse parse;119 memset(&parse, 0, sizeof(parse));120 parse.db = gDb;121 122 /* Build subquery: SELECT 1 AS x */123 Select *pSub = buildSelect_Const(&parse, "1");124 /* Optionally name the column as "x" */125 Token tX = makeToken("x");126 sqlite3ExprListSetName(&parse, pSub->pEList, &tX, 1);127 128 /* Build outer SELECT: SELECT 1 FROM (subquery) */129 Expr *pOne = sqlite3ExprAlloc(gDb, TK_INTEGER, &tX /* reuse token len 1? No, set correct */, 0);130 /* Recreate correct const token "1" */131 Token tOne = makeToken("1");132 if( pOne==0 ){ /* allocate if NULL, but should not happen */133 pOne = sqlite3ExprAlloc(gDb, TK_INTEGER, &tOne, 0);134 }else{135 /* Replace token to "1" in case previous was "x" */136 sqlite3ExprDelete(gDb, pOne);137 pOne = sqlite3ExprAlloc(gDb, TK_INTEGER, &tOne, 0);138 }139 TEST_ASSERT_NOT_NULL(pOne);140 141 ExprList *pOuterEList = sqlite3ExprListAppend(&parse, 0, pOne);142 TEST_ASSERT_NOT_NULL(pOuterEList);143 144 SrcList *pSrc = sqlite3SrcListAppend(gDb, 0, 0, 0);145 TEST_ASSERT_NOT_NULL(pSrc);146 SrcItem *pItem = &pSrc->a[pSrc->nSrc-1];147 pItem->pSelect = pSub; /* Attach the subquery as a FROM-term */148 149 Select *pOuter = sqlite3SelectNew(&parse, pOuterEList, pSrc, 0, 0, 0, 0, 0, 0, 0);150 TEST_ASSERT_NOT_NULL(pOuter);151 152 sqlite3SelectExpand(&parse, pOuter);153 sqlite3ResolveSelectNames(&parse, pOuter, NULL);154 155 /* No errors overall */156 TEST_ASSERT_EQUAL_INT(0, parse.nErr);157 158 /* Both outer and subquery should be marked resolved */159 TEST_ASSERT_TRUE((pOuter->selFlags & SF_Resolved)!=0);160 TEST_ASSERT_TRUE((pSub->selFlags & SF_Resolved)!=0);161 162 freeSelect(pOuter); /* frees subquery as well */163}164 165/* Test 4: Compound SELECT (pPrior) should resolve all arms */166void test_sqlite3ResolveSelectNames_compound_select_resolves_both_arms(void){167 Parse parse;168 memset(&parse, 0, sizeof(parse));169 parse.db = gDb;170 171 /* First arm: SELECT a FROM t1 */172 Select *pA = buildSelect_Col_From_Table(&parse, "a", "t1");173 /* Second arm: SELECT b FROM t1 */174 Select *pB = buildSelect_Col_From_Table(&parse, "b", "t1");175 176 /* Link as a compound select */177 pA->pPrior = pB;178 /* The operator kind is not strictly necessary for the walker,179 but set to TK_ALL for clarity if available */180 pA->op = TK_ALL;181 182 /* Expand both arms before resolving */183 sqlite3SelectExpand(&parse, pA);184 sqlite3SelectExpand(&parse, pB);185 186 sqlite3ResolveSelectNames(&parse, pA, NULL);187 188 TEST_ASSERT_EQUAL_INT(0, parse.nErr);189 TEST_ASSERT_TRUE((pA->selFlags & SF_Resolved)!=0);190 TEST_ASSERT_TRUE((pB->selFlags & SF_Resolved)!=0);191 192 freeSelect(pA); /* frees pB via pPrior chain */193}194 195/* Test 5: Outer NameContext allows correlated reference to resolve */196void test_sqlite3ResolveSelectNames_outer_name_context_resolves_correlated(void){197 Parse parse;198 memset(&parse, 0, sizeof(parse));199 parse.db = gDb;200 201 /* Build inner select: SELECT a (no FROM clause) */202 Token tA = makeToken("a");203 Expr *pAexpr = sqlite3ExprAlloc(gDb, TK_ID, &tA, 0);204 TEST_ASSERT_NOT_NULL(pAexpr);205 ExprList *pEList = sqlite3ExprListAppend(&parse, 0, pAexpr);206 TEST_ASSERT_NOT_NULL(pEList);207 Select *pInner = sqlite3SelectNew(&parse, pEList, 0, 0, 0, 0, 0, 0, 0, 0);208 TEST_ASSERT_NOT_NULL(pInner);209 210 /* Construct an outer NameContext that exposes table t1 */211 SrcList *pOuterSrc = sqlite3SrcListAppend(gDb, 0, &makeToken("t1"), 0);212 TEST_ASSERT_NOT_NULL(pOuterSrc);213 /* Ensure pTab is populated so resolver can find columns */214 Table *pTab = sqlite3FindTable(gDb, "t1", 0);215 TEST_ASSERT_NOT_NULL(pTab);216 pOuterSrc->a[pOuterSrc->nSrc-1].pTab = pTab;217 218 NameContext outerNC;219 memset(&outerNC, 0, sizeof(outerNC));220 outerNC.pParse = &parse;221 outerNC.pSrcList = pOuterSrc;222 223 /* Expand then resolve using the outer name context */224 sqlite3SelectExpand(&parse, pInner);225 sqlite3ResolveSelectNames(&parse, pInner, &outerNC);226 227 /* No errors; inner should be marked resolved */228 TEST_ASSERT_EQUAL_INT(0, parse.nErr);229 TEST_ASSERT_TRUE((pInner->selFlags & SF_Resolved)!=0);230 231 /* The single result expression should have been resolved to TK_COLUMN */232 TEST_ASSERT_NOT_NULL(pInner->pEList);233 TEST_ASSERT_EQUAL_INT(1, pInner->pEList->nExpr);234 Expr *pExpr = pInner->pEList->a[0].pExpr;235 TEST_ASSERT_NOT_NULL(pExpr);236 TEST_ASSERT_EQUAL_INT(TK_COLUMN, pExpr->op);237 238 /* Cleanup */239 sqlite3SrcListDelete(gDb, pOuterSrc);240 freeSelect(pInner);241}242 243/* Unity main */244int main(void){245 UNITY_BEGIN();246 RUN_TEST(test_sqlite3ResolveSelectNames_basic_select_from_table);247 RUN_TEST(test_sqlite3ResolveSelectNames_unresolved_column_error);248 RUN_TEST(test_sqlite3ResolveSelectNames_subquery_in_from_is_resolved);249 RUN_TEST(test_sqlite3ResolveSelectNames_compound_select_resolves_both_arms);250 RUN_TEST(test_sqlite3ResolveSelectNames_outer_name_context_resolves_correlated);251 return UNITY_END();252}