#include "sqliteInt.h" #include "unity.h" #include #include /* Helpers */ static Token mkToken(const char *z){ Token t; t.z = z; t.n = (int)strlen(z); return t; } static SrcList* makeSrcList(sqlite3 *db, const char *zDbName, const char *zTab){ /* Allocate a SrcList with a single item using SQLite's allocator so that sqlite3SrcListDelete() in the target function can free it safely. */ SrcList *p = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList)); TEST_ASSERT_NOT_NULL_MESSAGE(p, "Failed to allocate SrcList"); p->nAlloc = 1; p->nSrc = 1; p->a[0].zName = sqlite3DbStrDup(db, zTab); TEST_ASSERT_NOT_NULL_MESSAGE(p->a[0].zName, "Failed to dup table name"); if( zDbName ){ p->a[0].zDatabase = sqlite3DbStrDup(db, zDbName); TEST_ASSERT_NOT_NULL_MESSAGE(p->a[0].zDatabase, "Failed to dup db name"); } return p; } static void parseInit(Parse *pParse, sqlite3 *db){ memset(pParse, 0, sizeof(Parse)); pParse->db = db; } static void parseCleanup(Parse *pParse){ if( pParse->pVdbe ){ sqlite3VdbeDelete(pParse->pVdbe); pParse->pVdbe = NULL; } if( pParse->zErrMsg ){ sqlite3DbFree(pParse->db, pParse->zErrMsg); pParse->zErrMsg = NULL; } } /* Unity hooks */ void setUp(void) { /* no-op */ } void tearDown(void) { /* no-op */ } /* Tests */ void test_sqlite3AlterRenameColumn_no_such_table(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); Parse p; parseInit(&p, db); SrcList *pSrc = makeSrcList(db, NULL, "nope_table"); Token oldTok = mkToken("a"); Token newTok = mkToken("b"); sqlite3AlterRenameColumn(&p, pSrc, &oldTok, &newTok); TEST_ASSERT_TRUE_MESSAGE(p.nErr>0 || p.zErrMsg!=NULL, "Expected error for missing table"); /* Expect no VDBE was generated */ TEST_ASSERT_NULL(p.pVdbe); parseCleanup(&p); sqlite3_close(db); } void test_sqlite3AlterRenameColumn_view_error(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t1(a,b);" "CREATE VIEW v1 AS SELECT a,b FROM t1;", 0, 0, 0)); Parse p; parseInit(&p, db); SrcList *pSrc = makeSrcList(db, NULL, "v1"); Token oldTok = mkToken("a"); Token newTok = mkToken("x"); sqlite3AlterRenameColumn(&p, pSrc, &oldTok, &newTok); TEST_ASSERT_TRUE(p.nErr>0); TEST_ASSERT_NOT_NULL(p.zErrMsg); TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "cannot rename columns of")); /* Should not generate code on error */ TEST_ASSERT_NULL(p.pVdbe); parseCleanup(&p); sqlite3_close(db); } void test_sqlite3AlterRenameColumn_column_not_found(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t1(a,b);", 0, 0, 0)); Parse p; parseInit(&p, db); SrcList *pSrc = makeSrcList(db, NULL, "t1"); Token oldTok = mkToken("c"); /* does not exist */ Token newTok = mkToken("d"); sqlite3AlterRenameColumn(&p, pSrc, &oldTok, &newTok); TEST_ASSERT_TRUE(p.nErr>0); TEST_ASSERT_NOT_NULL(p.zErrMsg); TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "no such column")); TEST_ASSERT_NULL(p.pVdbe); parseCleanup(&p); sqlite3_close(db); } void test_sqlite3AlterRenameColumn_success_main_db(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t1(a,b,c);", 0, 0, 0)); Parse p; parseInit(&p, db); SrcList *pSrc = makeSrcList(db, NULL, "t1"); Token oldTok = mkToken("a"); Token newTok = mkToken("x"); sqlite3AlterRenameColumn(&p, pSrc, &oldTok, &newTok); TEST_ASSERT_EQUAL_INT(0, p.nErr); TEST_ASSERT_NULL(p.zErrMsg); TEST_ASSERT_NOT_NULL(p.pVdbe); /* sqlite3NestedParse should have added some ops */ TEST_ASSERT_TRUE(p.pVdbe->nOp > 0); parseCleanup(&p); sqlite3_close(db); } void test_sqlite3AlterRenameColumn_success_temp_db_quoted_newname(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TEMP TABLE tt(a,b);", 0, 0, 0)); Parse p; parseInit(&p, db); /* Force lookup in temp by providing zDatabase="temp" */ SrcList *pSrc = makeSrcList(db, "temp", "tt"); Token oldTok = mkToken("b"); Token newTok = mkToken("\"x y\""); /* quoted new name */ sqlite3AlterRenameColumn(&p, pSrc, &oldTok, &newTok); TEST_ASSERT_EQUAL_INT(0, p.nErr); TEST_ASSERT_NULL(p.zErrMsg); TEST_ASSERT_NOT_NULL(p.pVdbe); TEST_ASSERT_TRUE(p.pVdbe->nOp > 0); parseCleanup(&p); sqlite3_close(db); } void test_sqlite3AlterRenameColumn_cannot_alter_system_table(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); Parse p; parseInit(&p, db); /* Attempt to alter the sqlite_schema/system table */ SrcList *pSrc = makeSrcList(db, NULL, "sqlite_schema"); Token oldTok = mkToken("type"); Token newTok = mkToken("xtype"); sqlite3AlterRenameColumn(&p, pSrc, &oldTok, &newTok); TEST_ASSERT_TRUE(p.nErr>0); TEST_ASSERT_NOT_NULL(p.zErrMsg); TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "may not be altered")); TEST_ASSERT_NULL(p.pVdbe); parseCleanup(&p); sqlite3_close(db); } #ifndef SQLITE_OMIT_AUTHORIZATION static int denyAuthorizer(void *p, int op, const char *z1, const char *z2, const char *z3, const char *z4){ UNUSED_PARAMETER(p); UNUSED_PARAMETER(op); UNUSED_PARAMETER(z1); UNUSED_PARAMETER(z2); UNUSED_PARAMETER(z3); UNUSED_PARAMETER(z4); return SQLITE_DENY; } void test_sqlite3AlterRenameColumn_authorizer_denies(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t1(a,b);", 0, 0, 0)); TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_set_authorizer(db, denyAuthorizer, 0)); Parse p; parseInit(&p, db); SrcList *pSrc = makeSrcList(db, NULL, "t1"); Token oldTok = mkToken("a"); Token newTok = mkToken("x"); sqlite3AlterRenameColumn(&p, pSrc, &oldTok, &newTok); /* Expect abort without generating code */ TEST_ASSERT_TRUE(p.nErr>0 || p.zErrMsg!=NULL); TEST_ASSERT_NULL(p.pVdbe); sqlite3_set_authorizer(db, 0, 0); parseCleanup(&p); sqlite3_close(db); } #endif int main(void){ UNITY_BEGIN(); RUN_TEST(test_sqlite3AlterRenameColumn_no_such_table); RUN_TEST(test_sqlite3AlterRenameColumn_view_error); RUN_TEST(test_sqlite3AlterRenameColumn_column_not_found); RUN_TEST(test_sqlite3AlterRenameColumn_success_main_db); RUN_TEST(test_sqlite3AlterRenameColumn_success_temp_db_quoted_newname); RUN_TEST(test_sqlite3AlterRenameColumn_cannot_alter_system_table); #ifndef SQLITE_OMIT_AUTHORIZATION RUN_TEST(test_sqlite3AlterRenameColumn_authorizer_denies); #endif return UNITY_END(); }