Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_analyze_sampleInsert.c273 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6 7#ifdef SQLITE_ENABLE_STAT48/* Wrapper for the static function under test (provided by the source module). */9extern void test_sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero);10#endif11 12static sqlite3 *gDb = NULL;13 14void setUp(void) {15  /* Setup executed before each test */16}17 18void tearDown(void) {19  /* Cleanup executed after each test */20}21 22#ifdef SQLITE_ENABLE_STAT423/* Helpers to allocate and free StatAccum and StatSample internals */24static void initStatAccum(StatAccum *p, int nCol, int mxSample){25  memset(p, 0, sizeof(*p));26  if( gDb==NULL ){27    /* Ensure a db connection exists for any sqlite3Db* helpers used by internals */28    int rc = sqlite3_open(":memory:", &gDb);29    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);30  }31  p->db = gDb;32  p->nCol = nCol;33  p->nKeyCol = nCol>0 ? nCol-1 : 0;34  p->mxSample = mxSample;35  p->nSample = 0;36  p->nMaxEqZero = 0;37  p->iMin = 0;38  /* allocate the array of samples */39  p->a = (StatSample*)sqlite3_malloc64(sizeof(StatSample) * (size_t)mxSample);40  TEST_ASSERT_NOT_NULL(p->a);41  memset(p->a, 0, sizeof(StatSample) * (size_t)mxSample);42  for(int i=0;i<mxSample;i++){43    p->a[i].anEq  = (tRowcnt*)sqlite3_malloc64(sizeof(tRowcnt) * (size_t)nCol);44    p->a[i].anLt  = (tRowcnt*)sqlite3_malloc64(sizeof(tRowcnt) * (size_t)nCol);45    p->a[i].anDLt = (tRowcnt*)sqlite3_malloc64(sizeof(tRowcnt) * (size_t)nCol);46    TEST_ASSERT_NOT_NULL(p->a[i].anEq);47    TEST_ASSERT_NOT_NULL(p->a[i].anLt);48    TEST_ASSERT_NOT_NULL(p->a[i].anDLt);49    memset(p->a[i].anEq,  0, sizeof(tRowcnt) * (size_t)nCol);50    memset(p->a[i].anLt,  0, sizeof(tRowcnt) * (size_t)nCol);51    memset(p->a[i].anDLt, 0, sizeof(tRowcnt) * (size_t)nCol);52    p->a[i].isPSample = 0;53    p->a[i].iCol = 0;54    p->a[i].u.iRowid = 0;55    p->a[i].nRowid = 0;56  }57}58 59static void freeStatAccum(StatAccum *p){60  if( p && p->a ){61    /* Free the per-sample arrays */62    for(int i=0; i<p->mxSample; i++){63      if( p->a[i].anEq ) sqlite3_free(p->a[i].anEq);64      if( p->a[i].anLt ) sqlite3_free(p->a[i].anLt);65      if( p->a[i].anDLt ) sqlite3_free(p->a[i].anDLt);66      /* Rowid memory (u.aRowid) would be freed by sampleClear via sqlite3DbFree if set. */67      p->a[i].anEq = NULL;68      p->a[i].anLt = NULL;69      p->a[i].anDLt = NULL;70    }71    sqlite3_free(p->a);72    p->a = NULL;73  }74}75 76static void initSampleArrays(StatSample *s, int nCol){77  memset(s, 0, sizeof(*s));78  s->anEq  = (tRowcnt*)sqlite3_malloc64(sizeof(tRowcnt) * (size_t)nCol);79  s->anLt  = (tRowcnt*)sqlite3_malloc64(sizeof(tRowcnt) * (size_t)nCol);80  s->anDLt = (tRowcnt*)sqlite3_malloc64(sizeof(tRowcnt) * (size_t)nCol);81  TEST_ASSERT_NOT_NULL(s->anEq);82  TEST_ASSERT_NOT_NULL(s->anLt);83  TEST_ASSERT_NOT_NULL(s->anDLt);84  memset(s->anEq,  0, sizeof(tRowcnt) * (size_t)nCol);85  memset(s->anLt,  0, sizeof(tRowcnt) * (size_t)nCol);86  memset(s->anDLt, 0, sizeof(tRowcnt) * (size_t)nCol);87  s->nRowid = 0;88  s->u.iRowid = 0;89}90 91static void freeSampleArrays(StatSample *s){92  if( s->anEq )  sqlite3_free(s->anEq);93  if( s->anLt )  sqlite3_free(s->anLt);94  if( s->anDLt ) sqlite3_free(s->anDLt);95  s->anEq = s->anLt = s->anDLt = NULL;96}97 98/* Test 1: Basic insertion and zeroing behavior with available capacity */99void test_sampleInsert_basic_insertion_and_zeroing(void){100  const int nCol = 3;101  const int mxSample = 4;102  StatAccum acc; initStatAccum(&acc, nCol, mxSample);103 104  /* Prepare new periodic sample (so we skip upgrade path) */105  StatSample newS; initSampleArrays(&newS, nCol);106  newS.isPSample = 1; /* periodic sample */107  newS.iCol = 0;108  newS.anEq[0] = 7; newS.anEq[1] = 8; newS.anEq[2] = 9;109  newS.anLt[0] = 0; newS.anLt[1] = 0; newS.anLt[2] = 5; /* last column orders samples */110  newS.anDLt[0] = 0; newS.anDLt[1] = 0; newS.anDLt[2] = 0;111 112  TEST_ASSERT_EQUAL_INT(0, acc.nSample);113  TEST_ASSERT_EQUAL_INT(0, acc.nMaxEqZero);114 115  test_sampleInsert(&acc, &newS, 2);116 117  TEST_ASSERT_EQUAL_INT(1, acc.nSample);118  TEST_ASSERT_EQUAL_INT(2, acc.nMaxEqZero);119  TEST_ASSERT_TRUE(acc.a[0].isPSample == 1);120  TEST_ASSERT_EQUAL_INT(0, acc.a[0].iCol);121  TEST_ASSERT_EQUAL_INT64(5, acc.a[0].anLt[nCol-1]);122  /* First 2 anEq entries zeroed, the remainder preserved */123  TEST_ASSERT_EQUAL_INT64(0, acc.a[0].anEq[0]);124  TEST_ASSERT_EQUAL_INT64(0, acc.a[0].anEq[1]);125  TEST_ASSERT_EQUAL_INT64(9, acc.a[0].anEq[2]);126 127  freeSampleArrays(&newS);128  freeStatAccum(&acc);129}130 131/* Test 2: When full, removal uses p->iMin index and reuses its buffer pointers */132void test_sampleInsert_full_array_removal_reuse_pointers(void){133  const int nCol = 3;134  const int mxSample = 3;135  StatAccum acc; initStatAccum(&acc, nCol, mxSample);136 137  /* Fill up acc.a with 3 non-PSample entries, increasing anLt last column */138  for(int i=0;i<mxSample;i++){139    acc.a[i].isPSample = 0;140    acc.a[i].iCol = 0;141    acc.a[i].anEq[0] = (tRowcnt)(1+i);142    acc.a[i].anEq[1] = 0;143    acc.a[i].anEq[2] = 0;144    acc.a[i].anLt[nCol-1] = (tRowcnt)((i+1)*10); /* 10,20,30 */145  }146  acc.nSample = mxSample;147  acc.iMin = 1; /* mark middle entry as least desirable to be removed */148 149  /* Keep pointers of the to-be-removed entry's buffers */150  tRowcnt *oldEq  = acc.a[acc.iMin].anEq;151  tRowcnt *oldLt  = acc.a[acc.iMin].anLt;152  tRowcnt *oldDLt = acc.a[acc.iMin].anDLt;153 154  /* New periodic sample with last column anLt > last remaining (30) */155  StatSample newS; initSampleArrays(&newS, nCol);156  newS.isPSample = 1;157  newS.iCol = 0;158  newS.anEq[0] = 55; newS.anEq[1] = 77; newS.anEq[2] = 99;159  newS.anLt[0] = 0; newS.anLt[1] = 0; newS.anLt[2] = 35; /* > 30 after removal */160 161  test_sampleInsert(&acc, &newS, 1);162 163  /* Still full */164  TEST_ASSERT_EQUAL_INT(mxSample, acc.nSample);165  /* The new last entry should reuse the removed entry's buffers */166  StatSample *last = &acc.a[mxSample-1];167  TEST_ASSERT_TRUE(last->anEq  == oldEq);168  TEST_ASSERT_TRUE(last->anLt  == oldLt);169  TEST_ASSERT_TRUE(last->anDLt == oldDLt);170  /* nEqZero=1 => first element zeroed, others copied from newS */171  TEST_ASSERT_EQUAL_INT64(0, last->anEq[0]);172  TEST_ASSERT_EQUAL_INT64(77, last->anEq[1]);173  TEST_ASSERT_EQUAL_INT64(99, last->anEq[2]);174  TEST_ASSERT_TRUE(last->isPSample == 1);175  TEST_ASSERT_EQUAL_INT(0, last->iCol);176  TEST_ASSERT_EQUAL_INT64(35, last->anLt[nCol-1]);177  /* iMin recomputed and must point to a non-PSample entry */178  TEST_ASSERT_TRUE(acc.iMin >= 0 && acc.iMin < mxSample);179  TEST_ASSERT_TRUE(acc.a[acc.iMin].isPSample == 0);180 181  freeSampleArrays(&newS);182  freeStatAccum(&acc);183}184 185/* Test 3: Upgrade an existing non-PSample sharing the prefix (no append) */186void test_sampleInsert_upgrade_existing_sample(void){187  const int nCol = 3;188  const int mxSample = 3;189  StatAccum acc; initStatAccum(&acc, nCol, mxSample);190 191  /* Existing non-PSample with iCol=1, anEq[1]=3, anEq[0]=0 so it shares prefix at col0 */192  acc.a[0].isPSample = 0;193  acc.a[0].iCol = 1;194  acc.a[0].anEq[0] = 0;195  acc.a[0].anEq[1] = 3;196  acc.a[0].anLt[nCol-1] = 10;197  acc.nSample = 1;198 199  /* New non-PSample prefers this prefix (anEq[0]=5 > old anEq[1]=3) */200  StatSample newS; initSampleArrays(&newS, nCol);201  newS.isPSample = 0;202  newS.iCol = 0;203  newS.anEq[0] = 5; /* > 3 so sampleIsBetter is true */204  newS.anLt[nCol-1] = 20; /* Must be > last a[n-1] for order, here 10 */205 206  test_sampleInsert(&acc, &newS, 0);207 208  /* No append: nSample unchanged */209  TEST_ASSERT_EQUAL_INT(1, acc.nSample);210  /* Upgraded existing sample's iCol and anEq at that column */211  TEST_ASSERT_EQUAL_INT(0, acc.a[0].iCol);212  TEST_ASSERT_EQUAL_INT64(5, acc.a[0].anEq[0]);213  /* Other fields (like anLt) unchanged for the upgraded sample */214  TEST_ASSERT_EQUAL_INT64(10, acc.a[0].anLt[nCol-1]);215 216  freeSampleArrays(&newS);217  freeStatAccum(&acc);218}219 220/* Test 4: Early return if an existing PSample shares the prefix */221void test_sampleInsert_skip_due_to_psample(void){222  const int nCol = 3;223  const int mxSample = 2;224  StatAccum acc; initStatAccum(&acc, nCol, mxSample);225 226  /* Existing PSample with iCol=1 and anEq[0]==0 so it shares prefix col0 */227  acc.a[0].isPSample = 1;228  acc.a[0].iCol = 1;229  acc.a[0].anEq[0] = 0;230  acc.a[0].anEq[1] = 3;231  acc.a[0].anLt[nCol-1] = 10;232  acc.nSample = 1;233  acc.nMaxEqZero = 1;234 235  /* New non-PSample attempts same prefix */236  StatSample newS; initSampleArrays(&newS, nCol);237  newS.isPSample = 0;238  newS.iCol = 0;239  newS.anEq[0] = 5; /* required by assert */240  newS.anLt[nCol-1] = 20; /* ordering OK */241 242  test_sampleInsert(&acc, &newS, 2);243 244  /* Function should return early: no change to samples count or contents */245  TEST_ASSERT_EQUAL_INT(1, acc.nSample);246  TEST_ASSERT_TRUE(acc.a[0].isPSample == 1);247  TEST_ASSERT_EQUAL_INT(1, acc.a[0].iCol);248  TEST_ASSERT_EQUAL_INT64(0, acc.a[0].anEq[0]);249  /* But nMaxEqZero is updated before the early return */250  TEST_ASSERT_EQUAL_INT(2, acc.nMaxEqZero);251 252  freeSampleArrays(&newS);253  freeStatAccum(&acc);254}255 256#endif /* SQLITE_ENABLE_STAT4 */257 258int main(void){259  UNITY_BEGIN();260#ifndef SQLITE_ENABLE_STAT4261  TEST_IGNORE_MESSAGE("SQLITE_ENABLE_STAT4 not defined; sampleInsert tests skipped.");262#else263  RUN_TEST(test_sampleInsert_basic_insertion_and_zeroing);264  RUN_TEST(test_sampleInsert_full_array_removal_reuse_pointers);265  RUN_TEST(test_sampleInsert_upgrade_existing_sample);266  RUN_TEST(test_sampleInsert_skip_due_to_psample);267#endif268  int rc = UNITY_END();269#ifdef SQLITE_ENABLE_STAT4270  if( gDb ){ sqlite3_close(gDb); gDb = NULL; }271#endif272  return rc;273}