DBD-Oracle
view release on metacpan or search on metacpan
t/lib/DBDOracleTestLib.pm view on Meta::CPAN
# perl 5.6 doesn't define utf8::is_utf8()
unless ( defined &{'utf8::is_utf8'} ) {
die "Can't run this test using Perl $] without DBI >= 1.38"
unless $DBI::VERSION >= 1.38;
*utf8::is_utf8 = sub {
my $raw = shift;
return 0 if !defined $raw;
my $v = DBI::neat($raw);
return 1 if $v =~ m/^"/; # XXX ugly hack, sufficient here
return 0 if $v =~ m/^'/; # XXX ugly hack, sufficient here
carp "Emulated utf8::is_utf8 is unreliable for $v ($raw)";
return 0;
}
}
=head binmode STDOUT, ':utf8'
Wide character in print at t/nchar_test_lib.pl line 134 (#1)
(W utf8) Perl met a wide character (>255) when it wasn't expecting
one. This warning is by default on for I/O (like print). The easiest
way to quiet this warning is simply to add the :utf8 layer to the
output, e.g. binmode STDOUT, ':utf8'. Another way to turn off the
warning is to add no warnings 'utf8'; but that is often closer to
cheating. In general, you are supposed to explicitly mark the
filehandle with an encoding, see open and perlfunc/binmode.
=cut
eval { binmode STDOUT, ':utf8' }; # Fails for perl 5.6
diag("Can't set binmode(STDOUT, ':utf8'): $@") if $@;
eval { binmode STDERR, ':utf8' }; # Fails for perl 5.6
diag("Can't set binmode(STDERR, ':utf8'): $@") if $@;
# Test::More duplicates STDOUT/STDERR at the start but does not copy the IO
# layers from our STDOUT/STDERR. As a result any calls to Test::More::diag
# with utf8 data will show warnings. Similarly, if we pass utf8 into
# Test::More::pass, ok, etc etc. To get around this we specifically tell
# Test::More to use our newly changed STDOUT and STDERR for failure_output
# and output.
my $tb = Test::More->builder;
binmode( $tb->failure_output, ':utf8' );
binmode( $tb->output, ':utf8' );
sub long_test_cols {
my ($type) = @_;
return [ [ lng => $type ], ];
}
sub extra_wide_rows {
# Non-BMP characters require use of surrogates with UTF-16
# So U+10304 becomes U+D800 followed by U+DF04 (I think) in UTF-16.
#
# When encoded as standard UTF-8, which Oracle calls AL32UTF8, it should
# be a single UTF-8 code point (that happens to occupy 4 bytes).
#
# When encoded as "CESU-8", which Oracle calls "UTF8", each surrogate
# is treated as a code point so you get 2 UTF-8 code points
# (that happen to occupy 3 bytes each). That is not valid UTF-8.
# See http://www.unicode.org/reports/tr26/ for more information.
return unless ORA_OCI >= 9.2; # need AL32UTF8 for these to work
return (
[ "\x{10304}", 'SMP Plane 1 wide char' ], # OLD ITALIC LETTER E
[ "\x{20301}", 'SIP Plane 2 wide char' ]
, # CJK Unified Ideographs Extension B
);
}
{
my $char_cols =
[ [ ch => 'varchar2(20)' ], [ descr => 'varchar2(50)' ], ];
my $nchar_cols =
[ [ nch => 'nvarchar2(20)' ], [ descr => 'varchar2(50)' ], ];
my $wide_data =
[
[ "\x{03}", 'control-C' ],
[ 'a', 'lowercase a' ],
[ 'b', 'lowercase b' ],
[ "\x{263A}", 'smiley face' ],
# These are not safe for db's with US7ASCII
# [ "\x{A1}", "upside down bang" ],
# [ "\x{A2}", "cent char" ],
# [ "\x{A3}", "british pound" ],
];
sub _narrow_data # Assuming WE8ISO8859P1 or WE8MSWIN1252 character set
{
my $highbitset = [
# These non-unicode strings are not safe if client charset is utf8
# because we have to let oracle assume they're utf8 but they're not
[ chr(161), 'upside down bang' ],
[ chr(162), 'cent char' ],
[ chr(163), 'british pound' ],
];
[
[ 'a', 'lowercase a' ],
[ 'b', 'lowercase b' ],
[ chr(3), 'control-C' ],
( _nls_local_has_utf8() ) ? () : @$highbitset
];
}
my $tdata_hr = {
narrow_char => {
cols => $char_cols,
rows => _narrow_data()
},
narrow_nchar => {
cols => $nchar_cols,
rows => _narrow_data()
},
wide_char => {
cols => $char_cols,
rows => $wide_data
},
wide_nchar => {
cols => $nchar_cols,
rows => $wide_data
},
};
sub test_data {
my ($which) = @_;
my $test_data = $tdata_hr->{$which} or die;
$test_data->{dump} = 'DUMP(%s)';
if ( $ENV{DBD_ORACLE_TESTLOB} ) { # XXX temp. needs reworking
# Nvarchar -> Nclob and varchar -> clob
$test_data->{cols}[0][1] =~ s/varchar.*/CLOB/;
$test_data->{dump} = 'DUMP(DBMS_LOB.SUBSTR(%s))';
}
return $test_data;
}
}
sub oracle_test_dsn {
my ( $default, $dsn ) = ( 'dbi:Oracle:', $ENV{ORACLE_DSN} );
$dsn ||= $ENV{DBI_DSN}
if $ENV{DBI_DSN} && ( $ENV{DBI_DSN} =~ m/^$default/io );
$dsn ||= $default;
return $dsn;
}
sub db_handle {
my $p = shift;
t/lib/DBDOracleTestLib.pm view on Meta::CPAN
"nice_string test of $description" );
return $ok1 && $ok2;
}
sub create_table {
my ( $dbh, $tdata, $drop ) = @_;
my $tcols = $tdata->{cols};
my $table = table();
my $sql = "create table $table ( idx integer, ";
foreach my $col (@$tcols) {
$sql .= $$col[0] . ' ' . $$col[1] . ', ';
}
$sql .= ' dt date )';
drop_table($dbh) if $drop;
#$dbh->do(qq{ drop table $table }) if $drop;
$dbh->do($sql);
if ( $dbh->err && $dbh->err == 955 ) {
$dbh->do(qq{ drop table $table });
warn "Unexpectedly had to drop old test table '$table'\n"
unless $dbh->err;
$dbh->do($sql);
}
elsif ( $dbh->err ) {
return;
}
else {
#$sql =~ s/ \( */(\n\t/g;
#$sql =~ s/, */,\n\t/g;
note("$sql\n");
}
return $table;
# ok( not $dbh->err, "create table $table..." );
}
sub show_db_charsets {
my ($dbh) = @_;
my $out;
my $ora_server_version = join '.',
@{ $dbh->func('ora_server_version') || [] };
my $paramsH = $dbh->ora_nls_parameters();
$out =
sprintf
"Database $ora_server_version CHAR set is %s (%s), NCHAR set is %s (%s)\n",
$paramsH->{NLS_CHARACTERSET},
db_ochar_is_utf($dbh) ? 'Unicode' : 'Non-Unicode',
$paramsH->{NLS_NCHAR_CHARACTERSET},
db_nchar_is_utf($dbh) ? 'Unicode' : 'Non-Unicode';
note($out);
my $ora_client_version = ORA_OCI();
$out =
sprintf
"Client $ora_client_version NLS_LANG is '%s', NLS_NCHAR is '%s'\n",
ora_env_var('NLS_LANG') || '<unset>',
ora_env_var('NLS_NCHAR') || '<unset>';
note($out);
}
sub db_ochar_is_utf { return shift->ora_can_unicode & 2 }
sub db_nchar_is_utf { return shift->ora_can_unicode & 1 }
sub client_ochar_is_utf8 {
my $NLS_LANG = ora_env_var('NLS_LANG') || q();
$NLS_LANG =~ s/.*\.//;
return $NLS_LANG =~ m/utf8/i;
}
sub client_nchar_is_utf8 {
my $NLS_LANG = ora_env_var('NLS_LANG') || q();
$NLS_LANG =~ s/.*\.//;
my $NLS_NCHAR = ora_env_var('NLS_NCHAR') || $NLS_LANG;
return $NLS_NCHAR =~ m/utf8/i;
}
sub _nls_local_has_utf8 {
return client_ochar_is_utf8() || client_nchar_is_utf8();
}
sub set_nls_nchar {
my ( $cset, $verbose ) = @_;
if ( defined $cset ) {
$ENV{NLS_NCHAR} = "$cset";
}
else {
undef $ENV{NLS_NCHAR}; # XXX windows? (perhaps $ENV{NLS_NCHAR}=""?)
}
# Special treatment for environment variables under Cygwin -
# see comments in dbdimp.c for details.
DBD::Oracle::ora_cygwin_set_env( 'NLS_NCHAR', $ENV{NLS_NCHAR} || '' )
if $^O eq 'cygwin';
note(
defined ora_env_var('NLS_NCHAR')
? # defined?
"set \$ENV{NLS_NCHAR}=$cset\n"
: "set \$ENV{NLS_LANG}=undef\n"
) # XXX ?
if defined $verbose;
}
sub set_nls_lang_charset {
my ( $lang, $verbose ) = @_;
$ENV{NLS_LANG} = $lang ? "AMERICAN_AMERICA.$lang" : q();
note sprintf( q|set $ENV{NLS_LANG}='%s'|, $ENV{NLS_LANG} );
# Special treatment for environment variables under Cygwin -
# see comments in dbdimp.c for details.
DBD::Oracle::ora_cygwin_set_env( 'NLS_LANG', $ENV{NLS_LANG} || '' )
if $^O eq 'cygwin';
}
sub _byte_string {
my $ret = join( '|', unpack( 'C*', $_[0] ) );
return $ret;
}
sub nice_string {
my @raw_chars = ( utf8::is_utf8( $_[0] ) )
? unpack( 'U*', $_[0] ) # unpack unicode characters
: unpack( 'C*', $_[0] ); # not unicode, so unpack as bytes
my @chars = map {
$_ > 255
? # if wide character...
sprintf( "\\x{%04X}", $_ )
: # \x{...}
chr($_) =~ /[[:cntrl:]]/
? # else if control character ...
sprintf( "\\x%02X", $_ )
: # \x..
chr($_) # else as themselves
} @raw_chars;
for my $c (@chars) {
if ( $c =~ m/\\x\{08(..)}/ ) {
$c .= q|='| . chr( hex($1) ) . q(');
}
}
my $ret = join( q||, @chars );
}
sub view_with_sqlplus {
my ( $use_nls_lang, $tdata ) = @_;
my $table = table();
my $tcols = $tdata->{cols};
my $sqlfile = 'sql.txt';
my $cols = 'idx,nch_col';
open my $F, '>', $sqlfile or die "could open $sqlfile";
print $F $ENV{ORACLE_USERID} . "\n";
my $str = qq(
col idx form 99
col ch_col form a8
col nch_col form a16
select $cols from $table;
);
print $F $str;
print $F "exit;\n";
close $F;
my $nls = 'unset';
$nls = ora_env_var('NLS_LANG') if ora_env_var('NLS_LANG');
local $ENV{NLS_LANG} = '' if not $use_nls_lang;
print "From sqlplus...$str\n ...with NLS_LANG = $nls\n";
system("sqlplus -s \@$sqlfile");
unlink $sqlfile;
}
1;
( run in 0.595 second using v1.01-cache-2.11-cpan-d7f47b0818f )