I have a query like this: (on Postgresql 8.4, PHP-fpm 5.3.10 (fpm-fcgi))
select * from users where now() - interval \'2 minutes\' < seenlast ORDER BY seen
... - INTERVAL :myminute MINUTES ...
without the quotes is the proper method. If it helps, think of the placeholders as the equivalent of use old-school variable-based query building methods
... - INTERVAL $myminute MINUTES
except the placeholders take care of the injection vulnerabilities that the variables don't. Just because you're using placeholders doesn't mean you can change SQL syntax, so
... - INTERVAL '2 minutes'
... - INTERVAL ':myminute minute'
are not valid SQL.
followup for mu:
mysql> select now() + interval '2 minute';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
mysql> select now() + interval 2 minute;
+---------------------------+
| now() + interval 2 minute |
+---------------------------+
| 2013-01-22 13:38:24 |
+---------------------------+
1 row in set (0.02 sec)
I don't know much PDO or PHP but I think I know what's going wrong here.
When you say this:
interval '3 minutes'
You're really performing a cast operation that's the same as:
'3 minutes'::interval
cast('3 minutes' as interval)
So what you're doing is casting a TEXT value to an INTERVAL. That means that you need to produce something that looks like the string '3 minutes'
. You could paste the string pieces together using string concatenation:
# Use cast to make the precedence cleaner.
$query = $db_conn->prepare("select * from users where now() - cast(:myminute || ' minutes' as interval) < seenlast ORDER BY seenlast");
$query->bindParm(":myminute", $mymin)
Or you should be able to do the string wrangling in PHP:
$query = $db_conn->prepare("select * from users where now() - interval :myminute < seenlast ORDER BY seenlast");
$query->bindParm(":myminute", $mymin . ' minutes')
I have been struggling with Phalcon and its inner Models PDO parser for hours with the same problem.
I found this solution:
public static function getTimedoutRequests($secsThreshold) {
return self::find(
array(
// PDO is buggy here, can't use INTERVAL
"DATE_PART('epoch', create_time) < DATE_PART('epoch', NOW()) - ?0",
"bind" => array(
$secsThreshold
)
)
);
}
Intervals can be multiplied by numbers. So one approach to this is to prepare the statement saying interval '1 minute' * :myminutes
instead, passing the "myminutes" parameter as a simple integer.