|
|
#include "sqliteInt.h" |
|
|
#include "unity.h" |
|
|
#include <string.h> |
|
|
#include <stdlib.h> |
|
|
|
|
|
|
|
|
static sqlite3 *gDb = NULL; |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
int rc = sqlite3_open(":memory:", &gDb); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
TEST_ASSERT_NOT_NULL(gDb); |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
if (gDb) { |
|
|
sqlite3_close(gDb); |
|
|
gDb = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static SrcList* makeSrcList(const char *zName){ |
|
|
Token t; |
|
|
memset(&t, 0, sizeof(t)); |
|
|
t.z = zName; |
|
|
t.n = (int)strlen(zName); |
|
|
return sqlite3SrcListAppend(gDb, 0, &t, 0); |
|
|
} |
|
|
|
|
|
|
|
|
static void initParse(Parse *p){ |
|
|
memset(p, 0, sizeof(*p)); |
|
|
p->db = gDb; |
|
|
} |
|
|
|
|
|
|
|
|
void test_sqlite3AlterBeginAddColumn_success_creates_partial_copy(void) { |
|
|
char *err = 0; |
|
|
int rc; |
|
|
|
|
|
|
|
|
rc = sqlite3_exec(gDb, |
|
|
"CREATE TABLE t(a INTEGER DEFAULT 1, b TEXT, c REAL DEFAULT 3.14);", |
|
|
0, 0, &err); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "create failed"); |
|
|
if (err) sqlite3_free(err), err = 0; |
|
|
|
|
|
|
|
|
Table *pOrig = sqlite3FindTable(gDb, "t", "main"); |
|
|
TEST_ASSERT_NOT_NULL(pOrig); |
|
|
TEST_ASSERT_TRUE(pOrig->nCol > 0); |
|
|
|
|
|
|
|
|
SrcList *pSrc = makeSrcList("t"); |
|
|
TEST_ASSERT_NOT_NULL(pSrc); |
|
|
|
|
|
Parse parse; |
|
|
initParse(&parse); |
|
|
TEST_ASSERT_NULL(parse.pNewTable); |
|
|
|
|
|
|
|
|
sqlite3BtreeEnterAll(gDb); |
|
|
sqlite3AlterBeginAddColumn(&parse, pSrc); |
|
|
sqlite3BtreeLeaveAll(gDb); |
|
|
|
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, parse.nErr); |
|
|
TEST_ASSERT_NOT_NULL(parse.pNewTable); |
|
|
|
|
|
Table *pNew = parse.pNewTable; |
|
|
|
|
|
|
|
|
TEST_ASSERT_NOT_NULL(pNew->zName); |
|
|
TEST_ASSERT_EQUAL_STRING("sqlite_altertab_t", pNew->zName); |
|
|
|
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(pOrig->nCol, pNew->nCol); |
|
|
|
|
|
|
|
|
for(int i=0; i<pNew->nCol; i++){ |
|
|
Column *cOrig = &pOrig->aCol[i]; |
|
|
Column *cNew = &pNew->aCol[i]; |
|
|
TEST_ASSERT_NOT_NULL(cNew->zCnName); |
|
|
TEST_ASSERT_NOT_NULL(cOrig->zCnName); |
|
|
|
|
|
TEST_ASSERT(cNew->zCnName != cOrig->zCnName); |
|
|
TEST_ASSERT_EQUAL_STRING(cOrig->zCnName, cNew->zCnName); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(sqlite3StrIHash(cNew->zCnName), cNew->hName); |
|
|
} |
|
|
|
|
|
|
|
|
TEST_ASSERT(pNew->pSchema == pOrig->pSchema); |
|
|
TEST_ASSERT_TRUE(pNew->u.tab.addColOffset > 0); |
|
|
TEST_ASSERT_EQUAL_INT(pOrig->u.tab.addColOffset, pNew->u.tab.addColOffset); |
|
|
|
|
|
|
|
|
if( pOrig->u.tab.pDfltList ){ |
|
|
TEST_ASSERT_NOT_NULL(pNew->u.tab.pDfltList); |
|
|
TEST_ASSERT_NOT_NULL(pOrig->u.tab.pDfltList); |
|
|
TEST_ASSERT(pNew->u.tab.pDfltList != pOrig->u.tab.pDfltList); |
|
|
TEST_ASSERT_EQUAL_INT(pOrig->u.tab.pDfltList->nExpr, |
|
|
pNew->u.tab.pDfltList->nExpr); |
|
|
} |
|
|
|
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(1, pNew->nTabRef); |
|
|
|
|
|
|
|
|
sqlite3DeleteTable(gDb, pNew); |
|
|
parse.pNewTable = 0; |
|
|
} |
|
|
|
|
|
|
|
|
void test_sqlite3AlterBeginAddColumn_on_view_sets_error(void) { |
|
|
char *err = 0; |
|
|
int rc; |
|
|
|
|
|
rc = sqlite3_exec(gDb, "CREATE VIEW v AS SELECT 1 AS x;", 0, 0, &err); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "create view failed"); |
|
|
if (err) sqlite3_free(err), err = 0; |
|
|
|
|
|
SrcList *pSrc = makeSrcList("v"); |
|
|
TEST_ASSERT_NOT_NULL(pSrc); |
|
|
|
|
|
Parse parse; |
|
|
initParse(&parse); |
|
|
|
|
|
sqlite3BtreeEnterAll(gDb); |
|
|
sqlite3AlterBeginAddColumn(&parse, pSrc); |
|
|
sqlite3BtreeLeaveAll(gDb); |
|
|
|
|
|
TEST_ASSERT_TRUE(parse.nErr > 0); |
|
|
TEST_ASSERT_NULL(parse.pNewTable); |
|
|
TEST_ASSERT_NOT_NULL(parse.zErrMsg); |
|
|
TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "Cannot add a column to a view")); |
|
|
|
|
|
sqlite3DbFree(gDb, parse.zErrMsg); |
|
|
parse.zErrMsg = 0; |
|
|
} |
|
|
|
|
|
|
|
|
void test_sqlite3AlterBeginAddColumn_on_system_table_sets_error(void) { |
|
|
char *err = 0; |
|
|
int rc; |
|
|
|
|
|
|
|
|
rc = sqlite3_exec(gDb, |
|
|
"CREATE TABLE at(id INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);", |
|
|
0, 0, &err); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "create autoinc failed"); |
|
|
if (err) sqlite3_free(err), err = 0; |
|
|
|
|
|
|
|
|
rc = sqlite3_exec(gDb, "INSERT INTO at(b) VALUES('x');", 0, 0, &err); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "insert failed"); |
|
|
if (err) sqlite3_free(err), err = 0; |
|
|
|
|
|
|
|
|
SrcList *pSrc = makeSrcList("sqlite_sequence"); |
|
|
TEST_ASSERT_NOT_NULL(pSrc); |
|
|
|
|
|
Parse parse; |
|
|
initParse(&parse); |
|
|
|
|
|
sqlite3BtreeEnterAll(gDb); |
|
|
sqlite3AlterBeginAddColumn(&parse, pSrc); |
|
|
sqlite3BtreeLeaveAll(gDb); |
|
|
|
|
|
TEST_ASSERT_TRUE(parse.nErr > 0); |
|
|
TEST_ASSERT_NULL(parse.pNewTable); |
|
|
TEST_ASSERT_NOT_NULL(parse.zErrMsg); |
|
|
TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "table sqlite_sequence may not be altered")); |
|
|
|
|
|
sqlite3DbFree(gDb, parse.zErrMsg); |
|
|
parse.zErrMsg = 0; |
|
|
} |
|
|
|
|
|
|
|
|
void test_sqlite3AlterBeginAddColumn_table_not_found_sets_error(void) { |
|
|
SrcList *pSrc = makeSrcList("no_such_table_123"); |
|
|
TEST_ASSERT_NOT_NULL(pSrc); |
|
|
|
|
|
Parse parse; |
|
|
initParse(&parse); |
|
|
|
|
|
sqlite3BtreeEnterAll(gDb); |
|
|
sqlite3AlterBeginAddColumn(&parse, pSrc); |
|
|
sqlite3BtreeLeaveAll(gDb); |
|
|
|
|
|
TEST_ASSERT_TRUE(parse.nErr > 0); |
|
|
TEST_ASSERT_NULL(parse.pNewTable); |
|
|
TEST_ASSERT_NOT_NULL(parse.zErrMsg); |
|
|
TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "no such table")); |
|
|
|
|
|
sqlite3DbFree(gDb, parse.zErrMsg); |
|
|
parse.zErrMsg = 0; |
|
|
} |
|
|
|
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_sqlite3AlterBeginAddColumn_success_creates_partial_copy); |
|
|
RUN_TEST(test_sqlite3AlterBeginAddColumn_on_view_sets_error); |
|
|
RUN_TEST(test_sqlite3AlterBeginAddColumn_on_system_table_sets_error); |
|
|
RUN_TEST(test_sqlite3AlterBeginAddColumn_table_not_found_sets_error); |
|
|
return UNITY_END(); |
|
|
} |