Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_sqlite3_db_release_memory.c187 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdio.h>6 7/* Unity setup/teardown */8void setUp(void) {9  /* No-op */10}11void tearDown(void) {12  /* No-op */13}14 15/* Helper: execute SQL and assert success */16static void assertExecSQL(sqlite3 *db, const char *sql){17  char *zErr = NULL;18  int rc = sqlite3_exec(db, sql, 0, 0, &zErr);19  if( rc!=SQLITE_OK ){20    fprintf(stderr, "SQL error rc=%d: %s\nSQL: %s\n", rc, zErr ? zErr : "(null)", sql);21  }22  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);23  if( zErr ) sqlite3_free(zErr);24}25 26/* Helper: get current page-cache memory used (bytes) */27static int getCacheUsed(sqlite3 *db){28  int cur = 0, hiwtr = 0;29  int rc = sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiwtr, 0);30  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);31  return cur;32}33 34/* Helper: populate a table with many large rows to grow the cache */35static void populateLargeTable(sqlite3 *db, const char *qualifiedTableName, int nRows, int blobSize){36  char sql[256];37  snprintf(sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS %s(x);", qualifiedTableName);38  assertExecSQL(db, sql);39  assertExecSQL(db, "BEGIN");40  sqlite3_stmt *pStmt = NULL;41  snprintf(sql, sizeof(sql), "INSERT INTO %s(x) VALUES(randomblob(%d));", qualifiedTableName, blobSize);42  int rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, 0);43  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);44  for(int i=0; i<nRows; i++){45    rc = sqlite3_step(pStmt);46    TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc);47    rc = sqlite3_reset(pStmt);48    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);49  }50  rc = sqlite3_finalize(pStmt);51  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);52  assertExecSQL(db, "COMMIT");53}54 55/* Test 1: Basic success on fresh database */56void test_sqlite3_db_release_memory_basic_returns_ok(void){57  sqlite3 *db = NULL;58  int rc = sqlite3_open(":memory:", &db);59  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);60  TEST_ASSERT_NOT_NULL(db);61 62  rc = sqlite3_db_release_memory(db);63  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);64 65  rc = sqlite3_close(db);66  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);67}68 69/* Test 2: After heavy use, release memory does not increase cache usage (and typically reduces it) */70void test_sqlite3_db_release_memory_non_increasing_cache_after_work(void){71  sqlite3 *db = NULL;72  int rc = sqlite3_open(":memory:", &db);73  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);74 75  /* Grow the cache by inserting many large blobs */76  populateLargeTable(db, "t", 1500, 4000); /* ~6MB of data requested at SQL layer */77 78  int usedBefore = getCacheUsed(db);79  /* Ensure we actually used some cache (should be > 0) */80  TEST_ASSERT_MESSAGE(usedBefore > 0, "Expected non-zero cache use after large inserts");81 82  rc = sqlite3_db_release_memory(db);83  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);84 85  int usedAfter = getCacheUsed(db);86  TEST_ASSERT_LESS_OR_EQUAL_INT(usedBefore, usedBefore); /* sanity no-op compare */87  TEST_ASSERT_TRUE_MESSAGE(usedAfter <= usedBefore, "Cache used should not increase after release");88 89  rc = sqlite3_close(db);90  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);91}92 93/* Test 3: Works with attached databases (multiple Btrees/Pagers) */94void test_sqlite3_db_release_memory_with_attached_databases(void){95  sqlite3 *db = NULL;96  int rc = sqlite3_open(":memory:", &db);97  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);98 99  /* Attach another in-memory database */100  assertExecSQL(db, "ATTACH DATABASE ':memory:' AS aux");101 102  /* Populate both main and aux to exercise multiple pagers */103  populateLargeTable(db, "main.t", 1000, 4096);104  populateLargeTable(db, "aux.u", 1000, 4096);105 106  int usedBefore = getCacheUsed(db);107  TEST_ASSERT_MESSAGE(usedBefore > 0, "Expected non-zero cache use after populating main and aux");108 109  rc = sqlite3_db_release_memory(db);110  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);111 112  int usedAfter = getCacheUsed(db);113  TEST_ASSERT_TRUE_MESSAGE(usedAfter <= usedBefore, "Cache used should not increase after release with attached DBs");114 115  /* Clean up */116  rc = sqlite3_close(db);117  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);118}119 120/* Test 4: Idempotent-ish behavior on repeated calls (no increase in cache usage) */121void test_sqlite3_db_release_memory_multiple_calls_idempotent(void){122  sqlite3 *db = NULL;123  int rc = sqlite3_open(":memory:", &db);124  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);125 126  populateLargeTable(db, "t", 1200, 4096);127 128  int usedBefore = getCacheUsed(db);129  TEST_ASSERT_MESSAGE(usedBefore > 0, "Expected non-zero cache use before release");130 131  rc = sqlite3_db_release_memory(db);132  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);133  int usedAfter1 = getCacheUsed(db);134 135  rc = sqlite3_db_release_memory(db);136  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);137  int usedAfter2 = getCacheUsed(db);138 139  TEST_ASSERT_TRUE_MESSAGE(usedAfter1 <= usedBefore, "First release should not increase cache usage");140  TEST_ASSERT_TRUE_MESSAGE(usedAfter2 <= usedAfter1, "Second release should not increase cache usage");141 142  rc = sqlite3_close(db);143  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);144}145 146/* Test 5: Calling while a statement is active still returns OK */147void test_sqlite3_db_release_memory_with_active_statement(void){148  sqlite3 *db = NULL;149  int rc = sqlite3_open(":memory:", &db);150  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);151 152  populateLargeTable(db, "t", 800, 4096);153 154  sqlite3_stmt *pStmt = NULL;155  rc = sqlite3_prepare_v2(db, "SELECT * FROM t;", -1, &pStmt, 0);156  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);157  TEST_ASSERT_NOT_NULL(pStmt);158 159  /* Do not finalize yet; keep resources potentially pinned */160  int usedBefore = getCacheUsed(db);161  rc = sqlite3_db_release_memory(db);162  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);163  int usedAfter = getCacheUsed(db);164  /* We only assert non-increase; pinned pages may prevent reductions */165  TEST_ASSERT_TRUE_MESSAGE(usedAfter <= usedBefore, "Cache used should not increase after release with active stmt");166 167  rc = sqlite3_finalize(pStmt);168  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);169 170  /* After finalizing, another release should remain OK and not increase usage */171  rc = sqlite3_db_release_memory(db);172  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);173 174  rc = sqlite3_close(db);175  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);176}177 178/* Main to run tests */179int main(void){180  UNITY_BEGIN();181  RUN_TEST(test_sqlite3_db_release_memory_basic_returns_ok);182  RUN_TEST(test_sqlite3_db_release_memory_non_increasing_cache_after_work);183  RUN_TEST(test_sqlite3_db_release_memory_with_attached_databases);184  RUN_TEST(test_sqlite3_db_release_memory_multiple_calls_idempotent);185  RUN_TEST(test_sqlite3_db_release_memory_with_active_statement);186  return UNITY_END();187}