I'm using Symfony 2.6 and Doctrine 2.5, i'm trying to make a custom DQL function to implement the "?" Postgres operator (which is used to determine if an element with a certain key exists inside a jsonb field in Postgres) http://www.postgresql.org/docs/9.4/static/functions-json.html
This is the code (copied from DQL code of https://github.com/boldtrn/JsonbBundle i just changed the question mark)
class HasElement extends FunctionNode
{
public $leftHandSide = null;
public $rightHandSide = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->leftHandSide = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->rightHandSide = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return '(' .
$this->leftHandSide->dispatch($sqlWalker) . " ? " .
$this->rightHandSide->dispatch($sqlWalker) .
')';
}
}
But the question mark is considered a parameter placeholder when creating the query, I get a Syntax error and inside the query it's replaced by $2 before parameters being set.
SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "$2"
LINE 1: ...id = r1_.id WHERE r0_.file_id = $1 AND (r0_.attrs $2 $3)
Where the query was supposed to be "(r0_attrs ? $1)"
Is there some way to use question mark inside a DQL without it being considered a parameter? I have tried escaping and replacing with the unicode sequence but that didn't work
EDIT: Although The answer to this question is the same of the one this is marked as duplicate of (use the function rather than the alias operator), the error is different. Doctrine's parsing comes before PDO parameter assignment, if that wasn't the case i would've gotten this error instead:
PDOException: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound: SELECT * FROM tbl WHERE hst ? 'foo'
On top of that, only the general procedure is the same, but the specific answer is different (you need to use a different function)
I kept looking for a solution/alternative and I found that ?
is an alias for the function jsonb_exists(column_name, key)
which is what I'm going to use in my custom DQL function.
The same thing can apply to ?|
and ?&
So the class becomes this
class JsonbExistence extends FunctionNode
{
public $leftHandSide = null;
public $rightHandSide = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->leftHandSide = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->rightHandSide = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
// We use a workaround to allow this statement in a WHERE. Doctrine relies on the existence of an ComparisonOperator
return 'jsonb_exists(' .
$this->leftHandSide->dispatch($sqlWalker) .', '.
$this->rightHandSide->dispatch($sqlWalker) .
')';
}
}