1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
#!perl -w
## ----------------------------------------------------------------------------
## 31lob_extended.t
## By John Scoles, The Pythian Group
## ----------------------------------------------------------------------------
## This run through some bugs that have been found in earlier versions of DBD::Oracle
## Checks to ensure that these bugs no longer come up
## Basically this is testing the use of LOBs when returned via stored procedures with bind_param_inout
## ----------------------------------------------------------------------------
use Test::More;
use DBI;
use Config;
use DBD::Oracle qw(:ora_types);
use strict;
use warnings;
use Data::Dumper;
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,
});
if ($dbh) {
plan tests => 31;
$dbh->{LongReadLen} = 7000;
} else {
plan skip_all => "Unable to connect to Oracle";
diag('Test reported bugs');
}
my ($table, $data0, $data1) = setup_test($dbh);
#
# bug in DBD::Oracle 1.21 where if ora_auto_lobs is not set and we attempt to
# fetch from a table containing lobs which has more than one row
# we get a segfault. This was due to prefetching more than one row.
#
{
my $testname = "ora_auto_lobs prefetch";
my ($sth1, $ev);
eval {$sth1 = $dbh->prepare(
q/begin p_DBD_Oracle_drop_me(?); end;/, {ora_auto_lob => 0});
};
ok(!$@, "$testname - prepare call proc");
my $sth2;
ok($sth1->bind_param_inout(1, \$sth2, 500, {ora_type => ORA_RSET}),
"$testname - bind out cursor");
ok($sth1->execute, "$testname - execute to get out cursor");
my ($lobl);
($lobl) = $sth2->fetchrow;
test_lob($dbh, $lobl, $testname, 6000, $data0);
($lobl) = $sth2->fetchrow;
test_lob($dbh, $lobl, $testname, 6000, $data1);
ok($sth2->finish, "$testname - finished returned sth");
ok($sth1->finish, "$testname - finished sth");
}
#
# prior to DBD::Oracle 1.22 if ora_auto_lob was set on a statement which
# was used to return a cursor on a result-set containing lobs, the lobs
# were not automatically fetched.
#
{
my $testname = "ora_auto_lobs not fetching";
my ($sth1, $ev, $lob);
eval {$sth1 = $dbh->prepare(
# ora_auto_lobs is supposed to default to set
q/begin p_DBD_Oracle_drop_me(?); end;/);
};
ok(!$@, "$testname prepare call proc");
my $sth2;
ok($sth1->bind_param_inout(1, \$sth2, 500, {ora_type => ORA_RSET}),
"$testname - bind out cursor");
ok($sth1->execute, "$testname - execute to get out cursor");
($lob) = $sth2->fetchrow;
ok($lob, "$testname - fetch returns something");
isnt(ref $lob, 'OCILobLocatorPtr', "$testname - not a lob locator");
is($lob, $data0, "$testname, first lob matches");
($lob) = $sth2->fetchrow;
ok($lob, "$testname - fetch returns something");
isnt(ref $lob, 'OCILobLocatorPtr', "$testname - not a lob locator");
is($lob, $data1, "$testname, second lob matches");
ok($sth2->finish, "$testname - finished returned sth");
ok($sth1->finish, "$testname - finished sth");
}
sub test_lob
{
my ($h, $lobl, $testname, $size, $data) = @_;
ok($lobl, "$testname - lob locator retrieved");
is(ref($lobl), 'OCILobLocatorPtr', "$testname - is a lob locator");
SKIP: {
skip "did not receive a lob locator", 4
unless ref($lobl) eq 'OCILobLocatorPtr';
my ($lob_length, $lob, $ev);
eval {$lob_length = $h->ora_lob_length($lobl);};
$ev = $@;
diag($ev) if $ev;
ok(!$ev, "$testname - first lob length $lob_length");
is($lob_length, $size, "$testname - correct lob length");
eval {$lob = $h->ora_lob_read($lobl, 1, $lob_length);};
$ev = $@;
diag($ev) if ($ev);
ok(!$ev, "$testname - read lob");
is($lob, $data, "$testname - lob returned matches lob inserted");
}
}
sub setup_test
{
my ($h) = @_;
my ($table, $sth, $ev);
eval {$table = create_table($h, {cols => [['x', 'clob']]}, 1)};
BAIL_OUT("test table not created- $@") if $@;
ok(!$ev, "created test table");
eval {
$sth = $h->prepare(qq/insert into $table (idx, x) values(?,?)/);
};
BAIL_OUT("Failed to prepare insert into $table - $@") if $@;
my $data0 = 'x' x 6000;
my $data1 = 'y' x 6000;
eval {
$sth->execute(1, $data0);
$sth->execute(2, $data1);
};
BAIL_OUT("Failed to insert test data into $table - $@") if $@;
ok(!$ev, "created test data");
my $createproc = << "EOT";
CREATE OR REPLACE PROCEDURE p_DBD_Oracle_drop_me(pc OUT SYS_REFCURSOR) AS
l_cursor SYS_REFCURSOR;
BEGIN
OPEN l_cursor FOR
SELECT x from $table;
pc := l_cursor;
END;
EOT
eval {$h->do($createproc);};
BAIL_OUT("Failed to create test procedure - $@") if $@;
ok(!$ev, "created test procedure");
return ($table, $data0, $data1);
}
END {
return unless $dbh;
local $dbh->{PrintError} = 0;
local $dbh->{RaiseError} = 1;
eval {$dbh->do(q/drop procedure p_DBD_Oracle_drop_me/);};
if ($@) {
diag("procedure p_DBD_Oracle_drop_me possibly not dropped" .
"- check - $@\n") if $dbh->err ne '4043';
}
eval {drop_table($dbh);};
if ($@) {
diag("table $table possibly not dropped - check - $@\n")
if $dbh->err ne '942';
}
}
|