AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Prototype of the provided test wrapper for the static function */7int test_vtabIsReadOnly(Parse *pParse, Table *pTab);8 9/* Stub xUpdate implementation to indicate write-capable virtual table */10static int stub_xUpdate(sqlite3_vtab* pVtab, int op, sqlite3_value** argv, sqlite_int64* pRowid){11 (void)pVtab; (void)op; (void)argv; (void)pRowid;12 return SQLITE_OK;13}14 15/* Helpers to build a minimal virtual table environment */16static void initParse(sqlite3 *db, Parse *pParse, int inTrigger, int trustedOn){17 memset(pParse, 0, sizeof(Parse));18 pParse->db = db;19 if( inTrigger ){20 /* Any non-NULL indicates we are within a trigger's parse context */21 pParse->pToplevel = pParse;22 }else{23 pParse->pToplevel = 0;24 }25 /* Set or clear the trusted schema flag */26 if( trustedOn ){27 db->flags |= SQLITE_TrustedSchema;28 }else{29 db->flags &= ~SQLITE_TrustedSchema;30 }31}32 33static void setupVirtualTable(sqlite3 *db, Table *pTab, const char *zName,34 int hasXUpdate, int eRisk,35 VTable **ppVT, Module **ppMod, struct sqlite3_module **ppIface){36 VTable *pVT = (VTable*)sqlite3_malloc(sizeof(VTable));37 Module *pMod = (Module*)sqlite3_malloc(sizeof(Module));38 struct sqlite3_module *pIface = (struct sqlite3_module*)sqlite3_malloc(sizeof(struct sqlite3_module));39 40 TEST_ASSERT_NOT_NULL_MESSAGE(pVT, "Alloc VTable failed");41 TEST_ASSERT_NOT_NULL_MESSAGE(pMod, "Alloc Module failed");42 TEST_ASSERT_NOT_NULL_MESSAGE(pIface, "Alloc sqlite3_module failed");43 44 memset(pVT, 0, sizeof(VTable));45 memset(pMod, 0, sizeof(Module));46 memset(pIface, 0, sizeof(struct sqlite3_module));47 48 /* Configure the module interface: only xUpdate matters here */49 if( hasXUpdate ){50 pIface->xUpdate = stub_xUpdate;51 }else{52 pIface->xUpdate = 0;53 }54 55 pMod->pModule = pIface;56 57 pVT->db = db;58 pVT->pMod = pMod;59 pVT->eVtabRisk = eRisk;60 61 memset(pTab, 0, sizeof(Table));62 pTab->zName = zName ? zName : "vtab";63 pTab->tabFlags = TF_Virtual; /* Ensure IsVirtual(pTab) is true */64 pTab->u.vtab.p = pVT;65 66 if( ppVT ) *ppVT = pVT;67 if( ppMod ) *ppMod = pMod;68 if( ppIface ) *ppIface = pIface;69}70 71static void cleanupVirtualTable(Table *pTab){72 if( pTab==0 ) return;73 VTable *pVT = pTab->u.vtab.p;74 if( pVT ){75 Module *pMod = pVT->pMod;76 if( pMod ){77 if( pMod->pModule ){78 sqlite3_free((void*)pMod->pModule);79 }80 sqlite3_free(pMod);81 }82 sqlite3_free(pVT);83 }84 memset(&pTab->u, 0, sizeof(pTab->u));85}86 87/* Unity required */88void setUp(void) {89 /* No global setup needed */90}91void tearDown(void) {92 /* No global teardown needed */93}94 95/* Tests */96 97void test_vtabIsReadOnly_no_xUpdate_returns_1(void){98 sqlite3 *db = 0;99 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));100 101 Parse parse;102 initParse(db, &parse, /*inTrigger=*/0, /*trustedOn=*/1);103 104 Table tab;105 setupVirtualTable(db, &tab, "vt_no_update", /*hasXUpdate=*/0, /*eRisk=*/0, NULL, NULL, NULL);106 107 int rc = test_vtabIsReadOnly(&parse, &tab);108 TEST_ASSERT_EQUAL_INT_MESSAGE(1, rc, "vtab without xUpdate should be read-only (return 1)");109 TEST_ASSERT_NULL(parse.zErrMsg);110 111 cleanupVirtualTable(&tab);112 sqlite3_close(db);113}114 115void test_vtabIsReadOnly_with_xUpdate_not_in_trigger_no_error_returns_0(void){116 sqlite3 *db = 0;117 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));118 119 Parse parse;120 initParse(db, &parse, /*inTrigger=*/0, /*trustedOn=*/0);121 122 Table tab;123 /* Risk level high but not in trigger => no error */124 setupVirtualTable(db, &tab, "vt_update_ok", /*hasXUpdate=*/1, /*eRisk=*/2, NULL, NULL, NULL);125 126 int rc = test_vtabIsReadOnly(&parse, &tab);127 TEST_ASSERT_EQUAL_INT(0, rc);128 TEST_ASSERT_NULL_MESSAGE(parse.zErrMsg, "No error should be set when not in trigger");129 130 cleanupVirtualTable(&tab);131 sqlite3_close(db);132}133 134void test_vtabIsReadOnly_in_trigger_trusted_off_non_innocuous_sets_error(void){135 sqlite3 *db = 0;136 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));137 138 Parse parse;139 initParse(db, &parse, /*inTrigger=*/1, /*trustedOn=*/0);140 141 Table tab;142 setupVirtualTable(db, &tab, "vt_risky", /*hasXUpdate=*/1, /*eRisk=*/1, NULL, NULL, NULL);143 144 int rc = test_vtabIsReadOnly(&parse, &tab);145 TEST_ASSERT_EQUAL_INT(0, rc);146 TEST_ASSERT_NOT_NULL_MESSAGE(parse.zErrMsg, "Expected error message for risky vtab in trigger with trusted_schema=OFF");147 /* Error message contains table name */148 TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "vt_risky"));149 /* nErr should be incremented by sqlite3ErrorMsg */150 TEST_ASSERT_TRUE(parse.nErr > 0);151 152 sqlite3DbFree(db, parse.zErrMsg); parse.zErrMsg = 0;153 cleanupVirtualTable(&tab);154 sqlite3_close(db);155}156 157void test_vtabIsReadOnly_in_trigger_trusted_on_non_innocuous_allowed(void){158 sqlite3 *db = 0;159 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));160 161 Parse parse;162 initParse(db, &parse, /*inTrigger=*/1, /*trustedOn=*/1);163 164 Table tab;165 setupVirtualTable(db, &tab, "vt_noninnoc", /*hasXUpdate=*/1, /*eRisk=*/1, NULL, NULL, NULL);166 167 int rc = test_vtabIsReadOnly(&parse, &tab);168 TEST_ASSERT_EQUAL_INT(0, rc);169 TEST_ASSERT_NULL_MESSAGE(parse.zErrMsg, "No error expected when trusted_schema=ON for non-innocuous vtab");170 171 cleanupVirtualTable(&tab);172 sqlite3_close(db);173}174 175void test_vtabIsReadOnly_in_trigger_trusted_on_directonly_still_errors(void){176 sqlite3 *db = 0;177 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));178 179 Parse parse;180 initParse(db, &parse, /*inTrigger=*/1, /*trustedOn=*/1);181 182 Table tab;183 /* eRisk > 1 models DIRECTONLY */184 setupVirtualTable(db, &tab, "vt_directonly", /*hasXUpdate=*/1, /*eRisk=*/2, NULL, NULL, NULL);185 186 int rc = test_vtabIsReadOnly(&parse, &tab);187 TEST_ASSERT_EQUAL_INT(0, rc);188 TEST_ASSERT_NOT_NULL_MESSAGE(parse.zErrMsg, "DIRECTONLY vtab should be rejected in trigger even if trusted_schema=ON");189 TEST_ASSERT_NOT_NULL(strstr(parse.zErrMsg, "vt_directonly"));190 TEST_ASSERT_TRUE(parse.nErr > 0);191 192 sqlite3DbFree(db, parse.zErrMsg); parse.zErrMsg = 0;193 cleanupVirtualTable(&tab);194 sqlite3_close(db);195}196 197int main(void){198 UNITY_BEGIN();199 RUN_TEST(test_vtabIsReadOnly_no_xUpdate_returns_1);200 RUN_TEST(test_vtabIsReadOnly_with_xUpdate_not_in_trigger_no_error_returns_0);201 RUN_TEST(test_vtabIsReadOnly_in_trigger_trusted_off_non_innocuous_sets_error);202 RUN_TEST(test_vtabIsReadOnly_in_trigger_trusted_on_non_innocuous_allowed);203 RUN_TEST(test_vtabIsReadOnly_in_trigger_trusted_on_directonly_still_errors);204 return UNITY_END();205}