'Invalid schema name' 错误由 Doctrine 抛出,但原始的 SQL 似乎有效
'Invalid schema name' error thrown by Doctrine, but the raw SQL seems to work
我正在使用一些自定义 DQL 函数通过 PostgreSQL 中的一些 JSONB 字段过滤行。这是我的查询函数:
private function findTopLevelResources(): array {
return $this->createQueryBuilder('r')
->where("JSON_EXISTS(r.contents, '-1') = FALSE")
->getQuery()
->getResult();
}
运行 此代码从 AbstractPostgreSQLDriver
:
得到 DriverException
An exception occurred while executing 'SELECT r0_.id AS id_0, r0_.marking AS marking_1, r0_.contents AS contents_2, r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.contents?'-1' = false':
SQLSTATE[3F000]: Invalid schema name: 7 ERROR: schema "r0_" does not exist
LINE 1: ... r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.conten...
^
我尝试从 PHPStorm 手动执行原始 SQL 查询并且成功了,没有错误。
如何在 Doctrine 中使用它?
为什么这个查询不适用于 Doctrine,但当我手动测试它时却可以?
这里是 JSON_EXISTS
:(基于 syslogic/doctrine-json-functions)
class JsonExists extends FunctionNode
{
const FUNCTION_NAME = 'JSON_EXISTS';
const OPERATOR = '?';
public $jsonData;
public $jsonPath;
public function getSql(SqlWalker $sqlWalker)
{
$jsonData = $sqlWalker->walkStringPrimary($this->jsonData);
$jsonPath = $this->jsonPath->value;
return $jsonData . self::OPERATOR . "'$jsonPath'";
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->jsonData = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->jsonPath = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
通过 Symfony 的 YAML 配置注册,如下所示:
doctrine:
orm:
dql:
numeric_functions:
json_exists: Syslogic\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonExists
内容版本:
- PHP 7.1.1
- doctrine/dbal v2.6.1
- doctrine/orm 开发大师 e3ecec3 (== 2.6.x-dev)
- symfony/symfony v3.3.4
错误信息是一个错误的线索。
实际问题是由 PDO 引起的(这就是它在 PHPStorm 中起作用的原因)。当它看到这样的查询时:
SELECT * FROM foo WHERE contents?'bar'
它将其视为参数化查询,并将问号 ?
视为参数。由于某种原因,它有时会导致无意义的错误消息。这种特殊情况可以通过在问号后添加 space 来解决,但它不适用于运算符 ?|
和 ?&
,它们不能在 space 中中间.
解决方法是使用对应运算符的函数(this question saved the day)。可以使用这样的查询找出它们是如何被调用的:
SELECT oprname, oprcode FROM pg_operator WHERE oprname IN ('?', '?|', '?&')
这是与 JSON 相关的结果部分:
?
→jsonb_exists
?|
→jsonb_exists_any
?&
→jsonb_exists_all
因此,可以使用以下等效查询代替之前通过 PDO 导致问题的查询:
SELECT * FROM foo WHERE jsonb_exists(contents, 'bar')
我正在使用一些自定义 DQL 函数通过 PostgreSQL 中的一些 JSONB 字段过滤行。这是我的查询函数:
private function findTopLevelResources(): array {
return $this->createQueryBuilder('r')
->where("JSON_EXISTS(r.contents, '-1') = FALSE")
->getQuery()
->getResult();
}
运行 此代码从 AbstractPostgreSQLDriver
:
DriverException
An exception occurred while executing 'SELECT r0_.id AS id_0, r0_.marking AS marking_1, r0_.contents AS contents_2, r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.contents?'-1' = false':
SQLSTATE[3F000]: Invalid schema name: 7 ERROR: schema "r0_" does not exist
LINE 1: ... r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.conten...
^
我尝试从 PHPStorm 手动执行原始 SQL 查询并且成功了,没有错误。
如何在 Doctrine 中使用它?
为什么这个查询不适用于 Doctrine,但当我手动测试它时却可以?
这里是 JSON_EXISTS
:(基于 syslogic/doctrine-json-functions)
class JsonExists extends FunctionNode
{
const FUNCTION_NAME = 'JSON_EXISTS';
const OPERATOR = '?';
public $jsonData;
public $jsonPath;
public function getSql(SqlWalker $sqlWalker)
{
$jsonData = $sqlWalker->walkStringPrimary($this->jsonData);
$jsonPath = $this->jsonPath->value;
return $jsonData . self::OPERATOR . "'$jsonPath'";
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->jsonData = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->jsonPath = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
通过 Symfony 的 YAML 配置注册,如下所示:
doctrine:
orm:
dql:
numeric_functions:
json_exists: Syslogic\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonExists
内容版本:
- PHP 7.1.1
- doctrine/dbal v2.6.1
- doctrine/orm 开发大师 e3ecec3 (== 2.6.x-dev)
- symfony/symfony v3.3.4
错误信息是一个错误的线索。
实际问题是由 PDO 引起的(这就是它在 PHPStorm 中起作用的原因)。当它看到这样的查询时:
SELECT * FROM foo WHERE contents?'bar'
它将其视为参数化查询,并将问号 ?
视为参数。由于某种原因,它有时会导致无意义的错误消息。这种特殊情况可以通过在问号后添加 space 来解决,但它不适用于运算符 ?|
和 ?&
,它们不能在 space 中中间.
解决方法是使用对应运算符的函数(this question saved the day)。可以使用这样的查询找出它们是如何被调用的:
SELECT oprname, oprcode FROM pg_operator WHERE oprname IN ('?', '?|', '?&')
这是与 JSON 相关的结果部分:
?
→jsonb_exists
?|
→jsonb_exists_any
?&
→jsonb_exists_all
因此,可以使用以下等效查询代替之前通过 PDO 导致问题的查询:
SELECT * FROM foo WHERE jsonb_exists(contents, 'bar')