#include "sqliteInt.h" #include "unity.h" #include #include #include /* External wrapper for the static function under test */ extern void test_renameTableFunc(sqlite3_context *context, int NotUsed, sqlite3_value **argv); static void initStrValue(Mem *p, sqlite3 *db, const char *z){ sqlite3VdbeMemInit(p, db, 0); sqlite3VdbeMemSetStr(p, z, -1, SQLITE_UTF8, SQLITE_TRANSIENT); } static void initIntValue(Mem *p, sqlite3 *db, sqlite3_int64 v){ sqlite3VdbeMemInit(p, db, 0); sqlite3VdbeMemSetInt64(p, v); } static void releaseMemArray(Mem *a, int n){ for(int i=0; i0))"); Mem argvMem[7]; sqlite3_context ctx; memset(&ctx, 0, sizeof(ctx)); ctx.s.db = db; initStrValue(&argvMem[0], db, "main"); /* zDb */ initStrValue(&argvMem[1], db, "table"); /* type */ initStrValue(&argvMem[2], db, "t2"); /* object */ initStrValue(&argvMem[3], db, "CREATE TABLE t2(a, CHECK(a>0))"); /* input SQL */ initStrValue(&argvMem[4], db, "t2"); /* old name */ initStrValue(&argvMem[5], db, "t3"); /* new name */ initIntValue(&argvMem[6], db, 0); /* bTemp */ sqlite3_value *argv[7] = { (sqlite3_value*)&argvMem[0], (sqlite3_value*)&argvMem[1], (sqlite3_value*)&argvMem[2], (sqlite3_value*)&argvMem[3], (sqlite3_value*)&argvMem[4], (sqlite3_value*)&argvMem[5], (sqlite3_value*)&argvMem[6] }; test_renameTableFunc(&ctx, 0, argv); const unsigned char *zRes = sqlite3_value_text((sqlite3_value*)&ctx.s); TEST_ASSERT_NOT_NULL(zRes); TEST_ASSERT_EQUAL_STRING("CREATE TABLE \"t3\"(a, CHECK(a>0))", (const char*)zRes); sqlite3VdbeMemRelease(&ctx.s); releaseMemArray(argvMem, 7); sqlite3_close(db); } /* Ensure FK references to the old table are updated */ void test_renameTableFunc_updates_fk_references(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); execOrFail(db, "CREATE TABLE t2(x PRIMARY KEY)"); execOrFail(db, "CREATE TABLE t1(a REFERENCES t2)"); Mem argvMem[7]; sqlite3_context ctx; memset(&ctx, 0, sizeof(ctx)); ctx.s.db = db; initStrValue(&argvMem[0], db, "main"); initStrValue(&argvMem[1], db, "table"); initStrValue(&argvMem[2], db, "t1"); initStrValue(&argvMem[3], db, "CREATE TABLE t1(a REFERENCES t2)"); initStrValue(&argvMem[4], db, "t2"); initStrValue(&argvMem[5], db, "t3"); initIntValue(&argvMem[6], db, 0); sqlite3_value *argv[7] = { (sqlite3_value*)&argvMem[0], (sqlite3_value*)&argvMem[1], (sqlite3_value*)&argvMem[2], (sqlite3_value*)&argvMem[3], (sqlite3_value*)&argvMem[4], (sqlite3_value*)&argvMem[5], (sqlite3_value*)&argvMem[6] }; test_renameTableFunc(&ctx, 0, argv); const unsigned char *zRes = sqlite3_value_text((sqlite3_value*)&ctx.s); TEST_ASSERT_NOT_NULL(zRes); TEST_ASSERT_EQUAL_STRING("CREATE TABLE t1(a REFERENCES \"t3\")", (const char*)zRes); sqlite3VdbeMemRelease(&ctx.s); releaseMemArray(argvMem, 7); sqlite3_close(db); } /* Ensure table refs inside a CREATE VIEW SELECT are updated */ void test_renameTableFunc_updates_view_select_references(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); execOrFail(db, "CREATE TABLE t2(x)"); Mem argvMem[7]; sqlite3_context ctx; memset(&ctx, 0, sizeof(ctx)); ctx.s.db = db; initStrValue(&argvMem[0], db, "main"); initStrValue(&argvMem[1], db, "view"); initStrValue(&argvMem[2], db, "v"); initStrValue(&argvMem[3], db, "CREATE VIEW v AS SELECT x FROM t2"); initStrValue(&argvMem[4], db, "t2"); initStrValue(&argvMem[5], db, "t3"); initIntValue(&argvMem[6], db, 0); sqlite3_value *argv[7] = { (sqlite3_value*)&argvMem[0], (sqlite3_value*)&argvMem[1], (sqlite3_value*)&argvMem[2], (sqlite3_value*)&argvMem[3], (sqlite3_value*)&argvMem[4], (sqlite3_value*)&argvMem[5], (sqlite3_value*)&argvMem[6] }; test_renameTableFunc(&ctx, 0, argv); const char *zRes = (const char*)sqlite3_value_text((sqlite3_value*)&ctx.s); TEST_ASSERT_NOT_NULL(zRes); TEST_ASSERT_NOT_NULL(strstr(zRes, "FROM \"t3\"")); TEST_ASSERT_NULL(strstr(zRes, "t2")); sqlite3VdbeMemRelease(&ctx.s); releaseMemArray(argvMem, 7); sqlite3_close(db); } /* Ensure table refs inside CREATE TRIGGER (ON and body) are updated */ void test_renameTableFunc_updates_trigger_on_and_body_references(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); execOrFail(db, "CREATE TABLE t2(x)"); execOrFail(db, "CREATE TABLE log(y)"); const char *zTrig = "CREATE TRIGGER tr AFTER INSERT ON t2 " "BEGIN " " INSERT INTO log SELECT x FROM t2; " "END"; Mem argvMem[7]; sqlite3_context ctx; memset(&ctx, 0, sizeof(ctx)); ctx.s.db = db; initStrValue(&argvMem[0], db, "main"); initStrValue(&argvMem[1], db, "trigger"); initStrValue(&argvMem[2], db, "tr"); initStrValue(&argvMem[3], db, zTrig); initStrValue(&argvMem[4], db, "t2"); initStrValue(&argvMem[5], db, "t3"); initIntValue(&argvMem[6], db, 0); sqlite3_value *argv[7] = { (sqlite3_value*)&argvMem[0], (sqlite3_value*)&argvMem[1], (sqlite3_value*)&argvMem[2], (sqlite3_value*)&argvMem[3], (sqlite3_value*)&argvMem[4], (sqlite3_value*)&argvMem[5], (sqlite3_value*)&argvMem[6] }; test_renameTableFunc(&ctx, 0, argv); const char *zRes = (const char*)sqlite3_value_text((sqlite3_value*)&ctx.s); TEST_ASSERT_NOT_NULL(zRes); TEST_ASSERT_NOT_NULL(strstr(zRes, " ON \"t3\"")); TEST_ASSERT_NOT_NULL(strstr(zRes, " FROM \"t3\"")); TEST_ASSERT_NULL(strstr(zRes, "t2")); sqlite3VdbeMemRelease(&ctx.s); releaseMemArray(argvMem, 7); sqlite3_close(db); } /* Invalid SQL (not starting with CREATE) should set an error code on context */ void test_renameTableFunc_invalid_sql_sets_error(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); execOrFail(db, "CREATE TABLE t2(x)"); Mem argvMem[7]; sqlite3_context ctx; memset(&ctx, 0, sizeof(ctx)); ctx.s.db = db; initStrValue(&argvMem[0], db, "main"); initStrValue(&argvMem[1], db, "table"); initStrValue(&argvMem[2], db, "t2"); initStrValue(&argvMem[3], db, "SELECT 1"); /* invalid for this function */ initStrValue(&argvMem[4], db, "t2"); initStrValue(&argvMem[5], db, "t3"); initIntValue(&argvMem[6], db, 0); sqlite3_value *argv[7] = { (sqlite3_value*)&argvMem[0], (sqlite3_value*)&argvMem[1], (sqlite3_value*)&argvMem[2], (sqlite3_value*)&argvMem[3], (sqlite3_value*)&argvMem[4], (sqlite3_value*)&argvMem[5], (sqlite3_value*)&argvMem[6] }; test_renameTableFunc(&ctx, 0, argv); /* Expect an error code set on context (SQLITE_CORRUPT_BKPT) */ TEST_ASSERT_NOT_EQUAL(0, ctx.isError); sqlite3VdbeMemRelease(&ctx.s); releaseMemArray(argvMem, 7); sqlite3_close(db); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_renameTableFunc_rename_table_name_in_create_table); RUN_TEST(test_renameTableFunc_updates_fk_references); RUN_TEST(test_renameTableFunc_updates_view_select_references); RUN_TEST(test_renameTableFunc_updates_trigger_on_and_body_references); RUN_TEST(test_renameTableFunc_invalid_sql_sets_error); return UNITY_END(); }