| | #include "sqliteInt.h" |
| | #include "unity.h" |
| | #include <stdlib.h> |
| | #include <string.h> |
| | #include <stdio.h> |
| |
|
| | static sqlite3 *gDb = NULL; |
| |
|
| | |
| | extern void test_dropConstraintFunc(sqlite3_context*, int, sqlite3_value**); |
| |
|
| | |
| | static void register_dropc(sqlite3 *db){ |
| | int rc = sqlite3_create_function(db, "dropc", 2, SQLITE_UTF8, NULL, |
| | test_dropConstraintFunc, NULL, NULL); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_create_function(dropc) failed"); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static int call_dropc_text(sqlite3 *db, const char *zSql, const char *zName, |
| | char **pzOut, char **pzErr){ |
| | int rc; |
| | sqlite3_stmt *pStmt = NULL; |
| | *pzOut = NULL; |
| | *pzErr = NULL; |
| |
|
| | rc = sqlite3_prepare_v2(db, "SELECT dropc(?1, ?2)", -1, &pStmt, NULL); |
| | if( rc!=SQLITE_OK ){ |
| | *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); |
| | return 1; |
| | } |
| | rc = sqlite3_bind_text(pStmt, 1, zSql, -1, SQLITE_TRANSIENT); |
| | if( rc==SQLITE_OK ){ |
| | rc = sqlite3_bind_text(pStmt, 2, zName, -1, SQLITE_TRANSIENT); |
| | } |
| | if( rc!=SQLITE_OK ){ |
| | sqlite3_finalize(pStmt); |
| | *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); |
| | return 1; |
| | } |
| |
|
| | rc = sqlite3_step(pStmt); |
| | if( rc==SQLITE_ROW ){ |
| | const unsigned char *z = sqlite3_column_text(pStmt, 0); |
| | if( z ){ |
| | *pzOut = sqlite3_mprintf("%s", (const char*)z); |
| | }else{ |
| | *pzOut = NULL; |
| | } |
| | sqlite3_finalize(pStmt); |
| | return 0; |
| | }else{ |
| | *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); |
| | sqlite3_finalize(pStmt); |
| | return 1; |
| | } |
| | } |
| |
|
| | |
| | static int call_dropc_int(sqlite3 *db, const char *zSql, int iCol, |
| | char **pzOut, char **pzErr){ |
| | int rc; |
| | sqlite3_stmt *pStmt = NULL; |
| | *pzOut = NULL; |
| | *pzErr = NULL; |
| |
|
| | rc = sqlite3_prepare_v2(db, "SELECT dropc(?1, ?2)", -1, &pStmt, NULL); |
| | if( rc!=SQLITE_OK ){ |
| | *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); |
| | return 1; |
| | } |
| | rc = sqlite3_bind_text(pStmt, 1, zSql, -1, SQLITE_TRANSIENT); |
| | if( rc==SQLITE_OK ){ |
| | rc = sqlite3_bind_int(pStmt, 2, iCol); |
| | } |
| | if( rc!=SQLITE_OK ){ |
| | sqlite3_finalize(pStmt); |
| | *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); |
| | return 1; |
| | } |
| |
|
| | rc = sqlite3_step(pStmt); |
| | if( rc==SQLITE_ROW ){ |
| | const unsigned char *z = sqlite3_column_text(pStmt, 0); |
| | if( z ){ |
| | *pzOut = sqlite3_mprintf("%s", (const char*)z); |
| | }else{ |
| | *pzOut = NULL; |
| | } |
| | sqlite3_finalize(pStmt); |
| | return 0; |
| | }else{ |
| | *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); |
| | sqlite3_finalize(pStmt); |
| | return 1; |
| | } |
| | } |
| |
|
| | void setUp(void) { |
| | int rc = sqlite3_open(":memory:", &gDb); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed"); |
| | register_dropc(gDb); |
| | } |
| |
|
| | void tearDown(void) { |
| | if( gDb ){ |
| | sqlite3_close(gDb); |
| | gDb = NULL; |
| | } |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_drop_not_null_first_column(void){ |
| | const char *inSql = "CREATE TABLE t1(a NOT NULL,b)"; |
| | const char *expect = "CREATE TABLE t1(a ,b)"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_int(gDb, inSql, 0, &out, &err); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, err ? err : "Unexpected error"); |
| | TEST_ASSERT_NOT_NULL(out); |
| | TEST_ASSERT_EQUAL_STRING(expect, out); |
| | sqlite3_free(out); |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_drop_not_null_noop_when_absent(void){ |
| | const char *inSql = "CREATE TABLE t1(a,b)"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_int(gDb, inSql, 1, &out, &err); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, err ? err : "Unexpected error"); |
| | TEST_ASSERT_NOT_NULL(out); |
| | TEST_ASSERT_EQUAL_STRING(inSql, out); |
| | sqlite3_free(out); |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_drop_named_check_table_constraint(void){ |
| | const char *inSql = "CREATE TABLE t1(a,CONSTRAINT ck CHECK(a))"; |
| | const char *expect = "CREATE TABLE t1(a)"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_text(gDb, inSql, "ck", &out, &err); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, err ? err : "Unexpected error"); |
| | TEST_ASSERT_NOT_NULL(out); |
| | TEST_ASSERT_EQUAL_STRING(expect, out); |
| | sqlite3_free(out); |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_error_on_primary_key(void){ |
| | const char *inSql = "CREATE TABLE t1(a,CONSTRAINT pk PRIMARY KEY(a))"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_text(gDb, inSql, "pk", &out, &err); |
| | TEST_ASSERT_EQUAL_INT(1, rc); |
| | TEST_ASSERT_NULL(out); |
| | TEST_ASSERT_NOT_NULL(err); |
| | TEST_ASSERT_EQUAL_STRING("constraint may not be dropped: pk", err); |
| | sqlite3_free(err); |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_error_on_no_such_constraint(void){ |
| | const char *inSql = "CREATE TABLE t1(a,CONSTRAINT ck CHECK(a))"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_text(gDb, inSql, "nosuch", &out, &err); |
| | TEST_ASSERT_EQUAL_INT(1, rc); |
| | TEST_ASSERT_NULL(out); |
| | TEST_ASSERT_NOT_NULL(err); |
| | TEST_ASSERT_EQUAL_STRING("no such constraint: nosuch", err); |
| | sqlite3_free(err); |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_drop_named_not_null_column_constraint(void){ |
| | const char *inSql = "CREATE TABLE t1(a CONSTRAINT nn NOT NULL,b)"; |
| | const char *expect = "CREATE TABLE t1(a ,b)"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_text(gDb, inSql, "nn", &out, &err); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, err ? err : "Unexpected error"); |
| | TEST_ASSERT_NOT_NULL(out); |
| | TEST_ASSERT_EQUAL_STRING(expect, out); |
| | sqlite3_free(out); |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_case_insensitive_and_quoted_name(void){ |
| | const char *inSql = "CREATE TABLE t1(a,CONSTRAINT \"MiX\" CHECK(a>0))"; |
| | const char *expect = "CREATE TABLE t1(a)"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_text(gDb, inSql, "mix", &out, &err); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, err ? err : "Unexpected error"); |
| | TEST_ASSERT_NOT_NULL(out); |
| | TEST_ASSERT_EQUAL_STRING(expect, out); |
| | sqlite3_free(out); |
| | } |
| |
|
| | |
| | void test_dropConstraintFunc_drop_first_of_two_constraint_names(void){ |
| | const char *inSql = "CREATE TABLE t1(x CONSTRAINT one CONSTRAINT two NOT NULL)"; |
| | const char *expect = "CREATE TABLE t1(x CONSTRAINT two NOT NULL)"; |
| | char *out = NULL, *err = NULL; |
| | int rc = call_dropc_text(gDb, inSql, "one", &out, &err); |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, err ? err : "Unexpected error"); |
| | TEST_ASSERT_NOT_NULL(out); |
| | TEST_ASSERT_EQUAL_STRING(expect, out); |
| | sqlite3_free(out); |
| | } |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_dropConstraintFunc_drop_not_null_first_column); |
| | RUN_TEST(test_dropConstraintFunc_drop_not_null_noop_when_absent); |
| | RUN_TEST(test_dropConstraintFunc_drop_named_check_table_constraint); |
| | RUN_TEST(test_dropConstraintFunc_error_on_primary_key); |
| | RUN_TEST(test_dropConstraintFunc_error_on_no_such_constraint); |
| | RUN_TEST(test_dropConstraintFunc_drop_named_not_null_column_constraint); |
| | RUN_TEST(test_dropConstraintFunc_case_insensitive_and_quoted_name); |
| | RUN_TEST(test_dropConstraintFunc_drop_first_of_two_constraint_names); |
| | return UNITY_END(); |
| | } |