From a7868f74bf9f3fa9ce8356b8a5d5476269bc9aa9 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Thu, 12 Jun 2025 16:45:07 +0200 Subject: [PATCH] Pg: Be more strict with boolean bind parameters Reason for this is that, with FU::SQL, it's possible to accidentally introduce a bind parameter when a WHERE clause was intended (i.e. "WHERE $1"). That's pretty bad, but can easily be caught by simply not accepting *every* possible value as boolean. --- FU/Pg.pm | 10 ++++++---- c/pgtypes.c | 11 +++++++++-- t/pgtypes.t | 13 +++++++++++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/FU/Pg.pm b/FU/Pg.pm index 4a75617..e715d7b 100644 --- a/FU/Pg.pm +++ b/FU/Pg.pm @@ -631,10 +631,12 @@ Some built-in types deserve a few additional notes: =item bool -Boolean values are converted to C and C. As bind -parameters, Perl's idea of truthiness is used: C<0>, C and C<""> are -false, everything else is true. Objects that overload I are also -supported. C always converts to SQL C. +Boolean values are converted to C and C. + +As bind parameters, values recognized by C in L are +accepted, in addition to C<0>, C<"f"> and C<""> for false and C<1>, and C<"t"> +for true. C always converts to SQL C. Everything else throws an +error. =item bytea diff --git a/c/pgtypes.c b/c/pgtypes.c index 471b6d2..6b9b14a 100644 --- a/c/pgtypes.c +++ b/c/pgtypes.c @@ -82,8 +82,15 @@ RECVFN(bool) { } SENDFN(bool) { - int r = fu_2bool(aTHX_ val); /* So that we also recognize \0 and \1 */ - fustr_write_ch(out, r < 0 ? SvTRUE(val) : r); + int r = fu_2bool(aTHX_ val); + if (r < 0) { + STRLEN l; + const char *x = SvPV(val, l); + if (l == 0 || (l == 1 && (*x == '0' || *x == 'f'))) r = 0; + else if (l == 1 && (*x == '1' || *x == 't')) r = 1; + else SERR("invalid boolean value: %s", x); + } + fustr_write_ch(out, r); } RECVFN(void) { diff --git a/t/pgtypes.t b/t/pgtypes.t index 21c8eff..662de33 100644 --- a/t/pgtypes.t +++ b/t/pgtypes.t @@ -61,8 +61,17 @@ sub f($type, $p_in) { $array->[0] = 0; } -v bool => true, undef, 1, 't'; -v bool => false, undef, 0, 'f'; +v bool => true, true, 1, 't'; +v bool => \1, true, 1, 't'; +v bool => 1, true, 1, 't'; +v bool => 't', true, 1, 't'; +v bool => false, false, 0, 'f'; +v bool => \0, false, 0, 'f'; +v bool => 0, false, 0, 'f'; +v bool => '', false, 0, 'f'; +v bool => 'f', false, 0, 'f'; +f bool => 2; +f bool => []; v int2 => $_ for (1, -1, -32768, 32767, '12345', -12345, 123.0); f int2 => $_ for (-32769, 32768, [], '', 'a', 1.5);