|
|
#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(); |
|
|
} |