Revision history for DBIx-Fast 0.19 2026-09-28 - Typed exceptions (DBIx::Fast::X::Duplicate, ::Deadlock, ...); same text - Every module has $VERSION; META provides (kwalitee all green) - Changes in CPAN::Changes format; README regenerated from the POD - examples/errors-and-reads.pl: 0.18 error handling and read helpers - Every module: =encoding utf8, SYNOPSIS and SEE ALSO (enforced by a test) - META homepage and license URL; CONTRIBUTING.md - examples/benchmark-json.pl: Cpanel::JSON::XS vs JSON::PP - Fork safety: a forked child no longer drops the parent's MariaDB connection (DBD::MariaDB 1.24 disconnect_all bug, upstream PR #175) - Optional POSIX::AtFork: fork check without getpid() (reads ~10% faster) - Fix: MariaDB/MySQL analyze_indexes() never ran on a real server (reserved alias `reads`, ONLY_FULL_GROUP_BY, missing sql_text column) 0.18 2026-09-28 - CRUD: stricter WHERE/data validation (SQL::Abstract raw-SQL operators) - CRUD: statement cache for insert/update/delete/upsert (~10x faster) - upsert/insert_many/upsert_many: reject unbindable references - txn(): works with AutoCommit => 0 - DSN: keep user without password; percent-decoding; reject ';' in parts - load_extension(): only accepts module names - MariaDB profiler: EXPLAIN runs with max_statement_time - Pg schema: table_info/get_indexes are schema-aware - Docs: insert_many last_id is driver-dependent - Errors record the failing sql and binds (redacted with errors_redact) - on_error callback; error_mark/errors_since to scope errors - Exception text without timestamp (groupable in logs) - strict_reads: failed reads throw even with RaiseError => 0 - RaiseError => 0: a read whose prepare fails returns empty (no crash) - rows: affected rows of the last write - exists(), kv(), all_by() helpers - on_connect_sql: session SQL re-applied on every reconnect 0.17 2026-08-20 - DSN parsing is more accepting (strictly additive - no DSN that worked before changes): the native "dbi:..." prefix is case-insensitive; "dbi:SQLite::memory:" and other DSNs whose driver-specific part contains colons are no longer rejected; and a credential-less URI ("mariadb://localhost/db", socket / peer auth) is accepted. Verified byte-identical output for every previously-valid DSN. - The vestigial "quote" constructor option no longer runs a dead $dbh->quote() no-op on connect; it is still accepted (and stored in args) for backward compatibility but has no effect - identifier quoting is automatic and driver-aware. - Security: the CRUD operator whitelist now covers non-hash WHERE specs. update()/delete() accept SQL::Abstract's arrayref (OR-of-conditions) and scalarref (literal SQL) WHERE shapes; _safe_columns bailed out silently on anything that was not a hash, letting an injected operator or literal SQL through when the WHERE was built as an arrayref/scalarref from untrusted input. Now validated recursively; scalarref WHERE is rejected. Regression test in t/security.t. - Fix: read methods (all/flat/hash/val/array/count) use the 3-arg prepare_cached form, so a live query() iterator on the same SQL is no longer finished out from under the caller (silent truncation, a 0.17 regression). - Fix: execute() with no bind argument clears any $p left from a previous query instead of binding it to the new statement. - Fix: qualified table names ("schema.table") work in count(), upsert(), insert_many(), upsert_many() and Schema introspection (were quoted as one identifier via _quote_id; now per-segment via _quote_ident_path, matching insert/update/delete). - Fix: Schema tables cache is a hashref when the database has no tables (tn => 1 on an empty DB gave a misleading crash). - Fix: cache => 0 (or '') no longer switches caching on; the guard is truthiness, not defined-ness. - Fix: a transaction clears its savepoints on successful commit too, so a later rollback_to() cannot fire on a stale name. - Fix: t/security.t guards its LRU::Cache require (was bare, would fail on smokers without the optional backend); Result.pm POD link to query() points at DBIx::Fast::SQL; META repository url is a valid https URI (an SSH spec was silently dropped). [ New ] - DBIx::Fast::Connector: fork-safe lazy connections, throttled ping, automatic reconnect (replaces DBIx::Connector). - query() row-by-row iterator via DBIx::Fast::Result. - Query cache (DBIx::Fast::Cache / Cached): TTL, tag invalidation, LRU or CHI backends, CRUD auto-invalidation. - upsert() / insert_many() / upsert_many(), driver-aware. - txn(isolation => ...), whitelist-validated and restored on exit. - DBIx::Fast::Profile::Pg: native PostgreSQL diagnostics. - DBIx::Fast::Profile::mysql: native MySQL diagnostics (inherits the MariaDB profile; overrides EXPLAIN, removed-in-8.0 EXTENDED). - DBIx::Fast::Output: unified profiler output - text (default), JSON lines or callback; profile_output / $obj->output(...). - now_utc(); examples/profiler-pg.pl. [ Security ] - SQL injection hardening: operator whitelists for all CRUD WHERE/SET specs; identifiers validated AND quoted everywhere. - Credentials never echoed: connect/DSN errors redacted; errors_redact also scrubs backticks. - Fork safety: AutoInactiveDestroy + pid-guarded disconnect. - Cache keys include method + connection identity. - Deadlock retry gated on driver error codes, not message text; isolation-restore failure closes the connection (fail closed). - EXPLAIN allowlists (MariaDB/Pg) resist literal-quoting tricks, file access and DoS functions; terminal escapes stripped. [ Fixes ] - Transaction retry/rollback state, savepoint sequencing, memory leak (weakened back-refs), val() first-column contract. - DSN parsing: host/port, ':' in passwords, postgres:// schemes, driver-correct utf8 flags; Pg isolation and last_insert_id. - Cache: bounded tag index, TTL pushed down to CHI, honest stats. - Profiler text output degrades gracefully on bare installs: Cpanel::JSON::XS / Term::ANSIColor are recommends, so print_query falls back to core JSON::PP and colorless output when absent. - Profile::MariaDB information_schema queries carry explicit lowercase aliases (MySQL 8 uppercases unaliased columns) and get_processes no longer uses the MariaDB-only time_ms column. - Exceptions: Exception() honors errors_redact, attaches last_error only when recent, POD documents the real always-croak contract; a failed transaction records its error once, not three times. [ Performance ] - fetchall_arrayref C-loop fetches, prepare_cached everywhere, lazy SQL::Abstract, cheaper profiler/cache internals. [ Packaging ] - Query/CRUD methods live in the DBIx::Fast::SQL role, composed into DBIx::Fast - identical API, the main module is half the size and each file documents its own methods. - Test suite coherence pass: the committed fixture t/db/test.db is read-only (writing suites use tempdirs; regenerated from t/db/schema.sql, 455KB of stale rows dropped), duplicate suites merged (02-schema/dbix-fast/driver MariaDB.t), live tests skip cleanly when the server is down, tables are per-file prefixed and cleaned up, and the whole suite passes under prove -j. TableName() format-validates unconditionally (insert/update had accepted names count/upsert rejected). - Optional deps as recommends; whole distro on Object::Pad; full POD with coverage tests; 500+ tests on SQLite/MariaDB/Pg/MySQL (CI service containers); LICENSE, SECURITY.md, README.md. 0.161 2026-03-21 - Connection mode: ping → fixup (eliminates ping overhead per query) 0.16 2026-03-20 - Migration from Moo to Object::Pad (requires Perl v5.38+) - New: tracker() - query profiling across all methods (all/hash/val/flat/array/exec/insert/update/delete) - New: Profile::Base, Profile::MariaDB, Profile::SQLite (driver-specific diagnostics) - New: Transaction module with nested support, savepoints, deadlock retry - Removed: up2() (unused), Query.pm (unused), execute_prepare2 (duplicate), make_sen old (buggy) - Renamed: make_senN → make_sen (correct implementation) - Performance: statement caching (prepare_cached), inlined query methods, _make_where with join - Bug fixes: Schema typos, HandleError return 0, Time::HiRes import, `rows` keyword MariaDB 11+ - Bug fixes: Profile::MariaDB init (execute→exec), session stats columns, getrusage optional - Tests: 147 SQLite + 34 MariaDB + 14 profiler - Updated CI: Perl 5.38/5.40, bookworm, Object::Pad - Full POD documentation on all 8 modules - Added examples/profiler-mariadb.pl 0.15 2024-09-06 - args : SQLite 0.14 2024-09-03 - POD 0.13 2024-09-01 - t/exception.t - Clean 0.12 2024-09-01 - Test - DSN / URI - _check_dsn / _make_dsn_dbi 0.11 2024-09-01 - SQL::Abstract 0.10 2024-09-01 - _make_dsn - _check_dsn - driver && dbd - t/functions.t 0.09 2020-01-01 0.08 2016-01-26 - Force UTF8 0.07 2016-01-24 0.06 2015-03-23 0.05 2015-03-18T03:30:38+01:00 - More test - Method : array 0.04 2015-03-18T00:59:19+01:00 - Test 0.03 2015-03-17T00:50:31+01:00 - New methods : value & count - Dereference hash reference for using 'keys' 0.02 2015-03-17T00:20:48+01:00 - extra_args -> time NOW() 0.01 Unknown Release Date