AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Helper: open an in-memory database and assert success */7static sqlite3* open_memory_db(void){8 sqlite3 *db = 0;9 int rc = sqlite3_open(":memory:", &db);10 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");11 TEST_ASSERT_NOT_NULL(db);12 return db;13}14 15/* Helper: exec SQL and assert success */16static void exec_sql_or_fail(sqlite3 *db, const char *zSql){17 int rc = sqlite3_exec(db, zSql, 0, 0, 0);18 if( rc!=SQLITE_OK ){19 const char *zErr = sqlite3_errmsg(db);20 TEST_FAIL_MESSAGE(zErr ? zErr : "sqlite3_exec failed");21 }22}23 24/* Helper: fetch first CHECK expression for a table */25static Expr* first_check_expr(sqlite3 *db, const char *zTab){26 Table *pTab = sqlite3FindTable(db, zTab, "main");27 TEST_ASSERT_NOT_NULL_MESSAGE(pTab, "Table not found");28 TEST_ASSERT_NOT_NULL_MESSAGE(pTab->pCheck, "No CHECK constraints found");29 TEST_ASSERT_TRUE_MESSAGE(pTab->pCheck->nExpr >= 1, "Empty CHECK list");30 Expr *pExpr = pTab->pCheck->a[0].pExpr;31 TEST_ASSERT_NOT_NULL_MESSAGE(pExpr, "CHECK expression is NULL");32 return pExpr;33}34 35void setUp(void) {36 /* no-op */37}38 39void tearDown(void) {40 /* no-op */41}42 43/* Unchanged column referenced by CHECK => should return false */44void test_sqlite3ExprReferencesUpdatedColumn_unchanged_column_false(void){45 sqlite3 *db = open_memory_db();46 exec_sql_or_fail(db, "CREATE TABLE t1(a, b, CHECK(a > 0));");47 48 Expr *pExpr = first_check_expr(db, "t1");49 50 int aiChng[2] = { -1, -1 }; /* neither a nor b changed */51 int rc;52 53 rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0);54 TEST_ASSERT_FALSE(rc);55 56 sqlite3_close(db);57}58 59/* Changed column referenced by CHECK => should return true */60void test_sqlite3ExprReferencesUpdatedColumn_changed_column_true(void){61 sqlite3 *db = open_memory_db();62 exec_sql_or_fail(db, "CREATE TABLE t2(a, b, CHECK(a > 0));");63 64 Expr *pExpr = first_check_expr(db, "t2");65 66 int aiChng[2] = { 0, -1 }; /* a changed, b unchanged */67 int rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0);68 TEST_ASSERT_TRUE(rc);69 70 sqlite3_close(db);71}72 73/* Rowid reference: depends on chngRowid flag */74void test_sqlite3ExprReferencesUpdatedColumn_rowid_respected_by_flag(void){75 sqlite3 *db = open_memory_db();76 exec_sql_or_fail(db, "CREATE TABLE t3(a, b, CHECK(rowid > 5));");77 78 Expr *pExpr = first_check_expr(db, "t3");79 80 int aiChng[2] = { -1, -1 }; /* no columns changed */81 82 int rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0 /* chngRowid=false */);83 TEST_ASSERT_FALSE(rc);84 85 rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 1 /* chngRowid=true */);86 TEST_ASSERT_TRUE(rc);87 88 sqlite3_close(db);89}90 91/* Mixed: expression references rowid and a column ("b") */92void test_sqlite3ExprReferencesUpdatedColumn_mixed_rowid_and_column_cases(void){93 sqlite3 *db = open_memory_db();94 exec_sql_or_fail(db, "CREATE TABLE t4(a, b, CHECK(rowid > 5 AND b < 10));");95 96 Expr *pExpr = first_check_expr(db, "t4");97 int aiChng[2];98 99 /* Case A: b changed, rowid not changed => true */100 aiChng[0] = -1; aiChng[1] = 0;101 int rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0 /* chngRowid=false */);102 TEST_ASSERT_TRUE(rc);103 104 /* Case B: b unchanged, rowid changed => true */105 aiChng[0] = -1; aiChng[1] = -1;106 rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 1 /* chngRowid=true */);107 TEST_ASSERT_TRUE(rc);108 109 /* Case C: neither b nor rowid changed => false */110 aiChng[0] = -1; aiChng[1] = -1;111 rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0 /* chngRowid=false */);112 TEST_ASSERT_FALSE(rc);113 114 sqlite3_close(db);115}116 117/* Constant CHECK expression references no columns or rowid => always false */118void test_sqlite3ExprReferencesUpdatedColumn_constant_expr_false(void){119 sqlite3 *db = open_memory_db();120 exec_sql_or_fail(db, "CREATE TABLE t5(a, b, CHECK(1));");121 122 Expr *pExpr = first_check_expr(db, "t5");123 int aiChng[2] = { 0, 0 };124 125 int rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 1);126 TEST_ASSERT_FALSE(rc);127 128 sqlite3_close(db);129}130 131/* NULL expression => treated as no reference => false */132void test_sqlite3ExprReferencesUpdatedColumn_null_expr_false(void){133 int aiChng[2] = { 0, 0 };134 int rc = sqlite3ExprReferencesUpdatedColumn(NULL, aiChng, 1);135 TEST_ASSERT_FALSE(rc);136}137 138/* OR expression referencing different columns: any changed should trigger true */139void test_sqlite3ExprReferencesUpdatedColumn_or_expression_any_changed_triggers_true(void){140 sqlite3 *db = open_memory_db();141 exec_sql_or_fail(db, "CREATE TABLE t6(a, b, CHECK(a > 10 OR b < 5));");142 143 Expr *pExpr = first_check_expr(db, "t6");144 145 int aiChng[2];146 int rc;147 148 /* Neither a nor b changed => false */149 aiChng[0] = -1; aiChng[1] = -1;150 rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0);151 TEST_ASSERT_FALSE(rc);152 153 /* a changed => true */154 aiChng[0] = 0; aiChng[1] = -1;155 rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0);156 TEST_ASSERT_TRUE(rc);157 158 /* b changed => true */159 aiChng[0] = -1; aiChng[1] = 0;160 rc = sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, 0);161 TEST_ASSERT_TRUE(rc);162 163 sqlite3_close(db);164}165 166int main(void) {167 UNITY_BEGIN();168 RUN_TEST(test_sqlite3ExprReferencesUpdatedColumn_unchanged_column_false);169 RUN_TEST(test_sqlite3ExprReferencesUpdatedColumn_changed_column_true);170 RUN_TEST(test_sqlite3ExprReferencesUpdatedColumn_rowid_respected_by_flag);171 RUN_TEST(test_sqlite3ExprReferencesUpdatedColumn_mixed_rowid_and_column_cases);172 RUN_TEST(test_sqlite3ExprReferencesUpdatedColumn_constant_expr_false);173 RUN_TEST(test_sqlite3ExprReferencesUpdatedColumn_null_expr_false);174 RUN_TEST(test_sqlite3ExprReferencesUpdatedColumn_or_expression_any_changed_triggers_true);175 return UNITY_END();176}