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;