diff --git a/Changes b/Changes index 484153f5..dee5aeea 100644 --- a/Changes +++ b/Changes @@ -2,6 +2,9 @@ Changes for the DBD::Pg module RT refers to rt.cpan.org + - Support binding native boolean false on Perl 5.36 and newer + [Dagfinn Ilmari Mannsåker] + Version 3.18.0 (released December 6, 2023) - Support new PQclosePrepared function, added in Postgres 17 diff --git a/Pg.pm b/Pg.pm index b4665538..5191d8f9 100644 --- a/Pg.pm +++ b/Pg.pm @@ -4455,6 +4455,13 @@ set the L attribute to a true value to change Boolean values can be passed to PostgreSQL as TRUE, 't', 'true', 'y', 'yes' or '1' for true and FALSE, 'f', 'false', 'n', 'no' or '0' for false. +On Perl 5.36 and newer, distinguished boolean values (see +L) can be used as placeholder values. On older +versionos of Perl, false values returned by built-in operators (such +as C) must be converted to one of the above false values, or +bound with C PG_BOOL>, since they stringify to the empty +string. + =head2 Schema support The PostgreSQL schema concept may differ from those of other databases. In a nutshell, diff --git a/dbdimp.c b/dbdimp.c index ab74e09b..2bfab354 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -17,6 +17,10 @@ #define atoll(X) _atoi64(X) #endif +#ifndef SvIsBOOL +#define SvIsBOOL(sv) DBDPG_FALSE +#endif + #define DEBUG_LAST_RESULT 0 #if PGLIBVERSION < 80300 @@ -2625,9 +2629,16 @@ int dbd_bind_ph (SV * sth, imp_sth_t * imp_sth, SV * ph_name, SV * newvalue, IV (void)SvUPGRADE(newvalue, SVt_PV); if (SvOK(newvalue)) { - /* get the right encoding, without modifying the caller's copy */ - newvalue = pg_rightgraded_sv(aTHX_ newvalue, imp_dbh->pg_utf8_flag && PG_BYTEA!=currph->bind_type->type_id); - value_string = SvPV(newvalue, currph->valuelen); + if (SvIsBOOL(newvalue)) { + /* bind native booleans as 1/0 */ + value_string = SvTRUE(newvalue) ? "1" : "0"; + currph->valuelen = 1; + } + else { + /* get the right encoding, without modifying the caller's copy */ + newvalue = pg_rightgraded_sv(aTHX_ newvalue, imp_dbh->pg_utf8_flag && PG_BYTEA!=currph->bind_type->type_id); + value_string = SvPV(newvalue, currph->valuelen); + } Renew(currph->value, currph->valuelen+1, char); /* freed in dbd_st_destroy */ Copy(value_string, currph->value, currph->valuelen+1, char); currph->value[currph->valuelen] = '\0'; diff --git a/t/12placeholders.t b/t/12placeholders.t index c241563f..8b0c3dba 100644 --- a/t/12placeholders.t +++ b/t/12placeholders.t @@ -17,7 +17,7 @@ my $dbh = connect_database(); if (! $dbh) { plan skip_all => 'Connection to database failed, cannot continue testing'; } -plan tests => 261; +plan tests => 264; my $t='Connect to database for placeholder testing'; isnt ($dbh, undef, $t); @@ -819,6 +819,7 @@ undef => 'NULL', '0e0' => 'TRUE', '0 but true' => 'TRUE', '0 BUT TRUE' => 'TRUE', +'real true' => 'TRUE', 'f' => 'FALSE', 'F' => 'FALSE', 0 => 'FALSE', @@ -827,6 +828,7 @@ undef => 'NULL', 'false' => 'FALSE', 'FALSE' => 'FALSE', '' => 'FALSE', +'real false' => 'FALSE', 12 => 'ERROR', '01' => 'ERROR', '00' => 'ERROR', @@ -839,10 +841,12 @@ undef => 'NULL', ); while (my ($name,$res) = each %booltest) { - $name = undef if $name eq 'undef'; - $t = sprintf 'Boolean quoting of %s', - defined $name ? qq{"$name"} : 'undef'; - eval { $result = $dbh->quote($name, {pg_type => PG_BOOL}); }; + my ($bool, $desc) = + $name eq 'undef' ? (undef, $name) : + $name =~ /\Areal/ ? (!!($name =~ / true\z/), $name) : + ($name, qq{"$name"}); + $t = "Boolean quoting of $desc", + eval { $result = $dbh->quote($bool, {pg_type => PG_BOOL}); }; if ($@) { if ($res eq 'ERROR' and $@ =~ /Invalid boolean/) { pass ($t); @@ -889,6 +893,14 @@ $dbh->{pg_bool_tf} = 1; is_deeply ($sth->fetch, [104,'f'], $t); $dbh->{pg_bool_tf} = 0; +SKIP: { + skip 'Cannot test native false without builtin::is_bool', 1 unless defined &builtin::is_bool; + $t = q{Inserting into a boolean column with native false works}; + $sth = $dbh->prepare($SQL); + $sth->execute(105, !!0, 'Boolean native false'); + is_deeply ($sth->fetch, [105, 0], $t); +} + ## Test of placeholder escaping. Enabled by default, so let's jump right in $t = q{Basic placeholder escaping works via backslash-question mark for \?};