| #include "sqliteInt.h" |
| #include "unity.h" |
|
|
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
|
|
| |
| static int exec_sql(sqlite3 *db, const char *sql, char **pzErr){ |
| return sqlite3_exec(db, sql, 0, 0, pzErr); |
| } |
|
|
| static void assert_exec_ok(sqlite3 *db, const char *sql){ |
| char *zErr = NULL; |
| int rc = exec_sql(db, sql, &zErr); |
| if( zErr ){ |
| |
| sqlite3_free(zErr); |
| zErr = NULL; |
| } |
| TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, sql); |
| } |
|
|
| static int exec_expect_error_contains(sqlite3 *db, const char *sql, const char *needle, int *pRcOut){ |
| char *zErr = NULL; |
| int rc = exec_sql(db, sql, &zErr); |
| if( pRcOut ) *pRcOut = rc; |
| int ok = (rc!=SQLITE_OK) && (zErr!=NULL) && (strstr(zErr, needle)!=0); |
| if( zErr ) sqlite3_free(zErr); |
| return ok; |
| } |
|
|
| static char *get_table_sql(sqlite3 *db, const char *zName){ |
| sqlite3_stmt *pStmt = NULL; |
| const char *zSql = "SELECT sql FROM sqlite_schema WHERE name=?1"; |
| if( sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0)!=SQLITE_OK ){ |
| return NULL; |
| } |
| sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); |
| char *zOut = NULL; |
| if( sqlite3_step(pStmt)==SQLITE_ROW ){ |
| const unsigned char *z = sqlite3_column_text(pStmt, 0); |
| if( z ){ |
| zOut = sqlite3_mprintf("%s", z); |
| } |
| } |
| sqlite3_finalize(pStmt); |
| return zOut; |
| } |
|
|
| |
| void setUp(void) { |
| |
| } |
| void tearDown(void) { |
| |
| } |
|
|
| |
| void test_sqlite3AlterAddConstraint_add_named_and_enforce(void){ |
| sqlite3 *db = NULL; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| assert_exec_ok(db, "CREATE TABLE t1(x)"); |
| assert_exec_ok(db, "INSERT INTO t1 VALUES(1)"); |
|
|
| |
| assert_exec_ok(db, "ALTER TABLE t1 ADD CONSTRAINT ck_pos CHECK(x>0)"); |
|
|
| |
| int rc = SQLITE_OK; |
| TEST_ASSERT_TRUE_MESSAGE( |
| exec_expect_error_contains(db, "INSERT INTO t1 VALUES(0)", "CHECK constraint failed", &rc), |
| "Expected CHECK constraint failure on INSERT after ALTER" |
| ); |
| TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_CONSTRAINT, rc, "Expected SQLITE_CONSTRAINT"); |
|
|
| |
| assert_exec_ok(db, "INSERT INTO t1 VALUES(2)"); |
|
|
| |
| TEST_ASSERT_TRUE_MESSAGE( |
| exec_expect_error_contains(db, |
| "ALTER TABLE t1 ADD CONSTRAINT ck_pos CHECK(x<10)", |
| "already exists", |
| NULL |
| ), |
| "Expected duplicate constraint name error" |
| ); |
|
|
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterAddConstraint_violation_on_alter(void){ |
| sqlite3 *db = NULL; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| assert_exec_ok(db, "CREATE TABLE t2(x)"); |
| assert_exec_ok(db, "INSERT INTO t2 VALUES(-1)"); |
|
|
| |
| int rc = SQLITE_OK; |
| TEST_ASSERT_TRUE_MESSAGE( |
| exec_expect_error_contains(db, |
| "ALTER TABLE t2 ADD CHECK(x>0)", |
| "constraint failed", |
| &rc |
| ), |
| "Expected 'constraint failed' during ALTER due to existing data" |
| ); |
| TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_CONSTRAINT, rc, "Expected SQLITE_CONSTRAINT"); |
|
|
| |
| char *zSchema = get_table_sql(db, "t2"); |
| TEST_ASSERT_NOT_NULL(zSchema); |
| TEST_ASSERT_TRUE(strstr(zSchema, "CHECK")==NULL); |
| sqlite3_free(zSchema); |
|
|
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterAddConstraint_trim_line_comment_preserve_c_comment(void){ |
| sqlite3 *db = NULL; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| assert_exec_ok(db, "CREATE TABLE t3(x)"); |
| assert_exec_ok(db, "INSERT INTO t3 VALUES(1)"); |
|
|
| |
| assert_exec_ok(db, "ALTER TABLE t3 ADD CHECK (x>0) /*C-keep*/ -- line-drop"); |
|
|
| char *zSchema = get_table_sql(db, "t3"); |
| TEST_ASSERT_NOT_NULL(zSchema); |
|
|
| |
| TEST_ASSERT_NOT_NULL_MESSAGE(strstr(zSchema, "/*C-keep*/"), "Expected C-style comment preserved in schema SQL"); |
| TEST_ASSERT_NULL_MESSAGE(strstr(zSchema, "-- line-drop"), "Expected '--' trailing comment removed from schema SQL"); |
|
|
| sqlite3_free(zSchema); |
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterAddConstraint_direct_call_smoke(void){ |
| sqlite3 *db = NULL; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
| assert_exec_ok(db, "CREATE TABLE t4(a)"); |
|
|
| |
| Parse p; |
| memset(&p, 0, sizeof(p)); |
| p.db = db; |
| |
| sqlite3GetVdbe(&p); |
| TEST_ASSERT_NOT_NULL(p.pVdbe); |
|
|
| |
| Token tTbl = { "t4", 2 }; |
| SrcList *pSrc = sqlite3SrcListAppend(db, 0, &tTbl, 0); |
| TEST_ASSERT_NOT_NULL(pSrc); |
| TEST_ASSERT_EQUAL_INT(1, pSrc->nSrc); |
|
|
| |
| const char *zCons = "CONSTRAINT ckx CHECK(a>0) /*preserve*/ -- trim"; |
| Token firstTok; |
| firstTok.z = zCons; |
| firstTok.n = (int)strlen(zCons); |
| Token nameTok = { "ckx", 3 }; |
| const char *zExpr = "a>0"; |
| int nExpr = 3; |
|
|
| |
| p.sLastToken.z = zCons + strlen(zCons); |
| p.sLastToken.n = 0; |
|
|
| |
| sqlite3AlterAddConstraint(&p, pSrc, &firstTok, &nameTok, zExpr, nExpr); |
|
|
| |
| TEST_ASSERT_NOT_NULL(p.pVdbe); |
| TEST_ASSERT_EQUAL_INT(0, p.nErr); |
|
|
| |
| sqlite3SrcListDelete(db, pSrc); |
| sqlite3VdbeDelete(p.pVdbe); |
| sqlite3_close(db); |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
| RUN_TEST(test_sqlite3AlterAddConstraint_add_named_and_enforce); |
| RUN_TEST(test_sqlite3AlterAddConstraint_violation_on_alter); |
| RUN_TEST(test_sqlite3AlterAddConstraint_trim_line_comment_preserve_c_comment); |
| RUN_TEST(test_sqlite3AlterAddConstraint_direct_call_smoke); |
| return UNITY_END(); |
| } |