AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6 7/* Wrapper for the static function under test (provided by the module) */8extern int test_resizeIndexObject(Parse *pParse, Index *pIdx, int N);9 10static const char *C_BIN = "BINARY";11static const char *C_NOCASE= "NOCASE";12static const char *C_RTRIM = "RTRIM";13static const char *C_CUSTOM= "CUSTOM";14 15/* Unity fixtures */16void setUp(void) {17 /* no-op */18}19void tearDown(void) {20 /* no-op */21}22 23/* Helper to initialize an Index with given sizes and sample contents */24static void initIndexWithArrays(25 sqlite3 *db,26 Index *pIdx,27 int nCol,28 int nKeyCol29){30 memset(pIdx, 0, sizeof(*pIdx));31 pIdx->nColumn = (u16)nCol;32 pIdx->nKeyCol = (i16)nKeyCol;33 pIdx->isResized = 0;34 35 /* Allocate and populate arrays using the db allocator */36 const char **az = (const char**)sqlite3DbMallocZero(db, sizeof(char*)*nCol);37 LogEst *ar = (LogEst*)sqlite3DbMallocZero(db, sizeof(LogEst)*(nKeyCol+1));38 i16 *ac = (i16*)sqlite3DbMallocZero(db, sizeof(i16)*nCol);39 u8 *as = (u8*)sqlite3DbMallocZero(db, sizeof(u8)*nCol);40 41 /* Fill initial values deterministically */42 for(int i=0; i<nCol; i++){43 /* rotate through a few static collation strings */44 switch(i % 4){45 case 0: az[i] = C_BIN; break;46 case 1: az[i] = C_NOCASE; break;47 case 2: az[i] = C_RTRIM; break;48 default: az[i] = C_CUSTOM; break;49 }50 ac[i] = (i16)(10 + i);51 as[i] = (u8)(i & 1);52 }53 for(int i=0; i<=nKeyCol; i++){54 ar[i] = (LogEst)(100 + i);55 }56 57 pIdx->azColl = az;58 pIdx->aiRowLogEst = ar;59 pIdx->aiColumn = ac;60 pIdx->aSortOrder = as;61}62 63/* Helper to free initial arrays if they are still separate allocations */64static void freeInitialIndexArrays(sqlite3 *db, Index *pIdx,65 const char **azOrig,66 LogEst *arOrig,67 i16 *acOrig,68 u8 *asOrig){69 if(azOrig) sqlite3DbFree(db, (void*)azOrig);70 if(arOrig) sqlite3DbFree(db, (void*)arOrig);71 if(acOrig) sqlite3DbFree(db, (void*)acOrig);72 if(asOrig) sqlite3DbFree(db, (void*)asOrig);73}74 75/* Test 1: No-op when N <= nColumn */76void test_resizeIndexObject_noop_when_N_le_nColumn(void){77 sqlite3 *db = 0;78 Parse parse;79 memset(&parse, 0, sizeof(parse));80 81 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));82 parse.db = db;83 84 Index idx;85 initIndexWithArrays(db, &idx, /*nCol*/3, /*nKeyCol*/3);86 87 /* Save original pointers and snapshot of contents */88 const char **azOrig = idx.azColl;89 LogEst *arOrig = idx.aiRowLogEst;90 i16 *acOrig = idx.aiColumn;91 u8 *asOrig = idx.aSortOrder;92 93 /* Keep copies of values for verification */94 const char *azSave[3] = { azOrig[0], azOrig[1], azOrig[2] };95 LogEst arSave[4] = { arOrig[0], arOrig[1], arOrig[2], arOrig[3] };96 i16 acSave[3] = { acOrig[0], acOrig[1], acOrig[2] };97 u8 asSave[3] = { asOrig[0], asOrig[1], asOrig[2] };98 99 int rc = test_resizeIndexObject(&parse, &idx, /*N*/3);100 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101 102 /* Verify no changes */103 TEST_ASSERT_EQUAL_UINT16(3, idx.nColumn);104 TEST_ASSERT_EQUAL_INT(0, idx.isResized);105 TEST_ASSERT_EQUAL_PTR(azOrig, idx.azColl);106 TEST_ASSERT_EQUAL_PTR(arOrig, idx.aiRowLogEst);107 TEST_ASSERT_EQUAL_PTR(acOrig, idx.aiColumn);108 TEST_ASSERT_EQUAL_PTR(asOrig, idx.aSortOrder);109 110 TEST_ASSERT_EQUAL_PTR(azSave[0], idx.azColl[0]);111 TEST_ASSERT_EQUAL_PTR(azSave[1], idx.azColl[1]);112 TEST_ASSERT_EQUAL_PTR(azSave[2], idx.azColl[2]);113 114 TEST_ASSERT_EQUAL_INT(arSave[0], idx.aiRowLogEst[0]);115 TEST_ASSERT_EQUAL_INT(arSave[1], idx.aiRowLogEst[1]);116 TEST_ASSERT_EQUAL_INT(arSave[2], idx.aiRowLogEst[2]);117 TEST_ASSERT_EQUAL_INT(arSave[3], idx.aiRowLogEst[3]);118 119 TEST_ASSERT_EQUAL_INT(acSave[0], idx.aiColumn[0]);120 TEST_ASSERT_EQUAL_INT(acSave[1], idx.aiColumn[1]);121 TEST_ASSERT_EQUAL_INT(acSave[2], idx.aiColumn[2]);122 123 TEST_ASSERT_EQUAL_INT(asSave[0], idx.aSortOrder[0]);124 TEST_ASSERT_EQUAL_INT(asSave[1], idx.aSortOrder[1]);125 TEST_ASSERT_EQUAL_INT(asSave[2], idx.aSortOrder[2]);126 127 /* Cleanup */128 freeInitialIndexArrays(db, &idx, azOrig, arOrig, acOrig, asOrig);129 sqlite3_close(db);130}131 132/* Test 2: Grow to larger N, with nKeyCol == nColumn.133 Validate copy, zero-initialization, pointer layout and flags. */134void test_resizeIndexObject_grow_and_layout_and_zeroing(void){135 sqlite3 *db = 0;136 Parse parse;137 memset(&parse, 0, sizeof(parse));138 139 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));140 parse.db = db;141 142 Index idx;143 initIndexWithArrays(db, &idx, /*nCol*/2, /*nKeyCol*/2);144 145 const char **azOrig = idx.azColl;146 LogEst *arOrig = idx.aiRowLogEst;147 i16 *acOrig = idx.aiColumn;148 u8 *asOrig = idx.aSortOrder;149 150 /* Save value snapshots */151 const char *azSave[2] = { azOrig[0], azOrig[1] };152 LogEst arSave[3] = { arOrig[0], arOrig[1], arOrig[2] };153 i16 acSave[2] = { acOrig[0], acOrig[1] };154 u8 asSave[2] = { asOrig[0], asOrig[1] };155 156 int N = 5; /* Ensure N > nColumn and N > nKeyCol+1 to check zeroing */157 int rc = test_resizeIndexObject(&parse, &idx, N);158 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);159 160 /* Flags and sizes */161 TEST_ASSERT_EQUAL_UINT16(N, idx.nColumn);162 TEST_ASSERT_EQUAL_INT(1, idx.isResized);163 164 /* Pointers should change from originals */165 TEST_ASSERT_NOT_EQUAL_PTR(azOrig, idx.azColl);166 TEST_ASSERT_NOT_EQUAL_PTR(arOrig, idx.aiRowLogEst);167 TEST_ASSERT_NOT_EQUAL_PTR(acOrig, idx.aiColumn);168 TEST_ASSERT_NOT_EQUAL_PTR(asOrig, idx.aSortOrder);169 170 /* Verify exact contiguous layout as implemented */171 char *base = (char*)idx.azColl;172 TEST_ASSERT_EQUAL_PTR(base + (ptrdiff_t)(sizeof(char*)*N), (char*)idx.aiRowLogEst);173 TEST_ASSERT_EQUAL_PTR(base + (ptrdiff_t)(sizeof(char*)*N + sizeof(LogEst)*N),174 (char*)idx.aiColumn);175 TEST_ASSERT_EQUAL_PTR(base + (ptrdiff_t)(sizeof(char*)*N + sizeof(LogEst)*N + sizeof(i16)*N),176 (char*)idx.aSortOrder);177 178 /* Verify preserved values */179 TEST_ASSERT_EQUAL_PTR(azSave[0], idx.azColl[0]);180 TEST_ASSERT_EQUAL_PTR(azSave[1], idx.azColl[1]);181 182 TEST_ASSERT_EQUAL_INT(arSave[0], idx.aiRowLogEst[0]);183 TEST_ASSERT_EQUAL_INT(arSave[1], idx.aiRowLogEst[1]);184 TEST_ASSERT_EQUAL_INT(arSave[2], idx.aiRowLogEst[2]);185 186 TEST_ASSERT_EQUAL_INT(acSave[0], idx.aiColumn[0]);187 TEST_ASSERT_EQUAL_INT(acSave[1], idx.aiColumn[1]);188 189 TEST_ASSERT_EQUAL_INT(asSave[0], idx.aSortOrder[0]);190 TEST_ASSERT_EQUAL_INT(asSave[1], idx.aSortOrder[1]);191 192 /* Verify zero-initialization of new slots:193 - azColl[2..4] should be NULL194 - aiRowLogEst[3..4] should be 0195 - aiColumn[2..4] should be 0196 - aSortOrder[2..4] should be 0197 */198 for(int i=2; i<N; i++){199 TEST_ASSERT_NULL(idx.azColl[i]);200 TEST_ASSERT_EQUAL_INT(0, idx.aiColumn[i]);201 TEST_ASSERT_EQUAL_INT(0, idx.aSortOrder[i]);202 }203 for(int i=3; i<N; i++){204 TEST_ASSERT_EQUAL_INT(0, idx.aiRowLogEst[i]);205 }206 207 /* Cleanup:208 - Free original separate allocations209 - Free the single contiguous block now referenced by idx.azColl210 */211 freeInitialIndexArrays(db, &idx, azOrig, arOrig, acOrig, asOrig);212 sqlite3DbFree(db, (void*)idx.azColl);213 sqlite3_close(db);214}215 216/* Test 3: Grow when nKeyCol < nColumn, ensuring aiRowLogEst copies nKeyCol+1217 elements and remaining slots are zeroed. */218void test_resizeIndexObject_grow_with_fewer_keycols(void){219 sqlite3 *db = 0;220 Parse parse;221 memset(&parse, 0, sizeof(parse));222 223 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));224 parse.db = db;225 226 /* nColumn = 3, nKeyCol = 2 */227 Index idx;228 initIndexWithArrays(db, &idx, /*nCol*/3, /*nKeyCol*/2);229 230 const char **azOrig = idx.azColl;231 LogEst *arOrig = idx.aiRowLogEst;232 i16 *acOrig = idx.aiColumn;233 u8 *asOrig = idx.aSortOrder;234 235 /* Save original values */236 const char *azSave[3] = { azOrig[0], azOrig[1], azOrig[2] };237 LogEst arSave[3] = { arOrig[0], arOrig[1], arOrig[2] }; /* nKeyCol+1 == 3 */238 i16 acSave[3] = { acOrig[0], acOrig[1], acOrig[2] };239 u8 asSave[3] = { asOrig[0], asOrig[1], asOrig[2] };240 241 int N = 4; /* Ensure N > nColumn and N >= nKeyCol+1 */242 int rc = test_resizeIndexObject(&parse, &idx, N);243 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);244 245 TEST_ASSERT_EQUAL_UINT16(N, idx.nColumn);246 TEST_ASSERT_EQUAL_INT(1, idx.isResized);247 248 /* Check preserved values */249 TEST_ASSERT_EQUAL_PTR(azSave[0], idx.azColl[0]);250 TEST_ASSERT_EQUAL_PTR(azSave[1], idx.azColl[1]);251 TEST_ASSERT_EQUAL_PTR(azSave[2], idx.azColl[2]);252 253 TEST_ASSERT_EQUAL_INT(arSave[0], idx.aiRowLogEst[0]);254 TEST_ASSERT_EQUAL_INT(arSave[1], idx.aiRowLogEst[1]);255 TEST_ASSERT_EQUAL_INT(arSave[2], idx.aiRowLogEst[2]);256 257 TEST_ASSERT_EQUAL_INT(acSave[0], idx.aiColumn[0]);258 TEST_ASSERT_EQUAL_INT(acSave[1], idx.aiColumn[1]);259 TEST_ASSERT_EQUAL_INT(acSave[2], idx.aiColumn[2]);260 261 TEST_ASSERT_EQUAL_INT(asSave[0], idx.aSortOrder[0]);262 TEST_ASSERT_EQUAL_INT(asSave[1], idx.aSortOrder[1]);263 TEST_ASSERT_EQUAL_INT(asSave[2], idx.aSortOrder[2]);264 265 /* Zero-initialization for new slots (index 3) */266 TEST_ASSERT_NULL(idx.azColl[3]);267 TEST_ASSERT_EQUAL_INT(0, idx.aiColumn[3]);268 TEST_ASSERT_EQUAL_INT(0, idx.aSortOrder[3]);269 270 /* aiRowLogEst has size N; slots beyond nKeyCol+1 (i.e., index >= 3) should be 0 */271 for(int i=3; i<N; i++){272 TEST_ASSERT_EQUAL_INT(0, idx.aiRowLogEst[i]);273 }274 275 /* Free allocations */276 freeInitialIndexArrays(db, &idx, azOrig, arOrig, acOrig, asOrig);277 sqlite3DbFree(db, (void*)idx.azColl);278 sqlite3_close(db);279}280 281int main(void){282 UNITY_BEGIN();283 RUN_TEST(test_resizeIndexObject_noop_when_N_le_nColumn);284 RUN_TEST(test_resizeIndexObject_grow_and_layout_and_zeroing);285 RUN_TEST(test_resizeIndexObject_grow_with_fewer_keycols);286 return UNITY_END();287}