#include "sqliteInt.h" #include "unity.h" #include #include #include /* Wrapper for the static function (provided by build system as per instructions) */ extern void test_renameColumnFunc(sqlite3_context *context, int NotUsed, sqlite3_value **argv); /* Unity setup/teardown */ void setUp(void) { /* no-op */ } void tearDown(void) { /* no-op */ } /* Helpers to build sqlite3_value* arguments */ static sqlite3_value *make_text_value(sqlite3 *db, const char *z){ Mem *p = sqlite3ValueNew(db); if( z ){ sqlite3VdbeMemSetStr(p, z, (int)strlen(z), SQLITE_UTF8, SQLITE_TRANSIENT); }else{ sqlite3VdbeMemSetNull(p); } return (sqlite3_value*)p; } static sqlite3_value *make_int_value(sqlite3 *db, int v){ Mem *p = sqlite3ValueNew(db); sqlite3VdbeMemSetInt64(p, (i64)v); return (sqlite3_value*)p; } static void free_value(sqlite3 *db, sqlite3_value *v){ if( v ){ sqlite3ValueFree((Mem*)v); } } /* Execute SQL and assert success */ static void exec_ok(sqlite3 *db, const char *zSql){ char *zErr = 0; int rc = sqlite3_exec(db, zSql, 0, 0, &zErr); if( rc!=SQLITE_OK ){ /* Provide diagnostic if fails */ fprintf(stderr, "exec error: rc=%d sql=[%s] err=[%s]\n", rc, zSql, zErr ? zErr : "(null)"); } TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_exec failed"); sqlite3_free(zErr); } /* Call the wrapper and return heap copy of result text, or NULL if no text result */ static char *call_rename( sqlite3 *db, const char *zSql, /* argv[0] */ const char *zType, /* argv[1] */ const char *zObject, /* argv[2] */ const char *zDb, /* argv[3] */ const char *zTable, /* argv[4] */ int iCol, /* argv[5] */ const char *zNew, /* argv[6] */ int bQuote, /* argv[7] */ int bTemp /* argv[8] */ ){ sqlite3_value *argv[9]; sqlite3_context ctx; Mem out; char *zRet = NULL; /* Prepare argv[] */ argv[0] = make_text_value(db, zSql); argv[1] = make_text_value(db, zType); argv[2] = make_text_value(db, zObject); argv[3] = make_text_value(db, zDb); argv[4] = make_text_value(db, zTable); argv[5] = make_int_value(db, iCol); argv[6] = make_text_value(db, zNew); argv[7] = make_int_value(db, bQuote); argv[8] = make_int_value(db, bTemp); /* Prepare context and result container */ memset(&ctx, 0, sizeof(ctx)); memset(&out, 0, sizeof(out)); out.db = db; sqlite3VdbeMemZero(&out); ctx.db = db; ctx.pOut = &out; /* Invoke the function */ test_renameColumnFunc(&ctx, 9, argv); /* Collect result text if any */ if( (out.flags & MEM_Str)!=0 && out.z!=0 ){ zRet = sqlite3_mprintf("%s", out.z); }else{ zRet = NULL; } /* Cleanup */ sqlite3VdbeMemRelease(&out); for(int i=0;i<9;i++) free_value(db, argv[i]); return zRet; } /* Test: Basic table column rename, unquoted original, no forced quoting */ void test_renameColumnFunc_table_basic_unquoted_noquote(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); exec_ok(db, "CREATE TABLE t(a, b, c)"); const char *zSql = "CREATE TABLE t(a, b, c)"; char *zOut = call_rename(db, zSql, "table", "t", "main", "t", 1, "d", 0, 0); TEST_ASSERT_NOT_NULL(zOut); TEST_ASSERT_EQUAL_STRING("CREATE TABLE t(a, d, c)", zOut); sqlite3_free(zOut); sqlite3_close(db); } /* Test: Basic table column rename, unquoted original, forced quoting of new name */ void test_renameColumnFunc_table_basic_unquoted_forcequote(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); exec_ok(db, "CREATE TABLE t(a, b, c)"); const char *zSql = "CREATE TABLE t(a, b, c)"; char *zOut = call_rename(db, zSql, "table", "t", "main", "t", 1, "d", 1, 0); TEST_ASSERT_NOT_NULL(zOut); TEST_ASSERT_EQUAL_STRING("CREATE TABLE t(a, \"d\", c)", zOut); sqlite3_free(zOut); sqlite3_close(db); } /* Test: Table column rename when original identifier is quoted; bQuote=0 should still quote */ void test_renameColumnFunc_table_original_quoted(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); exec_ok(db, "CREATE TABLE t(\"a\", \"b\", c)"); const char *zSql = "CREATE TABLE t(\"a\", \"b\", c)"; char *zOut = call_rename(db, zSql, "table", "t", "main", "t", 1, "x", 0, 0); TEST_ASSERT_NOT_NULL(zOut); TEST_ASSERT_EQUAL_STRING("CREATE TABLE t(\"a\", \"x\", c)", zOut); sqlite3_free(zOut); sqlite3_close(db); } /* Test: View rewrite - rename column referenced by view select list */ void test_renameColumnFunc_view_rewrite_select_list(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); exec_ok(db, "CREATE TABLE t(a, b)"); const char *zSql = "CREATE VIEW v AS SELECT a, b FROM t"; char *zOut = call_rename(db, zSql, "view", "v", "main", "t", 1, "d", 0, 0); TEST_ASSERT_NOT_NULL(zOut); TEST_ASSERT_EQUAL_STRING("CREATE VIEW v AS SELECT a, d FROM t", zOut); sqlite3_free(zOut); sqlite3_close(db); } /* Test: Trigger rewrite - rename in UPDATE OF clause */ void test_renameColumnFunc_trigger_update_of_clause(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); exec_ok(db, "CREATE TABLE t(a, b)"); const char *zSql = "CREATE TRIGGER tr AFTER UPDATE OF b ON t BEGIN SELECT 1; END"; char *zOut = call_rename(db, zSql, "trigger", "tr", "main", "t", 1, "d", 0, 0); TEST_ASSERT_NOT_NULL(zOut); TEST_ASSERT_EQUAL_STRING( "CREATE TRIGGER tr AFTER UPDATE OF d ON t BEGIN SELECT 1; END", zOut ); sqlite3_free(zOut); sqlite3_close(db); } /* Test: Invalid column index (out of range) - expect no result (NULL) */ void test_renameColumnFunc_invalid_col_index_no_result(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); exec_ok(db, "CREATE TABLE t(a, b)"); const char *zSql = "CREATE TABLE t(a, b)"; /* iCol==2 is out of range for 2-column table (0,1 valid) */ char *zOut = call_rename(db, zSql, "table", "t", "main", "t", 2, "d", 0, 0); TEST_ASSERT_NULL(zOut); sqlite3_free(zOut); /* safe even if NULL */ sqlite3_close(db); } /* Test: Non-existent table name - expect no result (NULL) */ void test_renameColumnFunc_wrong_table_no_result(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); exec_ok(db, "CREATE TABLE t(a, b)"); const char *zSql = "CREATE TABLE t(a, b)"; char *zOut = call_rename(db, zSql, "table", "t", "main", "nope", 1, "d", 0, 0); TEST_ASSERT_NULL(zOut); sqlite3_free(zOut); sqlite3_close(db); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_renameColumnFunc_table_basic_unquoted_noquote); RUN_TEST(test_renameColumnFunc_table_basic_unquoted_forcequote); RUN_TEST(test_renameColumnFunc_table_original_quoted); RUN_TEST(test_renameColumnFunc_view_rewrite_select_list); RUN_TEST(test_renameColumnFunc_trigger_update_of_clause); RUN_TEST(test_renameColumnFunc_invalid_col_index_no_result); RUN_TEST(test_renameColumnFunc_wrong_table_no_result); return UNITY_END(); }