AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Globals for test setup */7static sqlite3 *gDb = NULL;8static Parse gParse;9 10/* Helpers to construct minimal internal structures needed by xferOptimization */11 12static SrcList* makeSrcList(sqlite3 *db, int n){13 /* Allocate a SrcList with n entries */14 size_t sz = sizeof(SrcList) + (n>0 ? (size_t)(n-1)*sizeof(SrcItem) : 0);15 SrcList *p = (SrcList*)sqlite3DbMallocZero(db, (int)sz);16 if( p ){17 p->nSrc = n;18 p->nAlloc = n;19 }20 return p;21}22 23static Expr* makeExprOp(sqlite3 *db, int op){24 Expr *e = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));25 if( e ) e->op = (u8)op;26 return e;27}28 29static ExprList* makeExprListWithExpr(sqlite3 *db, Expr *e){30 ExprList *el = (ExprList*)sqlite3DbMallocZero(db, sizeof(ExprList));31 if( el ){32 el->nExpr = 1;33 el->nAlloc = 1;34 el->a = (struct ExprList_item*)sqlite3DbMallocZero(db, sizeof(struct ExprList_item));35 if( el->a ){36 el->a[0].pExpr = e;37 }38 }39 return el;40}41 42static Select* makeSelectStar(sqlite3 *db, SrcList *pSrc){43 Select *s = (Select*)sqlite3DbMallocZero(db, sizeof(Select));44 if( s ){45 Expr *star = makeExprOp(db, TK_ASTERISK);46 ExprList *elist = makeExprListWithExpr(db, star);47 s->pEList = elist;48 s->pSrc = pSrc;49 }50 return s;51}52 53static void freeSelectLite(sqlite3 *db, Select *s){54 if( !s ) return;55 if( s->pEList ){56 if( s->pEList->a ){57 if( s->pEList->a[0].pExpr ){58 sqlite3DbFree(db, s->pEList->a[0].pExpr);59 }60 sqlite3DbFree(db, s->pEList->a);61 }62 sqlite3DbFree(db, s->pEList);63 }64 if( s->pOrderBy ){65 sqlite3DbFree(db, s->pOrderBy);66 }67 if( s->pGroupBy ){68 sqlite3DbFree(db, s->pGroupBy);69 }70 if( s->pLimit ){71 sqlite3DbFree(db, s->pLimit);72 }73 if( s->pWhere ){74 sqlite3DbFree(db, s->pWhere);75 }76 if( s->pWith ){77 sqlite3DbFree(db, s->pWith);78 }79 if( s->pPrior ){80 /* pPrior may be a tiny allocated Select used just as a non-NULL marker */81 sqlite3DbFree(db, s->pPrior);82 }83 if( s->pSrc ){84 int i;85 for(i=0; i<s->pSrc->nSrc; i++){86 if( s->pSrc->a[i].zName ){87 sqlite3DbFree(db, s->pSrc->a[i].zName);88 }89 if( s->pSrc->a[i].zDatabase ){90 sqlite3DbFree(db, s->pSrc->a[i].zDatabase);91 }92 }93 sqlite3DbFree(db, s->pSrc);94 }95 sqlite3DbFree(db, s);96}97 98static Table* makeDummyDestTable(sqlite3 *db){99 Table *p = (Table*)sqlite3DbMallocZero(db, sizeof(Table));100 if( p ){101 p->zName = "dummy_dest";102 p->tabFlags = 0; /* Ensure not virtual */103 }104 return p;105}106 107/* Unity fixtures */108void setUp(void) {109 int rc = sqlite3_open(":memory:", &gDb);110 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);111 memset(&gParse, 0, sizeof(gParse));112 gParse.db = gDb;113}114 115void tearDown(void) {116 if( gDb ){117 sqlite3_close(gDb);118 gDb = NULL;119 }120}121 122/* Tests for early-return syntactic constraints */123 124void test_xferOptimization_parse_with_clause_returns_0(void){125 Table *pDest = makeDummyDestTable(gDb);126 SrcList *src = makeSrcList(gDb, 1);127 Select *sel = makeSelectStar(gDb, src);128 129 gParse.pWith = (With*)sqlite3DbMallocZero(gDb, sizeof(With)); /* non-NULL marker */130 131 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);132 TEST_ASSERT_EQUAL_INT(0, rc);133 134 sqlite3DbFree(gDb, gParse.pWith); gParse.pWith = NULL;135 sqlite3DbFree(gDb, pDest);136 freeSelectLite(gDb, sel);137}138 139void test_xferOptimization_select_with_clause_returns_0(void){140 Table *pDest = makeDummyDestTable(gDb);141 SrcList *src = makeSrcList(gDb, 1);142 Select *sel = makeSelectStar(gDb, src);143 sel->pWith = (With*)sqlite3DbMallocZero(gDb, sizeof(With));144 145 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);146 TEST_ASSERT_EQUAL_INT(0, rc);147 148 sqlite3DbFree(gDb, pDest);149 freeSelectLite(gDb, sel);150}151 152void test_xferOptimization_from_clause_count_not_one_returns_0(void){153 Table *pDest = makeDummyDestTable(gDb);154 SrcList *src = makeSrcList(gDb, 2); /* nSrc != 1 */155 Select *sel = makeSelectStar(gDb, src);156 157 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);158 TEST_ASSERT_EQUAL_INT(0, rc);159 160 sqlite3DbFree(gDb, pDest);161 freeSelectLite(gDb, sel);162}163 164void test_xferOptimization_from_subquery_returns_0(void){165 Table *pDest = makeDummyDestTable(gDb);166 SrcList *src = makeSrcList(gDb, 1);167 src->a[0].fg.isSubquery = 1; /* FROM contains subquery */168 Select *sel = makeSelectStar(gDb, src);169 170 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);171 TEST_ASSERT_EQUAL_INT(0, rc);172 173 sqlite3DbFree(gDb, pDest);174 freeSelectLite(gDb, sel);175}176 177void test_xferOptimization_with_where_returns_0(void){178 Table *pDest = makeDummyDestTable(gDb);179 SrcList *src = makeSrcList(gDb, 1);180 Select *sel = makeSelectStar(gDb, src);181 sel->pWhere = makeExprOp(gDb, TK_INTEGER); /* non-NULL */182 183 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);184 TEST_ASSERT_EQUAL_INT(0, rc);185 186 sqlite3DbFree(gDb, pDest);187 freeSelectLite(gDb, sel);188}189 190void test_xferOptimization_with_orderby_returns_0(void){191 Table *pDest = makeDummyDestTable(gDb);192 SrcList *src = makeSrcList(gDb, 1);193 Select *sel = makeSelectStar(gDb, src);194 sel->pOrderBy = (ExprList*)sqlite3DbMallocZero(gDb, sizeof(ExprList));195 196 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);197 TEST_ASSERT_EQUAL_INT(0, rc);198 199 sqlite3DbFree(gDb, pDest);200 freeSelectLite(gDb, sel);201}202 203void test_xferOptimization_with_groupby_returns_0(void){204 Table *pDest = makeDummyDestTable(gDb);205 SrcList *src = makeSrcList(gDb, 1);206 Select *sel = makeSelectStar(gDb, src);207 sel->pGroupBy = (ExprList*)sqlite3DbMallocZero(gDb, sizeof(ExprList));208 209 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);210 TEST_ASSERT_EQUAL_INT(0, rc);211 212 sqlite3DbFree(gDb, pDest);213 freeSelectLite(gDb, sel);214}215 216void test_xferOptimization_with_limit_returns_0(void){217 Table *pDest = makeDummyDestTable(gDb);218 SrcList *src = makeSrcList(gDb, 1);219 Select *sel = makeSelectStar(gDb, src);220 sel->pLimit = makeExprOp(gDb, TK_INTEGER);221 222 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);223 TEST_ASSERT_EQUAL_INT(0, rc);224 225 sqlite3DbFree(gDb, pDest);226 freeSelectLite(gDb, sel);227}228 229void test_xferOptimization_compound_select_returns_0(void){230 Table *pDest = makeDummyDestTable(gDb);231 SrcList *src = makeSrcList(gDb, 1);232 Select *sel = makeSelectStar(gDb, src);233 sel->pPrior = (Select*)sqlite3DbMallocZero(gDb, sizeof(Select));234 235 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);236 TEST_ASSERT_EQUAL_INT(0, rc);237 238 sqlite3DbFree(gDb, pDest);239 freeSelectLite(gDb, sel);240}241 242void test_xferOptimization_distinct_returns_0(void){243 Table *pDest = makeDummyDestTable(gDb);244 SrcList *src = makeSrcList(gDb, 1);245 Select *sel = makeSelectStar(gDb, src);246 sel->selFlags |= SF_Distinct;247 248 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);249 TEST_ASSERT_EQUAL_INT(0, rc);250 251 sqlite3DbFree(gDb, pDest);252 freeSelectLite(gDb, sel);253}254 255void test_xferOptimization_result_not_asterisk_returns_0(void){256 Table *pDest = makeDummyDestTable(gDb);257 SrcList *src = makeSrcList(gDb, 1);258 Select *sel = makeSelectStar(gDb, src);259 /* Replace '*' with a non-asterisk expression to trigger early return */260 if( sel->pEList && sel->pEList->a && sel->pEList->a[0].pExpr ){261 sel->pEList->a[0].pExpr->op = TK_INTEGER;262 }263 264 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);265 TEST_ASSERT_EQUAL_INT(0, rc);266 267 sqlite3DbFree(gDb, pDest);268 freeSelectLite(gDb, sel);269}270 271/* Tests that exercise sqlite3LocateTableItem semantics but still return early */272 273void test_xferOptimization_locate_table_missing_returns_0(void){274 Table *pDest = makeDummyDestTable(gDb);275 SrcList *src = makeSrcList(gDb, 1);276 src->a[0].zName = sqlite3DbStrDup(gDb, "no_such_table");277 Select *sel = makeSelectStar(gDb, src);278 279 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, 0);280 TEST_ASSERT_EQUAL_INT(0, rc);281 282 sqlite3DbFree(gDb, pDest);283 freeSelectLite(gDb, sel);284}285 286void test_xferOptimization_same_table_returns_0(void){287 /* Create a real table t1 and use it as both src and dest */288 int rcExec = sqlite3_exec(gDb, "CREATE TABLE t1(a TEXT, b INT);", 0, 0, 0);289 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rcExec);290 291 Table *t1 = sqlite3FindTable(gDb, "t1", "main");292 TEST_ASSERT_NOT_NULL(t1);293 294 SrcList *src = makeSrcList(gDb, 1);295 src->a[0].zName = sqlite3DbStrDup(gDb, "t1");296 Select *sel = makeSelectStar(gDb, src);297 298 int iDbDest = sqlite3SchemaToIndex(gDb, t1->pSchema);299 int rc = test_xferOptimization(&gParse, t1, sel, OE_Abort, iDbDest);300 TEST_ASSERT_EQUAL_INT(0, rc);301 302 freeSelectLite(gDb, sel);303}304 305/* Semantic checks leading to success and to empty-dest-only case */306 307void test_xferOptimization_valid_simple_tables_returns_1(void){308 int rcExec = sqlite3_exec(gDb,309 "CREATE TABLE src(a TEXT, b INT);"310 "CREATE TABLE dest(a TEXT, b INT);",311 0, 0, 0312 );313 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rcExec);314 315 Table *pDest = sqlite3FindTable(gDb, "dest", "main");316 Table *pSrcTab = sqlite3FindTable(gDb, "src", "main");317 TEST_ASSERT_NOT_NULL(pDest);318 TEST_ASSERT_NOT_NULL(pSrcTab);319 320 SrcList *src = makeSrcList(gDb, 1);321 src->a[0].zName = sqlite3DbStrDup(gDb, "src");322 Select *sel = makeSelectStar(gDb, src);323 324 int iDbDest = sqlite3SchemaToIndex(gDb, pDest->pSchema);325 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Abort, iDbDest);326 327 TEST_ASSERT_EQUAL_INT(1, rc);328 329 freeSelectLite(gDb, sel);330}331 332void test_xferOptimization_valid_but_requires_empty_dest_returns_0(void){333 int rcExec = sqlite3_exec(gDb,334 "CREATE TABLE srcX(a TEXT, b INT);"335 "CREATE TABLE destX(a TEXT, b INT);",336 0, 0, 0337 );338 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rcExec);339 340 Table *pDest = sqlite3FindTable(gDb, "destX", "main");341 TEST_ASSERT_NOT_NULL(pDest);342 343 SrcList *src = makeSrcList(gDb, 1);344 src->a[0].zName = sqlite3DbStrDup(gDb, "srcX");345 Select *sel = makeSelectStar(gDb, src);346 347 int iDbDest = sqlite3SchemaToIndex(gDb, pDest->pSchema);348 /* Use onError = OE_Ignore to trigger the "destination must be empty" path,349 which causes xferOptimization to return 0 after generating VDBE code. */350 int rc = test_xferOptimization(&gParse, pDest, sel, OE_Ignore, iDbDest);351 352 TEST_ASSERT_EQUAL_INT(0, rc);353 354 freeSelectLite(gDb, sel);355}356 357int main(void){358 UNITY_BEGIN();359 360 RUN_TEST(test_xferOptimization_parse_with_clause_returns_0);361 RUN_TEST(test_xferOptimization_select_with_clause_returns_0);362 RUN_TEST(test_xferOptimization_from_clause_count_not_one_returns_0);363 RUN_TEST(test_xferOptimization_from_subquery_returns_0);364 RUN_TEST(test_xferOptimization_with_where_returns_0);365 RUN_TEST(test_xferOptimization_with_orderby_returns_0);366 RUN_TEST(test_xferOptimization_with_groupby_returns_0);367 RUN_TEST(test_xferOptimization_with_limit_returns_0);368 RUN_TEST(test_xferOptimization_compound_select_returns_0);369 RUN_TEST(test_xferOptimization_distinct_returns_0);370 RUN_TEST(test_xferOptimization_result_not_asterisk_returns_0);371 RUN_TEST(test_xferOptimization_locate_table_missing_returns_0);372 RUN_TEST(test_xferOptimization_same_table_returns_0);373 RUN_TEST(test_xferOptimization_valid_simple_tables_returns_1);374 RUN_TEST(test_xferOptimization_valid_but_requires_empty_dest_returns_0);375 376 return UNITY_END();377}