AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6static sqlite3 *gDb = NULL;7static Parse gParse;8 9static DbFixer initFixer(int iDb, const char *zType, const char *zName){10 DbFixer fixer;11 Token *pTok = (Token*)sqlite3DbMallocZero(gDb, sizeof(Token));12 if( pTok ){13 pTok->z = zName;14 pTok->n = (int)strlen(zName);15 }16 sqlite3FixInit(&fixer, &gParse, iDb, zType, pTok);17 return fixer;18}19 20static Expr* makeVariableExpr(sqlite3 *db){21 Expr *e = (Expr*)sqlite3DbMallocZero(db, sizeof(Expr));22 if( e ){23 e->op = TK_VARIABLE;24 }25 return e;26}27 28static SrcList* makeSrcListWithDb(sqlite3 *db, const char *zDbName){29 /* Allocate a SrcList with exactly 1 entry */30 SrcList *pList = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList));31 if( pList ){32 pList->nSrc = 1;33 pList->nAlloc = 1;34 /* Ensure flags are zeroed (isSubquery=0, fixedSchema=0 by default) */35 pList->a[0].u4.zDatabase = sqlite3DbStrDup(db, zDbName);36 }37 return pList;38}39 40#ifndef SQLITE_OMIT_UPSERT41static Upsert* makeUpsertWithWhere(sqlite3 *db, Expr *pWhere){42 Upsert *pUp = (Upsert*)sqlite3DbMallocZero(db, sizeof(Upsert));43 if( pUp ){44 pUp->pUpsertWhere = pWhere;45 pUp->pNextUpsert = 0;46 }47 return pUp;48}49#endif50 51void setUp(void) {52 int rc = sqlite3_open(":memory:", &gDb);53 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);54 memset(&gParse, 0, sizeof(gParse));55 gParse.db = gDb;56 /* Ensure init.busy starts at 0 for predictable behavior */57 gDb->init.busy = 0;58}59 60void tearDown(void) {61 if( gParse.zErrMsg ){62 sqlite3DbFree(gDb, gParse.zErrMsg);63 gParse.zErrMsg = 0;64 }65 sqlite3_close(gDb);66 gDb = NULL;67}68 69/* Test: NULL pStep returns 0 */70void test_sqlite3FixTriggerStep_null_step_returns_ok(void) {71#ifndef SQLITE_OMIT_TRIGGER72 DbFixer fixer = initFixer(0, "trigger", "trg");73 int rc = sqlite3FixTriggerStep(&fixer, NULL);74 TEST_ASSERT_EQUAL_INT(0, rc);75#else76 TEST_IGNORE_MESSAGE("SQLITE_OMIT_TRIGGER defined; sqlite3FixTriggerStep unavailable.");77#endif78}79 80/* Test: Empty TriggerStep (all NULL subnodes) returns 0 */81void test_sqlite3FixTriggerStep_empty_step_returns_ok(void) {82#ifndef SQLITE_OMIT_TRIGGER83 DbFixer fixer = initFixer(0, "trigger", "trg");84 TriggerStep step;85 memset(&step, 0, sizeof(step));86 int rc = sqlite3FixTriggerStep(&fixer, &step);87 TEST_ASSERT_EQUAL_INT(0, rc);88#else89 TEST_IGNORE_MESSAGE("SQLITE_OMIT_TRIGGER defined; sqlite3FixTriggerStep unavailable.");90#endif91}92 93/* Test: Variable in WHERE when init.busy==0 produces error and returns 1 */94void test_sqlite3FixTriggerStep_where_variable_errors_when_not_init_busy(void) {95#ifndef SQLITE_OMIT_TRIGGER96 DbFixer fixer = initFixer(0, "trigger", "trg");97 TriggerStep step;98 memset(&step, 0, sizeof(step));99 step.pWhere = makeVariableExpr(gDb);100 TEST_ASSERT_NOT_NULL(step.pWhere);101 gDb->init.busy = 0; /* ensure error path */102 103 int rc = sqlite3FixTriggerStep(&fixer, &step);104 TEST_ASSERT_EQUAL_INT(1, rc);105 TEST_ASSERT_NOT_NULL(gParse.zErrMsg);106 TEST_ASSERT_NOT_EQUAL(-1, strstr(gParse.zErrMsg, "cannot use variables") ? 0 : -1);107 108 sqlite3DbFree(gDb, gParse.zErrMsg); gParse.zErrMsg = 0;109#else110 TEST_IGNORE_MESSAGE("SQLITE_OMIT_TRIGGER defined; sqlite3FixTriggerStep unavailable.");111#endif112}113 114/* Test: Variable becomes NULL and returns 0 when init.busy==1 */115void test_sqlite3FixTriggerStep_where_variable_converted_when_init_busy(void) {116#ifndef SQLITE_OMIT_TRIGGER117 DbFixer fixer = initFixer(0, "trigger", "trg");118 TriggerStep step;119 memset(&step, 0, sizeof(step));120 step.pWhere = makeVariableExpr(gDb);121 TEST_ASSERT_NOT_NULL(step.pWhere);122 gDb->init.busy = 1; /* conversion path */123 124 int rc = sqlite3FixTriggerStep(&fixer, &step);125 TEST_ASSERT_EQUAL_INT(0, rc);126 TEST_ASSERT_EQUAL_INT(TK_NULL, step.pWhere->op);127 TEST_ASSERT_NULL(gParse.zErrMsg);128 gDb->init.busy = 0; /* reset */129#else130 TEST_IGNORE_MESSAGE("SQLITE_OMIT_TRIGGER defined; sqlite3FixTriggerStep unavailable.");131#endif132}133 134/* Test: Cross-database reference in pSrc triggers error via sqlite3FixSrcList */135void test_sqlite3FixTriggerStep_src_crossdb_error(void) {136#ifndef SQLITE_OMIT_TRIGGER137 DbFixer fixer = initFixer(0, "trigger", "trg"); /* fix to main (iDb=0) */138 TriggerStep step;139 memset(&step, 0, sizeof(step));140 step.pSrc = makeSrcListWithDb(gDb, "temp"); /* references TEMP instead of MAIN */141 TEST_ASSERT_NOT_NULL(step.pSrc);142 TEST_ASSERT_NOT_NULL(step.pSrc->a[0].u4.zDatabase);143 144 int rc = sqlite3FixTriggerStep(&fixer, &step);145 TEST_ASSERT_EQUAL_INT(1, rc);146 TEST_ASSERT_NOT_NULL(gParse.zErrMsg);147 TEST_ASSERT_NOT_EQUAL(-1, strstr(gParse.zErrMsg, "cannot reference objects in database") ? 0 : -1);148 149 sqlite3DbFree(gDb, gParse.zErrMsg); gParse.zErrMsg = 0;150#else151 TEST_IGNORE_MESSAGE("SQLITE_OMIT_TRIGGER defined; sqlite3FixTriggerStep unavailable.");152#endif153}154 155/* Test: Upsert chain triggers error when containing a variable and init.busy==0 */156void test_sqlite3FixTriggerStep_upsert_where_variable_errors(void) {157#if !defined(SQLITE_OMIT_TRIGGER) && !defined(SQLITE_OMIT_UPSERT)158 DbFixer fixer = initFixer(0, "trigger", "trg");159 TriggerStep step;160 memset(&step, 0, sizeof(step));161 Expr *e = makeVariableExpr(gDb);162 TEST_ASSERT_NOT_NULL(e);163 Upsert *pUp = makeUpsertWithWhere(gDb, e);164 TEST_ASSERT_NOT_NULL(pUp);165 step.pUpsert = pUp;166 gDb->init.busy = 0;167 168 int rc = sqlite3FixTriggerStep(&fixer, &step);169 TEST_ASSERT_EQUAL_INT(1, rc);170 TEST_ASSERT_NOT_NULL(gParse.zErrMsg);171 TEST_ASSERT_NOT_EQUAL(-1, strstr(gParse.zErrMsg, "cannot use variables") ? 0 : -1);172 173 sqlite3DbFree(gDb, gParse.zErrMsg); gParse.zErrMsg = 0;174#else175 TEST_IGNORE_MESSAGE("SQLITE_OMIT_TRIGGER or SQLITE_OMIT_UPSERT defined; test skipped.");176#endif177}178 179/* Test: Multiple TriggerStep nodes - aborts on the first failing step */180void test_sqlite3FixTriggerStep_multiple_steps_abort_on_second(void) {181#ifndef SQLITE_OMIT_TRIGGER182 DbFixer fixer = initFixer(0, "trigger", "trg");183 TriggerStep step1, step2;184 memset(&step1, 0, sizeof(step1));185 memset(&step2, 0, sizeof(step2));186 187 /* First step OK (empty) */188 /* Second step has a variable in WHERE that should error out */189 step2.pWhere = makeVariableExpr(gDb);190 TEST_ASSERT_NOT_NULL(step2.pWhere);191 step1.pNext = &step2;192 193 gDb->init.busy = 0;194 int rc = sqlite3FixTriggerStep(&fixer, &step1);195 TEST_ASSERT_EQUAL_INT(1, rc);196 TEST_ASSERT_NOT_NULL(gParse.zErrMsg);197 TEST_ASSERT_NOT_EQUAL(-1, strstr(gParse.zErrMsg, "cannot use variables") ? 0 : -1);198 199 sqlite3DbFree(gDb, gParse.zErrMsg); gParse.zErrMsg = 0;200#else201 TEST_IGNORE_MESSAGE("SQLITE_OMIT_TRIGGER defined; sqlite3FixTriggerStep unavailable.");202#endif203}204 205int main(void) {206 UNITY_BEGIN();207 RUN_TEST(test_sqlite3FixTriggerStep_null_step_returns_ok);208 RUN_TEST(test_sqlite3FixTriggerStep_empty_step_returns_ok);209 RUN_TEST(test_sqlite3FixTriggerStep_where_variable_errors_when_not_init_busy);210 RUN_TEST(test_sqlite3FixTriggerStep_where_variable_converted_when_init_busy);211 RUN_TEST(test_sqlite3FixTriggerStep_src_crossdb_error);212 RUN_TEST(test_sqlite3FixTriggerStep_upsert_where_variable_errors);213 RUN_TEST(test_sqlite3FixTriggerStep_multiple_steps_abort_on_second);214 return UNITY_END();215}