I'd like to propose a small enhancement to DBD::Oracle. When I connect
via sqlplus, I see:
ORA-28002: the password will expire within 9951 days
When I connect via DBI using normal user/pass credentials, I also see
that information, automatically generated by the connect:
DBD::Oracle::dr
connect warning: ORA-28002: the password will expire within 9951 days (DBD
SUCCESS_WITH_INFO: OCISessionBegin) at
/oracle/local/perl/lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi/DBI.pm
line 671, line 1.
However, when I connect via DBI using an oracle
wallet (SEPS) entry, that information is never presented. I tracked the
inconsistency to DBD-Oracle-1.74/lib/DBD/Oracle.pm , line 309:
309
unless (length $user_only) {
310 $user_only = $dbh->selectrow_array(q{
311 SELECT SYS_CONTEXT('userenv','session_user') FROM DUAL
312 })||'';
313 $dbh_inner->{Username} = $user_only;
314 # these two are just for
backwards compatibility
315 $dbh_inner->{USER} =
$dbh_inner->{CURRENT_USER} = uc $user_only;
316 }
$user_only is null
when a wallet entry is used, so the code goes back to the db to get the
username. Unfortunately that overwrites (clears) $dbh->err, $dbh->errstr,
and $dbh->state, which had contained the expiration info.
I'm thinking
maybe it should save off the existing values for those 3 attributes, run
the query, and then append the old values onto those resulting from the
selectrow_array. (Technically that would leave them in the wrong order -
with the selectrow_array info ahead of the connect info - but maybe that's
not important.) The attached patch rather clumsily does that, and has
resolved the problem in my environment. I'm happy to revise the patch -
just tell me where it's lacking.
To create the test condition, I did
this:
create profile myprofile limit PASSWORD_LOCK_TIME 1
PASSWORD_GRACE_TIME 9876 PASSWORD_LIFE_TIME 1;
alter user myuser profile
myprofile; diff -r -u DBD-Oracle-1.74/lib/DBD/Oracle.pm
DBD-Oracle-1.74.ora-28002/lib/DBD/Oracle.pm
--- DBD-Oracle-1.74/lib/DBD/Oracle.pm 2014-04-24 19:03:05.000000000 -0600
+++ DBD-Oracle-1.74.ora-28002/lib/DBD/Oracle.pm 2015-04-20 09:32:28.000000000
-0600
@@ -307,9 +307,19 @@
}
unless (length $user_only) {
+ # It may be we've already encountered a warning by this point,
+ # such as "ORA-28002: the password will expire within %d days".
+ # We'll cache it for reinstatement.
+ my ($err, $errstr, $state) =
+ ($dbh->err, $dbh->errstr, $dbh->state);
$user_only = $dbh->selectrow_array(q{
SELECT SYS_CONTEXT('userenv','session_user') FROM DUAL
})||'';
+ # Now we'll reinstate the earlier warning. We're just
+ # appending it, so in the extremeley unlikely case that the
+ # selectrow_array we just issued also issued a warning, the
+ # 2 warnings will appear out of order.
+ $dbh->set_err($err, $errstr, $state) if defined $err;
$dbh_inner->{Username} = $user_only;
# these two are just for backwards compatibility
$dbh_inner->{USER} = $dbh_inner->{CURRENT_USER} = uc $user_only;