|
|
#include "sqliteInt.h" |
|
|
#include "unity.h" |
|
|
#include <string.h> |
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
|
extern int test_renameEditSql( |
|
|
sqlite3_context *pCtx, |
|
|
RenameCtx *pRename, |
|
|
const char *zSql, |
|
|
const char *zNew, |
|
|
int bQuote |
|
|
); |
|
|
|
|
|
|
|
|
static void addTokenSpan(sqlite3 *db, RenameCtx *p, const char *zSql, int start, int n){ |
|
|
RenameToken *pTok = (RenameToken*)sqlite3DbMallocZero(db, sizeof(RenameToken)); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(pTok, "Failed to allocate RenameToken"); |
|
|
pTok->t.z = zSql + start; |
|
|
pTok->t.n = n; |
|
|
pTok->pNext = p->pList; |
|
|
p->pList = pTok; |
|
|
p->nList++; |
|
|
} |
|
|
|
|
|
|
|
|
static void addTokenForSubstring(sqlite3 *db, RenameCtx *p, const char *zSql, const char *sub){ |
|
|
const char *pos = strstr(zSql, sub); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(pos, "Substring not found in SQL"); |
|
|
int start = (int)(pos - zSql); |
|
|
addTokenSpan(db, p, zSql, start, (int)strlen(sub)); |
|
|
} |
|
|
|
|
|
|
|
|
static void initContext(sqlite3_context *pCtx, sqlite3 *db, Vdbe *pVdbe){ |
|
|
memset(pCtx, 0, sizeof(*pCtx)); |
|
|
memset(pVdbe, 0, sizeof(*pVdbe)); |
|
|
pVdbe->db = db; |
|
|
pCtx->pVdbe = pVdbe; |
|
|
sqlite3VdbeMemInit(&pCtx->s, db, 0); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int call_and_result(sqlite3 *db, RenameCtx *pRename, const char *zSql, |
|
|
const char *zNew, int bQuote, char const **pzOut){ |
|
|
sqlite3_context ctx; |
|
|
Vdbe vdbe; |
|
|
initContext(&ctx, db, &vdbe); |
|
|
|
|
|
int rc = test_renameEditSql(&ctx, pRename, zSql, zNew, bQuote); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(ctx.s.z, "No result text produced"); |
|
|
*pzOut = (const char*)ctx.s.z; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mem sCopy = ctx.s; |
|
|
|
|
|
memset(&ctx.s, 0, sizeof(ctx.s)); |
|
|
sqlite3VdbeMemRelease(&sCopy); |
|
|
return rc; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void test_renameEditSql_basic_unquoted_multiple(void){ |
|
|
sqlite3 *db = 0; |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
|
|
|
const char *zSql = "CREATE TABLE t (old, b, old);"; |
|
|
RenameCtx ctxRename; |
|
|
memset(&ctxRename, 0, sizeof(ctxRename)); |
|
|
|
|
|
|
|
|
|
|
|
const char *first = strstr(zSql, "old"); |
|
|
const char *second = strstr(first+1, "old"); |
|
|
TEST_ASSERT_NOT_NULL(first); |
|
|
TEST_ASSERT_NOT_NULL(second); |
|
|
addTokenSpan(db, &ctxRename, zSql, (int)(second - zSql), 3); |
|
|
addTokenSpan(db, &ctxRename, zSql, (int)(first - zSql), 3); |
|
|
|
|
|
const char *zNew = "newname"; |
|
|
const char *zOut = NULL; |
|
|
call_and_result(db, &ctxRename, zSql, zNew, 0, &zOut); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING("CREATE TABLE t (newname, b, newname);", zOut); |
|
|
|
|
|
TEST_ASSERT_NULL(ctxRename.pList); |
|
|
|
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
void test_renameEditSql_force_quote_bQuote1(void){ |
|
|
sqlite3 *db = 0; |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
|
|
|
const char *zSql = "CREATE TABLE t (old);"; |
|
|
RenameCtx ctxRename; |
|
|
memset(&ctxRename, 0, sizeof(ctxRename)); |
|
|
|
|
|
addTokenForSubstring(db, &ctxRename, zSql, "old"); |
|
|
|
|
|
const char *zNew = "col name"; |
|
|
const char *zOut = NULL; |
|
|
call_and_result(db, &ctxRename, zSql, zNew, 1, &zOut); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING("CREATE TABLE t (\"col name\");", zOut); |
|
|
TEST_ASSERT_NULL(ctxRename.pList); |
|
|
|
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
void test_renameEditSql_quoted_input_bQuote0(void){ |
|
|
sqlite3 *db = 0; |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
|
|
|
const char *zSql = "SELECT \"old\" FROM t;"; |
|
|
RenameCtx ctxRename; |
|
|
memset(&ctxRename, 0, sizeof(ctxRename)); |
|
|
|
|
|
addTokenForSubstring(db, &ctxRename, zSql, "\"old\""); |
|
|
|
|
|
const char *zNew = "foo"; |
|
|
const char *zOut = NULL; |
|
|
call_and_result(db, &ctxRename, zSql, zNew, 0, &zOut); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING("SELECT \"foo\" FROM t;", zOut); |
|
|
TEST_ASSERT_NULL(ctxRename.pList); |
|
|
|
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void test_renameEditSql_null_zNew_single_quote_conversion_with_space(void){ |
|
|
sqlite3 *db = 0; |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
|
|
|
|
|
|
{ |
|
|
const char *zSql = "SELECT \"string\"'alias'"; |
|
|
RenameCtx ctxRename; |
|
|
memset(&ctxRename, 0, sizeof(ctxRename)); |
|
|
addTokenForSubstring(db, &ctxRename, zSql, "\"string\""); |
|
|
const char *zOut = NULL; |
|
|
call_and_result(db, &ctxRename, zSql, NULL, 0, &zOut); |
|
|
TEST_ASSERT_EQUAL_STRING("SELECT 'string' 'alias'", zOut); |
|
|
TEST_ASSERT_NULL(ctxRename.pList); |
|
|
} |
|
|
|
|
|
|
|
|
{ |
|
|
const char *zSql = "SELECT \"data\";"; |
|
|
RenameCtx ctxRename; |
|
|
memset(&ctxRename, 0, sizeof(ctxRename)); |
|
|
addTokenForSubstring(db, &ctxRename, zSql, "\"data\""); |
|
|
const char *zOut = NULL; |
|
|
call_and_result(db, &ctxRename, zSql, NULL, 0, &zOut); |
|
|
TEST_ASSERT_EQUAL_STRING("SELECT 'data';", zOut); |
|
|
TEST_ASSERT_NULL(ctxRename.pList); |
|
|
} |
|
|
|
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
void test_renameEditSql_no_tokens_sql_unchanged(void){ |
|
|
sqlite3 *db = 0; |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
|
|
|
const char *zSql = "CREATE VIEW v AS SELECT a, b FROM t;"; |
|
|
RenameCtx ctxRename; |
|
|
memset(&ctxRename, 0, sizeof(ctxRename)); |
|
|
|
|
|
const char *zOut = NULL; |
|
|
call_and_result(db, &ctxRename, zSql, "x", 0, &zOut); |
|
|
TEST_ASSERT_EQUAL_STRING(zSql, zOut); |
|
|
TEST_ASSERT_NULL(ctxRename.pList); |
|
|
|
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
void test_renameEditSql_multiple_tokens_out_of_order(void){ |
|
|
sqlite3 *db = 0; |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); |
|
|
|
|
|
const char *zSql = "UPDATE t SET old = 1, x = old, y = old;"; |
|
|
RenameCtx ctxRename; |
|
|
memset(&ctxRename, 0, sizeof(ctxRename)); |
|
|
|
|
|
|
|
|
const char *p = zSql; |
|
|
int offs[3]; |
|
|
for(int i=0;i<3;i++){ |
|
|
p = strstr(p, "old"); |
|
|
TEST_ASSERT_NOT_NULL(p); |
|
|
offs[i] = (int)(p - zSql); |
|
|
p += 3; |
|
|
} |
|
|
|
|
|
addTokenSpan(db, &ctxRename, zSql, offs[2], 3); |
|
|
addTokenSpan(db, &ctxRename, zSql, offs[0], 3); |
|
|
addTokenSpan(db, &ctxRename, zSql, offs[1], 3); |
|
|
|
|
|
const char *zOut = NULL; |
|
|
call_and_result(db, &ctxRename, zSql, "nn", 0, &zOut); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING("UPDATE t SET nn = 1, x = nn, y = nn;", zOut); |
|
|
TEST_ASSERT_NULL(ctxRename.pList); |
|
|
|
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_renameEditSql_basic_unquoted_multiple); |
|
|
RUN_TEST(test_renameEditSql_force_quote_bQuote1); |
|
|
RUN_TEST(test_renameEditSql_quoted_input_bQuote0); |
|
|
RUN_TEST(test_renameEditSql_null_zNew_single_quote_conversion_with_space); |
|
|
RUN_TEST(test_renameEditSql_no_tokens_sql_unchanged); |
|
|
RUN_TEST(test_renameEditSql_multiple_tokens_out_of_order); |
|
|
return UNITY_END(); |
|
|
} |