-
-
Save anonymous/2df2059cb23644670251 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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