Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_build_sqlite3ClearStatTables.c296 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* Wrapper for the static function under test (provided by the build harness) */8extern void test_sqlite3ClearStatTables(Parse *pParse, int iDb, const char *zType, const char *zName);9 10typedef struct AuthEvent {11  int code;12  char db[64];13  char tbl[64];14} AuthEvent;15 16#define MAX_EVENTS 6417typedef struct AuthLog {18  int n;19  AuthEvent ev[MAX_EVENTS];20} AuthLog;21 22static int auth_cb(void *pArg, int code,23                   const char *p1, const char *p2,24                   const char *zDb, const char *zTrig){25  AuthLog *pLog = (AuthLog*)pArg;26  if( code==SQLITE_DELETE ){27    if( pLog->n < MAX_EVENTS ){28      AuthEvent *e = &pLog->ev[pLog->n++];29      e->code = code;30      e->db[0] = '\0';31      e->tbl[0] = '\0';32      if( zDb ) {33        strncpy(e->db, zDb, sizeof(e->db)-1);34        e->db[sizeof(e->db)-1] = '\0';35      }36      if( p1 ) {37        strncpy(e->tbl, p1, sizeof(e->tbl)-1);38        e->tbl[sizeof(e->tbl)-1] = '\0';39      }40    }41  }42  /* Always allow */43  return SQLITE_OK;44}45 46static int findDbIndex(sqlite3 *db, const char *zName){47  int i;48  for(i=0; i<db->nDb; i++){49    if( db->aDb[i].zDbSName && 0==sqlite3StrICmp(db->aDb[i].zDbSName, zName) ){50      return i;51    }52  }53  return -1;54}55 56static int stat_exists(sqlite3 *db, const char *zDbName, int n){57  char zTab[24];58  sqlite3_snprintf(sizeof(zTab), zTab, "sqlite_stat%d", n);59  return sqlite3FindTable(db, zTab, zDbName)!=0;60}61 62static int count_existing_stat_tables(sqlite3 *db, const char *zDbName){63  int i, c=0;64  for(i=1; i<=4; i++){65    if( stat_exists(db, zDbName, i) ) c++;66  }67  return c;68}69 70static void populate_main_stats(sqlite3 *db){71  /* Create objects and run ANALYZE to ensure sqlite_stat tables exist */72  char *errmsg = 0;73  int rc;74  rc = sqlite3_exec(db,75    "PRAGMA foreign_keys=OFF; "76    "CREATE TABLE IF NOT EXISTS t1(x); "77    "CREATE INDEX IF NOT EXISTS i1 ON t1(x); "78    "INSERT INTO t1(x) VALUES(1),(2),(3); "79    "ANALYZE;",80    0, 0, &errmsg81  );82  if( rc!=SQLITE_OK ){83    /* Try a simpler ANALYZE in case of errors */84    if( errmsg ) sqlite3_free(errmsg);85    sqlite3_exec(db, "ANALYZE;", 0, 0, 0);86  }else if( errmsg ){87    sqlite3_free(errmsg);88  }89}90 91static void populate_aux_stats(sqlite3 *db, const char *zAux){92  char *sql = sqlite3_mprintf(93    "ATTACH ':memory:' AS %Q; "94    "CREATE TABLE IF NOT EXISTS %Q.t2(y); "95    "INSERT INTO %Q.t2(y) VALUES(1),(2); "96    "ANALYZE %Q;", zAux, zAux, zAux, zAux);97  if( sql ){98    sqlite3_exec(db, sql, 0, 0, 0);99    sqlite3_free(sql);100  }101}102 103void setUp(void) {104  /* no-op */105}106 107void tearDown(void) {108  /* no-op */109}110 111static void init_parse(sqlite3 *db, Parse *p){112  memset(p, 0, sizeof(*p));113  p->db = db;114  p->rc = SQLITE_OK;115  p->nErr = 0;116}117 118/* Test 1: No stats present -> no DELETEs emitted */119void test_sqlite3ClearStatTables_no_stats_emits_nothing(void){120  sqlite3 *db = 0;121  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));122  AuthLog log; memset(&log, 0, sizeof(log));123  sqlite3_set_authorizer(db, auth_cb, &log);124 125  Parse p;126  init_parse(db, &p);127 128  int iMain = findDbIndex(db, "main");129  TEST_ASSERT_TRUE(iMain >= 0);130 131  test_sqlite3ClearStatTables(&p, iMain, "tbl", "t1");132 133  TEST_ASSERT_EQUAL_INT(0, log.n);134  TEST_ASSERT_EQUAL_INT(0, p.nErr);135 136  sqlite3_set_authorizer(db, 0, 0);137  sqlite3_close(db);138}139 140/* Test 2: Main DB stats present -> DELETE emitted for each existing sqlite_statN */141void test_sqlite3ClearStatTables_main_stats_deletes_issued(void){142  sqlite3 *db = 0;143  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));144 145  populate_main_stats(db);146 147  int expected = count_existing_stat_tables(db, "main");148  TEST_ASSERT_TRUE_MESSAGE(expected >= 1, "Expected at least one sqlite_stat table in main schema after ANALYZE");149 150  AuthLog log; memset(&log, 0, sizeof(log));151  sqlite3_set_authorizer(db, auth_cb, &log);152 153  Parse p;154  init_parse(db, &p);155 156  int iMain = findDbIndex(db, "main");157  TEST_ASSERT_TRUE(iMain >= 0);158 159  test_sqlite3ClearStatTables(&p, iMain, "tbl", "t1");160 161  TEST_ASSERT_EQUAL_INT(expected, log.n);162  for(int i=0; i<log.n; i++){163    TEST_ASSERT_EQUAL_INT(SQLITE_DELETE, log.ev[i].code);164    TEST_ASSERT_TRUE(!sqlite3StrICmp(log.ev[i].db, "main"));165    /* Table must be one of sqlite_stat1..sqlite_stat4 that exist */166    int seen = 0;167    for(int n=1; n<=4; n++){168      char zTab[24];169      sqlite3_snprintf(sizeof(zTab), zTab, "sqlite_stat%d", n);170      if( stat_exists(db, "main", n) && sqlite3StrICmp(log.ev[i].tbl, zTab)==0 ){171        seen = 1;172        break;173      }174    }175    TEST_ASSERT_TRUE_MESSAGE(seen, "DELETE issued for unexpected table name in main schema");176  }177 178  sqlite3_set_authorizer(db, 0, 0);179  sqlite3_close(db);180}181 182/* Test 3: Attached DB stats present -> DELETE emitted in correct schema */183void test_sqlite3ClearStatTables_attached_db_schema_correct(void){184  sqlite3 *db = 0;185  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));186 187  const char *zAux = "aux";188  populate_aux_stats(db, zAux);189 190  int expected = count_existing_stat_tables(db, zAux);191  TEST_ASSERT_TRUE_MESSAGE(expected >= 1, "Expected at least one sqlite_stat table in aux schema after ANALYZE aux");192 193  int iAux = findDbIndex(db, zAux);194  TEST_ASSERT_TRUE_MESSAGE(iAux >= 0, "Attached schema index not found");195 196  AuthLog log; memset(&log, 0, sizeof(log));197  sqlite3_set_authorizer(db, auth_cb, &log);198 199  Parse p;200  init_parse(db, &p);201 202  test_sqlite3ClearStatTables(&p, iAux, "idx", "i2_we_dont_care");203 204  TEST_ASSERT_EQUAL_INT(expected, log.n);205  for(int i=0; i<log.n; i++){206    TEST_ASSERT_EQUAL_INT(SQLITE_DELETE, log.ev[i].code);207    TEST_ASSERT_TRUE(!sqlite3StrICmp(log.ev[i].db, zAux));208    int seen = 0;209    for(int n=1; n<=4; n++){210      char zTab[24];211      sqlite3_snprintf(sizeof(zTab), zTab, "sqlite_stat%d", n);212      if( stat_exists(db, zAux, n) && sqlite3StrICmp(log.ev[i].tbl, zTab)==0 ){213        seen = 1;214        break;215      }216    }217    TEST_ASSERT_TRUE_MESSAGE(seen, "DELETE issued for unexpected table name in aux schema");218  }219 220  sqlite3_set_authorizer(db, 0, 0);221  sqlite3_close(db);222}223 224/* Test 4: Pre-existing parse error suppresses nested deletes */225void test_sqlite3ClearStatTables_preexisting_error_suppresses(void){226  sqlite3 *db = 0;227  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));228 229  populate_main_stats(db);230  int expected = count_existing_stat_tables(db, "main");231  TEST_ASSERT_TRUE(expected >= 1);232 233  AuthLog log; memset(&log, 0, sizeof(log));234  sqlite3_set_authorizer(db, auth_cb, &log);235 236  Parse p;237  init_parse(db, &p);238  p.nErr = 1; /* Simulate existing error */239 240  int iMain = findDbIndex(db, "main");241  test_sqlite3ClearStatTables(&p, iMain, "tbl", "t1");242 243  TEST_ASSERT_EQUAL_INT(0, log.n); /* No nested parse -> no authorizer hits */244 245  sqlite3_set_authorizer(db, 0, 0);246  sqlite3_close(db);247}248 249/* Test 5: Quoting-safe zName with embedded quotes and spaces */250void test_sqlite3ClearStatTables_weird_name_quoted_ok(void){251  sqlite3 *db = 0;252  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));253 254  populate_main_stats(db);255  int expected = count_existing_stat_tables(db, "main");256  TEST_ASSERT_TRUE(expected >= 1);257 258  AuthLog log; memset(&log, 0, sizeof(log));259  sqlite3_set_authorizer(db, auth_cb, &log);260 261  Parse p;262  init_parse(db, &p);263 264  int iMain = findDbIndex(db, "main");265  const char *zWeird = "weird ' name \" with spaces";266  test_sqlite3ClearStatTables(&p, iMain, "tbl", zWeird);267 268  TEST_ASSERT_EQUAL_INT(expected, log.n);269  TEST_ASSERT_EQUAL_INT(0, p.nErr);270  for(int i=0; i<log.n; i++){271    TEST_ASSERT_TRUE(!sqlite3StrICmp(log.ev[i].db, "main"));272    /* Table names still must be sqlite_statN */273    int ok = 0;274    for(int n=1; n<=4; n++){275      char zTab[24];276      sqlite3_snprintf(sizeof(zTab), zTab, "sqlite_stat%d", n);277      if( stat_exists(db, "main", n) && sqlite3StrICmp(log.ev[i].tbl, zTab)==0 ){278        ok = 1; break;279      }280    }281    TEST_ASSERT_TRUE(ok);282  }283 284  sqlite3_set_authorizer(db, 0, 0);285  sqlite3_close(db);286}287 288int main(void){289  UNITY_BEGIN();290  RUN_TEST(test_sqlite3ClearStatTables_no_stats_emits_nothing);291  RUN_TEST(test_sqlite3ClearStatTables_main_stats_deletes_issued);292  RUN_TEST(test_sqlite3ClearStatTables_attached_db_schema_correct);293  RUN_TEST(test_sqlite3ClearStatTables_preexisting_error_suppresses);294  RUN_TEST(test_sqlite3ClearStatTables_weird_name_quoted_ok);295  return UNITY_END();296}