Revision history for DBIO-MySQL-EV

0.900001  2026-07-12

    * Storage
        - DBIO::MySQL::EV::Storage becomes a thin transport over the shared
          core Model-B machinery (720 -> 623 lines, ~208 code lines / 22
          subs): select_async/…/delete_async, _run_crud, txn_do_async, the
          sync fallbacks, _generate_sql, sql_maker, new, schema/debug/
          connected/disconnect/DESTROY, pipeline and the prepared-statement
          cache are all deleted and now inherited from core
          DBIO::Storage::Async (coderef-identity asserted in tests). What's
          kept is genuine MySQL value-add: _transform_sql as identity
          (MySQL speaks '?' natively, no ?->$N rewrite; applied first in
          the query seams to keep the core '?'-seam contract uniform),
          insert_async/_run_crud_pinned(insert) (no RETURNING, so INSERT +
          SELECT LAST_INSERT_ID() ride the same pinned session and the LII
          folds onto the auto-increment column), and
          _normalize_async_connect_info (dbname -> database). pool()
          now passes storage => $self so core's _setup_pool_connection
          fires on_connect_do/on_connect_call replay for every spawned EV
          pool connection (_run_pool_connect_statement drives it
          synchronously on the EV::MariaDB handle). transport_capabilities
          is (on_connect_replay) only -- no LISTEN/NOTIFY/COPY; pipeline is
          not claimed as a capability (EV::MariaDB pipelines automatically
          at the wire with no explicit-mode API to map onto the base
          seams). karr #18, #19, core #70.

    * Bugfixes
        - AccessBroker::Credentials was removed from core (split into
          ::Static for single-identity and DBIO::Replicated for routing); a
          stale local copy had masked the break, so a fresh install/smoker
          hit "Can't locate DBIO/AccessBroker/Credentials.pm". Switched the
          test to ::Static, mirroring the dbio-postgresql fix. karr #10.
        - The async path retained bind values on the in-flight bind
          arrayref after a query's Future completed (the sync path clears
          them once execute() returns), causing a re-issued query on the
          same handle to see stale binds while a prior future was pending,
          and memory growth proportional to total binds ever issued rather
          than outstanding queries. Bind values are now cleared in the
          completion handler (fires on both done and fail), never on the
          issuing side (which would corrupt a still-pending query's
          binds). Per CurtisPoe architecture review #5, karr #11.
        - Three driver bugs surfaced by the first end-to-end test driving
          the real DBIO facade through EV::MariaDB + EV::run (the
          mock-based suite only ever proved the Future API shape, never
          that the driver works against a live DB): Storage.pm's pool()
          was missing a lazy require for QueryExecutor (fired "Can't
          locate object method 'new'" on first use); txn_do_async held its
          coderef Future only weakly via a bare ->then->catch chain, so it
          could be GC'd before BEGIN's callback fired, silently hanging any
          EV::run-based wait loop -- fixed with ->retain, mirroring the
          dbio-postgresql-async fix; and QueryExecutor's execute() passed a
          bind arrayref to $mdb->query, which silently ignores it, so
          bound queries either threw a syntax error or ran with stale
          binds from the previous prepared statement -- now routed through
          prepare+execute whenever binds are non-empty. txn_do_async's
          on_fail also now surfaces a ROLLBACK failure as a wrapped error
          instead of dropping it silently.
        - Fix PRODUCTION BUG: the first bound async query on a cold pool
          connection died 'not connected' (karr #20). DBIO::MySQL::EV::Pool
          wired on_connect => sub {} -- a pure no-op -- so it never tracked
          connection readiness; core DBIO::Storage::PoolBase's
          connection-readiness gate (karr #75) had nothing to wait on.
          _create_connection now registers a real per-connection readiness
          Future (core _register_connection_ready) resolved from
          EV::MariaDB's on_connect/on_error, and a new
          _connection_ready_future override looks it up -- mirroring
          dbio-postgresql-ev's karr #9 fix. New offline regression test
          t/08-pool-readiness.t (mirrors PG's t/04). Closes karr #19's
          leftover gap.
    * Async opt-in via { async => 'ev' } (ADR 0030, karr #14)
        - Dropped the connection()/storage_type hijack in DBIO::MySQL::EV.
          Loading the MySQL::EV component is now an inert marker; the EV
          backend is reached explicitly through
          MyApp::Schema->connect($dsn, $u, $p, { async => 'ev' }), which
          resolves the 'ev' mode via DBIO::MySQL::Storage's mode registry
          (the registration is its own karr ticket on the dbio-mysql
          board). PostgreSQL's DBIO::PostgreSQL::EV has no such override
          either; this brings MySQL to parity.
    * insert_async resolves with the returned-columns HASHREF (ADR 0031 §3)
        - MySQL has no RETURNING clause; the EV storage reads
          SELECT LAST_INSERT_ID() on the pinned connection and assembles
          the hashref = { %to_insert, $col => $lii_id } via the new
          _insert_returned_columns hook (overrides the inherited
          RETURNING-row -> hashref default). $col is the source's first
          is_auto_increment column, falling back to the first PK column
          not supplied in %to_insert. The legacy ->last_insert_id
          side-effect is preserved. create_async / Row::insert_async
          fold the hashref back via _store_inserted_columns.
    * select_async / select_single_async shapes (ADR 0031 §3)
        - select_async resolves with the raw row arrayrefs (cursor ->all
          shape) and select_single_async with a single row arrayref,
          matching the sync cursor shape and what _inflate_fetched_rows /
          _construct_results consume.
    * Future then auto-wrap (ADR 0031 §4)
        - The backend Future is plain Future (perl-Future), whose ->then
          natively auto-wraps a plain return into a resolved Future --
          compliance is transitive. Documented in POD and verified by
          t/storage-facade-mock.t.

    * Packaging
        - Renamed distribution DBIO-MySQL-Async to DBIO-MySQL-EV and namespace
          DBIO::MySQL::Async to DBIO::MySQL::EV. The EV::MariaDB driver is
          hard-wired to the EV event loop; the DBIO::MySQL::Async namespace is
          freed for a future loop-agnostic driver built on DBIO::Async::Storage.
          CPAN namespace migration — the old distribution stays on CPAN. No
          behaviour change.

    * Tests
        - Add maint/k8s/mysql-pod.yaml (mysql:8.0, mysql_native_password
          forced so the libmariadb-based clients authenticate over a plain
          port-forward) for live integration testing, and
          DBIO::MySQL::EV::TestHarness (installable, gated on
          DBIO_TEST_MYSQL_DSN, mirrors the PostgreSQL-EV harness API).
        - Fixed test/harness-only bugs surfaced on the first live run
          (no production runtime change): PoolBase::acquire can hand off
          an EV::MariaDB handle before its async connect completes when no
          on_connect action is configured, so pooled-connection tests now
          wait for readiness explicitly (_await_connected) or warm the
          pool first; a live SELECT used an invalid bare '*' after a named
          select-expression and a plain-string column alias that got
          backtick-quoted into an unknown column; and a broker test now
          asserts the achievable truth (broker attaches to the sync
          storage; a schema-level connect() cannot select an async mode
          and attach a broker at the same time). karr #19, #21.

    * Dependencies
        - Requires core DBIO >= 0.900001 (family-wide version alignment)

    * Project
        - Added SECURITY.md (CPAN Security Group guidelines v1.5.0)

0.900000  2026-06-23
    First release. Future-based async MySQL/MariaDB storage for DBIO via EV::MariaDB.

    * Storage
        - DBIO::MySQL::Async::Storage on DBIO::Storage::Async, speaking the
          MariaDB C client directly through EV::MariaDB (no DBI / DBD::mysql)
        - Async select/insert/update/delete returning Future objects
        - Sync fallback (->all, ->first, ...) via blocking ->get on the Future

    * Transactions
        - txn_do_async driving the BEGIN/COMMIT/ROLLBACK chain
        - TransactionContext pinning one pooled connection for the txn duration

    * Pipelining
        - Pipeline mode batching queries into a single network round-trip,
          up to 64 in-flight

    * Connection pool
        - Connection pool with transaction pinning, built on
          DBIO::Storage::PoolBase

    * AccessBroker
        - Accept AccessBroker objects via Schema->connect($broker)
        - Refresh async conninfo through the broker for newly created
          pooled connections