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;

Reply via email to