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 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
|
#!/usr/bin/perl -w
use strict;
use warnings;
use lib qw(t);
use Test::More;
use TestLib qw(connect prove_reqs show_reqs test_dir);
my ( $required, $recommended ) = prove_reqs();
my ( undef, $extra_recommended ) = prove_reqs( { 'DBD::SQLite' => 0, } );
show_reqs( $required, { %$recommended, %$extra_recommended } );
my @test_dbds = ( 'SQL::Statement', grep { /^dbd:/i } keys %{$recommended} );
my $testdir = test_dir();
my @external_dbds = ( keys %$extra_recommended, grep { /^dbd::(?:dbm|csv)/i } keys %{$recommended} );
foreach my $test_dbd (@test_dbds)
{
my ( $dbh, $sth );
note("Running tests for $test_dbd");
my $temp = "";
# XXX
# my $test_dbd_tbl = "${test_dbd}::Table";
# $test_dbd_tbl->can("fetch") or $temp = "$temp";
$test_dbd eq "DBD::File" and $temp = "TEMP";
$test_dbd eq "SQL::Statement" and $temp = "TEMP";
$dbh = connect(
$test_dbd,
{
PrintError => 0,
RaiseError => 0,
f_dir => $testdir,
}
);
my $external_dsn;
if (%$extra_recommended)
{
if ( $extra_recommended->{'DBD::SQLite'} )
{
$external_dsn = "DBI:SQLite:dbname=" . File::Spec->catfile( $testdir, 'sqlite.db' );
}
}
elsif (@external_dbds)
{
if ( $test_dbd eq $external_dbds[0] and @external_dbds > 1 )
{
$external_dsn = $external_dbds[1];
}
else
{
$external_dsn = $external_dbds[0];
}
$external_dsn =~ s/^dbd::(\w+)$/dbi:$1:/i;
my @valid_dsns = DBI->data_sources( $external_dsn, { f_dir => $testdir } );
$external_dsn = $valid_dsns[0];
}
#######################
# identifier names
#######################
$dbh->do($_) for split /\n/, <<"";
CREATE TEMP TABLE Prof (pid INT, pname VARCHAR(30))
INSERT INTO Prof VALUES (1,'Sue')
INSERT INTO Prof VALUES (2,'Bob')
INSERT INTO Prof VALUES (3,'Tom')
$sth = $dbh->prepare("SELECT * FROM Prof");
$sth->execute();
is_deeply( $sth->col_names(), [qw(pid pname)], "Column Names: select list = *" );
$sth = $dbh->prepare("SELECT pname,pID FROM Prof");
$sth->execute();
is_deeply( $sth->col_names(), [qw(pname pID)], 'Column Names: select list = named' );
$sth = $dbh->prepare('SELECT pname AS "ProfName", pId AS "Magic#" from prof');
$sth->execute();
no warnings;
is_deeply( $sth->col_names(), [qw("ProfName" "Magic#")],
"Column Names: select list = aliased" );
use warnings;
$sth = $dbh->prepare(q{SELECT pid, concat(pname, ' is #', pId ) from prof});
$sth->execute();
is_deeply( $sth->col_names(), [qw(pid concat)], "Column Names: select list with function" );
$sth = $dbh->prepare(
q{SELECT pid AS "ID", concat(pname, ' is #', pId ) AS "explanation" from prof});
$sth->execute();
is_deeply( $sth->col_names(), [qw("ID" "explanation")],
"Column Names: select list with function = aliased" );
my @rt34121_checks = (
{
descr => 'camelcased',
cols => [qw("fOo")],
tbls => [qw("SomeTable")]
},
{
descr => 'reserved names',
cols => [qw("text")],
tbls => [qw("Table")]
},
##
## According to jZed,
##
## Verbatim from Martin Gruber and Joe Celko (who is on the standards committee
## and whom I have talked to in person about this), _SQL Instant Reference_, Sybex
##
## "A regular and a delimited identifier are equal if they contain the same
## characters, taking case into account, but first converting the regular
## (but not the delimited) identifier to all uppercase letters. In effect
## a delimited identifier that contains lowercase letters can never equal a
## regular identifier although it may equal another delimited one."
##
{
descr => 'not quoted',
cols => [qw(Foo)],
tbls => [qw(SomeTable)],
icols => [qw(foo)],
itbls => [qw(sometable)], # none quoted identifiers are lowercased internally
},
);
for my $check (@rt34121_checks)
{
$sth = $dbh->prepare(
sprintf(
q{SELECT %s FROM %s},
join( ", ", @{ $check->{cols} } ),
join( ", ", @{ $check->{tbls} } )
)
);
is_deeply( $sth->col_names(),
$check->{icols} || $check->{cols},
"Raw SQL hidden absent from column name [rt.cpan.org #34121] ($check->{descr})" );
is_deeply( $sth->tbl_names(),
$check->{itbls} || $check->{tbls},
"Raw SQL hidden absent from table name [rt.cpan.org #34121] ($check->{descr})" );
}
$dbh->do("CREATE $temp TABLE allcols ( f1 char(10), f2 char(10) )");
$sth = $dbh->prepare("INSERT INTO allcols (f1,f2) VALUES (?,?)")
or diag( "Can't prepare insert sth: " . $dbh->errstr() );
$sth->execute( 'abc', 'def' );
my $allcols_before = $sth->all_cols();
$sth->execute( 'abc', 'def' ) for 1 .. 100;
my $allcols_after = $sth->all_cols();
is_deeply( $allcols_before, $allcols_after,
'->{all_cols} structure does not grow beyond control' );
#########################
# migration of t/07case.t
#########################
# NOTE: DBD::DBM requires at least 2 columns
my %create = (
lower => "CREATE $temp TABLE tbl (id INT, col INT)",
upper => "CREATE $temp TABLE tbl (ID INT, COL INT)",
mixed => "CREATE $temp TABLE tbl (iD INT, cOl INT)",
);
my %query = (
lower => "SELECT id,col FROM tbl WHERE 1=0",
upper => "SELECT ID,COL FROM tbl WHERE 1=0",
mixed => "SELECT Id,cOl FROM tbl WHERE 1=0",
asterisked => "SELECT * FROM tbl WHERE 1=0",
);
for my $create_case (qw(lower upper mixed))
{
$dbh->do("DROP TABLE IF EXISTS tbl");
$dbh->do( $create{$create_case} );
for my $query_case (qw(lower upper mixed asterisked))
{
my $sth = $dbh->prepare( $query{$query_case} );
my $msg = sprintf( "%s/%s", $create_case, $query_case );
ok( $sth->execute(), "execute for '$msg'" ) or diag( $dbh->errstr() );
my $col = $sth->col_names()->[1];
is( $col, 'col', $msg ) if ( $query_case eq 'lower' );
is( $col, 'COL', $msg ) if ( $query_case eq 'upper' );
is( $col, 'cOl', $msg ) if ( $query_case eq 'mixed' );
is( $col, 'col', $msg ) if ( $query_case eq 'asterisked' );
}
$dbh->do("DROP TABLE IF EXISTS tbl");
}
SKIP:
{
skip( 'No external usable data source installed', 1 ) unless ($external_dsn);
skip( "Need DBI statement handle - can't use when executing direct", 1 )
if ( $dbh->isa('TestLib::Direct') );
my $xb_dbh = DBI->connect($external_dsn);
$xb_dbh->do($_) for split /\n/, <<"";
CREATE TABLE pg (id INT, col INT)
INSERT INTO pg VALUES (3,7)
my $xb_sth = $xb_dbh->prepare("SELECT * FROM pg WHERE 1=0");
$xb_sth->execute();
my $nameOfCol = $xb_sth->{NAME}->[1];
$dbh->do("CREATE $temp TABLE tbl AS IMPORT(?)",{},$xb_sth);
for my $query_case(qw(lower upper mixed asterisked)) {
my $sth = $dbh->prepare( $query{$query_case} );
$sth->execute();
my $msg = sprintf( "imported table : %s", $query_case );
my $col = $sth->col_names()->[1];
is($col, 'col',$msg) if $query_case eq 'lower';
is($col, 'COL',$msg) if $query_case eq 'upper';
is($col, 'cOl',$msg) if $query_case eq 'mixed';
is($col, $nameOfCol,$msg) if $query_case eq 'asterisked';
}
$xb_dbh->do("DROP TABLE pg");
$dbh->do("DROP TABLE IF EXISTS tbl");
$xb_dbh->disconnect;
}
}
done_testing();
__END__
PostgreSQL
Case insensitive comparisons
Always stores in lower case
Always returns lower case
S::S 0.x
Case *sensitive* comparisons (if you created with "MYCOL" you can
not query with "mycol" or "MyCol")
Stores in mixed case
Always returns stored case
SQLite and S::S 1.x
Case insensitive comparisons
Stores in mixed case
Returns stored case for *, query case otherwise
Returns stored case for asterisked queries
* except in 1.12 with TEMP files, upper-cases columns
Returns query case if columns are specified in query
S::S 1.12
file-based table : same as 1.x
TEMP table : same, except upper cases on asterisked queries
imported table : same, except upper cases on asterisked queries
|