proposed DBD::Oracle patch for ORA-28002

"J.D. Laub" <[email protected]>
Newsgroups gmane.comp.lang.perl.modules.dbi.sybase.devel
Message-ID <[email protected]>

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;
ora-28002.patch (text/plain, 1.1 KB)
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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.