AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Helper to initialize a Parse object with an in-memory DB and a Vdbe */6static void initParseWithVdbe(sqlite3 **pDb, Parse *pParse){7 int rc = sqlite3_open(":memory:", pDb);8 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);9 memset(pParse, 0, sizeof(*pParse));10 pParse->db = *pDb;11 12 /* Create a Vdbe to ensure sqlite3VdbeReleaseRegisters has a valid context */13 Vdbe *v = sqlite3VdbeCreate(pParse);14 TEST_ASSERT_NOT_NULL(v);15}16 17/* Helper to cleanup Parse object */18static void cleanupParse(sqlite3 *db, Parse *pParse){19 if( pParse->pVdbe ){20 sqlite3VdbeDelete(pParse->pVdbe);21 pParse->pVdbe = 0;22 }23 if( db ){24 sqlite3_close(db);25 }26}27 28void setUp(void) {29 /* No global setup */30}31void tearDown(void) {32 /* No global cleanup */33}34 35/* Test nReg==1 path: behaves like sqlite3ReleaseTempReg (pushes onto aTempReg), 36 and does not alter multi-range cache values. */37void test_sqlite3ReleaseTempRange_single_reg_pushes_temp_stack(void){38 sqlite3 *db = NULL;39 Parse p;40 initParseWithVdbe(&db, &p);41 42 /* Allocate a single temp register */43 int r = sqlite3GetTempReg(&p);44 TEST_ASSERT_EQUAL_INT(1, r);45 TEST_ASSERT_EQUAL_INT(1, p.nMem);46 47 /* Seed existing range cache; should remain unchanged by single-reg release */48 p.nRangeReg = 2;49 p.iRangeReg = 10;50 51 /* Release single register via sqlite3ReleaseTempRange (nReg==1 path) */52 sqlite3ReleaseTempRange(&p, r, 1);53 54 /* Temp reg stack should now contain 'r' */55 TEST_ASSERT_EQUAL_INT(1, p.nTempReg);56 TEST_ASSERT_EQUAL_INT(r, p.aTempReg[0]);57 58 /* Range cache should be unchanged */59 TEST_ASSERT_EQUAL_INT(2, p.nRangeReg);60 TEST_ASSERT_EQUAL_INT(10, p.iRangeReg);61 62 /* nMem is not changed by release */63 TEST_ASSERT_EQUAL_INT(1, p.nMem);64 65 cleanupParse(db, &p);66}67 68/* Test that releasing a larger block updates the cached range (iRangeReg/nRangeReg). */69void test_sqlite3ReleaseTempRange_caches_range_when_larger_than_existing(void){70 sqlite3 *db = NULL;71 Parse p;72 initParseWithVdbe(&db, &p);73 74 p.nRangeReg = 3;75 p.iRangeReg = 20;76 TEST_ASSERT_EQUAL_INT(0, p.nTempReg);77 78 sqlite3ReleaseTempRange(&p, 5, 7);79 TEST_ASSERT_EQUAL_INT(7, p.nRangeReg);80 TEST_ASSERT_EQUAL_INT(5, p.iRangeReg);81 82 /* Temp stack not involved for multi-reg release */83 TEST_ASSERT_EQUAL_INT(0, p.nTempReg);84 85 cleanupParse(db, &p);86}87 88/* Test that releasing an equal or smaller block does not modify the range cache. */89void test_sqlite3ReleaseTempRange_does_not_change_cache_when_smaller_or_equal(void){90 sqlite3 *db = NULL;91 Parse p;92 initParseWithVdbe(&db, &p);93 94 p.nRangeReg = 8;95 p.iRangeReg = 12;96 97 /* Equal size: no change */98 sqlite3ReleaseTempRange(&p, 3, 8);99 TEST_ASSERT_EQUAL_INT(8, p.nRangeReg);100 TEST_ASSERT_EQUAL_INT(12, p.iRangeReg);101 102 /* Smaller size: no change */103 sqlite3ReleaseTempRange(&p, 7, 5);104 TEST_ASSERT_EQUAL_INT(8, p.nRangeReg);105 TEST_ASSERT_EQUAL_INT(12, p.iRangeReg);106 107 cleanupParse(db, &p);108}109 110/* Test interplay with sqlite3GetTempRange:111 - Allocate a range (no cache) -> new registers [1..5]112 - Release it -> caches [1..5]113 - Allocate 3 -> reuses [1..3] from cache, cache becomes [4..5]114 - Allocate 2 -> reuses [4..5], cache becomes empty115 - Allocate 1 -> new allocation (nMem increased), returns 6116*/117void test_sqlite3ReleaseTempRange_with_GetTempRange_reuse_logic(void){118 sqlite3 *db = NULL;119 Parse p;120 initParseWithVdbe(&db, &p);121 122 /* Allocate 5 (no cache) */123 int i1 = sqlite3GetTempRange(&p, 5);124 TEST_ASSERT_EQUAL_INT(1, i1);125 TEST_ASSERT_EQUAL_INT(5, p.nMem);126 127 /* Release 5 -> cache becomes [1..5] */128 sqlite3ReleaseTempRange(&p, i1, 5);129 TEST_ASSERT_EQUAL_INT(5, p.nRangeReg);130 TEST_ASSERT_EQUAL_INT(1, p.iRangeReg);131 132 /* Allocate 3 from cache -> should get 1..3 */133 int i2 = sqlite3GetTempRange(&p, 3);134 TEST_ASSERT_EQUAL_INT(1, i2);135 TEST_ASSERT_EQUAL_INT(4, p.iRangeReg);136 TEST_ASSERT_EQUAL_INT(2, p.nRangeReg);137 TEST_ASSERT_EQUAL_INT(5, p.nMem); /* nMem unchanged by cache usage */138 139 /* Allocate 2 from cache -> should get 4..5; cache now empty */140 int i3 = sqlite3GetTempRange(&p, 2);141 TEST_ASSERT_EQUAL_INT(4, i3);142 TEST_ASSERT_EQUAL_INT(6, p.iRangeReg); /* advanced past end */143 TEST_ASSERT_EQUAL_INT(0, p.nRangeReg);144 TEST_ASSERT_EQUAL_INT(5, p.nMem);145 146 /* Allocate 1 (no cache) -> new reg at nMem+1 = 6 */147 int i4 = sqlite3GetTempRange(&p, 1);148 TEST_ASSERT_EQUAL_INT(6, i4);149 TEST_ASSERT_EQUAL_INT(6, p.nMem);150 151 cleanupParse(db, &p);152}153 154/* Edge case: releasing single register with iReg==0 should be a no-op for temp stack155 and should not alter the range cache. */156void test_sqlite3ReleaseTempRange_single_reg_zero_iReg_noop(void){157 sqlite3 *db = NULL;158 Parse p;159 initParseWithVdbe(&db, &p);160 161 p.nRangeReg = 1;162 p.iRangeReg = 7;163 p.nTempReg = 0;164 165 sqlite3ReleaseTempRange(&p, 0, 1);166 167 TEST_ASSERT_EQUAL_INT(1, p.nRangeReg);168 TEST_ASSERT_EQUAL_INT(7, p.iRangeReg);169 TEST_ASSERT_EQUAL_INT(0, p.nTempReg);170 171 cleanupParse(db, &p);172}173 174/* Multiple releases: the largest released block should be kept in the cache */175void test_sqlite3ReleaseTempRange_keeps_largest_released_block(void){176 sqlite3 *db = NULL;177 Parse p;178 initParseWithVdbe(&db, &p);179 180 /* Initially no cache */181 TEST_ASSERT_EQUAL_INT(0, p.nRangeReg);182 183 /* Release 4 at 10 -> cache 4/10 */184 sqlite3ReleaseTempRange(&p, 10, 4);185 TEST_ASSERT_EQUAL_INT(4, p.nRangeReg);186 TEST_ASSERT_EQUAL_INT(10, p.iRangeReg);187 188 /* Release 3 at 1 -> smaller, cache unchanged */189 sqlite3ReleaseTempRange(&p, 1, 3);190 TEST_ASSERT_EQUAL_INT(4, p.nRangeReg);191 TEST_ASSERT_EQUAL_INT(10, p.iRangeReg);192 193 /* Release 6 at 8 -> larger, cache updated */194 sqlite3ReleaseTempRange(&p, 8, 6);195 TEST_ASSERT_EQUAL_INT(6, p.nRangeReg);196 TEST_ASSERT_EQUAL_INT(8, p.iRangeReg);197 198 cleanupParse(db, &p);199}200 201int main(void){202 UNITY_BEGIN();203 RUN_TEST(test_sqlite3ReleaseTempRange_single_reg_pushes_temp_stack);204 RUN_TEST(test_sqlite3ReleaseTempRange_caches_range_when_larger_than_existing);205 RUN_TEST(test_sqlite3ReleaseTempRange_does_not_change_cache_when_smaller_or_equal);206 RUN_TEST(test_sqlite3ReleaseTempRange_with_GetTempRange_reuse_logic);207 RUN_TEST(test_sqlite3ReleaseTempRange_single_reg_zero_iReg_noop);208 RUN_TEST(test_sqlite3ReleaseTempRange_keeps_largest_released_block);209 return UNITY_END();210}