#!perl -w # vim: ft=perl # # This checks for UTF-8 parameter support. # use strict; use warnings FATAL => 'all'; use DBI; use Test::More; use vars qw($table $test_dsn $test_user $test_password); use vars qw($COL_NULLABLE $COL_KEY); use lib 't', '.'; require 'lib.pl'; my $tb = Test::More->builder; binmode $tb->output, ":utf8"; binmode $tb->failure_output, ":utf8"; binmode $tb->todo_output, ":utf8"; my $dbh = DbiTestConnect($test_dsn, $test_user, $test_password, { RaiseError => 1, PrintError => 0 }); my $nasty_unicode1 = "\N{U+C3}\N{U+BF}"; # looks like character 0xff, if you accidentally utf8 decode utf8::downgrade($nasty_unicode1); my $nasty_unicode2 = $nasty_unicode1; utf8::upgrade($nasty_unicode2); is($nasty_unicode1, $nasty_unicode2, "Perl's internal form does not matter"); my $nasty_bytes1 = chr(0xc3).chr(0xbf); # looks like character 0xff, if you accidentally utf8 decode utf8::downgrade($nasty_bytes1); my $nasty_bytes2 = $nasty_bytes1; utf8::upgrade($nasty_bytes2); is($nasty_bytes1, $nasty_bytes2, "Perl's internal form does not matter"); is($nasty_unicode1, $nasty_bytes1, "Perl does not distinguish between bytes and Unicode string"); is($nasty_unicode2, $nasty_bytes2, "Perl does not distinguish between bytes and Unicode string"); foreach my $server_prepare (0, 1) { my $enable_str = "mariadb_server_prepare=$server_prepare"; my $enable_hash = { RaiseError => 1, PrintError => 0, mariadb_server_prepare => $server_prepare, mariadb_server_prepare_disable_fallback => 1 }; $dbh = DBI->connect($test_dsn, $test_user, $test_password, $enable_hash); foreach my $charset ("latin1", "utf8") { $dbh->do(qq{ CREATE TEMPORARY TABLE unicode_test ( payload VARCHAR(20), id int(10) ) CHARACTER SET $charset }) or die $dbh->errstr; my $nasty_unicode1_param = $nasty_unicode1; my $nasty_unicode2_param = $nasty_unicode2; $dbh->do("INSERT INTO unicode_test (id, payload) VALUES (1, ?), (2, ?)", {}, $nasty_unicode1_param, $nasty_unicode2_param); $dbh->do("INSERT INTO unicode_test (id, payload) VALUES (3, '$nasty_unicode1_param')"); $dbh->do("INSERT INTO unicode_test (id, payload) VALUES (4, '$nasty_unicode2_param')"); my $sth = $dbh->prepare("INSERT INTO unicode_test (id, payload) VALUES (?, ?)"); $sth->execute(5, $nasty_unicode1_param); $sth->execute(6, $nasty_unicode2_param); $sth = $dbh->prepare("INSERT INTO unicode_test (id, payload) VALUES (?, ?)"); $sth->bind_param(1, 7); $sth->bind_param(2, $nasty_unicode1_param); $sth->execute; $sth = $dbh->prepare("INSERT INTO unicode_test (id, payload) VALUES (?, ?)"); $sth->bind_param(1, 8); $sth->bind_param(2, $nasty_unicode2_param); $sth->execute; { my $sql = "INSERT INTO unicode_test (id, payload) VALUES (?, ?)"; $sth = $dbh->prepare($sql); } $sth->execute(9, $nasty_unicode1_param); $sth->execute(10, $nasty_unicode2_param); { my $sql = "INSERT INTO unicode_test (id, payload) VALUES (?, ?)"; $sth = $dbh->prepare($sql); } { my $param = 1; my $val = 11; $sth->bind_param($param, $val); } { my $param = 2; my $val = $nasty_unicode1_param; $sth->bind_param($param, $val); } $sth->execute; { my $sql = "INSERT INTO unicode_test (id, payload) VALUES (?, ?)"; $sth = $dbh->prepare($sql); } { my $param = 1; my $val = 12; $sth->bind_param($param, $val); } { my $param = 2; my $val = $nasty_unicode2_param; $sth->bind_param($param, $val); } $sth->execute; my @trials = ( 'do with supplied params', 'do with interpolated string', 'prepare then execute', 'prepare, bind, execute', 'prepare (free param) then execute', 'prepare (free param), bind (free param), execute', ); for (my $i = 0; $i<@trials; $i++) { my $id1 = $i*2+1; my $id2 = $i*2+2; (my $out) = $dbh->selectrow_array("SELECT payload FROM unicode_test WHERE id = $id1"); is($out, "\N{U+C3}\N{U+BF}", "unicode / $trials[$i] / utf8::downgrade / $charset / $enable_str"); ($out) = $dbh->selectrow_array("SELECT payload FROM unicode_test WHERE id = $id2"); is($out, "\N{U+C3}\N{U+BF}", "unicode / $trials[$i] / utf8::upgrade / $charset / $enable_str"); } $dbh->do("DROP TEMPORARY TABLE unicode_test"); $dbh->do(qq{ CREATE TEMPORARY TABLE blob_test ( payload BLOB, id int(10) ) CHARACTER SET $charset }) or die $dbh->errstr; my $nasty_bytes1_param = $nasty_bytes1; my $nasty_bytes2_param = $nasty_bytes2; $sth = $dbh->prepare("INSERT INTO blob_test (id, payload) VALUES (?, ?)"); $sth->bind_param(1, 1); $sth->bind_param(2, $nasty_bytes1_param, DBI::SQL_BLOB); $sth->execute; $sth = $dbh->prepare("INSERT INTO blob_test (id, payload) VALUES (?, ?)"); $sth->bind_param(1, 2); $sth->bind_param(2, $nasty_bytes2_param, DBI::SQL_BLOB); $sth->execute; { my $sql = "INSERT INTO blob_test (id, payload) VALUES (?, ?)"; $sth = $dbh->prepare($sql); } { my $param = 1; my $val = 3; $sth->bind_param($param, $val); } { my $param = 2; my $val = $nasty_bytes1_param; my $type = DBI::SQL_BLOB; $sth->bind_param($param, $val, $type); } $sth->execute; { my $sql = "INSERT INTO blob_test (id, payload) VALUES (?, ?)"; $sth = $dbh->prepare($sql); } { my $param = 1; my $val = 4; $sth->bind_param($param, $val); } { my $param = 2; my $val = $nasty_bytes2_param; my $type = DBI::SQL_BLOB; $sth->bind_param($param, $val, $type); } $sth->execute; @trials = ( 'prepare, bind, execute', 'prepare (free param), bind (free param), execute', ); for (my $i = 0; $i<@trials; $i++) { my $id1 = $i*2+1; my $id2 = $i*2+2; (my $out) = $dbh->selectrow_array("SELECT payload FROM blob_test WHERE id = $id1"); is($out, chr(0xc3).chr(0xbf), "blob / $trials[$i] / utf8::downgrade / $charset / $enable_str"); ($out) = $dbh->selectrow_array("SELECT payload FROM blob_test WHERE id = $id2"); is($out, chr(0xc3).chr(0xbf), "blob / $trials[$i] / utf8::upgrade / $charset / $enable_str"); } $dbh->do("DROP TEMPORARY TABLE blob_test"); } } done_testing();