AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* The target function is static in analyze.c; a wrapper named test_sampleCopy7** is provided by the module for testing.8*/9#ifdef SQLITE_ENABLE_STAT410typedef struct StatAccum StatAccum;11typedef struct StatSample StatSample;12 13/* Duplicate the struct layouts from analyze.c so we can construct inputs.14 These must match exactly for ABI compatibility. */15struct StatSample {16 tRowcnt *anDLt; /* sqlite_stat4.nDLt */17#ifdef SQLITE_ENABLE_STAT418 tRowcnt *anEq; /* sqlite_stat4.nEq */19 tRowcnt *anLt; /* sqlite_stat4.nLt */20 union {21 i64 iRowid; /* Rowid in main table of the key */22 u8 *aRowid; /* Key for WITHOUT ROWID tables */23 } u;24 u32 nRowid; /* Sizeof aRowid[] */25 u8 isPSample; /* True if a periodic sample */26 int iCol; /* If !isPSample, the reason for inclusion */27 u32 iHash; /* Tiebreaker hash */28#endif29};30 31struct StatAccum {32 sqlite3 *db; /* Database connection, for malloc() */33 tRowcnt nEst;34 tRowcnt nRow;35 int nLimit;36 int nCol; /* Number of columns in index + pk/rowid */37 int nKeyCol;38 u8 nSkipAhead;39 StatSample current;40#ifdef SQLITE_ENABLE_STAT441 tRowcnt nPSample;42 int mxSample;43 u32 iPrn;44 StatSample *aBest;45 int iMin;46 int nSample;47 int nMaxEqZero;48 int iGet;49 StatSample *a;50#endif51};52 53extern void test_sampleCopy(StatAccum*, StatSample*, StatSample*);54#endif /* SQLITE_ENABLE_STAT4 */55 56void setUp(void) {57 /* no-op */58}59 60void tearDown(void) {61 /* no-op */62}63 64#ifdef SQLITE_ENABLE_STAT465 66/* Helper to allocate StatSample arrays */67static void allocSampleArrays(StatSample *pS, int nCol){68 size_t n = sizeof(tRowcnt) * (size_t)nCol;69 pS->anEq = (tRowcnt*)sqlite3_malloc(n);70 pS->anLt = (tRowcnt*)sqlite3_malloc(n);71 pS->anDLt = (tRowcnt*)sqlite3_malloc(n);72 TEST_ASSERT_NOT_NULL(pS->anEq);73 TEST_ASSERT_NOT_NULL(pS->anLt);74 TEST_ASSERT_NOT_NULL(pS->anDLt);75}76 77static void freeSampleArrays(StatSample *pS){78 if( pS->anEq ) sqlite3_free(pS->anEq);79 if( pS->anLt ) sqlite3_free(pS->anLt);80 if( pS->anDLt ) sqlite3_free(pS->anDLt);81 pS->anEq = pS->anLt = pS->anDLt = 0;82}83 84/* Initialize arrays with simple patterns for verification */85static void fillArrays(StatSample *pS, int nCol, tRowcnt base){86 int i;87 for(i=0; i<nCol; i++){88 pS->anEq[i] = base + (tRowcnt)i;89 pS->anLt[i] = base + (tRowcnt)(100 + i);90 pS->anDLt[i] = base + (tRowcnt)(200 + i);91 }92}93 94static void assertArraysEqual(const StatSample *a, const StatSample *b, int nCol){95 TEST_ASSERT_NOT_NULL(a->anEq);96 TEST_ASSERT_NOT_NULL(a->anLt);97 TEST_ASSERT_NOT_NULL(a->anDLt);98 TEST_ASSERT_NOT_NULL(b->anEq);99 TEST_ASSERT_NOT_NULL(b->anLt);100 TEST_ASSERT_NOT_NULL(b->anDLt);101 TEST_ASSERT_EQUAL_INT(0, memcmp(a->anEq, b->anEq, sizeof(tRowcnt)*(size_t)nCol));102 TEST_ASSERT_EQUAL_INT(0, memcmp(a->anLt, b->anLt, sizeof(tRowcnt)*(size_t)nCol));103 TEST_ASSERT_EQUAL_INT(0, memcmp(a->anDLt, b->anDLt, sizeof(tRowcnt)*(size_t)nCol));104}105 106/* Test: Copy fields and arrays; deep-copy blob rowid */107void test_sampleCopy_copies_blob_rowid_and_arrays(void){108 sqlite3 *db = 0;109 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));110 111 const int nCol = 3;112 StatAccum acc;113 memset(&acc, 0, sizeof(acc));114 acc.db = db;115 acc.nCol = nCol;116 117 StatSample fromS, toS;118 memset(&fromS, 0, sizeof(fromS));119 memset(&toS, 0, sizeof(toS));120 121 allocSampleArrays(&fromS, nCol);122 allocSampleArrays(&toS, nCol);123 124 fromS.isPSample = 1;125 fromS.iCol = 2;126 fromS.iHash = 0xC0FFEE01u;127 fillArrays(&fromS, nCol, (tRowcnt)10);128 129 /* Source has a blob rowid. */130 fromS.nRowid = 4;131 fromS.u.aRowid = (u8*)sqlite3DbMallocRawNN(db, fromS.nRowid);132 TEST_ASSERT_NOT_NULL(fromS.u.aRowid);133 fromS.u.aRowid[0] = 0x11;134 fromS.u.aRowid[1] = 0x22;135 fromS.u.aRowid[2] = 0x33;136 fromS.u.aRowid[3] = 0x44;137 138 /* Destination pre-populated with different values and pre-existing blob */139 toS.isPSample = 0;140 toS.iCol = 0;141 toS.iHash = 0;142 fillArrays(&toS, nCol, (tRowcnt)0);143 144 toS.nRowid = 2;145 toS.u.aRowid = (u8*)sqlite3DbMallocRawNN(db, toS.nRowid);146 TEST_ASSERT_NOT_NULL(toS.u.aRowid);147 toS.u.aRowid[0] = 0xAA;148 toS.u.aRowid[1] = 0xBB;149 150 test_sampleCopy(&acc, &toS, &fromS);151 152 /* Verify simple fields */153 TEST_ASSERT_EQUAL_UINT8(fromS.isPSample, toS.isPSample);154 TEST_ASSERT_EQUAL_INT(fromS.iCol, toS.iCol);155 TEST_ASSERT_EQUAL_UINT32(fromS.iHash, toS.iHash);156 157 /* Verify arrays copied */158 assertArraysEqual(&fromS, &toS, nCol);159 160 /* Verify blob rowid deep copy */161 TEST_ASSERT_EQUAL_UINT(fromS.nRowid, toS.nRowid);162 TEST_ASSERT_NOT_NULL(toS.u.aRowid);163 TEST_ASSERT_NOT_EQUAL(fromS.u.aRowid, toS.u.aRowid);164 TEST_ASSERT_EQUAL_INT(0, memcmp(fromS.u.aRowid, toS.u.aRowid, fromS.nRowid));165 166 /* Cleanup */167 sqlite3DbFree(db, fromS.u.aRowid);168 sqlite3DbFree(db, toS.u.aRowid);169 freeSampleArrays(&fromS);170 freeSampleArrays(&toS);171 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));172}173 174/* Test: Copy with integer rowid; ensure destination blob rowid is replaced */175void test_sampleCopy_replaces_blob_with_int_rowid(void){176 sqlite3 *db = 0;177 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));178 179 const int nCol = 4;180 StatAccum acc;181 memset(&acc, 0, sizeof(acc));182 acc.db = db;183 acc.nCol = nCol;184 185 StatSample fromS, toS;186 memset(&fromS, 0, sizeof(fromS));187 memset(&toS, 0, sizeof(toS));188 189 allocSampleArrays(&fromS, nCol);190 allocSampleArrays(&toS, nCol);191 192 fillArrays(&fromS, nCol, (tRowcnt)50);193 fromS.isPSample = 0;194 fromS.iCol = 7;195 fromS.iHash = 0xABCDEF12u;196 197 /* Source uses integer rowid */198 fromS.nRowid = 0;199 fromS.u.iRowid = (i64)0x123456789ABCDEFiULL;200 201 /* Destination currently has a blob rowid to be replaced */202 toS.nRowid = 3;203 toS.u.aRowid = (u8*)sqlite3DbMallocRawNN(db, toS.nRowid);204 TEST_ASSERT_NOT_NULL(toS.u.aRowid);205 toS.u.aRowid[0] = 1; toS.u.aRowid[1] = 2; toS.u.aRowid[2] = 3;206 207 test_sampleCopy(&acc, &toS, &fromS);208 209 /* Verify fields and arrays copied */210 TEST_ASSERT_EQUAL_UINT8(fromS.isPSample, toS.isPSample);211 TEST_ASSERT_EQUAL_INT(fromS.iCol, toS.iCol);212 TEST_ASSERT_EQUAL_UINT32(fromS.iHash, toS.iHash);213 assertArraysEqual(&fromS, &toS, nCol);214 215 /* Verify integer rowid set on destination */216 TEST_ASSERT_EQUAL_UINT(0, toS.nRowid);217 TEST_ASSERT_EQUAL_INT64(fromS.u.iRowid, toS.u.iRowid);218 219 /* Cleanup (toS had its blob freed inside sampleCopy) */220 freeSampleArrays(&fromS);221 freeSampleArrays(&toS);222 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));223}224 225/* Test: Deep copy semantics for blob rowid - mutate source after copy */226void test_sampleCopy_deep_copy_rowid_blob_mutation_source_does_not_affect_dest(void){227 sqlite3 *db = 0;228 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));229 230 const int nCol = 2;231 StatAccum acc;232 memset(&acc, 0, sizeof(acc));233 acc.db = db;234 acc.nCol = nCol;235 236 StatSample fromS, toS;237 memset(&fromS, 0, sizeof(fromS));238 memset(&toS, 0, sizeof(toS));239 240 allocSampleArrays(&fromS, nCol);241 allocSampleArrays(&toS, nCol);242 fillArrays(&fromS, nCol, (tRowcnt)5);243 244 /* Source blob rowid */245 fromS.nRowid = 5;246 fromS.u.aRowid = (u8*)sqlite3DbMallocRawNN(db, fromS.nRowid);247 TEST_ASSERT_NOT_NULL(fromS.u.aRowid);248 for(int i=0;i<fromS.nRowid;i++) fromS.u.aRowid[i] = (u8)(0xA0 + i);249 250 test_sampleCopy(&acc, &toS, &fromS);251 252 /* Mutate source rowid after copy */253 for(int i=0;i<fromS.nRowid;i++) fromS.u.aRowid[i] ^= 0xFF;254 255 /* Destination should remain with original bytes */256 TEST_ASSERT_EQUAL_UINT(fromS.nRowid, toS.nRowid);257 for(int i=0;i<toS.nRowid;i++){258 TEST_ASSERT_EQUAL_HEX8((u8)(0xA0 + i), toS.u.aRowid[i]);259 }260 261 /* Cleanup */262 sqlite3DbFree(db, fromS.u.aRowid);263 sqlite3DbFree(db, toS.u.aRowid);264 freeSampleArrays(&fromS);265 freeSampleArrays(&toS);266 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));267}268 269#else /* !SQLITE_ENABLE_STAT4 */270 271/* If STAT4 is not enabled, the function under test does not exist. */272void test_sampleCopy_skipped_without_STAT4(void){273 TEST_ASSERT_TRUE(1);274}275 276#endif /* SQLITE_ENABLE_STAT4 */277 278int main(void) {279 UNITY_BEGIN();280#ifdef SQLITE_ENABLE_STAT4281 RUN_TEST(test_sampleCopy_copies_blob_rowid_and_arrays);282 RUN_TEST(test_sampleCopy_replaces_blob_with_int_rowid);283 RUN_TEST(test_sampleCopy_deep_copy_rowid_blob_mutation_source_does_not_affect_dest);284#else285 RUN_TEST(test_sampleCopy_skipped_without_STAT4);286#endif287 return UNITY_END();288}