File size: 6,229 Bytes
7510827 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
#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();
} |