AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Forward declaration of the test wrapper provided in the module */6int test_resolveCompoundOrderBy(Parse *pParse, Select *pSelect);7 8/* Global DB for each test */9static sqlite3 *gDb = NULL;10 11/* Helpers */12static Token mkToken(const char *z){13 Token t;14 t.z = (char*)z;15 t.n = (int)strlen(z);16 return t;17}18 19static Expr* makeIdExpr(sqlite3 *db, const char *z){20 Token t = mkToken(z);21 return sqlite3ExprAlloc(db, TK_ID, &t, 0);22}23 24static Expr* makeIntExpr(sqlite3 *db, int v){25 return sqlite3ExprInt32(db, v);26}27 28static ExprList* appendExpr(Parse *pParse, ExprList *pList, Expr *pExpr){29 return sqlite3ExprListAppend(pParse, pList, pExpr);30}31 32static ExprList* makeOrderBy1(Parse *pParse, Expr *p1){33 ExprList *p = NULL;34 p = appendExpr(pParse, p, p1);35 return p;36}37 38static ExprList* makeOrderBy2(Parse *pParse, Expr *p1, Expr *p2){39 ExprList *p = NULL;40 p = appendExpr(pParse, p, p1);41 p = appendExpr(pParse, p, p2);42 return p;43}44 45static ExprList* makeEListWithAliases(Parse *pParse, const char **aliases, int nAlias){46 ExprList *p = NULL;47 for(int i=0; i<nAlias; i++){48 /* The actual expression does not matter for alias matching. Use integer constants. */49 p = appendExpr(pParse, p, makeIntExpr(pParse->db, i+100));50 if( aliases && aliases[i] ){51 Token t = mkToken(aliases[i]);52 /* Set alias on the most recently appended item */53 sqlite3ExprListSetName(pParse, p, &t, 1);54 }55 }56 return p;57}58 59static Select* makeSelect(Parse *pParse, ExprList *pEList, ExprList *pOrderBy){60 Select *pSel = (Select*)sqlite3DbMallocZero(pParse->db, sizeof(Select));61 TEST_ASSERT_NOT_NULL(pSel);62 pSel->pEList = pEList;63 pSel->pOrderBy = pOrderBy;64 return pSel;65}66 67void setUp(void) {68 int rc = sqlite3_open(":memory:", &gDb);69 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);70}71 72void tearDown(void) {73 if( gDb ){74 sqlite3_close(gDb);75 gDb = NULL;76 }77}78 79/* Test: No ORDER BY clause should return 0 (no errors) */80void test_resolveCompoundOrderBy_no_order_by_returns0(void){81 Parse s = {0};82 s.db = gDb;83 84 const char *aliases[] = { "c1" };85 ExprList *pEList = makeEListWithAliases(&s, aliases, 1);86 Select *pSel = makeSelect(&s, pEList, NULL);87 88 int rc = test_resolveCompoundOrderBy(&s, pSel);89 TEST_ASSERT_EQUAL_INT(0, rc);90 91 sqlite3SelectDelete(gDb, pSel);92}93 94/* Test: ORDER BY integer within range is accepted and transformed */95void test_resolveCompoundOrderBy_integer_within_range(void){96 Parse s = (Parse){0};97 s.db = gDb;98 99 const char *aliases[] = { "a", "b", "c" };100 ExprList *pEList = makeEListWithAliases(&s, aliases, 3);101 ExprList *pOrderBy = makeOrderBy1(&s, makeIntExpr(gDb, 2));102 Select *pSel = makeSelect(&s, pEList, pOrderBy);103 104 int rc = test_resolveCompoundOrderBy(&s, pSel);105 TEST_ASSERT_EQUAL_INT(0, rc);106 107 TEST_ASSERT_EQUAL_INT(1, pOrderBy->a[0].fg.done);108 TEST_ASSERT_EQUAL_UINT16(2, pOrderBy->a[0].u.x.iOrderByCol);109 TEST_ASSERT_NOT_NULL(pOrderBy->a[0].pExpr);110 TEST_ASSERT_EQUAL_INT(TK_INTEGER, pOrderBy->a[0].pExpr->op);111 112 sqlite3SelectDelete(gDb, pSel);113}114 115/* Test: ORDER BY integer out of range should raise an error */116void test_resolveCompoundOrderBy_integer_out_of_range(void){117 Parse s = (Parse){0};118 s.db = gDb;119 120 const char *aliases[] = { "a" };121 ExprList *pEList = makeEListWithAliases(&s, aliases, 1);122 /* ORDER BY 2 while only 1 column available */123 ExprList *pOrderBy = makeOrderBy1(&s, makeIntExpr(gDb, 2));124 Select *pSel = makeSelect(&s, pEList, pOrderBy);125 126 int rc = test_resolveCompoundOrderBy(&s, pSel);127 TEST_ASSERT_EQUAL_INT(1, rc);128 TEST_ASSERT_NOT_NULL(s.zErrMsg);129 TEST_ASSERT_NOT_EQUAL(NULL, strstr(s.zErrMsg, "out of range"));130 131 sqlite3SelectDelete(gDb, pSel);132}133 134/* Test: ORDER BY alias name resolves to correct column index */135void test_resolveCompoundOrderBy_alias_match(void){136 Parse s = (Parse){0};137 s.db = gDb;138 139 const char *aliases[] = { "c1", "c2" };140 ExprList *pEList = makeEListWithAliases(&s, aliases, 2);141 142 Expr *pId = makeIdExpr(gDb, "c1");143 ExprList *pOrderBy = makeOrderBy1(&s, pId);144 145 Select *pSel = makeSelect(&s, pEList, pOrderBy);146 147 int rc = test_resolveCompoundOrderBy(&s, pSel);148 TEST_ASSERT_EQUAL_INT(0, rc);149 150 TEST_ASSERT_EQUAL_INT(1, pOrderBy->a[0].fg.done);151 TEST_ASSERT_EQUAL_UINT16(1, pOrderBy->a[0].u.x.iOrderByCol);152 TEST_ASSERT_NOT_NULL(pOrderBy->a[0].pExpr);153 TEST_ASSERT_EQUAL_INT(TK_INTEGER, pOrderBy->a[0].pExpr->op);154 155 sqlite3SelectDelete(gDb, pSel);156}157 158/* Test: ORDER BY identifier that does not match any result column generates error */159void test_resolveCompoundOrderBy_identifier_no_match_errors(void){160 Parse s = (Parse){0};161 s.db = gDb;162 163 const char *aliases[] = { "a" };164 ExprList *pEList = makeEListWithAliases(&s, aliases, 1);165 ExprList *pOrderBy = makeOrderBy1(&s, makeIdExpr(gDb, "b")); /* Does not match */166 Select *pSel = makeSelect(&s, pEList, pOrderBy);167 168 int rc = test_resolveCompoundOrderBy(&s, pSel);169 TEST_ASSERT_EQUAL_INT(1, rc);170 TEST_ASSERT_NOT_NULL(s.zErrMsg);171 TEST_ASSERT_NOT_EQUAL(NULL, strstr(s.zErrMsg, "does not match any column"));172 173 sqlite3SelectDelete(gDb, pSel);174}175 176/* Test: ORDER BY with COLLATE wrapper preserves COLLATE and replaces inner expr */177void test_resolveCompoundOrderBy_collate_wrapped_expr(void){178 Parse s = (Parse){0};179 s.db = gDb;180 181 const char *aliases[] = { "x" };182 ExprList *pEList = makeEListWithAliases(&s, aliases, 1);183 184 Expr *pInner = makeIdExpr(gDb, "x");185 Expr *pCollated = sqlite3ExprAddCollateString(gDb, pInner, "BINARY");186 ExprList *pOrderBy = makeOrderBy1(&s, pCollated);187 188 Select *pSel = makeSelect(&s, pEList, pOrderBy);189 190 int rc = test_resolveCompoundOrderBy(&s, pSel);191 TEST_ASSERT_EQUAL_INT(0, rc);192 193 TEST_ASSERT_EQUAL_INT(1, pOrderBy->a[0].fg.done);194 TEST_ASSERT_EQUAL_UINT16(1, pOrderBy->a[0].u.x.iOrderByCol);195 /* The outer expression should remain TK_COLLATE with integer left child */196 TEST_ASSERT_NOT_NULL(pOrderBy->a[0].pExpr);197 TEST_ASSERT_EQUAL_INT(TK_COLLATE, pOrderBy->a[0].pExpr->op);198 TEST_ASSERT_NOT_NULL(pOrderBy->a[0].pExpr->pLeft);199 TEST_ASSERT_EQUAL_INT(TK_INTEGER, pOrderBy->a[0].pExpr->pLeft->op);200 201 sqlite3SelectDelete(gDb, pSel);202}203 204/* Test: Too many ORDER BY terms compared to SQLITE_LIMIT_COLUMN should error */205void test_resolveCompoundOrderBy_too_many_terms_limit_error(void){206 Parse s = (Parse){0};207 s.db = gDb;208 209 /* Set a very low column limit for ORDER BY term count check */210 int prior = sqlite3_limit(gDb, SQLITE_LIMIT_COLUMN, 1);211 (void)prior; /* unused */212 213 const char *aliases[] = { "a", "b" };214 ExprList *pEList = makeEListWithAliases(&s, aliases, 2);215 ExprList *pOrderBy = makeOrderBy2(&s, makeIntExpr(gDb, 1), makeIntExpr(gDb, 2));216 Select *pSel = makeSelect(&s, pEList, pOrderBy);217 218 int rc = test_resolveCompoundOrderBy(&s, pSel);219 TEST_ASSERT_EQUAL_INT(1, rc);220 TEST_ASSERT_NOT_NULL(s.zErrMsg);221 TEST_ASSERT_NOT_EQUAL(NULL, strstr(s.zErrMsg, "too many terms"));222 223 sqlite3SelectDelete(gDb, pSel);224 225 /* Restore a reasonable limit for other tests just in case */226 sqlite3_limit(gDb, SQLITE_LIMIT_COLUMN, 2000);227}228 229/* Test: Compound SELECT chain; ORDER BY alias resolved in a later SELECT */230void test_resolveCompoundOrderBy_compound_chain_resolution(void){231 Parse s = (Parse){0};232 s.db = gDb;233 234 /* Left-most SELECT: aliases do not include "x" */235 const char *leftAliases[] = { "a1", "a2" };236 ExprList *pLeftEList = makeEListWithAliases(&s, leftAliases, 2);237 Select *pLeft = makeSelect(&s, pLeftEList, NULL);238 239 /* Right-most SELECT: alias contains "x" */240 const char *rightAliases[] = { "x", "y" };241 ExprList *pRightEList = makeEListWithAliases(&s, rightAliases, 2);242 ExprList *pOrderBy = makeOrderBy1(&s, makeIdExpr(gDb, "x"));243 Select *pRight = makeSelect(&s, pRightEList, pOrderBy);244 245 /* Link as a compound: right->pPrior = left, ORDER BY belongs to right-most */246 pRight->pPrior = pLeft;247 248 int rc = test_resolveCompoundOrderBy(&s, pRight); /* Pass the SELECT containing ORDER BY */249 TEST_ASSERT_EQUAL_INT(0, rc);250 TEST_ASSERT_EQUAL_INT(1, pOrderBy->a[0].fg.done);251 TEST_ASSERT_EQUAL_UINT16(1, pOrderBy->a[0].u.x.iOrderByCol);252 253 /* Free starting from left-most is fine after function linked pNext pointers */254 /* resolveCompoundOrderBy built pNext chain; delete from left-most cleans all */255 sqlite3SelectDelete(gDb, pLeft);256}257 258int main(void) {259 UNITY_BEGIN();260 RUN_TEST(test_resolveCompoundOrderBy_no_order_by_returns0);261 RUN_TEST(test_resolveCompoundOrderBy_integer_within_range);262 RUN_TEST(test_resolveCompoundOrderBy_integer_out_of_range);263 RUN_TEST(test_resolveCompoundOrderBy_alias_match);264 RUN_TEST(test_resolveCompoundOrderBy_identifier_no_match_errors);265 RUN_TEST(test_resolveCompoundOrderBy_collate_wrapped_expr);266 RUN_TEST(test_resolveCompoundOrderBy_too_many_terms_limit_error);267 RUN_TEST(test_resolveCompoundOrderBy_compound_chain_resolution);268 return UNITY_END();269}