AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Helper: create an integer constant expression with given string value */7static Expr* makeIntExpr(sqlite3 *db, const char *z){8 return sqlite3Expr(db, TK_INTEGER, z);9}10 11/* Helper: build an ExprList of integer constants from an array of string literals */12static ExprList* makeIntList(Parse *pParse, const char **vals, int n){13 ExprList *pList = 0;14 for(int i=0; i<n; i++){15 Expr *pItem = makeIntExpr(pParse->db, vals[i]);16 pList = sqlite3ExprListAppend(pParse, pList, pItem);17 }18 return pList;19}20 21/* Helper: build an IN expression with a scalar LHS and list RHS */22static Expr* makeInExprWithList(Parse *pParse, const char *lhsVal, const char **rhsVals, int nRhs){23 Expr *pLhs = makeIntExpr(pParse->db, lhsVal);24 Expr *pIn = sqlite3ExprAlloc(pParse->db, TK_IN, 0, 0);25 pIn->pLeft = pLhs;26 pIn->x.pList = makeIntList(pParse, rhsVals, nRhs);27 /* Ensure the x union is interpreted as list (not select). Leaving flags as 0 is fine. */28 return pIn;29}30 31void setUp(void) {32 /* Setup code here, or leave empty */33}34 35void tearDown(void) {36 /* Cleanup code here, or leave empty */37}38 39/* Test: NOOP path when RHS is a list with <=2 entries and NOOP_OK is set. */40void test_sqlite3FindInIndex_noop_for_small_list_membership(void){41 sqlite3 *db = 0;42 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));43 44 Parse pParse; memset(&pParse, 0, sizeof(pParse));45 pParse.db = db;46 47 const char *rhsVals[] = { "2", "3" };48 Expr *pIn = makeInExprWithList(&pParse, "1", rhsVals, 2);49 50 int aiMap[1] = { -1 };51 int prNull = 0xdeadbeef; /* should remain unchanged for NOOP */52 int iTab = -999;53 int inFlags = IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK;54 55 int nTab0 = pParse.nTab;56 int eType = sqlite3FindInIndex(&pParse, pIn, (u32)inFlags, &prNull, aiMap, &iTab);57 58 TEST_ASSERT_EQUAL_INT(IN_INDEX_NOOP, eType);59 TEST_ASSERT_EQUAL_INT(-1, iTab);60 TEST_ASSERT_EQUAL_INT(nTab0, pParse.nTab); /* allocation backed out */61 TEST_ASSERT_EQUAL_INT(0, aiMap[0]); /* default mapping applied */62 TEST_ASSERT_EQUAL_INT(0xdeadbeef, prNull); /* unchanged */63 64 sqlite3ExprDelete(db, pIn);65 sqlite3_close(db);66}67 68/* Test: EPH path for list RHS with membership (no NOOP_OK) should allocate a has-null register. */69void test_sqlite3FindInIndex_eph_membership_sets_hasnull_and_tab(void){70 sqlite3 *db = 0;71 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));72 73 Parse pParse; memset(&pParse, 0, sizeof(pParse));74 pParse.db = db;75 76 const char *rhsVals[] = { "5", "6", "7" };77 Expr *pIn = makeInExprWithList(&pParse, "1", rhsVals, 3);78 79 int aiMap[1] = { -1 };80 int prNull = 0;81 int iTab = -999;82 int inFlags = IN_INDEX_MEMBERSHIP; /* NOOP_OK not set */83 84 int nTab0 = pParse.nTab;85 int nMem0 = pParse.nMem;86 int eType = sqlite3FindInIndex(&pParse, pIn, (u32)inFlags, &prNull, aiMap, &iTab);87 88 TEST_ASSERT_EQUAL_INT(IN_INDEX_EPH, eType);89 TEST_ASSERT_EQUAL_INT(nTab0, iTab); /* first allocated cursor index */90 TEST_ASSERT_EQUAL_INT(nTab0 + 1, pParse.nTab); /* one cursor consumed */91 TEST_ASSERT_GREATER_THAN_INT(0, prNull); /* register allocated */92 TEST_ASSERT_EQUAL_INT(nMem0 + 1, pParse.nMem); /* one reg allocated */93 TEST_ASSERT_EQUAL_INT(0, aiMap[0]);94 95 sqlite3ExprDelete(db, pIn);96 sqlite3_close(db);97}98 99/* Test: EPH path for list RHS with IN_INDEX_LOOP should NOT allocate has-null register. */100void test_sqlite3FindInIndex_eph_loop_no_hasnull(void){101 sqlite3 *db = 0;102 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));103 104 Parse pParse; memset(&pParse, 0, sizeof(pParse));105 pParse.db = db;106 107 const char *rhsVals[] = { "10", "20", "30" };108 Expr *pIn = makeInExprWithList(&pParse, "1", rhsVals, 3);109 110 int aiMap[1] = { -1 };111 int prNull = 12345; /* should remain unchanged */112 int iTab = -999;113 int inFlags = IN_INDEX_LOOP; /* Iterate over RHS members */114 115 int nTab0 = pParse.nTab;116 int nMem0 = pParse.nMem;117 int eType = sqlite3FindInIndex(&pParse, pIn, (u32)inFlags, &prNull, aiMap, &iTab);118 119 TEST_ASSERT_EQUAL_INT(IN_INDEX_EPH, eType);120 TEST_ASSERT_EQUAL_INT(nTab0, iTab);121 TEST_ASSERT_EQUAL_INT(nTab0 + 1, pParse.nTab);122 TEST_ASSERT_EQUAL_INT(12345, prNull); /* unchanged because LOOP path */123 TEST_ASSERT_EQUAL_INT(nMem0, pParse.nMem); /* no reg allocated for has-null */124 TEST_ASSERT_EQUAL_INT(0, aiMap[0]);125 126 sqlite3ExprDelete(db, pIn);127 sqlite3_close(db);128}129 130int main(void) {131 UNITY_BEGIN();132 RUN_TEST(test_sqlite3FindInIndex_noop_for_small_list_membership);133 RUN_TEST(test_sqlite3FindInIndex_eph_membership_sets_hasnull_and_tab);134 RUN_TEST(test_sqlite3FindInIndex_eph_loop_no_hasnull);135 return UNITY_END();136}