AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Global database handle for tests */6static sqlite3 *gDb = NULL;7 8/* Helper: enter/leave the schema-related mutexes expected by sqlite3SchemaMutexHeld */9static void enterSchemaMutex(sqlite3 *db, int iDb){10 /* db->mutex must be held before entering any Btree mutex */11 sqlite3_mutex_enter(db->mutex);12 if( iDb>=0 && iDb<db->nDb && db->aDb[iDb].pBt ){13 sqlite3BtreeEnter(db->aDb[iDb].pBt);14 }15}16static void leaveSchemaMutex(sqlite3 *db, int iDb){17 if( iDb>=0 && iDb<db->nDb && db->aDb[iDb].pBt ){18 sqlite3BtreeLeave(db->aDb[iDb].pBt);19 }20 sqlite3_mutex_leave(db->mutex);21}22 23/* Helpers to find table/index in schema hash */24static Table* findTable(sqlite3 *db, int iDb, const char *zName){25 Schema *pSchema = db->aDb[iDb].pSchema;26 return (Table*)sqlite3HashFind(&pSchema->tblHash, zName);27}28static Index* findIndex(sqlite3 *db, int iDb, const char *zName){29 Schema *pSchema = db->aDb[iDb].pSchema;30 return (Index*)sqlite3HashFind(&pSchema->idxHash, zName);31}32 33/* Unity setup/teardown */34void setUp(void) {35 int rc = sqlite3_open(":memory:", &gDb);36 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);37 TEST_ASSERT_NOT_NULL(gDb);38}39void tearDown(void) {40 if( gDb ){41 int rc = sqlite3_close(gDb);42 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);43 gDb = NULL;44 }45}46 47/* Test: Remove main schema table with multiple indices */48void test_sqlite3UnlinkAndDeleteTable_removes_table_and_indices_main(void){49 int rc;50 51 rc = sqlite3_exec(gDb, "CREATE TABLE t1(a, b);", 0, 0, 0);52 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);53 rc = sqlite3_exec(gDb, "CREATE INDEX i1 ON t1(a);", 0, 0, 0);54 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);55 rc = sqlite3_exec(gDb, "CREATE INDEX i2 ON t1(b);", 0, 0, 0);56 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);57 58 /* Pre-check under schema mutex */59 enterSchemaMutex(gDb, 0);60 TEST_ASSERT_NOT_NULL(findTable(gDb, 0, "t1"));61 TEST_ASSERT_NOT_NULL(findIndex(gDb, 0, "i1"));62 TEST_ASSERT_NOT_NULL(findIndex(gDb, 0, "i2"));63 64 /* Call function under required mutex */65 sqlite3UnlinkAndDeleteTable(gDb, 0, "t1");66 67 /* Verify removal and DBFLAG_SchemaChange set */68 TEST_ASSERT_NULL(findTable(gDb, 0, "t1"));69 TEST_ASSERT_NULL(findIndex(gDb, 0, "i1"));70 TEST_ASSERT_NULL(findIndex(gDb, 0, "i2"));71 TEST_ASSERT_TRUE( (gDb->mDbFlags & DBFLAG_SchemaChange)!=0 );72 leaveSchemaMutex(gDb, 0);73}74 75/* Test: Non-existent table name should not modify schema, but sets flag */76void test_sqlite3UnlinkAndDeleteTable_nonexistent_table_sets_flag_only(void){77 int rc;78 79 rc = sqlite3_exec(gDb, "CREATE TABLE t3(x);", 0, 0, 0);80 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);81 82 enterSchemaMutex(gDb, 0);83 TEST_ASSERT_NOT_NULL(findTable(gDb, 0, "t3"));84 TEST_ASSERT_NULL(findTable(gDb, 0, "nosuch"));85 86 /* Call for a non-existent table */87 sqlite3UnlinkAndDeleteTable(gDb, 0, "nosuch");88 89 /* Ensure existing table unchanged and flag set */90 TEST_ASSERT_NOT_NULL(findTable(gDb, 0, "t3"));91 TEST_ASSERT_TRUE( (gDb->mDbFlags & DBFLAG_SchemaChange)!=0 );92 leaveSchemaMutex(gDb, 0);93}94 95/* Test: Remove TEMP schema table and index (iDb=1) */96void test_sqlite3UnlinkAndDeleteTable_removes_temp_table_and_index(void){97 int rc;98 99 rc = sqlite3_exec(gDb, "CREATE TEMP TABLE tt(a);", 0, 0, 0);100 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101 rc = sqlite3_exec(gDb, "CREATE INDEX ii ON tt(a);", 0, 0, 0);102 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);103 104 /* Ensure TEMP schema was initialized */105 TEST_ASSERT_TRUE(gDb->nDb>=2);106 TEST_ASSERT_NOT_NULL(gDb->aDb[1].pSchema);107 108 enterSchemaMutex(gDb, 1);109 TEST_ASSERT_NOT_NULL(findTable(gDb, 1, "tt"));110 TEST_ASSERT_NOT_NULL(findIndex(gDb, 1, "ii"));111 112 sqlite3UnlinkAndDeleteTable(gDb, 1, "tt");113 114 TEST_ASSERT_NULL(findTable(gDb, 1, "tt"));115 TEST_ASSERT_NULL(findIndex(gDb, 1, "ii"));116 TEST_ASSERT_TRUE( (gDb->mDbFlags & DBFLAG_SchemaChange)!=0 );117 leaveSchemaMutex(gDb, 1);118}119 120/* Test: Zero-length table name (allowed by function's testcase), should be no-op but set flag */121void test_sqlite3UnlinkAndDeleteTable_zero_length_name_noop_sets_flag(void){122 /* Ensure mDbFlags starts clear for this connection */123 TEST_ASSERT_TRUE( (gDb->mDbFlags & DBFLAG_SchemaChange)==0 );124 125 enterSchemaMutex(gDb, 0);126 /* This should not crash or modify schema; it simply attempts to remove empty-name key */127 sqlite3UnlinkAndDeleteTable(gDb, 0, "");128 TEST_ASSERT_TRUE( (gDb->mDbFlags & DBFLAG_SchemaChange)!=0 );129 leaveSchemaMutex(gDb, 0);130}131 132int main(void) {133 UNITY_BEGIN();134 RUN_TEST(test_sqlite3UnlinkAndDeleteTable_removes_table_and_indices_main);135 RUN_TEST(test_sqlite3UnlinkAndDeleteTable_nonexistent_table_sets_flag_only);136 RUN_TEST(test_sqlite3UnlinkAndDeleteTable_removes_temp_table_and_index);137 RUN_TEST(test_sqlite3UnlinkAndDeleteTable_zero_length_name_noop_sets_flag);138 return UNITY_END();139}