AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Globals for each test */7static sqlite3 *gDb = NULL;8static Parse gParse;9 10/* Helpers to create minimal structures */11 12static Table* makeTable(sqlite3 *db, const char *zName){13 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));14 if( pTab && zName ){15 pTab->zName = sqlite3DbStrDup(db, zName);16 }17 return pTab;18}19 20static SrcList* makeSrcList1(sqlite3 *db, Table *pTab, int iCursor){21 /* SrcList already includes space for one SrcItem in its size */22 SrcList *p = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList));23 if( p ){24 p->nSrc = 1;25 p->nAlloc = 1;26 p->a[0].pTab = pTab;27 p->a[0].iCursor = iCursor;28 }29 return p;30}31 32static Expr* makeIntLiteral(sqlite3 *db, int val){33 Expr *p = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));34 if( p ){35 p->op = TK_INTEGER;36 /* For integer constants, the walker will not treat them as column refs */37 /* Optionally set u.iValue or zToken, but not required for this walker */38 p->u.iValue = val;39 }40 return p;41}42 43static Expr* makeColumnExpr(sqlite3 *db, int iCursor, int iColumn, Table *pTab){44 Expr *p = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));45 if( p ){46 p->op = TK_COLUMN;47 p->iTable = iCursor; /* Cursor id matching SrcList.a[i].iCursor */48 p->iColumn = iColumn; /* Column index (can be 0 for our purposes) */49 p->y.pTab = pTab; /* Associate to the Table (best effort) */50 }51 return p;52}53 54static ExprList* makeExprList1(Parse *pParse, Expr *pExpr){55 ExprList *pList = NULL;56 pList = sqlite3ExprListAppend(pParse, pList, pExpr);57 return pList;58}59 60static Expr* makeAggFuncWithArgs(sqlite3 *db, ExprList *pArgs){61 Expr *p = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));62 if( p ){63 p->op = TK_AGG_FUNCTION;64 /* ExprUseXList(p) will expect x.pList to be used */65 p->x.pList = pArgs;66 }67 return p;68}69 70static Expr* makeOrderByExpr(sqlite3 *db, ExprList *pOrderList){71 Expr *p = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));72 if( p ){73 p->op = TK_ORDER;74 p->x.pList = pOrderList;75 }76 return p;77}78 79static Win* makeWinWithFilter(sqlite3 *db, Expr *pFilter){80 Win *pW = (Win*)sqlite3DbMallocZero(db, sizeof(Win));81 if( pW ){82 pW->pFilter = pFilter;83 }84 return pW;85}86 87/* Unity setup/teardown */88void setUp(void) {89 memset(&gParse, 0, sizeof(gParse));90 int rc = sqlite3_open(":memory:", &gDb);91 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);92 gParse.db = gDb;93}94 95void tearDown(void) {96 if( gDb ){97 sqlite3_close(gDb);98 gDb = NULL;99 }100 memset(&gParse, 0, sizeof(gParse));101}102 103/* Tests */104 105void test_sqlite3ReferencesSrcList_no_references_returns_neg1(void){106 /* Build: sum(1) with any SrcList -> expect -1 (no table references) */107 Table *pTab = makeTable(gDb, "t1");108 SrcList *pSrc = makeSrcList1(gDb, pTab, 1);109 110 Expr *pArg = makeIntLiteral(gDb, 1);111 ExprList *pArgs = makeExprList1(&gParse, pArg);112 Expr *pFunc = makeAggFuncWithArgs(gDb, pArgs);113 114 int res = sqlite3ReferencesSrcList(&gParse, pFunc, pSrc);115 TEST_ASSERT_EQUAL_INT(-1, res);116 117 sqlite3ExprDelete(gDb, pFunc);118 sqlite3DbFree(gDb, pSrc);119 if( pTab ){120 sqlite3DbFree(gDb, pTab->zName);121 sqlite3DbFree(gDb, pTab);122 }123}124 125void test_sqlite3ReferencesSrcList_references_in_src_returns_1(void){126 /* Build: sum(col) where col is from cursor 42; SrcList contains cursor 42 */127 Table *pTab = makeTable(gDb, "t_in");128 SrcList *pSrc = makeSrcList1(gDb, pTab, 42);129 130 Expr *pCol = makeColumnExpr(gDb, 42, 0, pTab);131 ExprList *pArgs = makeExprList1(&gParse, pCol);132 Expr *pFunc = makeAggFuncWithArgs(gDb, pArgs);133 134 int res = sqlite3ReferencesSrcList(&gParse, pFunc, pSrc);135 TEST_ASSERT_EQUAL_INT(1, res);136 137 sqlite3ExprDelete(gDb, pFunc);138 sqlite3DbFree(gDb, pSrc);139 if( pTab ){140 sqlite3DbFree(gDb, pTab->zName);141 sqlite3DbFree(gDb, pTab);142 }143}144 145void test_sqlite3ReferencesSrcList_references_outside_src_returns_0(void){146 /* Build: sum(col) where col is from cursor 99; SrcList has cursor 1 */147 Table *pTabIn = makeTable(gDb, "t_in");148 SrcList *pSrc = makeSrcList1(gDb, pTabIn, 1);149 150 Table *pTabOut = makeTable(gDb, "t_out");151 Expr *pCol = makeColumnExpr(gDb, 99, 0, pTabOut);152 ExprList *pArgs = makeExprList1(&gParse, pCol);153 Expr *pFunc = makeAggFuncWithArgs(gDb, pArgs);154 155 int res = sqlite3ReferencesSrcList(&gParse, pFunc, pSrc);156 TEST_ASSERT_EQUAL_INT(0, res);157 158 sqlite3ExprDelete(gDb, pFunc);159 sqlite3DbFree(gDb, pSrc);160 if( pTabIn ){161 sqlite3DbFree(gDb, pTabIn->zName);162 sqlite3DbFree(gDb, pTabIn);163 }164 if( pTabOut ){165 sqlite3DbFree(gDb, pTabOut->zName);166 sqlite3DbFree(gDb, pTabOut);167 }168}169 170void test_sqlite3ReferencesSrcList_orderby_list_considered(void){171 /* Build: sum(1) ORDER BY col_in, where col_in is from cursor 7 in SrcList */172 Table *pTab = makeTable(gDb, "t_order");173 SrcList *pSrc = makeSrcList1(gDb, pTab, 7);174 175 Expr *pArg = makeIntLiteral(gDb, 123);176 ExprList *pArgs = makeExprList1(&gParse, pArg);177 Expr *pFunc = makeAggFuncWithArgs(gDb, pArgs);178 179 Expr *pOBCol = makeColumnExpr(gDb, 7, 0, pTab);180 ExprList *pOBList = makeExprList1(&gParse, pOBCol);181 Expr *pOrder = makeOrderByExpr(gDb, pOBList);182 pFunc->pLeft = pOrder;183 184 int res = sqlite3ReferencesSrcList(&gParse, pFunc, pSrc);185 TEST_ASSERT_EQUAL_INT(1, res);186 187 sqlite3ExprDelete(gDb, pFunc);188 sqlite3DbFree(gDb, pSrc);189 if( pTab ){190 sqlite3DbFree(gDb, pTab->zName);191 sqlite3DbFree(gDb, pTab);192 }193}194 195void test_sqlite3ReferencesSrcList_window_filter_considered(void){196 /* Build: sum(1) FILTER (WHERE col_in) where col_in belongs to SrcList cursor 5 */197 Table *pTab = makeTable(gDb, "t_win");198 SrcList *pSrc = makeSrcList1(gDb, pTab, 5);199 200 Expr *pArg = makeIntLiteral(gDb, 0);201 ExprList *pArgs = makeExprList1(&gParse, pArg);202 Expr *pFunc = makeAggFuncWithArgs(gDb, pArgs);203 204 Expr *pFilterCol = makeColumnExpr(gDb, 5, 1, pTab);205 Win *pW = makeWinWithFilter(gDb, pFilterCol);206 pFunc->flags |= EP_WinFunc;207 pFunc->y.pWin = pW;208 209 int res = sqlite3ReferencesSrcList(&gParse, pFunc, pSrc);210 TEST_ASSERT_EQUAL_INT(1, res);211 212 /* Cleanup: sqlite3ExprDelete will delete pFilterCol via walker only if attached from pFunc.213 But pFilter is not part of Expr tree, so free it explicitly first. */214 sqlite3ExprDelete(gDb, pFilterCol);215 sqlite3DbFree(gDb, pW);216 sqlite3ExprDelete(gDb, pFunc);217 sqlite3DbFree(gDb, pSrc);218 if( pTab ){219 sqlite3DbFree(gDb, pTab->zName);220 sqlite3DbFree(gDb, pTab);221 }222}223 224void test_sqlite3ReferencesSrcList_mixed_in_and_outside_prefers_1(void){225 /* Build: sum(col_in, col_out) with SrcList containing only col_in's table.226 Expect 1 since inside reference exists, even though an outside reference also exists. */227 Table *pTabIn = makeTable(gDb, "t_in");228 SrcList *pSrc = makeSrcList1(gDb, pTabIn, 11);229 230 Table *pTabOut = makeTable(gDb, "t_out");231 Expr *pColIn = makeColumnExpr(gDb, 11, 0, pTabIn);232 Expr *pColOut = makeColumnExpr(gDb, 22, 0, pTabOut);233 234 ExprList *pArgs = NULL;235 pArgs = sqlite3ExprListAppend(&gParse, pArgs, pColIn);236 pArgs = sqlite3ExprListAppend(&gParse, pArgs, pColOut);237 238 Expr *pFunc = makeAggFuncWithArgs(gDb, pArgs);239 240 int res = sqlite3ReferencesSrcList(&gParse, pFunc, pSrc);241 TEST_ASSERT_EQUAL_INT(1, res);242 243 sqlite3ExprDelete(gDb, pFunc);244 sqlite3DbFree(gDb, pSrc);245 if( pTabIn ){246 sqlite3DbFree(gDb, pTabIn->zName);247 sqlite3DbFree(gDb, pTabIn);248 }249 if( pTabOut ){250 sqlite3DbFree(gDb, pTabOut->zName);251 sqlite3DbFree(gDb, pTabOut);252 }253}254 255/* Main runner */256int main(void) {257 UNITY_BEGIN();258 RUN_TEST(test_sqlite3ReferencesSrcList_no_references_returns_neg1);259 RUN_TEST(test_sqlite3ReferencesSrcList_references_in_src_returns_1);260 RUN_TEST(test_sqlite3ReferencesSrcList_references_outside_src_returns_0);261 RUN_TEST(test_sqlite3ReferencesSrcList_orderby_list_considered);262 RUN_TEST(test_sqlite3ReferencesSrcList_window_filter_considered);263 RUN_TEST(test_sqlite3ReferencesSrcList_mixed_in_and_outside_prefers_1);264 return UNITY_END();265}