Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 287beec

Browse files
committedOct 31, 2024
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 287beec

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed
 

‎t/gh447-paramvalues.t

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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($sth->{ParamValues}, undef, "ParamValues is undef before SHOW");
40+
41+
$sth->execute();
42+
# is($sth->errstr, '', 'no error');
43+
44+
ok((defined($row= $sth->fetchrow_arrayref) &&
45+
(!defined($errstr = $sth->errstr) || $sth->errstr eq '')),
46+
"Testing if result set and no errors");
47+
48+
is($sth->{ParamValues}, undef, "ParamValues is still undef after execution");
49+
50+
$sth->finish;
51+
is($sth->{ParamValues}, undef, "ParamValues undef after finish");
52+
undef $sth;
53+
54+
55+
# test prepare/execute statement with a placeholder
56+
57+
$sth = $dbh->prepare("INSERT INTO $table values (?, ?)");
58+
is($sth->{ParamValues}, undef, "ParamValues is undef before INSERT");
59+
60+
# insert rows with placeholder
61+
my %rowdata;
62+
my @chars = grep !/[0O1Iil]/, 0..9, 'A'..'Z', 'a'..'z';
63+
64+
for (my $i = 1 ; $i < 4; $i++) {
65+
my $word = join '', map { $chars[rand @chars] } 0 .. 16;
66+
$rowdata{$i} = $word; # save for later
67+
$rows = $sth->execute($i, $word);
68+
is($rows, 1, "Should have inserted one row");
69+
my $attrib = $sth->{ParamValues};
70+
is_deeply($attrib, {1 => $i, 2 => $word}, "row $i ParamValues hashref as expected");
71+
# we're checking here that list context doesnt cause segfault
72+
my %copy = %$attrib;
73+
is_deeply(\%copy, {1 => $i, 2 => $word}, "...and copied hashref as well");
74+
}
75+
76+
$sth->finish;
77+
is($sth->{ParamValues}, undef, "ParamValues undef after finish");
78+
undef $sth;
79+
80+
81+
# test prepare/execute with bind_param
82+
83+
$sth = $dbh->prepare("SELECT * FROM $table WHERE id = ? OR name = ?");
84+
is($sth->{ParamValues}, undef, "ParamValues is undef before bind_param");
85+
$sth->bind_param(1, 1, DBI::SQL_INTEGER);
86+
$sth->bind_param(2, $rowdata{1});
87+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{1}},
88+
"ParamValues contains bound values after bind_param");
89+
90+
my %copy = do { my $attrib = $sth->{ParamValues}; %$attrib };
91+
ok( %copy, 'copied ParamValues without segfault');
92+
93+
$rows = $sth->execute;
94+
is($rows, 1, 'execute selected 1 row');
95+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{1}},
96+
"ParamValues still contains values after execute");
97+
%copy = do { my $attrib = $sth->{ParamValues}; %$attrib };
98+
ok( %copy, 'copied ParamValues without segfault');
99+
100+
# try changing one parameter only
101+
$sth->bind_param(2, $rowdata{2});
102+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{2}},
103+
"ParamValues updated with another bind_param");
104+
$rows = $sth->execute;
105+
is($rows, 2, 'execute selected 2 rows because changed param value');
106+
107+
# try execute with args (the bound values take precedent?)
108+
$rows = $sth->execute(3, $rowdata{3});
109+
is($rows, 2, 'execute used bound params, ignored exec args');
110+
is_deeply($sth->{ParamValues}, {1 => 1, 2 => $rowdata{2}},
111+
"ParamValues reflect bound params -- execute args ignored");
112+
113+
$sth->bind_param(1, undef, DBI::SQL_INTEGER);
114+
is_deeply($sth->{ParamValues}, {1 => undef, 2 => $rowdata{2}},
115+
"ParamValues includes undef param after binding");
116+
%copy = do { my $attrib = $sth->{ParamValues}; %$attrib };
117+
ok( %copy, 'copied ParamValues without segfault');
118+
119+
$rows = $sth->execute(1);
120+
is($rows, 1, 'execute used bound undef value, not exec arg');
121+
is_deeply($sth->{ParamValues}, {1 => undef, 2 => $rowdata{2}},
122+
"ParamValues unchanged after execution");
123+
124+
undef $sth;
125+
126+
127+
# clean up
128+
$dbh->do("DROP TABLE IF EXISTS $table");
129+
130+
# Install a handler so that a warning about unfreed resources gets caught
131+
$SIG{__WARN__} = sub { die @_ };
132+
133+
$dbh->disconnect();
134+
135+
undef $dbh;
136+
137+
done_testing();
138+

0 commit comments

Comments
 (0)
Please sign in to comment.