diff --git a/FU/SQL.pm b/FU/SQL.pm index 8e61945..56027e0 100644 --- a/FU/SQL.pm +++ b/FU/SQL.pm @@ -180,8 +180,7 @@ B are interpreted as raw SQL fragments. =item 2. -Objects returned by other functions listed below can be included as -SQL fragments. +Objects returned by other functions listed below are included as SQL fragments. =item 3. @@ -200,8 +199,8 @@ These rules allow for flexible SQL construction: There is some magic going on in order to differentiate between a I and other arguments. The rule is that anything that is C and read-only (as per -C) is considered raw SQL. Variables are by definition -writable: +C) is considered raw SQL. Regular variables, array +elements and hash values are always writable: my $x = 'SELECT 1'; SQL $x; # BAD: $x is used as bind parameter instead @@ -210,8 +209,16 @@ writable: my $x = SQL 'SELECT 1'; SQL $x; -In most cases, though, this is the behavior you want. In the few cases where it -isn't, you can always use C or C to force an argument as bind +Constants created with C are considered string literals, and +there are probably plenty of other creative ways to end up with variables that +may be considered a "string literal" by this module. L, +L, other modules and tied hashes or arrays all have the +potential to create read-only strings, but I don't expect that these are +commonly applied on untrusted user input. + +In most cases, this heuristic should work out well. In the few cases where it +doesn't, or when you're not entirely sure what kind of value you're dealing +with, you can always use C or C to force an argument as bind parameter or SQL string. =item P($val) @@ -235,7 +242,7 @@ Force the given C<$sql> string to be included as SQL. For example: SQL 'WHERE * FROM', RAW $tables[1]; # 'SELECT * FROM b' -Absolutely do not use this function with untrusted input. +Never use this function with untrusted input. =item PARENS(@args) @@ -271,7 +278,7 @@ C<'1=1'> (i.e. true) if C<@conditions> is an empty list. =item AND($hashref) -A special form of C that tests the given column for equality instead. +A special form of C that tests the given columns for equality instead. The keys of the hashref are interpreted as raw SQL and the values as bind parameters. @@ -335,8 +342,7 @@ convenient insert-or-update: SQL 'INSERT INTO table', VALUES($data), 'ON CONFLICT (name) DO UPDATE', SET($data); -(The bind parameters are duplicated though, there's no duplicate detection yet. -Not sure if that's even worth it) +(The bind parameters are duplicated though) =item IN($arrayref) diff --git a/t/sql.t b/t/sql.t index db5172e..b035a19 100644 --- a/t/sql.t +++ b/t/sql.t @@ -68,4 +68,22 @@ t IN([]), '= ANY($1)', [[]], in_style => 'pg', placeholder_style => 'pg'; t WHERE({ id => IN([1,2]) }), 'WHERE ( id IN(?,?) )', [1,2]; +sub somefunc { 'not actually const' } +t SQL(somefunc), '?', [somefunc]; + +use constant constval => 'this is a constant'; +t SQL(constval), constval, []; + +sub otherfunc { constval } +t SQL(otherfunc), '?', [otherfunc]; + +sub passthrough { $_[0] } +t SQL(passthrough 'hi'), '?', ['hi']; + +use Hash::Util; +my %hash = (v => 'value'); +Hash::Util::lock_keys(%hash); +Hash::Util::lock_value(%hash, 'v'); +t SQL($hash{v}), 'value', []; + done_testing;