#!perl -w
sub ok ($$;$) {
my($n, $ok, $warn) = @_;
++$t;
die "sequence error, expected $n but actually $t"
if $n and $n != $t;
($ok) ? print "ok $t\n"
: print "# failed test $t at line ".(caller)[2]."\nnot ok $t\n";
if (!$ok && $warn) {
$warn = $DBI::errstr || "(DBI::errstr undefined)" if $warn eq '1';
warn "$warn\n";
}
}
use DBI;
use DBD::Oracle qw(ORA_RSET SQLCS_NCHAR);
use strict;
unshift @INC ,'t';
require 'nchar_test_lib.pl';
$| = 1;
my $dsn = oracle_test_dsn();
my $dbuser = $ENV{ORACLE_USERID} || 'scott/tiger';
my $dbh = DBI->connect($dsn, $dbuser, '', { PrintError => 0 });
unless($dbh) {
warn "Unable to connect to Oracle ($DBI::errstr)\nTests skiped.\n";
print "1..0\n";
exit 0;
}
# ORA-00900: invalid SQL statement
# ORA-06553: PLS-213: package STANDARD not accessible
my $tst = $dbh->prepare(q{declare foo char(50); begin RAISE INVALID_NUMBER; end;});
if ($dbh->err && ($dbh->err==900 || $dbh->err==6553 || $dbh->err==600)) {
warn "Your Oracle server doesn't support PL/SQL" if $dbh->err== 900;
warn "Your Oracle PL/SQL is not properly installed" if $dbh->err==6553||$dbh->err==600;
warn "Tests skipped\n";
print "1..0\n";
exit 0;
}
my $tests;
print "1..$tests\n";
my($csr, $p1, $p2, $tmp, @tmp);
#DBI->trace(4,"trace.log");
# --- test raising predefined exception
ok(0, $csr = $dbh->prepare(q{
begin RAISE INVALID_NUMBER; end;
}), 1);
# ORA-01722: invalid number
ok(0, ! $csr->execute, 1);
ok(0, $DBI::err == 1722);
ok(0, $DBI::err == 1722); # make sure error doesn't get cleared
# --- test raising user defined exception
ok(0, $csr = $dbh->prepare(q{
DECLARE FOO EXCEPTION;
begin raise FOO; end;
}), 1);
# ORA-06510: PL/SQL: unhandled user-defined exception
ok(0, ! $csr->execute, 1);
ok(0, $DBI::err == 6510);
# --- test raise_application_error with literal values
ok(0, $csr = $dbh->prepare(q{
declare err_num number; err_msg char(510);
begin RAISE_APPLICATION_ERROR(-20101,'app error'); end;
}), 1);
# ORA-20101: app error
ok(0, ! $csr->execute, 1);
ok(0, $DBI::err == 20101);
ok(0, $DBI::errstr =~ m/app error/);
# --- test raise_application_error with 'in' parameters
ok(0, $csr = $dbh->prepare(q{
declare err_num varchar2(555); err_msg varchar2(510);
--declare err_num number; err_msg char(510);
begin
err_num := :1;
err_msg := :2;
raise_application_error(-20000-err_num, 'msg is '||err_msg);
end;
}), 1);
ok(0, ! $csr->execute(42, "hello world"), 1);
ok(0, $DBI::err == 20042, $DBI::err);
ok(0, $DBI::errstr =~ m/msg is hello world/, 1);
# --- test named numeric in/out parameters
ok(0, $csr = $dbh->prepare(q{
begin
:arg := :arg * :mult;
end;
}), 1);
$p1 = 3;
ok(0, $csr->bind_param_inout(':arg', \$p1, 50), 1);
ok(0, $csr->bind_param(':mult', 2), 1);
ok(0, $csr->execute, 1);
ok(0, $p1 == 6);
# execute 10 times from $p1=1, 2, 4, 8, ... 1024
$p1 = 1; foreach (1..10) { $csr->execute || die $DBI::errstr; }
ok(0, $p1 == 1024);
# --- test undef parameters
ok(0, $csr = $dbh->prepare(q{
declare foo char(500);
begin foo := :arg; end;
}), 1);
my $undef;
ok(0, $csr->bind_param_inout(':arg', \$undef,10), 1);
ok(0, $csr->execute, 1);
# --- test named string in/out parameters
ok(0, $csr = $dbh->prepare(q{
declare str varchar2(1000);
begin
:arg := nvl(upper(:arg), 'null');
:arg := :arg || :append;
end;
}), 1);
undef $p1;
$p1 = "hello world";
ok(0, $csr->bind_param_inout(':arg', \$p1, 1000), 1);
ok(0, $csr->bind_param(':append', "!"), 1);
ok(0, $csr->execute, 1);
ok(0, $p1 eq "HELLO WORLD!");
# execute 10 times growing $p1 to force realloc
foreach (1..10) {
$p1 .= " xxxxxxxxxx";
$csr->execute || die $DBI::errstr;
}
my $expect = "HELLO WORLD!" . (" XXXXXXXXXX!" x 10);
ok(0, $p1 eq $expect);
# --- test binding a null and getting a string back
undef $p1;
ok(0, $csr->execute, 1);
ok(0, $p1 eq 'null!');
$csr->finish;
ok(0, $csr = $dbh->prepare(q{
begin
:out := nvl(upper(:in), 'null');
end;
}), 1);
#$csr->trace(3);
my $out;
ok(0, $csr->bind_param_inout(':out', \$out, 1000), 1);
ok(0, $csr->bind_param(':in', "foo", DBI::SQL_CHAR()), 1);
ok(0, $csr->execute, 1);
ok(0, $out eq "FOO");
ok(0, $csr->bind_param(':in', ""), 1);
ok(0, $csr->execute, 1);
ok(0, $out eq "null");
# --- test out buffer being too small
ok(0, $csr = $dbh->prepare(q{
begin
select rpad('foo',200) into :arg from dual;
end;
}), 1);
#$csr->trace(3);
undef $p1; # force buffer to be freed
ok(0, $csr->bind_param_inout(':arg', \$p1, 20), 1);
# Execute fails with:
# ORA-06502: PL/SQL: numeric or value error
# ORA-06512: at line 3 (DBD ERROR: OCIStmtExecute)
$tmp = $csr->execute;
#$tmp = undef if DBD::Oracle::ORA_OCI()>=8; # because BindByName given huge max len
ok(0, !defined $tmp, 1);
# rebind with more space - and it should work
ok(0, $csr->bind_param_inout(':arg', \$p1, 200), 1);
ok(0, $csr->execute, 1);
ok(0, length($p1) == 200, 0);
# --- test plsql_errstr function
#$csr = $dbh->prepare(q{
# create or replace procedure perl_dbd_oracle_test as
# begin
# procedure filltab( stuff out tab ); asdf
# end;
#});
#ok(0, ! $csr);
#if ($dbh->err && $dbh->err == 6550) { # PL/SQL error
# warn "errstr: ".$dbh->errstr;
# my $msg = $dbh->func('plsql_errstr');
# warn "plsql_errstr: $msg";
# ok(0, $msg =~ /Encountered the symbol/, "plsql_errstr: $msg");
#}
#else {
# warn "plsql_errstr test skipped ($DBI::err)\n";
# ok(0, 1);
#}
#die;
# --- test dbms_output_* functions
$dbh->{PrintError} = 1;
ok(0, $dbh->func(30000, 'dbms_output_enable'), 1);
#$dbh->trace(3);
my @ary = ("foo", ("bar" x 15), "baz", "boo");
ok(0, $dbh->func(@ary, 'dbms_output_put'), 1);
@ary = scalar $dbh->func('dbms_output_get'); # scalar context
ok(0, @ary==1 && $ary[0] && $ary[0] eq 'foo', 0);
@ary = scalar $dbh->func('dbms_output_get'); # scalar context
ok(0, @ary==1 && $ary[0] && $ary[0] eq 'bar' x 15, 0);
@ary = $dbh->func('dbms_output_get'); # list context
ok(0, join(':',@ary) eq 'baz:boo', 0);
$dbh->{PrintError} = 0;
#$dbh->trace(0);
# --- test cursor variables
if (1) {
my $cur_query = q{
SELECT object_name, owner
FROM all_objects
WHERE object_name LIKE :p1
ORDER BY object_name
};
my $cur1 = 42;
#$dbh->trace(4);
my $parent = $dbh->prepare(qq{
BEGIN OPEN :cur1 FOR $cur_query; END;
});
ok(0, $parent, $DBI::errstr);
ok(0, $parent->bind_param(":p1", "V%"));
ok(0, $parent->bind_param_inout(":cur1", \$cur1, 0, { ora_type => ORA_RSET } ));
ok(0, $parent->execute());
my @r;
push @r, @tmp while @tmp = $cur1->fetchrow_array;
ok(0, @r>0, "rows: ".@r);
#$dbh->trace(0); $parent->trace(0);
# compare results with normal execution of query
my $s1 = $dbh->selectall_arrayref($cur_query, undef, "V%");
my @s1 = map { @$_ } @$s1;
ok(0, "@r" eq "@s1", "\nref=(@r),\nsql=(@s1)");
# --- test re-bind and re-execute of same 'parent' statement
my $cur1_str = "$cur1";
#$dbh->trace(4); $parent->trace(4);
ok(0, $parent->bind_param(":p1", "U%"));
ok(0, $parent->execute());
ok(0, "$cur1" ne $cur1_str); # must be ref to new handle object
@r = ();
push @r, @tmp while @tmp = $cur1->fetchrow_array;
#$dbh->trace(0); $parent->trace(0); $cur1->trace(0);
my $s2 = $dbh->selectall_arrayref($cur_query, undef, "U%");
my @s2 = map { @$_ } @$s2;
ok(0, "@r" eq "@s2", "\nref=(@r),\nsql=(@s2)");
}
print "test bind_param_inout of param that's not assigned to in executed statement\n";
# See http://www.mail-archive.com/dbi-users@perl.org/msg18835.html
if (1) {
my $sth = $dbh->prepare (q(
BEGIN
-- :p1 := :p1 ;
-- :p2 := :p2 ;
IF :p2 != :p3 THEN
:p1 := 'AAA' ;
:p2 := 'Z' ;
END IF ;
END ;
)) ;
my ($p1, $p2, $p3) = ('Hello', 'Y', 'Y') ;
$sth->bind_param_inout(':p1', \$p1, 30) ;
$sth->bind_param_inout(':p2', \$p2, 1) ;
$sth->bind_param_inout(':p3', \$p3, 1) ;
print "Before p1=[$p1] p2=[$p2] p3=[$p3]\n" ;
ok(0, $sth->execute);
ok(0, $p1 eq 'Hello');
ok(0, $p2 eq 'Y');
ok(0, $p3 eq 'Y');
print "After p1=[$p1] p2=[$p2] p3=[$p3]\n" ;
}
SKIP: {
sub skip { ok(0,1) for (1..$_[1]); print "$_[0]\n"; local $^W; last SKIP };
print "test nvarchar2 arg passing to functions\n";
# http://www.nntp.perl.org/group/perl.dbi.users/24217
my $ora_server_version = $dbh->func("ora_server_version");
skip "Client/server version < 9.0", 15
if DBD::Oracle::ORA_OCI() < 9.0 || $ora_server_version->[0] < 9;
my $func_name = "dbd_oracle_nvctest".($ENV{DBD_ORACLE_SEQ}||'');
$dbh->do(qq{
CREATE OR REPLACE FUNCTION $func_name(arg nvarchar2, arg2 nvarchar2)
RETURN int IS
BEGIN
if arg is null or arg2 is null then
return -1;
else
return 1;
end if;
END;
}) or skip("Can't create a function ($DBI::errstr)", 15);
my $sth = $dbh->prepare(qq{SELECT $func_name(?, ?) FROM DUAL}, {
# Oracle 8 describe fails with ORA-06553: PLS-561: charset mismatch
ora_check_sql => 0,
});
ok(0, $sth, sprintf("Can't prepare select from function (%s)",$DBI::errstr||''));
skip("Can't select from function ($DBI::errstr)", 14) unless $sth;
for (1..2) {
ok(0, $sth->bind_param(1, "foo", { ora_csform => SQLCS_NCHAR }));
ok(0, $sth->bind_param(2, "bar", { ora_csform => SQLCS_NCHAR }));
ok(0, $sth->execute());
ok(0, my($returnVal) = $sth->fetchrow_array);
ok(0, $returnVal eq "1");
}
ok(0, $sth->execute("baz",undef));
ok(0, my($returnVal) = $sth->fetchrow_array);
ok(0, $returnVal eq "-1");
ok(0, $dbh->do(qq{drop function $func_name}));
}
# --- To do
# test NULLs at first bind
# NULLs later binds.
# returning NULLs
# multiple params, mixed types and in only vs inout
print "test ping\n";
ok(0, $dbh->ping);
$dbh->disconnect;
ok(0, !$dbh->ping);
exit 0;
BEGIN { $tests = 82 }
# end.
__END__