sqlite / tests /tests_alter_sqlite3AlterDropColumn.c
AryaWu's picture
Upload folder using huggingface_hub
7510827 verified
#include "sqliteInt.h"
#include "unity.h"
#include <string.h>
#include <stdio.h>
/* Helper: execute SQL and assert success */
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);
}
/* Helper: create a SrcList for a single table name */
static SrcList *makeSrcList(sqlite3 *db, const char *zName){
Token tName;
tName.z = zName;
tName.n = (int)strlen(zName);
return sqlite3SrcListAppend(db, 0, &tName, 0);
}
/* Helper: initialize a Parse object */
static void initParse(sqlite3 *db, Parse *p){
memset(p, 0, sizeof(*p));
p->db = db;
}
/* Helper: free Parse resources left after calling the target function */
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) {
/* No global setup */
}
void tearDown(void) {
/* No global teardown */
}
/* Test: dropping a non-existent column reports an error */
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)); /* rough check */
/* Also check substring for robustness */
TEST_ASSERT_NOT_EQUAL(NULL, strstr(p.zErrMsg, "no such column"));
cleanupParse(db, &p);
sqlite3_close(db);
}
/* Test: cannot drop PRIMARY KEY column */
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);
}
/* Test: cannot drop a column with a column-level UNIQUE constraint */
void test_sqlite3AlterDropColumn_drop_unique_column(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
/* Column-level UNIQUE to set COLFLAG_UNIQUE */
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);
}
/* Test: cannot drop the last remaining column of a table */
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);
}
/* Test: cannot drop a column from a view */
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);
}
/* Test: successful generation for dropping a regular column from a table */
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();
}