File size: 7,729 Bytes
7510827 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
#include "sqliteInt.h"
#include "unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static sqlite3 *gDb = NULL;
/* The wrapper for the static function under test is assumed to be provided. */
extern void test_dropConstraintFunc(sqlite3_context*, int, sqlite3_value**);
/* Register the test function as an SQL scalar function "dropc". */
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");
}
/* Helper: call dropc(SQL, TEXT) and capture result or error.
On success, returns 0 and *pzOut is sqlite3_malloc()'d string (caller must sqlite3_free()).
On error, returns 1 and *pzErr is sqlite3_malloc()'d string (caller must sqlite3_free()).
*/
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; /* explicit NULL result */
}
sqlite3_finalize(pStmt);
return 0;
}else{
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
sqlite3_finalize(pStmt);
return 1;
}
}
/* Helper: call dropc(SQL, INTEGER) and capture result or error. */
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;
}
}
/* Drop NOT NULL on first column */
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);
}
/* Drop NOT NULL on column that is not NOT NULL -> should return original SQL unchanged */
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);
}
/* Drop named CHECK table constraint and verify comma handling */
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);
}
/* Attempt to drop disallowed constraint (PRIMARY KEY) -> error */
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);
}
/* Named constraint not found -> error */
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);
}
/* Drop named NOT NULL column constraint */
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);
}
/* Case-insensitive and quoted constraint name matching */
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);
}
/* Drop only the first of two consecutive CONSTRAINT names */
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();
} |