Skip to content

Instantly share code, notes, and snippets.

Created March 17, 2015 23:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/2df2059cb23644670251 to your computer and use it in GitHub Desktop.
Save anonymous/2df2059cb23644670251 to your computer and use it in GitHub Desktop.
diff --git a/lib/Mojo/Pg.pm b/lib/Mojo/Pg.pm
index 4870d84..8e0769c 100644
--- a/lib/Mojo/Pg.pm
+++ b/lib/Mojo/Pg.pm
@@ -21,8 +21,7 @@ has options => sub {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 0,
- RaiseError => 1,
- pg_server_prepare => 0
+ RaiseError => 1
};
};
has [qw(password username)] => '';
@@ -40,8 +39,13 @@ sub db {
# Fork-safety
delete @$self{qw(pid queue)} unless ($self->{pid} //= $$) eq $$;
- my ($dbh, $handle) = @{$self->_dequeue};
- return Mojo::Pg::Database->new(dbh => $dbh, handle => $handle, pg => $self);
+ my ($dbh, $handle, $sths) = @{$self->_dequeue};
+ return Mojo::Pg::Database->new(
+ dbh => $dbh,
+ handle => $handle,
+ pg => $self,
+ queue => $sths
+ );
}
sub from_string {
@@ -88,9 +92,9 @@ sub _dequeue {
}
sub _enqueue {
- my ($self, $dbh, $handle) = @_;
+ my ($self, $dbh, $handle, $sths) = @_;
my $queue = $self->{queue} ||= [];
- push @$queue, [$dbh, $handle] if $dbh->{Active};
+ push @$queue, [$dbh, $handle, $sths] if $dbh->{Active};
shift @$queue while @$queue > $self->max_connections;
}
diff --git a/lib/Mojo/Pg/Database.pm b/lib/Mojo/Pg/Database.pm
index eb8d0bf..5253841 100644
--- a/lib/Mojo/Pg/Database.pm
+++ b/lib/Mojo/Pg/Database.pm
@@ -11,6 +11,7 @@ use Mojo::Util 'deprecated';
use Scalar::Util 'weaken';
has [qw(dbh pg)];
+has max_statements => 10;
sub DESTROY {
my $self = shift;
@@ -19,7 +20,7 @@ sub DESTROY {
$_->{cb}($self, 'Premature connection close', undef) for @$waiting;
return unless (my $pg = $self->pg) && (my $dbh = $self->dbh);
- $pg->_enqueue($dbh, $self->{handle});
+ $pg->_enqueue($dbh, @$self{qw(handle queue)});
}
sub backlog { scalar @{shift->{waiting} || []} }
@@ -35,6 +36,7 @@ sub begin {
sub disconnect {
my $self = shift;
$self->_unwatch;
+ delete $self->{queue};
$self->dbh->disconnect;
}
@@ -88,19 +90,19 @@ sub query {
my @values = map { _json($_) ? encode_json $_->{json} : $_ } @_;
# Dollar only
- my $dbh = $self->dbh;
- local $dbh->{pg_placeholder_dollaronly} = 1 if delete $self->{dollar_only};
+ local $self->dbh->{pg_placeholder_dollaronly} = 1
+ if delete $self->{dollar_only};
# Blocking
unless ($cb) {
- my $sth = $dbh->prepare($query);
+ my $sth = $self->_dequeue($query);
$sth->execute(@values);
$self->_notifications;
- return Mojo::Pg::Results->new(sth => $sth);
+ return Mojo::Pg::Results->new(db => $self, sth => $sth);
}
# Non-blocking
- my $sth = $dbh->prepare($query, {pg_async => PG_ASYNC});
+ my $sth = $self->_dequeue($query, 1);
push @{$self->{waiting}}, {args => \@values, cb => $cb, sth => $sth};
$self->$_ for qw(_next _watch);
}
@@ -117,6 +119,25 @@ sub unlisten {
return $self;
}
+sub _dequeue {
+ my ($self, $query, $async) = @_;
+
+ my $queue = $self->{queue} ||= [];
+ for (my $i = 0; $i <= $#$queue; $i++) {
+ my $sth = $queue->[$i];
+ return splice @$queue, $i, 1
+ if !(!$sth->{pg_async} ^ !$async) && $sth->{Statement} eq $query;
+ }
+
+ return $self->dbh->prepare($query, $async ? {pg_async => PG_ASYNC} : ());
+}
+
+sub _enqueue {
+ my ($self, $sth) = @_;
+ push @{$self->{queue}}, $sth;
+ shift @{$self->{queue}} while @{$self->{queue}} > $self->max_statements;
+}
+
sub _json { ref $_[0] eq 'HASH' && (keys %{$_[0]})[0] eq 'json' }
sub _next {
@@ -157,7 +178,7 @@ sub _watch {
my $result = do { local $dbh->{RaiseError} = 0; $dbh->pg_result };
my $err = defined $result ? undef : $dbh->errstr;
- $self->$cb($err, Mojo::Pg::Results->new(sth => $sth));
+ $self->$cb($err, Mojo::Pg::Results->new(db => $self, sth => $sth));
$self->_next;
$self->_unwatch unless $self->backlog || $self->is_listening;
}
diff --git a/lib/Mojo/Pg/Results.pm b/lib/Mojo/Pg/Results.pm
index 72bf8ca..d802921 100644
--- a/lib/Mojo/Pg/Results.pm
+++ b/lib/Mojo/Pg/Results.pm
@@ -5,7 +5,12 @@ use Mojo::Collection;
use Mojo::JSON 'decode_json';
use Mojo::Util 'tablify';
-has 'sth';
+has [qw(db sth)];
+
+sub DESTROY {
+ my $self = shift;
+ if ((my $db = $self->db) && (my $sth = $self->sth)) { $db->_enqueue($sth) }
+}
sub array { ($_[0]->_expand($_[0]->sth->fetchrow_arrayref))[0] }
diff --git a/t/connection.t b/t/connection.t
index 9400ed8..8526c4b 100644
--- a/t/connection.t
+++ b/t/connection.t
@@ -12,8 +12,7 @@ my $options = {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 0,
- RaiseError => 1,
- pg_server_prepare => 0
+ RaiseError => 1
};
is_deeply $pg->options, $options, 'right options';
@@ -26,8 +25,7 @@ $options = {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 0,
- RaiseError => 1,
- pg_server_prepare => 0
+ RaiseError => 1
};
is_deeply $pg->options, $options, 'right options';
@@ -40,8 +38,7 @@ $options = {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 1,
- RaiseError => 1,
- pg_server_prepare => 0
+ RaiseError => 1
};
is_deeply $pg->options, $options, 'right options';
@@ -55,8 +52,7 @@ $options = {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 0,
- RaiseError => 1,
- pg_server_prepare => 0
+ RaiseError => 1
};
is_deeply $pg->options, $options, 'right options';
@@ -69,8 +65,7 @@ $options = {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 0,
- RaiseError => 1,
- pg_server_prepare => 0
+ RaiseError => 1
};
is_deeply $pg->options, $options, 'right options';
@@ -84,8 +79,7 @@ $options = {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 1,
- RaiseError => 0,
- pg_server_prepare => 0
+ RaiseError => 0
};
is_deeply $pg->options, $options, 'right options';
@@ -98,8 +92,7 @@ $options = {
AutoCommit => 1,
AutoInactiveDestroy => 1,
PrintError => 0,
- RaiseError => 0,
- pg_server_prepare => 0
+ RaiseError => 0
};
is_deeply $pg->options, $options, 'right options';
diff --git a/t/database.t b/t/database.t
index 16f42b7..6ef5e02 100644
--- a/t/database.t
+++ b/t/database.t
@@ -73,13 +73,27 @@ is $pg->db->dbh, $dbh, 'same database handle';
$pg->db->disconnect;
isnt $pg->db->dbh, $dbh, 'different database handles';
+# Statement cache
+$db = $pg->db;
+is $db->max_statements, 10, 'right default';
+my $sth = $db->query('select 3 as three')->sth;
+is $db->query('select 3 as three')->sth, $sth, 'same statement handle';
+isnt $db->query('select 4 as four')->sth, $sth, 'different statement handles';
+is $db->query('select 3 as three')->sth, $sth, 'same statement handle';
+undef $db;
+$db = $pg->db->max_statements(2);
+is $db->query('select 3 as three')->sth, $sth, 'same statement handle';
+isnt $db->query('select 5 as five')->sth, $sth, 'different statement handles';
+isnt $db->query('select 6 as six')->sth, $sth, 'different statement handles';
+isnt $db->query('select 3 as three')->sth, $sth, 'different statement handles';
+
# Dollar only
$db = $pg->db;
-is $db->dollar_only->query('select $1 as test', 23)->hash->{test}, 23,
+is $db->dollar_only->query('select $1::int as test', 23)->hash->{test}, 23,
'right result';
-eval { $db->dollar_only->query('select ? as test', 23) };
+eval { $db->dollar_only->query('select ?::int as test', 23) };
like $@, qr/called with 1 bind variables when 0 are needed/, 'right error';
-is $db->query('select ? as test', 23)->hash->{test}, 23, 'right result';
+is $db->query('select ?::int as test', 23)->hash->{test}, 23, 'right result';
# JSON
$db = $pg->db;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment