Skip to content

Commit b7cec57

Browse files
committed
tests for $sth->{ParamValues} attrib
confirming behavior of this attribute before and after execution on prepared statements, with and without bound values. and confirming that no segfaults happen (gh perl5-dbi#447)
1 parent 0c8c2d3 commit b7cec57

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

t/gh447-paramvalues.t

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use strict;
2+
use warnings;
3+
4+
use Test::More;
5+
use DBI;
6+
use lib 't', '.';
7+
require 'lib.pl';
8+
9+
my ($row, $sth, $dbh);
10+
my ($def, $rows, $errstr, $ret_ref);
11+
use vars qw($test_dsn $test_user $test_password);
12+
my $table = 'dbd_mysql_gh447';
13+
14+
eval {$dbh = DBI->connect($test_dsn, $test_user, $test_password,
15+
{ RaiseError => 1, AutoCommit => 1});};
16+
17+
if ($@) {
18+
plan skip_all =>
19+
"no database connection";
20+
}
21+
22+
# in case exit early, ensure we clean up
23+
END {
24+
if ($dbh) {
25+
$dbh->do("DROP TABLE IF EXISTS $table");
26+
$dbh->disconnect();
27+
}
28+
}
29+
30+
# ------ set up
31+
ok(defined $dbh, "Connected to database");
32+
$dbh->do("DROP TABLE IF EXISTS $table");
33+
$dbh->do("CREATE TABLE $table (id INT(4), name VARCHAR(64))");
34+
35+
36+
# test prepare/execute statement without a placeholder
37+
38+
$sth = $dbh->prepare("SHOW TABLES LIKE '$table'");
39+
is_deeply($sth->{ParamValues}, {}, "ParamValues is empty hashref before SHOW");
40+
$sth->execute();
41+
42+
is_deeply($sth->{ParamValues}, {}, "ParamValues is still empty after execution");
43+
44+
$sth->finish;
45+
is_deeply($sth->{ParamValues}, {}, "ParamValues empty after finish");
46+
undef $sth;
47+
48+
49+
# test prepare/execute statement with a placeholder
50+
51+
$sth = $dbh->prepare("INSERT INTO $table values (?, ?)");
52+
is_deeply($sth->{ParamValues}, {1 => undef, 2 => undef},
53+
"ParamValues is correct hashref before INSERT");
54+
55+
# insert rows with placeholder
56+
my %rowdata;
57+
my @chars = grep !/[0O1Iil]/, 0..9, 'A'..'Z', 'a'..'z';
58+
59+
for (my $i = 1 ; $i < 4; $i++) {
60+
my $word = join '', map { $chars[rand @chars] } 0 .. 16;
61+
$rowdata{$i} = $word; # save for later
62+
$rows = $sth->execute($i, $word);
63+
is($rows, 1, "Should have inserted one row");
64+
my $attrib = $sth->{ParamValues};
65+
is_deeply($attrib, {1 => $i, 2 => $word}, "row $i ParamValues hashref as expected");
66+
# we're checking here that list context doesnt cause segfault
67+
my %copy = %$attrib;
68+
is_deeply(\%copy, {1 => $i, 2 => $word}, "...and copied hashref as well");
69+
}
70+
71+
$sth->finish;
72+
is_deeply($sth->{ParamValues}, {}, "ParamValues empty after finish");
73+
undef $sth;
74+
75+
76+
# test prepare/execute with bind_param
77+
78+
$sth = $dbh->prepare("SELECT * FROM $table WHERE id = ? OR name = ?");
79+
is_deeply($sth->{ParamValues}, {1 => undef, 2 => undef},
80+
"ParamValues is hashref with keys before bind_param");
81+
$sth->bind_param(1, 1, DBI::SQL_INTEGER);
82+
$sth->bind_param(2, $rowdata{1});
83+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{1}},
84+
"ParamValues contains bound values after bind_param");
85+
86+
my %copy = do { my $attrib = $sth->{ParamValues}; %$attrib };
87+
ok( %copy, 'copied ParamValues without segfault');
88+
89+
$rows = $sth->execute;
90+
is($rows, 1, 'execute selected 1 row');
91+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{1}},
92+
"ParamValues still contains values after execute");
93+
%copy = do { my $attrib = $sth->{ParamValues}; %$attrib };
94+
ok( %copy, 'copied ParamValues without segfault');
95+
96+
# try changing one parameter only
97+
$sth->bind_param(2, $rowdata{2});
98+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{2}},
99+
"ParamValues updated with another bind_param");
100+
$rows = $sth->execute;
101+
is($rows, 2, 'execute selected 2 rows because changed param value');
102+
103+
# try execute with args (the bound values take precedent?)
104+
$rows = $sth->execute(3, $rowdata{3});
105+
is($rows, 2, 'execute used bound params, ignored exec args');
106+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{2}},
107+
"ParamValues reflect bound params -- execute args ignored");
108+
109+
$sth->bind_param(1, undef, DBI::SQL_INTEGER);
110+
is_deeply($sth->{ParamValues}, {1 => undef, 2 => $rowdata{2}},
111+
"ParamValues includes undef param after binding");
112+
%copy = do { my $attrib = $sth->{ParamValues}; %$attrib };
113+
ok( %copy, 'copied ParamValues without segfault');
114+
115+
$rows = $sth->execute(1);
116+
is($rows, 1, 'execute used bound undef value, not exec arg');
117+
is_deeply($sth->{ParamValues}, {1 => undef, 2 => $rowdata{2}},
118+
"ParamValues unchanged after execution");
119+
120+
undef $sth;
121+
122+
123+
# clean up
124+
$dbh->do("DROP TABLE IF EXISTS $table");
125+
126+
# Install a handler so that a warning about unfreed resources gets caught
127+
$SIG{__WARN__} = sub { die @_ };
128+
129+
$dbh->disconnect();
130+
131+
undef $dbh;
132+
133+
done_testing();
134+

0 commit comments

Comments
 (0)