AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6#include <stdio.h>7 8/* Helpers */9static int exec_sql(sqlite3 *db, const char *sql, char **pzErr){10 return sqlite3_exec(db, sql, 0, 0, pzErr);11}12 13static void assert_exec_ok(sqlite3 *db, const char *sql){14 char *zErr = NULL;15 int rc = exec_sql(db, sql, &zErr);16 if( zErr ){17 /* Ensure any error message is freed even if rc==SQLITE_OK (unlikely) */18 sqlite3_free(zErr);19 zErr = NULL;20 }21 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, sql);22}23 24static int exec_expect_error_contains(sqlite3 *db, const char *sql, const char *needle, int *pRcOut){25 char *zErr = NULL;26 int rc = exec_sql(db, sql, &zErr);27 if( pRcOut ) *pRcOut = rc;28 int ok = (rc!=SQLITE_OK) && (zErr!=NULL) && (strstr(zErr, needle)!=0);29 if( zErr ) sqlite3_free(zErr);30 return ok;31}32 33static char *get_table_sql(sqlite3 *db, const char *zName){34 sqlite3_stmt *pStmt = NULL;35 const char *zSql = "SELECT sql FROM sqlite_schema WHERE name=?1";36 if( sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0)!=SQLITE_OK ){37 return NULL;38 }39 sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);40 char *zOut = NULL;41 if( sqlite3_step(pStmt)==SQLITE_ROW ){42 const unsigned char *z = sqlite3_column_text(pStmt, 0);43 if( z ){44 zOut = sqlite3_mprintf("%s", z);45 }46 }47 sqlite3_finalize(pStmt);48 return zOut;49}50 51/* Unity fixtures */52void setUp(void) {53 /* empty */54}55void tearDown(void) {56 /* empty */57}58 59/* Test: Successful ALTER adds named constraint and enforces it for new rows */60void test_sqlite3AlterAddConstraint_add_named_and_enforce(void){61 sqlite3 *db = NULL;62 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));63 64 assert_exec_ok(db, "CREATE TABLE t1(x)");65 assert_exec_ok(db, "INSERT INTO t1 VALUES(1)");66 67 /* Add a named CHECK constraint */68 assert_exec_ok(db, "ALTER TABLE t1 ADD CONSTRAINT ck_pos CHECK(x>0)");69 70 /* Inserting a violating row should now fail */71 int rc = SQLITE_OK;72 TEST_ASSERT_TRUE_MESSAGE(73 exec_expect_error_contains(db, "INSERT INTO t1 VALUES(0)", "CHECK constraint failed", &rc),74 "Expected CHECK constraint failure on INSERT after ALTER"75 );76 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_CONSTRAINT, rc, "Expected SQLITE_CONSTRAINT");77 78 /* Valid insert still succeeds */79 assert_exec_ok(db, "INSERT INTO t1 VALUES(2)");80 81 /* Adding another constraint with the same name should fail */82 TEST_ASSERT_TRUE_MESSAGE(83 exec_expect_error_contains(db,84 "ALTER TABLE t1 ADD CONSTRAINT ck_pos CHECK(x<10)",85 "already exists",86 NULL87 ),88 "Expected duplicate constraint name error"89 );90 91 sqlite3_close(db);92}93 94/* Test: ALTER fails if existing rows violate the new CHECK expression */95void test_sqlite3AlterAddConstraint_violation_on_alter(void){96 sqlite3 *db = NULL;97 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));98 99 assert_exec_ok(db, "CREATE TABLE t2(x)");100 assert_exec_ok(db, "INSERT INTO t2 VALUES(-1)");101 102 /* This should fail because existing row violates x>0 */103 int rc = SQLITE_OK;104 TEST_ASSERT_TRUE_MESSAGE(105 exec_expect_error_contains(db,106 "ALTER TABLE t2 ADD CHECK(x>0)",107 "constraint failed",108 &rc109 ),110 "Expected 'constraint failed' during ALTER due to existing data"111 );112 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_CONSTRAINT, rc, "Expected SQLITE_CONSTRAINT");113 114 /* Schema should not be modified */115 char *zSchema = get_table_sql(db, "t2");116 TEST_ASSERT_NOT_NULL(zSchema);117 TEST_ASSERT_TRUE(strstr(zSchema, "CHECK")==NULL);118 sqlite3_free(zSchema);119 120 sqlite3_close(db);121}122 123/* Test: Trailing '--' is trimmed but trailing '/* ... *\/' comment is preserved */124void test_sqlite3AlterAddConstraint_trim_line_comment_preserve_c_comment(void){125 sqlite3 *db = NULL;126 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));127 128 assert_exec_ok(db, "CREATE TABLE t3(x)");129 assert_exec_ok(db, "INSERT INTO t3 VALUES(1)");130 131 /* Trailing C-style comment should be preserved; trailing -- comment removed */132 assert_exec_ok(db, "ALTER TABLE t3 ADD CHECK (x>0) /*C-keep*/ -- line-drop");133 134 char *zSchema = get_table_sql(db, "t3");135 TEST_ASSERT_NOT_NULL(zSchema);136 137 /* Ensure C-style comment present, '--' tail absent */138 TEST_ASSERT_NOT_NULL_MESSAGE(strstr(zSchema, "/*C-keep*/"), "Expected C-style comment preserved in schema SQL");139 TEST_ASSERT_NULL_MESSAGE(strstr(zSchema, "-- line-drop"), "Expected '--' trailing comment removed from schema SQL");140 141 sqlite3_free(zSchema);142 sqlite3_close(db);143}144 145/* Direct call smoke test: invoke sqlite3AlterAddConstraint with constructed Parse/SrcList/Tokens */146void test_sqlite3AlterAddConstraint_direct_call_smoke(void){147 sqlite3 *db = NULL;148 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));149 assert_exec_ok(db, "CREATE TABLE t4(a)");150 151 /* Prepare Parse with a Vdbe */152 Parse p;153 memset(&p, 0, sizeof(p));154 p.db = db;155 /* Ensure there is a VDBE to receive generated bytecode */156 sqlite3GetVdbe(&p);157 TEST_ASSERT_NOT_NULL(p.pVdbe);158 159 /* Build a SrcList referring to table t4 */160 Token tTbl = { "t4", 2 };161 SrcList *pSrc = sqlite3SrcListAppend(db, 0, &tTbl, 0);162 TEST_ASSERT_NOT_NULL(pSrc);163 TEST_ASSERT_EQUAL_INT(1, pSrc->nSrc);164 165 /* Construct constraint text and tokens */166 const char *zCons = "CONSTRAINT ckx CHECK(a>0) /*preserve*/ -- trim";167 Token firstTok;168 firstTok.z = zCons;169 firstTok.n = (int)strlen(zCons);170 Token nameTok = { "ckx", 3 };171 const char *zExpr = "a>0";172 int nExpr = 3;173 174 /* Set sLastToken to mark the end of the constraint text buffer */175 p.sLastToken.z = zCons + strlen(zCons);176 p.sLastToken.n = 0;177 178 /* Invoke the target function directly */179 sqlite3AlterAddConstraint(&p, pSrc, &firstTok, &nameTok, zExpr, nExpr);180 181 /* Basic sanity: no parse errors recorded and VDBE remains allocated */182 TEST_ASSERT_NOT_NULL(p.pVdbe);183 TEST_ASSERT_EQUAL_INT(0, p.nErr);184 185 /* Cleanup */186 sqlite3SrcListDelete(db, pSrc);187 sqlite3VdbeDelete(p.pVdbe);188 sqlite3_close(db);189}190 191int main(void) {192 UNITY_BEGIN();193 RUN_TEST(test_sqlite3AlterAddConstraint_add_named_and_enforce);194 RUN_TEST(test_sqlite3AlterAddConstraint_violation_on_alter);195 RUN_TEST(test_sqlite3AlterAddConstraint_trim_line_comment_preserve_c_comment);196 RUN_TEST(test_sqlite3AlterAddConstraint_direct_call_smoke);197 return UNITY_END();198}