AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Globals for tests */7static sqlite3 *gDb = NULL;8 9/* Unity setup/teardown */10void setUp(void) {11 int rc = sqlite3_open(":memory:", &gDb);12 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);13 TEST_ASSERT_NOT_NULL(gDb);14}15 16void tearDown(void) {17 if (gDb) {18 sqlite3_close(gDb);19 gDb = NULL;20 }21}22 23/* Helper: create a SrcList with a single table name */24static SrcList* makeSrcList(const char *zName){25 Token t;26 memset(&t, 0, sizeof(t));27 t.z = zName;28 t.n = (int)strlen(zName);29 return sqlite3SrcListAppend(gDb, 0, &t, 0);30}31 32/* Helper: initialize a Parse object for our db */33static void initParse(Parse *p){34 memset(p, 0, sizeof(*p));35 p->db = gDb;36}37 38/* Test: successful copy for an ordinary table */39void test_sqlite3AlterBeginAddColumn_success_creates_partial_copy(void) {40 char *err = 0;41 int rc;42 43 /* Create a normal table with multiple columns and defaults */44 rc = sqlite3_exec(gDb,45 "CREATE TABLE t(a INTEGER DEFAULT 1, b TEXT, c REAL DEFAULT 3.14);",46 0, 0, &err);47 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "create failed");48 if (err) sqlite3_free(err), err = 0;49 50 /* Find original table metadata */51 Table *pOrig = sqlite3FindTable(gDb, "t", "main");52 TEST_ASSERT_NOT_NULL(pOrig);53 TEST_ASSERT_TRUE(pOrig->nCol > 0);54 55 /* Prepare SrcList and Parse */56 SrcList *pSrc = makeSrcList("t");57 TEST_ASSERT_NOT_NULL(pSrc);58 59 Parse parse;60 initParse(&parse);61 TEST_ASSERT_NULL(parse.pNewTable);62 63 /* Call the target function while holding btree mutexes */64 sqlite3BtreeEnterAll(gDb);65 sqlite3AlterBeginAddColumn(&parse, pSrc);66 sqlite3BtreeLeaveAll(gDb);67 68 /* Verify success: no error and pNewTable populated */69 TEST_ASSERT_EQUAL_INT(0, parse.nErr);70 TEST_ASSERT_NOT_NULL(parse.pNewTable);71 72 Table *pNew = parse.pNewTable;73 74 /* Name must be prefixed as "sqlite_altertab_t" */75 TEST_ASSERT_NOT_NULL(pNew->zName);76 TEST_ASSERT_EQUAL_STRING("sqlite_altertab_t", pNew->zName);77 78 /* Column count should match */79 TEST_ASSERT_EQUAL_INT(pOrig->nCol, pNew->nCol);80 81 /* Column names duplicated and hashes computed */82 for(int i=0; i<pNew->nCol; i++){83 Column *cOrig = &pOrig->aCol[i];84 Column *cNew = &pNew->aCol[i];85 TEST_ASSERT_NOT_NULL(cNew->zCnName);86 TEST_ASSERT_NOT_NULL(cOrig->zCnName);87 /* Ensure duplicated pointer (not aliasing original) and same content */88 TEST_ASSERT(cNew->zCnName != cOrig->zCnName);89 TEST_ASSERT_EQUAL_STRING(cOrig->zCnName, cNew->zCnName);90 /* Ensure hash is set to case-insensitive hash of the name */91 TEST_ASSERT_EQUAL_INT(sqlite3StrIHash(cNew->zCnName), cNew->hName);92 }93 94 /* Schema and addColOffset should match original */95 TEST_ASSERT(pNew->pSchema == pOrig->pSchema);96 TEST_ASSERT_TRUE(pNew->u.tab.addColOffset > 0);97 TEST_ASSERT_EQUAL_INT(pOrig->u.tab.addColOffset, pNew->u.tab.addColOffset);98 99 /* Default expression list should be duplicated if present on original */100 if( pOrig->u.tab.pDfltList ){101 TEST_ASSERT_NOT_NULL(pNew->u.tab.pDfltList);102 TEST_ASSERT_NOT_NULL(pOrig->u.tab.pDfltList);103 TEST_ASSERT(pNew->u.tab.pDfltList != pOrig->u.tab.pDfltList);104 TEST_ASSERT_EQUAL_INT(pOrig->u.tab.pDfltList->nExpr,105 pNew->u.tab.pDfltList->nExpr);106 }107 108 /* New table refcount should be 1 */109 TEST_ASSERT_EQUAL_INT(1, pNew->nTabRef);110 111 /* Cleanup: delete the allocated table copy */112 sqlite3DeleteTable(gDb, pNew);113 parse.pNewTable = 0;114}115 116/* Test: attempting to alter a view should raise an error */117void test_sqlite3AlterBeginAddColumn_on_view_sets_error(void) {118 char *err = 0;119 int rc;120 121 rc = sqlite3_exec(gDb, "CREATE VIEW v AS SELECT 1 AS x;", 0, 0, &err);122 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "create view failed");123 if (err) sqlite3_free(err), err = 0;124 125 SrcList *pSrc = makeSrcList("v");126 TEST_ASSERT_NOT_NULL(pSrc);127 128 Parse parse;129 initParse(&parse);130 131 sqlite3BtreeEnterAll(gDb);132 sqlite3AlterBeginAddColumn(&parse, pSrc);133 sqlite3BtreeLeaveAll(gDb);134 135 TEST_ASSERT_TRUE(parse.nErr > 0);136 TEST_ASSERT_NULL(parse.pNewTable);137 TEST_ASSERT_NOT_NULL(parse.zErrMsg);138 TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "Cannot add a column to a view"));139 140 sqlite3DbFree(gDb, parse.zErrMsg);141 parse.zErrMsg = 0;142}143 144/* Test: attempting to alter a system table (sqlite_sequence) should raise an error */145void test_sqlite3AlterBeginAddColumn_on_system_table_sets_error(void) {146 char *err = 0;147 int rc;148 149 /* Create an AUTOINCREMENT table to ensure sqlite_sequence exists */150 rc = sqlite3_exec(gDb,151 "CREATE TABLE at(id INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);",152 0, 0, &err);153 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "create autoinc failed");154 if (err) sqlite3_free(err), err = 0;155 156 /* Ensure sqlite_sequence exists by inserting a row (usually created at table create, but this is safe) */157 rc = sqlite3_exec(gDb, "INSERT INTO at(b) VALUES('x');", 0, 0, &err);158 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, err ? err : "insert failed");159 if (err) sqlite3_free(err), err = 0;160 161 /* Now attempt to alter sqlite_sequence */162 SrcList *pSrc = makeSrcList("sqlite_sequence");163 TEST_ASSERT_NOT_NULL(pSrc);164 165 Parse parse;166 initParse(&parse);167 168 sqlite3BtreeEnterAll(gDb);169 sqlite3AlterBeginAddColumn(&parse, pSrc);170 sqlite3BtreeLeaveAll(gDb);171 172 TEST_ASSERT_TRUE(parse.nErr > 0);173 TEST_ASSERT_NULL(parse.pNewTable);174 TEST_ASSERT_NOT_NULL(parse.zErrMsg);175 TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "table sqlite_sequence may not be altered"));176 177 sqlite3DbFree(gDb, parse.zErrMsg);178 parse.zErrMsg = 0;179}180 181/* Test: table not found should set an error and no pNewTable */182void test_sqlite3AlterBeginAddColumn_table_not_found_sets_error(void) {183 SrcList *pSrc = makeSrcList("no_such_table_123");184 TEST_ASSERT_NOT_NULL(pSrc);185 186 Parse parse;187 initParse(&parse);188 189 sqlite3BtreeEnterAll(gDb);190 sqlite3AlterBeginAddColumn(&parse, pSrc);191 sqlite3BtreeLeaveAll(gDb);192 193 TEST_ASSERT_TRUE(parse.nErr > 0);194 TEST_ASSERT_NULL(parse.pNewTable);195 TEST_ASSERT_NOT_NULL(parse.zErrMsg);196 TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "no such table"));197 198 sqlite3DbFree(gDb, parse.zErrMsg);199 parse.zErrMsg = 0;200}201 202/* Main runner */203int main(void) {204 UNITY_BEGIN();205 RUN_TEST(test_sqlite3AlterBeginAddColumn_success_creates_partial_copy);206 RUN_TEST(test_sqlite3AlterBeginAddColumn_on_view_sets_error);207 RUN_TEST(test_sqlite3AlterBeginAddColumn_on_system_table_sets_error);208 RUN_TEST(test_sqlite3AlterBeginAddColumn_table_not_found_sets_error);209 return UNITY_END();210}