AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <stdlib.h>6#include <string.h>7 8/* Helper to execute SQL and assert success */9static void exec_ok(sqlite3 *db, const char *sql){10 char *zErr = 0;11 int rc = sqlite3_exec(db, sql, 0, 0, &zErr);12 if( rc!=SQLITE_OK ){13 fprintf(stderr, "SQL error (%d): %s\nSQL: %s\n", rc, zErr ? zErr : "(null)", sql);14 }15 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "exec_ok failed");16 if( zErr ) sqlite3_free(zErr);17}18 19void setUp(void) {20 /* Setup code here, or leave empty */21}22 23void tearDown(void) {24 /* Cleanup code here, or leave empty */25}26 27/* Test that sqlite3Reprepare succeeds and transfers bindings from the old stmt */28void test_sqlite3Reprepare_success_transfers_bindings(void){29 sqlite3 *db = 0;30 sqlite3_stmt *stmt = 0;31 int rc;32 33 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));34 35 /* Prepare a simple statement with parameters */36 rc = sqlite3_prepare_v2(db, "SELECT ?1 + ?2", -1, &stmt, 0);37 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);38 TEST_ASSERT_NOT_NULL(stmt);39 40 /* Bind values */41 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_bind_int(stmt, 1, 7));42 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_bind_int(stmt, 2, 5));43 44 /* Call sqlite3Reprepare with db mutex held to satisfy internal assert */45 sqlite3_mutex_enter(db->mutex);46 rc = sqlite3Reprepare((Vdbe*)stmt);47 sqlite3_mutex_leave(db->mutex);48 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);49 50 /* Step the statement and verify result; bindings should be preserved */51 rc = sqlite3_step(stmt);52 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);53 TEST_ASSERT_EQUAL_INT(12, sqlite3_column_int(stmt, 0));54 rc = sqlite3_step(stmt);55 TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc);56 57 sqlite3_finalize(stmt);58 sqlite3_close(db);59}60 61/* Test that sqlite3Reprepare returns SQLITE_LOCKED when the schema is locked by another connection */62void test_sqlite3Reprepare_schema_locked_returns_locked(void){63 const char *dbFile = "test_reprepare_locked.sqlite";64 sqlite3 *db1 = 0;65 sqlite3 *db2 = 0;66 sqlite3_stmt *stmt = 0;67 int rc;68 69 /* Ensure clean start */70 remove(dbFile);71 72 /* Open two connections to the same on-disk database */73 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(dbFile, &db1));74 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(dbFile, &db2));75 76 /* Create an initial table so the database and schema exist */77 exec_ok(db1, "CREATE TABLE IF NOT EXISTS t0(x)");78 79 /* Prepare a trivial statement on db1 (does not reference schema itself) */80 rc = sqlite3_prepare_v2(db1, "SELECT ?1", -1, &stmt, 0);81 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);82 TEST_ASSERT_NOT_NULL(stmt);83 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_bind_int(stmt, 1, 123));84 85 /* In db2, begin an exclusive transaction and perform a schema change, leaving txn open */86 exec_ok(db2, "BEGIN EXCLUSIVE");87 exec_ok(db2, "CREATE TABLE t_lock(y)");88 89 /* Now attempt to reprepare on db1: should detect schema lock and return SQLITE_LOCKED */90 sqlite3_mutex_enter(db1->mutex);91 rc = sqlite3Reprepare((Vdbe*)stmt);92 sqlite3_mutex_leave(db1->mutex);93 94 TEST_ASSERT_EQUAL_INT(SQLITE_LOCKED, rc);95 96 /* Cleanup: rollback db2, finalize/close everything */97 exec_ok(db2, "ROLLBACK");98 sqlite3_finalize(stmt);99 sqlite3_close(db2);100 sqlite3_close(db1);101 102 /* Remove the test db file */103 remove(dbFile);104}105 106/* Test that sqlite3Reprepare returns an error when the SQL becomes invalid after a schema change */107void test_sqlite3Reprepare_invalid_sql_returns_error(void){108 sqlite3 *db = 0;109 sqlite3_stmt *stmt = 0;110 int rc;111 112 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));113 114 /* Create table and prepare a statement that references it */115 exec_ok(db, "CREATE TABLE t(a)");116 rc = sqlite3_prepare_v2(db, "SELECT a FROM t", -1, &stmt, 0);117 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);118 TEST_ASSERT_NOT_NULL(stmt);119 120 /* Drop the table so the SQL becomes invalid */121 exec_ok(db, "DROP TABLE t");122 123 /* Reprepare should now fail due to invalid SQL (no such table) */124 sqlite3_mutex_enter(db->mutex);125 rc = sqlite3Reprepare((Vdbe*)stmt);126 sqlite3_mutex_leave(db->mutex);127 128 /* Expect a non-OK error; per current code path, this is SQLITE_ERROR */129 TEST_ASSERT_NOT_EQUAL_INT(SQLITE_OK, rc);130 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);131 132 sqlite3_finalize(stmt);133 sqlite3_close(db);134}135 136int main(void){137 UNITY_BEGIN();138 139 RUN_TEST(test_sqlite3Reprepare_success_transfers_bindings);140 RUN_TEST(test_sqlite3Reprepare_schema_locked_returns_locked);141 RUN_TEST(test_sqlite3Reprepare_invalid_sql_returns_error);142 143 return UNITY_END();144}