diff --git a/site/doc/pages/mysql_connect.txt b/site/doc/pages/mysql_connect.txt index 087c4d5..6a4538c 100644 --- a/site/doc/pages/mysql_connect.txt +++ b/site/doc/pages/mysql_connect.txt @@ -15,6 +15,8 @@ Establishes a connection to a MySQL server and returns a pointer to the connecti This connection handle is then used with helpers such as `mysql_query()`, `mysql_error()`, and `mysql_disconnect()`. +MySQL handles are request-scoped framework resources. If a request exits without calling `mysql_disconnect()`, UCE closes any remaining MySQL handles during request cleanup. Call `mysql_disconnect()` when you want to close early, but never store a `MySQL*` in globals, sessions, or other state that can outlive the current request. + :example MySQL* db = mysql_connect(); print(db != 0 ? "connected to MySQL" : "no MySQL server reachable with these credentials", "\n"); diff --git a/site/doc/pages/mysql_disconnect.txt b/site/doc/pages/mysql_disconnect.txt index a3b657f..ecddfa8 100644 --- a/site/doc/pages/mysql_disconnect.txt +++ b/site/doc/pages/mysql_disconnect.txt @@ -10,7 +10,7 @@ m : pointer to an existing MySQL connection struct :content Closes an existing connection to a MySQL server. -Call this when you are done using a `MySQL*` connection handle. +Call this when you want to release a `MySQL*` connection handle before the request ends. UCE also closes any remaining MySQL handles automatically during request cleanup, including handles skipped by exceptions or fatal request recovery. A `MySQL*` is only valid inside the request that opened it; do not cache it across requests. :example MySQL* db = mysql_connect(); diff --git a/src/lib/mysql-connector.cpp b/src/lib/mysql-connector.cpp index 6998044..0fe8797 100644 --- a/src/lib/mysql-connector.cpp +++ b/src/lib/mysql-connector.cpp @@ -3,6 +3,10 @@ #include #include "mysql-connector.h" +// MySQL handles are request-scoped framework resources. User code may call +// mysql_disconnect() to close early, but leaked/exception-skipped handles are +// still closed by cleanup_mysql_connections() at request end. Handles must not +// be cached across requests or stored in globals/sessions. static void mysql_register_request_connection(MySQL* db) { if(!context || !db) diff --git a/src/lib/mysql-connector.h b/src/lib/mysql-connector.h index c1e778b..d37c84b 100644 --- a/src/lib/mysql-connector.h +++ b/src/lib/mysql-connector.h @@ -33,8 +33,10 @@ struct MySQL { DValue query(String q, StringMap params); DValue get_pending_result(); - // Unregisters from the request's connection tracking, so stack-allocated - // instances cannot leave dangling pointers behind for request cleanup. + // Unregisters from request connection tracking, so stack-allocated instances + // cannot leave dangling pointers behind for request cleanup. Heap handles + // returned by mysql_connect() are also request-owned and auto-closed at the + // end of the request if user code does not call mysql_disconnect() first. ~MySQL() { disconnect(); } }; diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index c85ebf1..206c72b 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -799,7 +799,9 @@ public: #ifdef UCE_WASM_HOST_CONNECTORS // Host-owned resource handle table (ยง3.1): connections opened by the guest - // live here and are closed when the workspace drops at request end. + // live here and are closed when the workspace drops at request end. This is + // the wasm-side enforcement of request-scoped DB lifecycle; app code should + // never cache these opaque handles across requests. std::vector sqlite_handles; std::vector mysql_handles; #endif