DBIO-PostgreSQL-EV

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

          (Storage.pm 1109 -> 938 lines). It inherits the shared machinery —
          select/insert/update/delete_async, _run_crud, txn_do_async, the
          insert-RETURNING overlay, pipeline, the sync fallbacks and SQL
          generation — and keeps only the EV/libpq wire seams plus EV value-add
          (listen/notify, copy_in, deploy_async). (karr #22, core #70)
        - Async is opt-in per connection via { async => 'ev' } (ADR 0030):
          loading the PostgreSQL::EV component is an inert marker, and the EV
          backend is reached explicitly through
          MyApp::Schema->connect($dsn, $u, $p, { async => 'ev' }). The async
          storage is embedded as the async backend of the sync storage rather
          than hijacking storage_type; it weakens its schema ref to break the
          embed cycle and accepts the sync driver's DBI-form connect_info. The
          legacy async_backend() instance method and async_fallback chain are
          gone — a *_async call on a sync instance now croaks explicitly rather
          than silently degrading. (ADR 0028, ADR 0030, karr #59)
        - insert_async resolves with a returned-columns HASHREF, not a positional
          row (ADR 0031 §3): _run_crud appends RETURNING * to the INSERT and folds
          the returned row onto the source's declared column order, so
          create_async / Row::insert_async see the autoinc PK on the row.
          select_async resolves with row arrayrefs (cursor ->all shape),
          select_single_async with a single row arrayref / undef; documented in

t/05-bind-release.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;
use Scalar::Util 'weaken';
use Future;

# OFFLINE regression test for karr #11 / CurtisPoe review #5 N1:
# "async bind-value leak". No EV::Pg, no real DB.
#
# WHAT THE TICKET FEARED (ported from the sync DBI driver's contract):
#   bind values issued through the async pool are retained on an in-flight
#   future / per-pool cache, so (1) a re-issued query could see stale binds
#   and (2) memory grows with total binds ever issued, not with outstanding
#   queries.

t/05-bind-release.t  view on Meta::CPAN

}

# --- 1. single pooled query: bind released once the future completes -------
{
  my ($storage, $pg) = new_storage;

  my $weak;
  my $f;
  {
    my $bind = [ 'payload' x 64 ];   # a large-ish bind, like the repro
    weaken($weak = $bind);
    $f = $storage->_query_async('SELECT $1', $bind);
  }   # the issuing-scope strong lexical dies here

  $pg->complete_one;
  $f->get;

  ok !defined $weak,
    'pooled query: bind arrayref is freed after the future completes '
    . '(completion closure does not retain it)';
}

# --- 2. pinned (transaction) query: same release contract ------------------
{
  my ($storage, $pg) = new_storage;

  my $weak;
  my $f;
  {
    my $bind = [ 'txn-payload' x 64 ];
    weaken($weak = $bind);
    $f = $storage->_query_async_pinned($pg, 'SELECT $1', $bind);
  }

  $pg->complete_one;
  $f->get;

  ok !defined $weak,
    'pinned (txn) query: bind arrayref is freed after completion too';
}

t/05-bind-release.t  view on Meta::CPAN

{
  my ($storage, $pg) = new_storage;

  my $N = 8;
  my @weak;
  my @f;
  for my $i (1 .. $N) {
    my $w;
    {
      my $bind = [ "row$i" x 32 ];
      weaken($w = $bind);
      push @f, $storage->_query_async("SELECT \$1 -- $i", $bind);
    }
    push @weak, $w;
  }

  is $pg->pending_count, $N, "all $N queries are in-flight at once";

  my $held_inflight = grep { defined } @weak;
  is $held_inflight, 0,
    "no bind arrayref is retained while $N queries are in-flight "



( run in 0.631 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )