AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdio.h>6 7static void exec_ok(sqlite3 *db, const char *sql){8 char *zErr = 0;9 int rc = sqlite3_exec(db, sql, 0, 0, &zErr);10 if( rc!=SQLITE_OK ){11 fprintf(stderr, "SQL error: rc=%d, msg=%s, sql=%s\n", rc, zErr ? zErr : "(null)", sql);12 }13 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);14 if( zErr ) sqlite3_free(zErr);15}16 17static void get_schema_counts(sqlite3 *db, int iDb, int *pTbl, int *pIdx, int *pTrig){18 Schema *pSchema = db->aDb[iDb].pSchema;19 TEST_ASSERT_NOT_NULL(pSchema);20 if( pTbl ) *pTbl = sqlite3HashCount(&pSchema->tblHash);21 if( pIdx ) *pIdx = sqlite3HashCount(&pSchema->idxHash);22 if( pTrig ) *pTrig = sqlite3HashCount(&pSchema->trigHash);23}24 25static void populate_main_and_temp(sqlite3 *db){26 exec_ok(db, "CREATE TABLE main.t1(x);");27 exec_ok(db, "CREATE TEMP TABLE tt(y);");28}29 30void setUp(void) {31 /* Setup per-test if needed */32}33 34void tearDown(void) {35 /* Cleanup per-test if needed */36}37 38/* Test: Immediate clearing when nSchemaLock == 0, for main (iDb=0) and temp (iDb=1). */39void test_sqlite3ResetOneSchema_immediate_clear_main_and_temp(void){40 sqlite3 *db = 0;41 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));42 TEST_ASSERT_NOT_NULL(db);43 44 populate_main_and_temp(db);45 46 int mainTblBefore=0, tempTblBefore=0;47 get_schema_counts(db, 0, &mainTblBefore, 0, 0);48 get_schema_counts(db, 1, &tempTblBefore, 0, 0);49 TEST_ASSERT_TRUE(mainTblBefore > 0);50 TEST_ASSERT_TRUE(tempTblBefore > 0);51 52 /* Set SchemaKnownOk to ensure it is cleared by the function */53 db->mDbFlags |= DBFLAG_SchemaKnownOk;54 55 /* Ensure no schema lock so clearing runs immediately */56 db->nSchemaLock = 0;57 58 /* Enter necessary mutexes to satisfy potential debug asserts */59 if( db->mutex ) sqlite3_mutex_enter(db->mutex);60 sqlite3BtreeEnterAll(db);61 62 sqlite3ResetOneSchema(db, 0);63 64 sqlite3BtreeLeaveAll(db);65 if( db->mutex ) sqlite3_mutex_leave(db->mutex);66 67 /* Verify flags were set for main and temp */68 TEST_ASSERT_TRUE(DbHasProperty(db, 0, DB_ResetWanted));69 TEST_ASSERT_TRUE(DbHasProperty(db, 1, DB_ResetWanted));70 71 /* Verify DBFLAG_SchemaKnownOk cleared */72 TEST_ASSERT_TRUE((db->mDbFlags & DBFLAG_SchemaKnownOk) == 0);73 74 /* Verify schemas cleared */75 int mainTblAfter=0, tempTblAfter=0;76 get_schema_counts(db, 0, &mainTblAfter, 0, 0);77 get_schema_counts(db, 1, &tempTblAfter, 0, 0);78 TEST_ASSERT_EQUAL_INT(0, mainTblAfter);79 TEST_ASSERT_EQUAL_INT(0, tempTblAfter);80 81 sqlite3_close(db);82}83 84/* Test: Deferred clearing when nSchemaLock > 0, then run with iDb<0 to perform deferred resets. */85void test_sqlite3ResetOneSchema_deferred_then_run(void){86 sqlite3 *db = 0;87 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));88 TEST_ASSERT_NOT_NULL(db);89 90 populate_main_and_temp(db);91 92 int mainTblBefore=0, tempTblBefore=0;93 get_schema_counts(db, 0, &mainTblBefore, 0, 0);94 get_schema_counts(db, 1, &tempTblBefore, 0, 0);95 TEST_ASSERT_TRUE(mainTblBefore > 0);96 TEST_ASSERT_TRUE(tempTblBefore > 0);97 98 /* Take a schema lock so clearing is deferred */99 db->nSchemaLock = 1;100 101 if( db->mutex ) sqlite3_mutex_enter(db->mutex);102 sqlite3BtreeEnterAll(db);103 104 sqlite3ResetOneSchema(db, 0);105 106 sqlite3BtreeLeaveAll(db);107 if( db->mutex ) sqlite3_mutex_leave(db->mutex);108 109 /* Verify schemas NOT cleared yet */110 int mainTblMid=0, tempTblMid=0;111 get_schema_counts(db, 0, &mainTblMid, 0, 0);112 get_schema_counts(db, 1, &tempTblMid, 0, 0);113 TEST_ASSERT_EQUAL_INT(mainTblBefore, mainTblMid);114 TEST_ASSERT_EQUAL_INT(tempTblBefore, tempTblMid);115 116 /* Flags should be set */117 TEST_ASSERT_TRUE(DbHasProperty(db, 0, DB_ResetWanted));118 TEST_ASSERT_TRUE(DbHasProperty(db, 1, DB_ResetWanted));119 120 /* Now drop lock and run with iDb<0 to process deferred clears */121 db->nSchemaLock = 0;122 sqlite3ResetOneSchema(db, -1);123 124 int mainTblAfter=0, tempTblAfter=0;125 get_schema_counts(db, 0, &mainTblAfter, 0, 0);126 get_schema_counts(db, 1, &tempTblAfter, 0, 0);127 TEST_ASSERT_EQUAL_INT(0, mainTblAfter);128 TEST_ASSERT_EQUAL_INT(0, tempTblAfter);129 130 sqlite3_close(db);131}132 133/* Test: Calling with iDb<0 does not set DB_ResetWanted and thus does nothing if nothing marked. */134void test_sqlite3ResetOneSchema_negative_noop_without_marks(void){135 sqlite3 *db = 0;136 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));137 TEST_ASSERT_NOT_NULL(db);138 139 populate_main_and_temp(db);140 141 int mainTblBefore=0, tempTblBefore=0;142 get_schema_counts(db, 0, &mainTblBefore, 0, 0);143 get_schema_counts(db, 1, &tempTblBefore, 0, 0);144 TEST_ASSERT_TRUE(mainTblBefore > 0);145 TEST_ASSERT_TRUE(tempTblBefore > 0);146 147 /* Ensure no marks are set; explicitly clear if they were */148 db->aDb[0].mDbFlags &= ~DB_ResetWanted;149 db->aDb[1].mDbFlags &= ~DB_ResetWanted;150 db->nSchemaLock = 0;151 152 sqlite3ResetOneSchema(db, -1);153 154 int mainTblAfter=0, tempTblAfter=0;155 get_schema_counts(db, 0, &mainTblAfter, 0, 0);156 get_schema_counts(db, 1, &tempTblAfter, 0, 0);157 158 /* Should remain unchanged */159 TEST_ASSERT_EQUAL_INT(mainTblBefore, mainTblAfter);160 TEST_ASSERT_EQUAL_INT(tempTblBefore, tempTblAfter);161 162 /* And no flags should be set */163 TEST_ASSERT_FALSE(DbHasProperty(db, 0, DB_ResetWanted));164 TEST_ASSERT_FALSE(DbHasProperty(db, 1, DB_ResetWanted));165 166 sqlite3_close(db);167}168 169/* Test: When iDb==1 (TEMP), only the TEMP schema is marked and cleared. */170void test_sqlite3ResetOneSchema_temp_only_when_iDb_is_1(void){171 sqlite3 *db = 0;172 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));173 TEST_ASSERT_NOT_NULL(db);174 175 populate_main_and_temp(db);176 177 int mainTblBefore=0, tempTblBefore=0;178 get_schema_counts(db, 0, &mainTblBefore, 0, 0);179 get_schema_counts(db, 1, &tempTblBefore, 0, 0);180 TEST_ASSERT_TRUE(mainTblBefore > 0);181 TEST_ASSERT_TRUE(tempTblBefore > 0);182 183 db->nSchemaLock = 0;184 185 if( db->mutex ) sqlite3_mutex_enter(db->mutex);186 sqlite3BtreeEnterAll(db);187 188 sqlite3ResetOneSchema(db, 1); /* iDb==1 refers to TEMP */189 190 sqlite3BtreeLeaveAll(db);191 if( db->mutex ) sqlite3_mutex_leave(db->mutex);192 193 /* TEMP should be cleared; MAIN should remain populated */194 int mainTblAfter=0, tempTblAfter=0;195 get_schema_counts(db, 0, &mainTblAfter, 0, 0);196 get_schema_counts(db, 1, &tempTblAfter, 0, 0);197 198 TEST_ASSERT_TRUE(mainTblAfter > 0);199 TEST_ASSERT_EQUAL_INT(0, tempTblAfter);200 201 /* Flags: TEMP marked, MAIN not marked by this call (only iDb==1) */202 TEST_ASSERT_FALSE(DbHasProperty(db, 0, DB_ResetWanted));203 TEST_ASSERT_TRUE(DbHasProperty(db, 1, DB_ResetWanted));204 205 sqlite3_close(db);206}207 208int main(void){209 UNITY_BEGIN();210 RUN_TEST(test_sqlite3ResetOneSchema_immediate_clear_main_and_temp);211 RUN_TEST(test_sqlite3ResetOneSchema_deferred_then_run);212 RUN_TEST(test_sqlite3ResetOneSchema_negative_noop_without_marks);213 RUN_TEST(test_sqlite3ResetOneSchema_temp_only_when_iDb_is_1);214 return UNITY_END();215}