AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Declare the test wrapper for the static function */6extern int test_resolveExprStep(Walker *pWalker, Expr *pExpr);7 8static sqlite3 *gDb = NULL;9 10void setUp(void) {11 int rc = sqlite3_open(":memory:", &gDb);12 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);13 TEST_ASSERT_NOT_NULL(gDb);14}15 16void tearDown(void) {17 if (gDb) {18 sqlite3_close(gDb);19 gDb = NULL;20 }21}22 23/* Helper: initialize a minimal Parse and NameContext and Walker */24static void initParseNcWalker(Parse *pParse, NameContext *pNC, Walker *pWalker){25 memset(pParse, 0, sizeof(*pParse));26 pParse->db = gDb;27 memset(pNC, 0, sizeof(*pNC));28 pNC->pParse = pParse;29 memset(pWalker, 0, sizeof(*pWalker));30 pWalker->xExprCallback = test_resolveExprStep;31 pWalker->pParse = pParse;32 pWalker->u.pNC = pNC;33}34 35/* Test: NOT NULL strength reduction applies in WHERE with non-nullable LHS */36void test_resolveExprStep_notnull_optimized_in_where(void){37 Parse sParse;38 NameContext sNC;39 Walker w;40 initParseNcWalker(&sParse, &sNC, &w);41 42 /* Mark this as WHERE context to allow optimization */43 sNC.ncFlags = NC_Where;44 45 /* Create expression: (123) IS NOT NULL */46 Expr *pLeft = sqlite3Expr(gDb, TK_INTEGER, "123");47 TEST_ASSERT_NOT_NULL(pLeft);48 Expr *pTop = sqlite3PExpr(&sParse, TK_NOTNULL, pLeft, 0);49 TEST_ASSERT_NOT_NULL(pTop);50 51 /* Capture nRef to ensure it is restored after optimization */52 sNC.nRef = 42;53 54 int rc = test_resolveExprStep(&w, pTop);55 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);56 57 /* After optimization, expression becomes integer constant 1 */58 TEST_ASSERT_EQUAL_INT(TK_INTEGER, pTop->op);59 TEST_ASSERT_TRUE( ExprHasProperty(pTop, EP_IntValue) );60 TEST_ASSERT_EQUAL_INT(1, pTop->u.iValue);61 TEST_ASSERT_NULL(pTop->pLeft); /* Left subtree deleted */62 TEST_ASSERT_EQUAL_INT(42, sNC.nRef); /* nRef restored */63 64 sqlite3ExprDelete(gDb, pTop);65}66 67/* Test: IS NULL strength reduction applies in WHERE with non-nullable LHS */68void test_resolveExprStep_isnull_optimized_in_where(void){69 Parse sParse;70 NameContext sNC;71 Walker w;72 initParseNcWalker(&sParse, &sNC, &w);73 sNC.ncFlags = NC_Where;74 75 Expr *pLeft = sqlite3Expr(gDb, TK_INTEGER, "999");76 TEST_ASSERT_NOT_NULL(pLeft);77 Expr *pTop = sqlite3PExpr(&sParse, TK_ISNULL, pLeft, 0);78 TEST_ASSERT_NOT_NULL(pTop);79 80 sNC.nRef = 77;81 82 int rc = test_resolveExprStep(&w, pTop);83 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);84 85 /* Becomes 0 */86 TEST_ASSERT_EQUAL_INT(TK_INTEGER, pTop->op);87 TEST_ASSERT_TRUE( ExprHasProperty(pTop, EP_IntValue) );88 TEST_ASSERT_EQUAL_INT(0, pTop->u.iValue);89 TEST_ASSERT_NULL(pTop->pLeft);90 TEST_ASSERT_EQUAL_INT(77, sNC.nRef);91 92 sqlite3ExprDelete(gDb, pTop);93}94 95/* Test: Strength reduction does not apply if not in WHERE */96void test_resolveExprStep_notnull_not_optimized_outside_where(void){97 Parse sParse;98 NameContext sNC;99 Walker w;100 initParseNcWalker(&sParse, &sNC, &w);101 sNC.ncFlags = 0; /* Not a WHERE clause */102 103 Expr *pLeft = sqlite3Expr(gDb, TK_INTEGER, "1");104 TEST_ASSERT_NOT_NULL(pLeft);105 Expr *pTop = sqlite3PExpr(&sParse, TK_NOTNULL, pLeft, 0);106 TEST_ASSERT_NOT_NULL(pTop);107 108 sNC.nRef = 5;109 110 int rc = test_resolveExprStep(&w, pTop);111 /* When not optimizing, it still returns PRUNE for this case */112 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);113 114 /* No change */115 TEST_ASSERT_EQUAL_INT(TK_NOTNULL, pTop->op);116 TEST_ASSERT_NOT_NULL(pTop->pLeft);117 TEST_ASSERT_EQUAL_INT(5, sNC.nRef);118 119 sqlite3ExprDelete(gDb, pTop);120}121 122/* Test: Strength reduction does not apply if LHS can be NULL */123void test_resolveExprStep_isnull_not_optimized_if_can_be_null(void){124 Parse sParse;125 NameContext sNC;126 Walker w;127 initParseNcWalker(&sParse, &sNC, &w);128 sNC.ncFlags = NC_Where;129 130 /* LHS is TK_NULL -> can be NULL */131 Expr *pLeft = sqlite3Expr(gDb, TK_NULL, 0);132 TEST_ASSERT_NOT_NULL(pLeft);133 Expr *pTop = sqlite3PExpr(&sParse, TK_ISNULL, pLeft, 0);134 TEST_ASSERT_NOT_NULL(pTop);135 136 sNC.nRef = 11;137 138 int rc = test_resolveExprStep(&w, pTop);139 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);140 141 /* No change */142 TEST_ASSERT_EQUAL_INT(TK_ISNULL, pTop->op);143 TEST_ASSERT_NOT_NULL(pTop->pLeft);144 TEST_ASSERT_EQUAL_INT(11, sNC.nRef);145 146 sqlite3ExprDelete(gDb, pTop);147}148 149/* Test: Function unlikely(X, 0.5) sets probability correctly */150void test_resolveExprStep_function_unlikely_probability_valid(void){151 Parse sParse;152 NameContext sNC;153 Walker w;154 initParseNcWalker(&sParse, &sNC, &w);155 156 /* Build argument list: unlikely(1, 0.5) */157 Expr *pArg0 = sqlite3Expr(gDb, TK_INTEGER, "1");158 Expr *pArg1 = sqlite3Expr(gDb, TK_FLOAT, "0.5");159 TEST_ASSERT_NOT_NULL(pArg0);160 TEST_ASSERT_NOT_NULL(pArg1);161 162 ExprList *pList = 0;163 pList = sqlite3ExprListAppend(&sParse, pList, pArg0);164 TEST_ASSERT_NOT_NULL(pList);165 pList = sqlite3ExprListAppend(&sParse, pList, pArg1);166 TEST_ASSERT_NOT_NULL(pList);167 168 Token tFunc;169 memset(&tFunc, 0, sizeof(tFunc));170 tFunc.z = "unlikely";171 tFunc.n = (int)strlen(tFunc.z);172 Expr *pFunc = sqlite3ExprFunction(&sParse, pList, &tFunc, 0);173 TEST_ASSERT_NOT_NULL(pFunc);174 175 int rc = test_resolveExprStep(&w, pFunc);176 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);177 178 /* EP_Unlikely should be set, and iTable should be 0.5 * 2^27 = 67108864 */179 TEST_ASSERT_TRUE( ExprHasProperty(pFunc, EP_Unlikely) );180 TEST_ASSERT_EQUAL_INT(67108864, pFunc->iTable);181 182 /* No error should be recorded */183 TEST_ASSERT_EQUAL_INT(0, sParse.nErr);184 185 sqlite3ExprDelete(gDb, pFunc);186}187 188/* Test: Function unlikely(X, 1.5) - invalid probability -> error */189void test_resolveExprStep_function_unlikely_probability_invalid(void){190 Parse sParse;191 NameContext sNC;192 Walker w;193 initParseNcWalker(&sParse, &sNC, &w);194 195 /* Build argument list: unlikely(1, 1.5) */196 Expr *pArg0 = sqlite3Expr(gDb, TK_INTEGER, "1");197 Expr *pArg1 = sqlite3Expr(gDb, TK_FLOAT, "1.5");198 TEST_ASSERT_NOT_NULL(pArg0);199 TEST_ASSERT_NOT_NULL(pArg1);200 201 ExprList *pList = 0;202 pList = sqlite3ExprListAppend(&sParse, pList, pArg0);203 TEST_ASSERT_NOT_NULL(pList);204 pList = sqlite3ExprListAppend(&sParse, pList, pArg1);205 TEST_ASSERT_NOT_NULL(pList);206 207 Token tFunc;208 memset(&tFunc, 0, sizeof(tFunc));209 tFunc.z = "unlikely";210 tFunc.n = (int)strlen(tFunc.z);211 Expr *pFunc = sqlite3ExprFunction(&sParse, pList, &tFunc, 0);212 TEST_ASSERT_NOT_NULL(pFunc);213 214 int nErrBefore = sParse.nErr;215 int ncErrBefore = sNC.nNcErr;216 217 int rc = test_resolveExprStep(&w, pFunc);218 TEST_ASSERT_EQUAL_INT(WRC_Prune, rc);219 220 /* Probability invalid -> iTable < 0 (specifically -1) and error counted */221 TEST_ASSERT_TRUE( pFunc->iTable < 0 );222 TEST_ASSERT_EQUAL_INT(nErrBefore + 1, sParse.nErr);223 TEST_ASSERT_EQUAL_INT(ncErrBefore + 1, sNC.nNcErr);224 225 sqlite3ExprDelete(gDb, pFunc);226}227 228/* Test: "x IS TRUE" transforms into TK_TRUTH */229void test_resolveExprStep_is_true_transforms_to_truth(void){230 Parse sParse;231 NameContext sNC;232 Walker w;233 initParseNcWalker(&sParse, &sNC, &w);234 235 /* left: 0; right: identifier "TRUE" -> should resolve to TK_TRUEFALSE */236 Expr *pLeft = sqlite3Expr(gDb, TK_INTEGER, "0");237 TEST_ASSERT_NOT_NULL(pLeft);238 239 Token tTrue;240 memset(&tTrue, 0, sizeof(tTrue));241 tTrue.z = "TRUE";242 tTrue.n = (int)strlen(tTrue.z);243 244 Expr *pRight = sqlite3ExprAlloc(gDb, TK_ID, &tTrue, 0);245 TEST_ASSERT_NOT_NULL(pRight);246 247 Expr *pTop = sqlite3PExpr(&sParse, TK_IS, pLeft, pRight);248 TEST_ASSERT_NOT_NULL(pTop);249 250 int rc = test_resolveExprStep(&w, pTop);251 252 /* For IS TRUE case, resolveExprStep returns WRC_Continue and sets TK_TRUTH */253 TEST_ASSERT_EQUAL_INT(WRC_Continue, rc);254 TEST_ASSERT_EQUAL_INT(TK_TRUTH, pTop->op);255 TEST_ASSERT_EQUAL_INT(TK_IS, pTop->op2);256 257 sqlite3ExprDelete(gDb, pTop);258}259 260int main(void) {261 UNITY_BEGIN();262 RUN_TEST(test_resolveExprStep_notnull_optimized_in_where);263 RUN_TEST(test_resolveExprStep_isnull_optimized_in_where);264 RUN_TEST(test_resolveExprStep_notnull_not_optimized_outside_where);265 RUN_TEST(test_resolveExprStep_isnull_not_optimized_if_can_be_null);266 RUN_TEST(test_resolveExprStep_function_unlikely_probability_valid);267 RUN_TEST(test_resolveExprStep_function_unlikely_probability_invalid);268 RUN_TEST(test_resolveExprStep_is_true_transforms_to_truth);269 return UNITY_END();270}