AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Helper capture for the authorizer */7typedef struct AuthCapture {8 int ret;9 int nCall;10 int lastCode;11 const char *a1;12 const char *a2;13 const char *a3;14 const char *a4;15} AuthCapture;16 17static int testAuth(void *pArg, int code, const char *a1, const char *a2,18 const char *a3, const char *a4){19 AuthCapture *cap = (AuthCapture*)pArg;20 cap->nCall++;21 cap->lastCode = code;22 cap->a1 = a1;23 cap->a2 = a2;24 cap->a3 = a3;25 cap->a4 = a4;26 return cap->ret;27}28 29/* Helpers to construct minimal structures needed by sqlite3AuthRead */30 31static Table* makeTestTable(sqlite3 *db, const char *zName,32 const char **colNames, int nCol, int iPKey){33 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));34 TEST_ASSERT_NOT_NULL(pTab);35 pTab->zName = sqlite3DbStrDup(db, zName);36 TEST_ASSERT_NOT_NULL(pTab->zName);37 pTab->nCol = (u16)nCol;38 if( nCol>0 ){39 pTab->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nCol);40 TEST_ASSERT_NOT_NULL(pTab->aCol);41 for(int i=0; i<nCol; i++){42 pTab->aCol[i].zCnName = sqlite3DbStrDup(db, colNames[i]);43 TEST_ASSERT_NOT_NULL(pTab->aCol[i].zCnName);44 }45 }46 pTab->iPKey = iPKey;47 return pTab;48}49 50static void freeTestTable(sqlite3 *db, Table *pTab){51 if( !pTab ) return;52 if( pTab->aCol ){53 for(int i=0; i<pTab->nCol; i++){54 if( pTab->aCol[i].zCnName ){55 sqlite3DbFree(db, (void*)pTab->aCol[i].zCnName);56 }57 }58 sqlite3DbFree(db, pTab->aCol);59 }60 if( pTab->zName ) sqlite3DbFree(db, pTab->zName);61 sqlite3DbFree(db, pTab);62}63 64static SrcList* makeSrcList1(sqlite3 *db, Table *pTab, int iCursor){65 SrcList *pList = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList));66 TEST_ASSERT_NOT_NULL(pList);67 pList->nSrc = 1;68 pList->nAlloc = 1;69 pList->a[0].iCursor = iCursor;70 pList->a[0].pSTab = pTab;71 return pList;72}73 74static void freeSrcList(sqlite3 *db, SrcList *pList){75 if( pList ) sqlite3DbFree(db, pList);76}77 78static void initParse(Parse *pParse, sqlite3 *db, const char *zCtx){79 memset(pParse, 0, sizeof(*pParse));80 pParse->db = db;81 pParse->zAuthContext = zCtx;82}83 84void setUp(void) {85 /* empty */86}87 88void tearDown(void) {89 /* empty */90}91 92/* Test: basic OK authorization with explicit column index */93void test_sqlite3AuthRead_basic_ok(void){94 sqlite3 *db = 0;95 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));96 AuthCapture cap = {0};97 cap.ret = SQLITE_OK;98 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));99 100 const char *cols[] = {"id","name"};101 Table *pTab = makeTestTable(db, "T", cols, 2, -1);102 SrcList *pList = makeSrcList1(db, pTab, 5);103 104 Parse sParse; initParse(&sParse, db, "ctx");105 Expr e; memset(&e, 0, sizeof(e));106 e.op = TK_COLUMN;107 e.iTable = 5;108 e.iColumn = 1; /* "name" */109 Schema *pSchema = db->aDb[0].pSchema;110 111 sqlite3AuthRead(&sParse, &e, pSchema, pList);112 113 TEST_ASSERT_EQUAL_INT(1, cap.nCall);114 TEST_ASSERT_EQUAL_INT(SQLITE_READ, cap.lastCode);115 TEST_ASSERT_NOT_NULL(cap.a1);116 TEST_ASSERT_NOT_NULL(cap.a2);117 TEST_ASSERT_NOT_NULL(cap.a3);118 TEST_ASSERT_NOT_NULL(cap.a4);119 TEST_ASSERT_EQUAL_STRING("T", cap.a1);120 TEST_ASSERT_EQUAL_STRING("name", cap.a2);121 TEST_ASSERT_EQUAL_STRING(db->aDb[0].zDbSName, cap.a3); /* usually "main" */122 TEST_ASSERT_EQUAL_STRING("ctx", cap.a4);123 124 TEST_ASSERT_EQUAL_INT(TK_COLUMN, e.op);125 TEST_ASSERT_EQUAL_INT(0, sParse.rc);126 TEST_ASSERT_NULL(sParse.zErrMsg);127 128 sqlite3_set_authorizer(db, NULL, NULL);129 sqlite3DbFree(db, sParse.zErrMsg);130 freeSrcList(db, pList);131 freeTestTable(db, pTab);132 sqlite3_close(db);133}134 135/* Test: SQLITE_IGNORE causes TK_NULL */136void test_sqlite3AuthRead_ignore_sets_null(void){137 sqlite3 *db = 0;138 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));139 AuthCapture cap = {0};140 cap.ret = SQLITE_IGNORE;141 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));142 143 const char *cols[] = {"id","name"};144 Table *pTab = makeTestTable(db, "T", cols, 2, -1);145 SrcList *pList = makeSrcList1(db, pTab, 3);146 147 Parse sParse; initParse(&sParse, db, "ctx");148 Expr e; memset(&e, 0, sizeof(e));149 e.op = TK_COLUMN;150 e.iTable = 3;151 e.iColumn = 0; /* "id" */152 Schema *pSchema = db->aDb[0].pSchema;153 154 sqlite3AuthRead(&sParse, &e, pSchema, pList);155 156 TEST_ASSERT_EQUAL_INT(1, cap.nCall);157 TEST_ASSERT_EQUAL_INT(TK_NULL, e.op);158 TEST_ASSERT_EQUAL_INT(0, sParse.rc);159 TEST_ASSERT_NULL(sParse.zErrMsg);160 161 sqlite3_set_authorizer(db, NULL, NULL);162 sqlite3DbFree(db, sParse.zErrMsg);163 freeSrcList(db, pList);164 freeTestTable(db, pTab);165 sqlite3_close(db);166}167 168/* Test: SQLITE_DENY results in parse error and no op change */169void test_sqlite3AuthRead_deny_sets_parse_error(void){170 sqlite3 *db = 0;171 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));172 AuthCapture cap = {0};173 cap.ret = SQLITE_DENY;174 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));175 176 const char *cols[] = {"id","name"};177 Table *pTab = makeTestTable(db, "T", cols, 2, -1);178 SrcList *pList = makeSrcList1(db, pTab, 1);179 180 Parse sParse; initParse(&sParse, db, "ctx");181 Expr e; memset(&e, 0, sizeof(e));182 e.op = TK_COLUMN;183 e.iTable = 1;184 e.iColumn = 1; /* "name" */185 Schema *pSchema = db->aDb[0].pSchema;186 187 sqlite3AuthRead(&sParse, &e, pSchema, pList);188 189 TEST_ASSERT_EQUAL_INT(1, cap.nCall);190 TEST_ASSERT_EQUAL_INT(TK_COLUMN, e.op);191 TEST_ASSERT_EQUAL_INT(SQLITE_AUTH, sParse.rc);192 TEST_ASSERT_NOT_NULL(sParse.zErrMsg);193 TEST_ASSERT_NOT_NULL(strstr(sParse.zErrMsg, "prohibited"));194 TEST_ASSERT_NOT_NULL(strstr(sParse.zErrMsg, "T.name"));195 196 sqlite3_set_authorizer(db, NULL, NULL);197 sqlite3DbFree(db, sParse.zErrMsg);198 freeSrcList(db, pList);199 freeTestTable(db, pTab);200 sqlite3_close(db);201}202 203/* Test: Invalid authorizer return yields "authorizer malfunction" and SQLITE_ERROR */204void test_sqlite3AuthRead_invalid_code_sets_malfunction(void){205 sqlite3 *db = 0;206 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));207 AuthCapture cap = {0};208 cap.ret = 12345; /* invalid */209 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));210 211 const char *cols[] = {"id","name"};212 Table *pTab = makeTestTable(db, "T", cols, 2, -1);213 SrcList *pList = makeSrcList1(db, pTab, 7);214 215 Parse sParse; initParse(&sParse, db, "ctx");216 Expr e; memset(&e, 0, sizeof(e));217 e.op = TK_COLUMN;218 e.iTable = 7;219 e.iColumn = 0; /* "id" */220 Schema *pSchema = db->aDb[0].pSchema;221 222 sqlite3AuthRead(&sParse, &e, pSchema, pList);223 224 TEST_ASSERT_EQUAL_INT(1, cap.nCall);225 TEST_ASSERT_EQUAL_INT(TK_COLUMN, e.op);226 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, sParse.rc);227 TEST_ASSERT_NOT_NULL(sParse.zErrMsg);228 TEST_ASSERT_NOT_NULL(strstr(sParse.zErrMsg, "authorizer malfunction"));229 230 sqlite3_set_authorizer(db, NULL, NULL);231 sqlite3DbFree(db, sParse.zErrMsg);232 freeSrcList(db, pList);233 freeTestTable(db, pTab);234 sqlite3_close(db);235}236 237/* Test: iColumn < 0 uses PRIMARY KEY name when iPKey>=0 */238void test_sqlite3AuthRead_uses_pk_when_iColumn_neg(void){239 sqlite3 *db = 0;240 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));241 AuthCapture cap = {0};242 cap.ret = SQLITE_OK;243 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));244 245 const char *cols[] = {"id","name"};246 Table *pTab = makeTestTable(db, "T", cols, 2, 0); /* iPKey = column 0 "id" */247 SrcList *pList = makeSrcList1(db, pTab, 9);248 249 Parse sParse; initParse(&sParse, db, "ctx");250 Expr e; memset(&e, 0, sizeof(e));251 e.op = TK_COLUMN;252 e.iTable = 9;253 e.iColumn = -1; /* will resolve to PK column name "id" */254 Schema *pSchema = db->aDb[0].pSchema;255 256 sqlite3AuthRead(&sParse, &e, pSchema, pList);257 258 TEST_ASSERT_EQUAL_INT(1, cap.nCall);259 TEST_ASSERT_EQUAL_STRING("id", cap.a2); /* column argument should be PK name */260 TEST_ASSERT_EQUAL_INT(TK_COLUMN, e.op);261 TEST_ASSERT_EQUAL_INT(0, sParse.rc);262 TEST_ASSERT_NULL(sParse.zErrMsg);263 264 sqlite3_set_authorizer(db, NULL, NULL);265 sqlite3DbFree(db, sParse.zErrMsg);266 freeSrcList(db, pList);267 freeTestTable(db, pTab);268 sqlite3_close(db);269}270 271/* Test: iColumn < 0 and no PK uses "ROWID" */272void test_sqlite3AuthRead_uses_rowid_when_no_pk(void){273 sqlite3 *db = 0;274 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));275 AuthCapture cap = {0};276 cap.ret = SQLITE_OK;277 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));278 279 const char *cols[] = {"c1","c2"};280 Table *pTab = makeTestTable(db, "T", cols, 2, -1); /* no PK */281 SrcList *pList = makeSrcList1(db, pTab, 2);282 283 Parse sParse; initParse(&sParse, db, "ctx");284 Expr e; memset(&e, 0, sizeof(e));285 e.op = TK_COLUMN;286 e.iTable = 2;287 e.iColumn = -1; /* will resolve to "ROWID" */288 Schema *pSchema = db->aDb[0].pSchema;289 290 sqlite3AuthRead(&sParse, &e, pSchema, pList);291 292 TEST_ASSERT_EQUAL_INT(1, cap.nCall);293 TEST_ASSERT_NOT_NULL(cap.a2);294 TEST_ASSERT_EQUAL_INT(0, strcmp(cap.a2, "ROWID"));295 TEST_ASSERT_EQUAL_INT(TK_COLUMN, e.op);296 TEST_ASSERT_EQUAL_INT(0, sParse.rc);297 TEST_ASSERT_NULL(sParse.zErrMsg);298 299 sqlite3_set_authorizer(db, NULL, NULL);300 sqlite3DbFree(db, sParse.zErrMsg);301 freeSrcList(db, pList);302 freeTestTable(db, pTab);303 sqlite3_close(db);304}305 306/* Test: TK_TRIGGER path uses pParse->pTriggerTab and respects IGNORE */307void test_sqlite3AuthRead_trigger_context_ignore_to_null(void){308 sqlite3 *db = 0;309 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));310 AuthCapture cap = {0};311 cap.ret = SQLITE_IGNORE;312 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));313 314 const char *cols[] = {"a","b"};315 Table *pTab = makeTestTable(db, "TrigTab", cols, 2, -1);316 317 Parse sParse; initParse(&sParse, db, "ctx");318 sParse.pTriggerTab = pTab;319 320 Expr e; memset(&e, 0, sizeof(e));321 e.op = TK_TRIGGER;322 e.iColumn = 1; /* "b" */323 Schema *pSchema = db->aDb[0].pSchema;324 325 sqlite3AuthRead(&sParse, &e, pSchema, NULL);326 327 TEST_ASSERT_EQUAL_INT(1, cap.nCall);328 TEST_ASSERT_EQUAL_STRING("TrigTab", cap.a1);329 TEST_ASSERT_EQUAL_STRING("b", cap.a2);330 TEST_ASSERT_EQUAL_INT(TK_NULL, e.op);331 TEST_ASSERT_EQUAL_INT(0, sParse.rc);332 TEST_ASSERT_NULL(sParse.zErrMsg);333 334 sqlite3_set_authorizer(db, NULL, NULL);335 sqlite3DbFree(db, sParse.zErrMsg);336 freeTestTable(db, pTab);337 sqlite3_close(db);338}339 340/* Test: schema not found (iDb<0) -> no authorizer call, no changes */341void test_sqlite3AuthRead_schema_not_found_no_call(void){342 sqlite3 *db = 0;343 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));344 AuthCapture cap = {0};345 cap.ret = SQLITE_OK;346 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));347 348 const char *cols[] = {"x"};349 Table *pTab = makeTestTable(db, "T", cols, 1, -1);350 SrcList *pList = makeSrcList1(db, pTab, 4);351 352 Parse sParse; initParse(&sParse, db, "ctx");353 Expr e; memset(&e, 0, sizeof(e));354 e.op = TK_COLUMN;355 e.iTable = 4;356 e.iColumn = 0;357 358 /* Create a Schema not attached to db so sqlite3SchemaToIndex returns -1 */359 Schema *pFakeSchema = (Schema*)sqlite3DbMallocZero(db, sizeof(Schema));360 TEST_ASSERT_NOT_NULL(pFakeSchema);361 362 sqlite3AuthRead(&sParse, &e, pFakeSchema, pList);363 364 TEST_ASSERT_EQUAL_INT(0, cap.nCall);365 TEST_ASSERT_EQUAL_INT(TK_COLUMN, e.op);366 TEST_ASSERT_EQUAL_INT(0, sParse.rc);367 TEST_ASSERT_NULL(sParse.zErrMsg);368 369 sqlite3_set_authorizer(db, NULL, NULL);370 sqlite3DbFree(db, pFakeSchema);371 sqlite3DbFree(db, sParse.zErrMsg);372 freeSrcList(db, pList);373 freeTestTable(db, pTab);374 sqlite3_close(db);375}376 377/* Test: table not found in SrcList (cursor mismatch) -> no authorizer call */378void test_sqlite3AuthRead_table_not_found_no_call(void){379 sqlite3 *db = 0;380 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));381 AuthCapture cap = {0};382 cap.ret = SQLITE_OK;383 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_set_authorizer(db, testAuth, &cap));384 385 const char *cols[] = {"c1","c2"};386 Table *pTab = makeTestTable(db, "T", cols, 2, -1);387 SrcList *pList = makeSrcList1(db, pTab, 10); /* iCursor=10 */388 389 Parse sParse; initParse(&sParse, db, "ctx");390 Expr e; memset(&e, 0, sizeof(e));391 e.op = TK_COLUMN;392 e.iTable = 11; /* mismatch: no entry with iCursor=11 */393 e.iColumn = 0;394 Schema *pSchema = db->aDb[0].pSchema;395 396 sqlite3AuthRead(&sParse, &e, pSchema, pList);397 398 TEST_ASSERT_EQUAL_INT(0, cap.nCall);399 TEST_ASSERT_EQUAL_INT(TK_COLUMN, e.op);400 TEST_ASSERT_EQUAL_INT(0, sParse.rc);401 TEST_ASSERT_NULL(sParse.zErrMsg);402 403 sqlite3_set_authorizer(db, NULL, NULL);404 sqlite3DbFree(db, sParse.zErrMsg);405 freeSrcList(db, pList);406 freeTestTable(db, pTab);407 sqlite3_close(db);408}409 410int main(void){411 UNITY_BEGIN();412 RUN_TEST(test_sqlite3AuthRead_basic_ok);413 RUN_TEST(test_sqlite3AuthRead_ignore_sets_null);414 RUN_TEST(test_sqlite3AuthRead_deny_sets_parse_error);415 RUN_TEST(test_sqlite3AuthRead_invalid_code_sets_malfunction);416 RUN_TEST(test_sqlite3AuthRead_uses_pk_when_iColumn_neg);417 RUN_TEST(test_sqlite3AuthRead_uses_rowid_when_no_pk);418 RUN_TEST(test_sqlite3AuthRead_trigger_context_ignore_to_null);419 RUN_TEST(test_sqlite3AuthRead_schema_not_found_no_call);420 RUN_TEST(test_sqlite3AuthRead_table_not_found_no_call);421 return UNITY_END();422}