| #include "sqliteInt.h" |
| #include "unity.h" |
|
|
| #include <string.h> |
| #include <stdio.h> |
|
|
| |
| static void execSQL(sqlite3 *db, const char *zSql){ |
| char *zErr = 0; |
| int rc = sqlite3_exec(db, zSql, 0, 0, &zErr); |
| if( rc!=SQLITE_OK ){ |
| fprintf(stderr, "SQL error (%d): %s while running: %s\n", rc, zErr?zErr:"(null)", zSql); |
| } |
| TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_exec failed"); |
| if( zErr ) sqlite3_free(zErr); |
| } |
|
|
| |
| static SrcList *makeSrcList(sqlite3 *db, const char *zName){ |
| Token tName; |
| tName.z = zName; |
| tName.n = (int)strlen(zName); |
| return sqlite3SrcListAppend(db, 0, &tName, 0); |
| } |
|
|
| |
| static void initParse(sqlite3 *db, Parse *p){ |
| memset(p, 0, sizeof(*p)); |
| p->db = db; |
| } |
|
|
| |
| static void cleanupParse(sqlite3 *db, Parse *p){ |
| if( p->zErrMsg ){ |
| sqlite3DbFree(db, p->zErrMsg); |
| p->zErrMsg = 0; |
| } |
| if( p->pVdbe ){ |
| sqlite3VdbeDelete(p->pVdbe); |
| p->pVdbe = 0; |
| } |
| } |
|
|
| void setUp(void) { |
| |
| } |
|
|
| void tearDown(void) { |
| |
| } |
|
|
| |
| void test_sqlite3AlterDropColumn_no_such_column(void){ |
| sqlite3 *db = 0; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| execSQL(db, "CREATE TABLE t1(a, b);"); |
|
|
| Parse p; |
| initParse(db, &p); |
| SrcList *pSrc = makeSrcList(db, "t1"); |
|
|
| Token tCol; |
| tCol.z = "c"; |
| tCol.n = 1; |
|
|
| sqlite3BtreeEnterAll(db); |
| sqlite3AlterDropColumn(&p, pSrc, &tCol); |
| sqlite3BtreeLeaveAll(db); |
|
|
| TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected error for non-existent column"); |
| TEST_ASSERT_NOT_NULL(p.zErrMsg); |
| TEST_ASSERT_NOT_EQUAL(-1, (int)sqlite3StrLike("no such column:%", p.zErrMsg, 0)); |
| |
| TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "no such column")); |
|
|
| cleanupParse(db, &p); |
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterDropColumn_drop_primary_key_column(void){ |
| sqlite3 *db = 0; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| execSQL(db, "CREATE TABLE tpk(a INTEGER PRIMARY KEY, b);"); |
|
|
| Parse p; |
| initParse(db, &p); |
| SrcList *pSrc = makeSrcList(db, "tpk"); |
|
|
| Token tCol; |
| tCol.z = "a"; |
| tCol.n = 1; |
|
|
| sqlite3BtreeEnterAll(db); |
| sqlite3AlterDropColumn(&p, pSrc, &tCol); |
| sqlite3BtreeLeaveAll(db); |
|
|
| TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected error dropping PRIMARY KEY column"); |
| TEST_ASSERT_NOT_NULL(p.zErrMsg); |
| TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "PRIMARY KEY")); |
|
|
| cleanupParse(db, &p); |
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterDropColumn_drop_unique_column(void){ |
| sqlite3 *db = 0; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| |
| execSQL(db, "CREATE TABLE tu(a UNIQUE, b);"); |
|
|
| Parse p; |
| initParse(db, &p); |
| SrcList *pSrc = makeSrcList(db, "tu"); |
|
|
| Token tCol; |
| tCol.z = "a"; |
| tCol.n = 1; |
|
|
| sqlite3BtreeEnterAll(db); |
| sqlite3AlterDropColumn(&p, pSrc, &tCol); |
| sqlite3BtreeLeaveAll(db); |
|
|
| TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected error dropping UNIQUE column"); |
| TEST_ASSERT_NOT_NULL(p.zErrMsg); |
| TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "UNIQUE")); |
|
|
| cleanupParse(db, &p); |
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterDropColumn_drop_only_remaining_column(void){ |
| sqlite3 *db = 0; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| execSQL(db, "CREATE TABLE t1col(a);"); |
|
|
| Parse p; |
| initParse(db, &p); |
| SrcList *pSrc = makeSrcList(db, "t1col"); |
|
|
| Token tCol; |
| tCol.z = "a"; |
| tCol.n = 1; |
|
|
| sqlite3BtreeEnterAll(db); |
| sqlite3AlterDropColumn(&p, pSrc, &tCol); |
| sqlite3BtreeLeaveAll(db); |
|
|
| TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected error dropping the only column"); |
| TEST_ASSERT_NOT_NULL(p.zErrMsg); |
| TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "no other columns exist")); |
|
|
| cleanupParse(db, &p); |
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterDropColumn_on_view(void){ |
| sqlite3 *db = 0; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| execSQL(db, "CREATE VIEW v1 AS SELECT 1 AS a, 2 AS b;"); |
|
|
| Parse p; |
| initParse(db, &p); |
| SrcList *pSrc = makeSrcList(db, "v1"); |
|
|
| Token tCol; |
| tCol.z = "a"; |
| tCol.n = 1; |
|
|
| sqlite3BtreeEnterAll(db); |
| sqlite3AlterDropColumn(&p, pSrc, &tCol); |
| sqlite3BtreeLeaveAll(db); |
|
|
| TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected error dropping column from view"); |
| TEST_ASSERT_NOT_NULL(p.zErrMsg); |
| TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "drop column from view")); |
|
|
| cleanupParse(db, &p); |
| sqlite3_close(db); |
| } |
|
|
| |
| void test_sqlite3AlterDropColumn_success_generates_vdbe(void){ |
| sqlite3 *db = 0; |
| TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
| execSQL(db, "CREATE TABLE tgood(a, b, c);"); |
| execSQL(db, "INSERT INTO tgood VALUES(1,2,3);"); |
|
|
| Parse p; |
| initParse(db, &p); |
| SrcList *pSrc = makeSrcList(db, "tgood"); |
|
|
| Token tCol; |
| tCol.z = "b"; |
| tCol.n = 1; |
|
|
| sqlite3BtreeEnterAll(db); |
| sqlite3AlterDropColumn(&p, pSrc, &tCol); |
| sqlite3BtreeLeaveAll(db); |
|
|
| TEST_ASSERT_EQUAL_INT_MESSAGE(0, p.nErr, "Unexpected error during valid drop column codegen"); |
| TEST_ASSERT_NOT_NULL_MESSAGE(p.pVdbe, "Expected VDBE code to be generated"); |
| TEST_ASSERT_TRUE_MESSAGE(p.nMem>0 || p.nTab>0, "Expected some registers/cursors allocated"); |
|
|
| cleanupParse(db, &p); |
| sqlite3_close(db); |
| } |
|
|
| int main(void){ |
| UNITY_BEGIN(); |
| RUN_TEST(test_sqlite3AlterDropColumn_no_such_column); |
| RUN_TEST(test_sqlite3AlterDropColumn_drop_primary_key_column); |
| RUN_TEST(test_sqlite3AlterDropColumn_drop_unique_column); |
| RUN_TEST(test_sqlite3AlterDropColumn_drop_only_remaining_column); |
| RUN_TEST(test_sqlite3AlterDropColumn_on_view); |
| RUN_TEST(test_sqlite3AlterDropColumn_success_generates_vdbe); |
| return UNITY_END(); |
| } |