DBIx-PgLink

 view release on metacpan or  search on metacpan

lib/DBIx/PgLink/RemoteAction.pm  view on Meta::CPAN

    my $sub_name = $_->{conv_to_remote};
    {
      name      => $_->{column_name},
      data_type => $t->{standard_type}, # standard type code
      conv_to_remote_coderef => $self->resolve_converter_method($sub_name),
    }
  } @{$q->params};

  # prepare result conversion (by field name)
  my %result_conv = map {
    $_->{column_name} => $self->resolve_converter_method( $_->{conv_to_local} )
  } grep { $_->{conv_to_local} } $a->columns->metadata;

  return {
    sth         => $self->adapter->prepare_cached($query_text),
    params      => \@params,
    result_conv => \%result_conv,
    returns_set => ($a->can('returns_set') ? $a->returns_set : 1), # return set by default
  };
};


sub remote_statement_bind_and_execute {
  my ($self, $st, $param_values) = @_;

  # typed binding ~2x times slower than untyped
  my $typed = $self->adapter->require_parameter_type;

  my $i = 0;
  for my $v (@{$param_values}) {
    my $m = $st->{params}->[$i++];

    my $sub = $m->{conv_to_remote_coderef};
    $sub->($self->adapter, $v) if $sub; # conversion

    if ($typed) {
      my $type_code = $m->{data_type}; # SQL Standard type code
      if (defined $type_code) {
        $st->{sth}->bind_param($i, $v, {TYPE=>$type_code});
        trace_msg('INFO', "Bind[$i/$type_code]: " . (defined $v ? $v : 'NULL')) if trace_level >= 3;
      } else {
        $st->{sth}->bind_param($i, $v);
        trace_msg('INFO', "Bind[$i]: " . (defined $v ? $v : 'NULL')) if trace_level >= 3;
      }
    }
  }

  if ($typed) {
    $st->{sth}->execute;
  } else {
    $st->{sth}->execute(@{$param_values});
  }
}


# cache to the session end
memoize 'remote_statement_prepare_cached';


# store session-level filter for SELECT remote data, by object_id
has 'query_session_filter' => (is=>'ro', isa=>'HashRef', default=>sub{{}} );


method remote_accessor_query => named (
  object_id    => { isa=>'Int', required=>1 },
  where        => { isa=>'Str', required=>0, default=>'' },
  param_values => { isa=>'PostgreSQLArray', required=>0, coerce=>1, default=>[] },
  param_types  => { isa=>'PostgreSQLArray', required=>0, coerce=>1, default=>[] },
) => sub {
  my ($self, $p) = @_;

  # use session filter, if there is no user-supplied params and WHERE-clause
  unless ($p->{where} || @{$p->{param_values}}) {
    my $f = $self->query_session_filter->{$p->{object_id}};
    $p = $f if $f;
  }

  my $a = $self->load_accessor_cached($p->{object_id});

  my $st = $self->remote_statement_prepare_cached(
    accessor => $a,
    action   => 'S', 
    where    => $p->{where},
  );

  trace_msg('INFO', "QUERY to " . $a->remote_object_quoted) if trace_level >= 2;
  # -------------------------------------------------------
  if (@{$p->{param_types}}) {
    $self->_bind_user_params( $st->{sth}, $p->{param_values}, $p->{param_types} );
    $st->{sth}->execute;
  } else {
    $self->remote_statement_bind_and_execute( $st, $p->{param_values} );
  }
  # -------------------------------------------------------

  if ($st->{returns_set}) {
    # return setof record
    while (my $row = $st->{sth}->fetchrow_hashref) {
      # convert resultset values by column name
      while (my ($col, $sub) = each %{$st->{result_conv}}) {
        $sub->( $self->adapter, $row->{$col} );
      }
      # pipe row to PostgreSQL
      main::return_next(\%{$row});
    }
    $st->{sth}->finish;
    return undef;
  } else {
    # return scalar
    my $result = $st->{sth}->fetchrow_array;
    my (undef, $sub) = each %{$st->{result_conv}}; # only one
    $sub->($result) if $sub;
    $st->{sth}->finish;
    return $result;
  }
};


method set_query_session_filter => named (
  object_id    => { isa=>'Int', required=>1 },
  where        => { isa=>'Str', required=>0, default=>'' },



( run in 2.445 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )