Committed by Greg Sabino Mullane <[email protected]>
Subject: [DBD::Pg 1/3] Further tweaking to the ping() and pg_ping() methods.
We now use an empty query consisting of a single SQL comment sent via PQexec.
---
Pg.pm | 5 +-
dbdimp.c | 35 ++++++-------
t/03dbmethod.t | 163 +++++++++++++++++++++------------------------------------
3 files changed, 79 insertions(+), 124 deletions(-)
diff --git a/Pg.pm b/Pg.pm
index de0eee2..703f882 100644
--- a/Pg.pm
+++ b/Pg.pm
@@ -2740,7 +2740,7 @@ server version 9.0 or higher.
The C<ping> method determines if there is a working connection to an active
database server. It does this by sending a small query to the server,
currently
-B<SELECT 'DBD::Pg ping test'>. It returns 0 (false) if the connection is not
valid,
+B<'DBD::Pg ping test v3.5.0'>. It returns 0 (false) if the connection is not
valid,
otherwise it returns a positive number (true). The value returned indicates
the
current state:
@@ -2768,7 +2768,8 @@ return the following:
--------------------------------------------------
-1 There is no connection to the database at all (e.g. after
disconnect)
-2 An unknown transaction status was returned (e.g. after forking)
- -3 The handle exists, but no data was returned from a test query.
+ -3 The test query failed (PQexec returned null)
+ -4 PQstatus returned a CONNECTION_BAD
=head3 B<get_info>
diff --git a/dbdimp.c b/dbdimp.c
index 359865c..d437d4d 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -455,6 +455,7 @@ int dbd_db_ping (SV * dbh)
D_imp_dbh(dbh);
PGTransactionStatusType tstatus;
ExecStatusType status;
+ PGresult * result;
if (TSTART_slow) TRC(DBILOGFP, "%sBegin dbd_db_ping\n", THEADER_slow);
@@ -464,8 +465,6 @@ int dbd_db_ping (SV * dbh)
}
tstatus = pg_db_txn_status(aTHX_ imp_dbh);
- /* 0=idle 1=active 2=intrans 3=inerror 4=unknown */
-
if (TRACE5_slow) TRC(DBILOGFP, "%sdbd_db_ping txn_status is %d\n",
THEADER_slow, tstatus);
if (tstatus >= 4) { /* Unknown, so we err on the side of "bad" */
@@ -473,30 +472,30 @@ int dbd_db_ping (SV * dbh)
return -2;
}
- /* No matter what state we are in, send a SELECT to the backend */
- status = _result(aTHX_ imp_dbh, "SELECT 'DBD::Pg ping test'");
-
- /* If we are idle or in a transaction, we should see tuples */
- if (0 == tstatus || 2 == tstatus) {
-
- if (PGRES_TUPLES_OK == status) {
- if (TEND_slow) TRC(DBILOGFP, "%sEnd dbd_pg_ping
(result: 1 PGRES_TUPLES_OK)\n", THEADER_slow);
- return 1+tstatus;
- }
+ /* No matter what state we are in, send an empty query to the backend */
+ result = PQexec(imp_dbh->conn, "/* DBD::Pg ping test v3.5.0 */");
+ if (NULL == result) {
+ /* Something very bad, usually indicating the backend is gone */
+ return -3;
+ }
+ status = PQresultStatus(result);
+ PQclear(result);
- /* Something is wrong, so we return an error */
- return -2;
+ /* We expect to see an empty query most times */
+ if (PGRES_EMPTY_QUERY == status) {
+ if (TEND_slow) TRC(DBILOGFP, "%sEnd dbd_pg_ping
(PGRES_EMPTY_QUERY)\n", THEADER_slow);
+ return 1+tstatus;
+ /* 0=idle 1=active 2=intrans 3=inerror 4=unknown */
}
- /* We are in some other state. As a status of 7 could be a bad query or
a dead database,
- we need to call PQstatus to be sure
- */
+ /* As a safety measure, check PQstatus as well */
if (CONNECTION_BAD == PQstatus(imp_dbh->conn)) {
if (TEND_slow) TRC(DBILOGFP, "%sEnd dbd_pg_ping (PQstatus
returned CONNECTION_BAD)\n", THEADER_slow);
- return -3;
+ return -4;
}
if (TEND_slow) TRC(DBILOGFP, "%sEnd dbd_pg_ping\n", THEADER_slow);
+
return 1+tstatus;
} /* end of dbd_db_ping */
diff --git a/t/03dbmethod.t b/t/03dbmethod.t
index e78f75d..0e5d94e 100644
--- a/t/03dbmethod.t
+++ b/t/03dbmethod.t
@@ -26,7 +26,7 @@ my $dbh = connect_database();
if (! $dbh) {
plan skip_all => 'Connection to database failed, cannot continue
testing';
}
-plan tests => 548;
+plan tests => 549;
isnt ($dbh, undef, 'Connect to database for database handle method testing');
@@ -1876,118 +1876,73 @@ is ($@, q{}, $t);
$dbh2->disconnect();
#
-# Test of the "ping" database handle method
+# Test of the "ping" and "pg_ping" database handle methods
#
-$t='DB handle method "ping" returns 1 on an idle connection';
-is ($dbh->ping(), 1, $t);
+my $mtvar; ## This is an implicit test of getcopydata: please leave this var
undefined
-$t='DB handle method "ping" returns 3 for a good connection inside a
transaction';
-$dbh->do('SELECT 123');
-is ($dbh->ping(), 3, $t);
-
-$t='DB handle method "ping" returns 1 on an idle connection';
-$dbh->commit();
-is ($dbh->ping(), 1, $t);
-
-my $mtvar; ## This is an implicit test of getline: please leave this var
undefined
-
-$t='DB handle method "ping" returns 2 when in COPY IN state';
-$dbh->do('COPY dbd_pg_test(id,pname) TO STDOUT');
-{
- local $SIG{__WARN__} = sub {};
- $dbh->pg_getline($mtvar,100);
-}
-is ($dbh->ping(), 2, $t);
-## This has sent a SELECT, which messes up our COPY state!
-$dbh->rollback();
-
-$t='DB handle method "ping" returns a 4 when inside a failed transaction';
-eval {
- $dbh->do('DBD::Pg creating an invalid command for testing');
-};
-is ($dbh->ping(), 4, $t);
-$dbh->rollback();
-
-$t='DB handle method "ping" returns 1 on an idle connection';
-$dbh->commit();
-is ($dbh->ping(), 1, $t);
-
-$t='DB handle method "ping" fails (returns 0) on a disconnected handle';
-$dbh->disconnect();
-is ($dbh->ping(), 0, $t);
-
-$t='Able to reconnect to the database after disconnect';
-$dbh = connect_database({nosetup => 1});
-isnt ($dbh, undef, $t);
-
-$t='DB handle method "ping" returns 1 on an idle connection';
-$dbh->commit();
-is ($dbh->ping(), 1, $t);
-
-$t='DB handle method "ping" returns 0 after a lost network connection (outside
transaction)';
-my $fd = $dbh->{pg_socket} or die "Could not determine socket";
-open(DBH_PG_FH, "<&=".$fd) or die "Could not open socket: $!";
-close DBH_PG_FH or die "Could not close socket: $!";
-is ($dbh->ping(), 0, $t);
-
-## Reconnect, and try the same thing but inside a transaction
-$t='DB handle method "ping" returns 0 after a lost network connection (inside
transaction)';
-diag "About to call...";
-$dbh->disconnect();
-$dbh = connect_database({nosetup => 1});
-$dbh->do("SELECT 'DBD::Pg testing'");
-$fd = $dbh->{pg_socket} or die "Could not determine socket";
-open(DBH_PG_FH, "<&=".$fd) or die "Could not open socket: $!";
-close DBH_PG_FH or die "Could not close socket: $!";
-is ($dbh->ping(), 0, $t);
-
-$t='DB handle method "ping" returns 0 after a lost network connection (inside
failed transaction)';
-$dbh->{InactiveDestroy} = 1;
-undef $dbh;
-$dbh = connect_database({nosetup => 1});
-eval { $dbh->do("SELECT 'DBD::Pg testing, will fail'::int"); };
-$fd = $dbh->{pg_socket} or die "Could not determine socket";
-open(DBH_PG_FH, "<&=".$fd) or die "Could not open socket: $!";
-close DBH_PG_FH or die "Could not close socket: $!";
-is ($dbh->ping(), 0, $t);
-
-$dbh->disconnect();
-$dbh = connect_database({nosetup => 1});
+for my $type (qw/ ping pg_ping /) {
+ $t=qq{DB handle method "$type" returns 1 on an idle connection};
+ $dbh->commit();
+ is ($dbh->$type(), 1, $t);
-#
-# Test of the "pg_ping" database handle method
-#
+ $t=qq{DB handle method "$type" returns 2 when in COPY IN state};
+ $dbh->do('COPY dbd_pg_test(id,pname) TO STDOUT');
+ $dbh->pg_getcopydata($mtvar);
+ is ($dbh->$type(), 2, $t);
+ ## the ping messes up the copy state, so all we can do is rollback
+ $dbh->rollback();
-$t='DB handle method "pg_ping" returns 1 on an idle connection';
-is ($dbh->pg_ping(), 1, $t);
+ $t=qq{DB handle method "$type" returns 2 when in COPY IN state};
+ $dbh->do('COPY dbd_pg_test(id,pname) FROM STDIN');
+ $dbh->pg_putcopydata("123\tfoobar\n");
+ is ($dbh->$type(), 2, $t);
+ $dbh->rollback();
-$t='DB handle method "pg_ping" returns 3 for a good connection inside a
transaction';
-$dbh->do('SELECT 123');
-is ($dbh->pg_ping(), 3, $t);
+ $t=qq{DB handle method "$type" returns 3 for a good connection inside a
transaction};
+ $dbh->do('SELECT 123');
+ is ($dbh->$type(), 3, $t);
-$t='DB handle method "pg_ping" returns 1 on an idle connection';
-$dbh->commit();
-is ($dbh->pg_ping(), 1, $t);
+ $t=qq{DB handle method "$type" returns a 4 when inside a failed
transaction};
+ eval {
+ $dbh->do('DBD::Pg creating an invalid command for testing');
+ };
+ is ($dbh->$type(), 4, $t);
+ $dbh->rollback();
-$t='DB handle method "pg_ping" returns 2 when in COPY IN state';
-$dbh->do('COPY dbd_pg_test(id,pname) TO STDOUT');
-$dbh->pg_getline($mtvar,100);
-is ($dbh->pg_ping(), 2, $t);
-$dbh->rollback();
+ my $val = $type eq 'ping' ? 0 : -1;
+ $t=qq{DB handle method "type" fails (returns $val) on a disconnected
handle};
+ $dbh->disconnect();
+ is ($dbh->$type(), $val, $t);
+
+ $t='Able to reconnect to the database after disconnect';
+ $dbh = connect_database({nosetup => 1});
+ isnt ($dbh, undef, $t);
+
+ $val = $type eq 'ping' ? 0 : -3;
+ $t=qq{DB handle method "$type" returns $val after a lost network
connection (outside transaction)};
+ socket_fail($dbh);
+ is ($dbh->$type(), $val, $t);
+
+ ## Reconnect, and try the same thing but inside a transaction
+ $val = $type eq 'ping' ? 0 : -3;
+ $t=qq{DB handle method "$type" returns $val after a lost network
connection (inside transaction)};
+ $dbh = connect_database({nosetup => 1});
+ $dbh->do("SELECT 'DBD::Pg testing'");
+ socket_fail($dbh);
+ is ($dbh->$type(), $val, $t);
+
+ $type eq 'ping' and $dbh = connect_database({nosetup => 1});
+}
-$t='DB handle method "pg_ping" returns 3 for a good connection inside a
transaction';
-$dbh->do('SELECT 123');
-is ($dbh->pg_ping(), 3, $t);
+exit;
-$t='DB handle method "pg_ping" returns a 4 when inside a failed transaction';
-eval {
- $dbh->do('DBD::Pg creating an invalid command for testing');
-};
-is ($dbh->pg_ping(), 4, $t);
+sub socket_fail {
+ my $dbh = shift;
+ $dbh->{InactiveDestroy} = 1;
+ my $fd = $dbh->{pg_socket} or die "Could not determine socket";
+ open(DBH_PG_FH, "<&=".$fd) or die "Could not open socket: $!";
+ close DBH_PG_FH or die "Could not close socket: $!";
+}
-$t='DB handle method "pg_ping" fails (returns -1) on a disconnected handle';
-cleanup_database($dbh,'test');
-$dbh->disconnect();
-is ($dbh->pg_ping(), -1, $t);
--
1.8.4