Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_fkey_sqlite3FkDropTable.c246 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/* Helper: create a SrcList for a given table in "main" schema */8static SrcList* makeSrcListForTable(sqlite3 *db, Table *pTab){9  SrcList *p = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList));10  TEST_ASSERT_NOT_NULL_MESSAGE(p, "Failed to allocate SrcList");11  p->nSrc = 1;12  p->nAlloc = 1;13  p->a[0].zName = sqlite3DbStrDup(db, pTab->zName);14  p->a[0].zDatabase = sqlite3DbStrDup(db, "main");15  p->a[0].pTab = pTab;16  p->a[0].pSchema = pTab->pSchema;17  return p;18}19 20/* Helper: count OP_FkIfZero instructions with a given P1 value */21static int countFkIfZeroOps(Vdbe *v, int p1){22  if( v==NULL ) return 0;23  int cnt = 0;24  int nOp = v->nOp;25  VdbeOp *aOp = v->aOp;26  for(int i=0; i<nOp; i++){27    if( aOp[i].opcode==OP_FkIfZero && aOp[i].p1==p1 ){28      cnt++;29    }30  }31  return cnt;32}33 34/* Helper: open an in-memory db and create schema, return db via out param */35static sqlite3* openDb(void){36  sqlite3 *db = 0;37  int rc = sqlite3_open(":memory:", &db);38  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");39  return db;40}41 42/* Helper: exec SQL and assert OK */43static void execSQL(sqlite3 *db, const char *zSql){44  char *zErr = 0;45  int rc = sqlite3_exec(db, zSql, 0, 0, &zErr);46  if( rc!=SQLITE_OK ){47    char msg[512];48    snprintf(msg, sizeof(msg), "SQL error (%d): %s while executing: %s", rc, zErr?zErr:"(null)", zSql);49    sqlite3_free(zErr);50    TEST_FAIL_MESSAGE(msg);51  }52}53 54/* Helper: find a Table* in main schema */55static Table* findTable(sqlite3 *db, const char *zName){56  Table *pTab = sqlite3FindTable(db, zName, "main");57  TEST_ASSERT_NOT_NULL_MESSAGE(pTab, "sqlite3FindTable returned NULL");58  return pTab;59}60 61/* Helper: cleanup VDBE if allocated */62static void destroyVdbe(Parse *pParse){63  if( pParse && pParse->pVdbe ){64    sqlite3VdbeDelete(pParse->pVdbe);65    pParse->pVdbe = 0;66  }67}68 69/* Unity fixtures */70void setUp(void) {71  /* No global setup needed */72}73void tearDown(void) {74  /* No global teardown needed */75}76 77/* Test 1: No FKs at all; with foreign_keys ON -> no VDBE generated */78void test_sqlite3FkDropTable_no_fk_no_vdbe(void){79  sqlite3 *db = openDb();80  execSQL(db, "CREATE TABLE t1(a);");81 82  /* Enable FK enforcement flag */83  db->flags |= SQLITE_ForeignKeys;84 85  Table *pTab = findTable(db, "t1");86  Parse parse;87  memset(&parse, 0, sizeof(parse));88  parse.db = db;89 90  SrcList *pName = makeSrcListForTable(db, pTab);91 92  sqlite3FkDropTable(&parse, pName, pTab);93 94  TEST_ASSERT_NULL(parse.pVdbe); /* No code generated */95  TEST_ASSERT_EQUAL_INT(0, parse.disableTriggers);96 97  sqlite3SrcListDelete(db, pName);98  sqlite3_close(db);99}100 101/* Test 2: Parent table referenced by a child; FK ON -> VDBE with post-delete immediate-check, no initial skip-check */102void test_sqlite3FkDropTable_parent_generates_delete_and_immediate_check(void){103  sqlite3 *db = openDb();104  execSQL(db, "CREATE TABLE p(id INTEGER PRIMARY KEY);");105  execSQL(db, "CREATE TABLE c(x, pid REFERENCES p(id));");106 107  db->flags |= SQLITE_ForeignKeys;108 109  Table *pTab = findTable(db, "p"); /* Parent table */110  Parse parse;111  memset(&parse, 0, sizeof(parse));112  parse.db = db;113 114  SrcList *pName = makeSrcListForTable(db, pTab);115 116  sqlite3FkDropTable(&parse, pName, pTab);117 118  TEST_ASSERT_NOT_NULL(parse.pVdbe);119  /* Should NOT have initial skip-check (P1==1) */120  TEST_ASSERT_EQUAL_INT(0, countFkIfZeroOps(parse.pVdbe, 1));121  /* Should have post-delete immediate-check (P1==0) if SQLITE_DeferFKs not set */122  TEST_ASSERT_TRUE(countFkIfZeroOps(parse.pVdbe, 0) >= 1);123  TEST_ASSERT_EQUAL_INT(0, parse.disableTriggers);124 125  destroyVdbe(&parse);126  sqlite3SrcListDelete(db, pName);127  sqlite3_close(db);128}129 130/* Test 3: Child table with DEFERRABLE INITIALLY DEFERRED; FK ON -> initial skip-check and post-delete immediate-check */131void test_sqlite3FkDropTable_child_deferred_has_skip_and_immediate_check(void){132  sqlite3 *db = openDb();133  execSQL(db, "CREATE TABLE p(id INTEGER PRIMARY KEY);");134  execSQL(db, "CREATE TABLE cd(x, pid REFERENCES p(id) DEFERRABLE INITIALLY DEFERRED);");135 136  db->flags |= SQLITE_ForeignKeys;137  db->flags &= ~SQLITE_DeferFKs; /* Ensure not set so immediate-check is added */138 139  Table *pTab = findTable(db, "cd"); /* Child table with deferred fk */140  Parse parse;141  memset(&parse, 0, sizeof(parse));142  parse.db = db;143 144  SrcList *pName = makeSrcListForTable(db, pTab);145 146  sqlite3FkDropTable(&parse, pName, pTab);147 148  TEST_ASSERT_NOT_NULL(parse.pVdbe);149  /* Should have initial skip-check (P1==1) */150  TEST_ASSERT_TRUE(countFkIfZeroOps(parse.pVdbe, 1) >= 1);151  /* Should have post-delete immediate-check (P1==0) */152  TEST_ASSERT_TRUE(countFkIfZeroOps(parse.pVdbe, 0) >= 1);153  TEST_ASSERT_EQUAL_INT(0, parse.disableTriggers);154 155  destroyVdbe(&parse);156  sqlite3SrcListDelete(db, pName);157  sqlite3_close(db);158}159 160/* Test 4: Child table with immediate (non-deferred) FK; FK ON and no SQLITE_DeferFKs -> no code generated */161void test_sqlite3FkDropTable_child_immediate_no_code(void){162  sqlite3 *db = openDb();163  execSQL(db, "CREATE TABLE p(id INTEGER PRIMARY KEY);");164  execSQL(db, "CREATE TABLE ci(x, pid REFERENCES p(id));"); /* immediate by default */165 166  db->flags |= SQLITE_ForeignKeys;167  db->flags &= ~SQLITE_DeferFKs;168 169  Table *pTab = findTable(db, "ci"); /* Child immediate FK */170  Parse parse;171  memset(&parse, 0, sizeof(parse));172  parse.db = db;173 174  SrcList *pName = makeSrcListForTable(db, pTab);175 176  sqlite3FkDropTable(&parse, pName, pTab);177 178  TEST_ASSERT_NULL(parse.pVdbe);179  TEST_ASSERT_EQUAL_INT(0, parse.disableTriggers);180 181  sqlite3SrcListDelete(db, pName);182  sqlite3_close(db);183}184 185/* Test 5: Child with immediate FK but SQLITE_DeferFKs set -> initial skip-check generated */186void test_sqlite3FkDropTable_child_immediate_with_DeferFKs_generates_skip(void){187  sqlite3 *db = openDb();188  execSQL(db, "CREATE TABLE p(id INTEGER PRIMARY KEY);");189  execSQL(db, "CREATE TABLE ci2(x, pid REFERENCES p(id));"); /* immediate */190 191  db->flags |= SQLITE_ForeignKeys;192  db->flags |= SQLITE_DeferFKs;193 194  Table *pTab = findTable(db, "ci2");195  Parse parse;196  memset(&parse, 0, sizeof(parse));197  parse.db = db;198 199  SrcList *pName = makeSrcListForTable(db, pTab);200 201  sqlite3FkDropTable(&parse, pName, pTab);202 203  TEST_ASSERT_NOT_NULL(parse.pVdbe);204  TEST_ASSERT_TRUE(countFkIfZeroOps(parse.pVdbe, 1) >= 1);205  /* Immediate-check block is skipped when SQLITE_DeferFKs is set; we don't assert its absence */206  TEST_ASSERT_EQUAL_INT(0, parse.disableTriggers);207 208  destroyVdbe(&parse);209  sqlite3SrcListDelete(db, pName);210  sqlite3_close(db);211}212 213/* Test 6: Foreign keys OFF even for parent -> no VDBE generated */214void test_sqlite3FkDropTable_fk_off_no_code_even_parent(void){215  sqlite3 *db = openDb();216  execSQL(db, "CREATE TABLE p(id INTEGER PRIMARY KEY);");217  execSQL(db, "CREATE TABLE c(x, pid REFERENCES p(id));");218 219  db->flags &= ~SQLITE_ForeignKeys; /* FK enforcement off */220 221  Table *pTab = findTable(db, "p"); /* Parent table */222  Parse parse;223  memset(&parse, 0, sizeof(parse));224  parse.db = db;225 226  SrcList *pName = makeSrcListForTable(db, pTab);227 228  sqlite3FkDropTable(&parse, pName, pTab);229 230  TEST_ASSERT_NULL(parse.pVdbe);231  TEST_ASSERT_EQUAL_INT(0, parse.disableTriggers);232 233  sqlite3SrcListDelete(db, pName);234  sqlite3_close(db);235}236 237int main(void){238  UNITY_BEGIN();239  RUN_TEST(test_sqlite3FkDropTable_no_fk_no_vdbe);240  RUN_TEST(test_sqlite3FkDropTable_parent_generates_delete_and_immediate_check);241  RUN_TEST(test_sqlite3FkDropTable_child_deferred_has_skip_and_immediate_check);242  RUN_TEST(test_sqlite3FkDropTable_child_immediate_no_code);243  RUN_TEST(test_sqlite3FkDropTable_child_immediate_with_DeferFKs_generates_skip);244  RUN_TEST(test_sqlite3FkDropTable_fk_off_no_code_even_parent);245  return UNITY_END();246}