Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_build_deleteTable.c212 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Wrapper provided in module for calling the static function */7extern void test_deleteTable(sqlite3 *db, Table *pTable);8 9static Table* makeOrdinaryTableWithColsAndIdx(sqlite3 *db, Schema *pSchema,10                                              int nCol, int nIdx){11  Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));12  TEST_ASSERT_NOT_NULL(pTab);13 14  pTab->pSchema = pSchema;15  pTab->tabFlags |= TF_Ephemeral; /* Avoid debug lookaside checks */16  pTab->zName = sqlite3DbStrDup(db, "t1");17  pTab->zColAff = sqlite3DbStrDup(db, "aa");18 19  /* Columns */20  pTab->nCol = nCol;21  pTab->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nCol);22  TEST_ASSERT_NOT_NULL(pTab->aCol);23  for(int i=0; i<nCol; i++){24    char zBuf[16];25    sqlite3_snprintf(sizeof(zBuf), zBuf, "c%d", i+1);26    pTab->aCol[i].zCnName = sqlite3DbStrDup(db, zBuf);27    TEST_ASSERT_NOT_NULL(pTab->aCol[i].zCnName);28    pTab->aCol[i].hName = sqlite3StrIHash(pTab->aCol[i].zCnName);29  }30 31  /* Indices chain */32  Index *pHead = NULL;33  for(int i=0; i<nIdx; i++){34    Index *pIdx = (Index*)sqlite3DbMallocZero(db, sizeof(Index));35    TEST_ASSERT_NOT_NULL(pIdx);36    /* Minimal, but sufficient for free-path */37    pIdx->pSchema = pSchema;38    pIdx->zName = (char*)"idx"; /* literal; not freed by sqlite3FreeIndex */39    pIdx->zColAff = sqlite3DbStrDup(db, "aa");40    TEST_ASSERT_NOT_NULL(pIdx->zColAff);41    if( (i%2)==0 ){42      /* Exercise azColl free path when isResized is true */43      pIdx->isResized = 1;44      pIdx->azColl = (const char**)sqlite3DbMallocZero(db, sizeof(char*)*2);45      TEST_ASSERT_NOT_NULL((void*)pIdx->azColl);46    }47    /* push-front into chain */48    pIdx->pNext = pHead;49    pHead = pIdx;50  }51  pTab->pIndex = pHead;52 53  return pTab;54}55 56static Table* makeViewTableWithSelect(sqlite3 *db, Schema *pSchema, int nCol){57  Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));58  TEST_ASSERT_NOT_NULL(pTab);59 60  pTab->pSchema = pSchema;61  pTab->tabFlags |= (TF_View | TF_Ephemeral); /* Mark as view; skip lookaside check */62  pTab->zName = sqlite3DbStrDup(db, "v1");63  pTab->zColAff = sqlite3DbStrDup(db, "a");64 65  /* Columns */66  pTab->nCol = nCol;67  pTab->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nCol);68  TEST_ASSERT_NOT_NULL(pTab->aCol);69  for(int i=0; i<nCol; i++){70    char zBuf[16];71    sqlite3_snprintf(sizeof(zBuf), zBuf, "x%d", i+1);72    pTab->aCol[i].zCnName = sqlite3DbStrDup(db, zBuf);73    TEST_ASSERT_NOT_NULL(pTab->aCol[i].zCnName);74    pTab->aCol[i].hName = sqlite3StrIHash(pTab->aCol[i].zCnName);75  }76 77  /* Minimal Select object to be deleted via sqlite3SelectDelete */78  pTab->u.view.pSelect = (Select*)sqlite3DbMallocZero(db, sizeof(Select));79  TEST_ASSERT_NOT_NULL(pTab->u.view.pSelect);80 81  return pTab;82}83 84void setUp(void) {85  /* nothing */86}87void tearDown(void) {88  /* nothing */89}90 91static sqlite3* open_db(void){92  sqlite3 *db = 0;93  int rc = sqlite3_open(":memory:", &db);94  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);95  TEST_ASSERT_NOT_NULL(db);96  return db;97}98 99static size_t strsz(const char *z){ return z ? (strlen(z)+1) : 0; }100 101/* Test 1: In byte-counting mode, memory is accounted and table fields are preserved */102void test_deleteTable_measurement_mode_preserves_and_counts(void){103  sqlite3 *db = open_db();104  Schema *pSchema = db->aDb[0].pSchema;105  TEST_ASSERT_NOT_NULL(pSchema);106 107  /* Build ordinary table with 2 columns and 2 indices */108  Table *pTab = makeOrdinaryTableWithColsAndIdx(db, pSchema, 2, 2);109 110  /* Compute a conservative minimum expected counted bytes */111  size_t expectedMin = 0;112  expectedMin += sizeof(Table);113  expectedMin += sizeof(Column)*2;114  expectedMin += strsz("t1");      /* zName */115  expectedMin += strsz("aa");      /* zColAff */116  expectedMin += strsz("c1") + strsz("c2");117  /* Two indices: each frees its zColAff and the Index struct itself.118     One of them (first created with even i) also frees azColl. */119  expectedMin += sizeof(Index) + strsz("aa") + sizeof(char*)*2; /* i=0: has azColl */120  expectedMin += sizeof(Index) + strsz("aa");                   /* i=1: no azColl */121 122  i64 nFreed = 0;123  db->pnBytesFreed = &nFreed;124 125  /* Call the wrapper to invoke the static function */126  test_deleteTable(db, pTab);127 128  /* In counting mode, fields should remain intact */129  TEST_ASSERT_NOT_NULL(pTab->aCol);130  TEST_ASSERT_EQUAL_INT(2, pTab->nCol);131  TEST_ASSERT_NOT_NULL(pTab->pIndex);132  TEST_ASSERT_TRUE(nFreed >= (i64)expectedMin);133 134  /* Now actually free structures (must hold schema mutex for hash unlink path) */135  db->pnBytesFreed = 0;136  sqlite3_mutex_enter(db->mutex);137  test_deleteTable(db, pTab);138  sqlite3_mutex_leave(db->mutex);139 140  sqlite3_close(db);141}142 143/* Test 2: In real-free mode, indices are unlinked from the schema hash */144void test_deleteTable_unlinks_indexes_from_schema_hash(void){145  sqlite3 *db = open_db();146  Schema *pSchema = db->aDb[0].pSchema;147  TEST_ASSERT_NOT_NULL(pSchema);148 149  /* Build table with 1 index */150  Table *pTab = makeOrdinaryTableWithColsAndIdx(db, pSchema, 1, 1);151  TEST_ASSERT_NOT_NULL(pTab->pIndex);152  /* Give the index a concrete name and register it in the schema idxHash */153  pTab->pIndex->zName = (char*)"idxA";154  /* Insert into schema hash (using internal sqlite3HashInsert) */155  sqlite3HashInsert(&pSchema->idxHash, pTab->pIndex->zName, pTab->pIndex);156  /* Sanity: should be findable */157  TEST_ASSERT_NOT_NULL(sqlite3HashFind(&pSchema->idxHash, "idxA"));158 159  /* Real free mode (pnBytesFreed == 0); hold schema mutex for assert */160  sqlite3_mutex_enter(db->mutex);161  test_deleteTable(db, pTab);162  sqlite3_mutex_leave(db->mutex);163 164  /* After deleteTable, the index should be unlinked from schema hash */165  void *pFound = sqlite3HashFind(&pSchema->idxHash, "idxA");166  TEST_ASSERT_NULL(pFound);167 168  sqlite3_close(db);169}170 171/* Test 3: View-table path in counting mode includes Select object and preserves fields */172void test_deleteTable_view_path_counts_and_preserves(void){173  sqlite3 *db = open_db();174  Schema *pSchema = db->aDb[0].pSchema;175  TEST_ASSERT_NOT_NULL(pSchema);176 177  Table *pTab = makeViewTableWithSelect(db, pSchema, 1);178 179  size_t expectedMin = 0;180  expectedMin += sizeof(Table);181  expectedMin += sizeof(Column)*1;182  expectedMin += strsz("v1");  /* zName */183  expectedMin += strsz("a");   /* zColAff */184  expectedMin += strsz("x1");  /* column name */185  expectedMin += sizeof(Select); /* view Select struct */186 187  i64 nFreed = 0;188  db->pnBytesFreed = &nFreed;189 190  test_deleteTable(db, pTab);191 192  /* In counting mode, verify preservation and accounting */193  TEST_ASSERT_NOT_NULL(pTab->aCol);194  TEST_ASSERT_EQUAL_INT(1, pTab->nCol);195  TEST_ASSERT_TRUE(nFreed >= (i64)expectedMin);196 197  /* Now actually free with mutex held */198  db->pnBytesFreed = 0;199  sqlite3_mutex_enter(db->mutex);200  test_deleteTable(db, pTab);201  sqlite3_mutex_leave(db->mutex);202 203  sqlite3_close(db);204}205 206int main(void){207  UNITY_BEGIN();208  RUN_TEST(test_deleteTable_measurement_mode_preserves_and_counts);209  RUN_TEST(test_deleteTable_unlinks_indexes_from_schema_hash);210  RUN_TEST(test_deleteTable_view_path_counts_and_preserves);211  return UNITY_END();212}