AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <string.h>5 6/* Unity setup/teardown */7void setUp(void) {8 /* Setup code here, or leave empty */9}10void tearDown(void) {11 /* Cleanup code here, or leave empty */12}13 14/* Helper to open an in-memory database and assert success */15static sqlite3* open_in_memory_db(void){16 sqlite3 *db = NULL;17 int rc = sqlite3_open(":memory:", &db);18 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open(:memory:) failed");19 TEST_ASSERT_NOT_NULL(db);20 return db;21}22 23/* Helper to close db safely */24static void close_db(sqlite3 *db){25 if( db ){26 int rc = sqlite3_close(db);27 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_close failed");28 }29}30 31/* Test: No-op when db->init.busy is non-zero */32void test_sqlite3ReadSchema_noop_when_busy(void){33 sqlite3 *db = open_in_memory_db();34 Parse pParse;35 memset(&pParse, 0, sizeof(pParse));36 pParse.db = db;37 38 /* Force busy to non-zero to take the no-op path */39 db->init.busy = 1;40 41 /* Snapshot flags to ensure no change */42 u32 preFlags = db->mDbFlags;43 44 /* Must hold the connection mutex to satisfy assert in sqlite3ReadSchema */45 sqlite3_mutex_enter(db->mutex);46 int rc = sqlite3ReadSchema(&pParse);47 sqlite3_mutex_leave(db->mutex);48 49 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);50 TEST_ASSERT_EQUAL_UINT32(preFlags, db->mDbFlags);51 TEST_ASSERT_EQUAL_INT(0, pParse.nErr);52 TEST_ASSERT_EQUAL_INT(0, pParse.rc);53 TEST_ASSERT_EQUAL_PTR(NULL, pParse.zErrMsg);54 55 close_db(db);56}57 58/* Test: On successful init with noSharedCache!=0, DBFLAG_SchemaKnownOk is set */59void test_sqlite3ReadSchema_sets_flag_on_success_when_noSharedCache(void){60 sqlite3 *db = open_in_memory_db();61 Parse pParse;62 memset(&pParse, 0, sizeof(pParse));63 pParse.db = db;64 65 /* Ensure we are in the path that calls sqlite3Init */66 db->init.busy = 0;67 68 /* Force noSharedCache true so the flag will be set on success */69 db->noSharedCache = 1;70 71 /* Clear the KnownOk flag before calling */72 db->mDbFlags &= ~DBFLAG_SchemaKnownOk;73 74 /* Hold both the connection mutex and all btree mutexes to satisfy asserts */75 sqlite3_mutex_enter(db->mutex);76 sqlite3BtreeEnterAll(db);77 int rc = sqlite3ReadSchema(&pParse);78 sqlite3BtreeLeaveAll(db);79 sqlite3_mutex_leave(db->mutex);80 81 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);82 TEST_ASSERT_EQUAL_INT(0, pParse.nErr);83 TEST_ASSERT_EQUAL_INT(0, pParse.rc);84 TEST_ASSERT_NOT_EQUAL(0, db->mDbFlags & DBFLAG_SchemaKnownOk);85 86 close_db(db);87}88 89/* Test: Error from sqlite3Init is propagated; pParse.rc and pParse.nErr updated */90void test_sqlite3ReadSchema_error_path_sets_parse_rc_and_nErr(void){91 sqlite3 *db = open_in_memory_db();92 char *errmsg = NULL;93 int rc;94 95 /* Enable writable_schema to inject a bogus trigger into sqlite_master */96 rc = sqlite3_exec(db, "PRAGMA writable_schema=ON;", 0, 0, &errmsg);97 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, errmsg ? errmsg : "PRAGMA writable_schema=ON failed");98 if( errmsg ){ sqlite3_free(errmsg); errmsg = NULL; }99 100 /* Create a simple table (target of the bogus trigger) */101 rc = sqlite3_exec(db, "CREATE TABLE t0(x);", 0, 0, &errmsg);102 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, errmsg ? errmsg : "CREATE TABLE t0 failed");103 if( errmsg ){ sqlite3_free(errmsg); errmsg = NULL; }104 105 /* Inject a trigger with invalid SQL in the body to ensure schema load fails */106 rc = sqlite3_exec(107 db,108 "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql) "109 "VALUES('trigger','tr_bad','t0',0,"110 "'CREATE TRIGGER tr_bad AFTER INSERT ON t0 BEGIN this is invalid SQL; END;');",111 0, 0, &errmsg112 );113 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, errmsg ? errmsg : "INSERT into sqlite_master failed");114 if( errmsg ){ sqlite3_free(errmsg); errmsg = NULL; }115 116 /* Force schema reload on next read */117 sqlite3ResetAllSchemasOfConnection(db);118 119 Parse pParse;120 memset(&pParse, 0, sizeof(pParse));121 pParse.db = db;122 123 /* Ensure we go through sqlite3Init (not busy) */124 db->init.busy = 0;125 126 /* Hold required mutexes to satisfy asserts during sqlite3Init */127 sqlite3_mutex_enter(db->mutex);128 sqlite3BtreeEnterAll(db);129 int readRc = sqlite3ReadSchema(&pParse);130 sqlite3BtreeLeaveAll(db);131 sqlite3_mutex_leave(db->mutex);132 133 TEST_ASSERT_NOT_EQUAL_MESSAGE(SQLITE_OK, readRc, "Expected schema load to fail due to invalid trigger SQL");134 TEST_ASSERT_EQUAL_INT(readRc, pParse.rc);135 TEST_ASSERT_EQUAL_INT(1, pParse.nErr);136 TEST_ASSERT_NOT_NULL(pParse.zErrMsg);137 138 /* Cleanup parse error message if set */139 if( pParse.zErrMsg ){140 sqlite3DbFree(db, pParse.zErrMsg);141 pParse.zErrMsg = NULL;142 }143 144 close_db(db);145}146 147/* Unity main */148int main(void){149 UNITY_BEGIN();150 RUN_TEST(test_sqlite3ReadSchema_noop_when_busy);151 RUN_TEST(test_sqlite3ReadSchema_sets_flag_on_success_when_noSharedCache);152 RUN_TEST(test_sqlite3ReadSchema_error_path_sets_parse_rc_and_nErr);153 return UNITY_END();154}