diff --git a/src/QueryReflection/QueryReflection.php b/src/QueryReflection/QueryReflection.php index 1f3f06e9..02c64800 100644 --- a/src/QueryReflection/QueryReflection.php +++ b/src/QueryReflection/QueryReflection.php @@ -32,6 +32,7 @@ use staabm\PHPStanDba\SchemaReflection\SchemaReflection; use staabm\PHPStanDba\SqlAst\ParserInference; use staabm\PHPStanDba\UnresolvableQueryException; +use staabm\PHPStanDba\UnresolvableQueryDynamicFromException; final class QueryReflection { @@ -291,13 +292,7 @@ public function resolveQueryStrings(Expr $queryExpr, Scope $scope): iterable $queryString = $this->resolveQueryExpr($queryExpr, $scope); if (null !== $queryString) { - $normalizedQuery = QuerySimulation::stripComments($this->normalizeQueryString($queryString)); - - // query simulation might lead in a invalid query, skip those - $error = $this->validateQueryString($normalizedQuery); - if ($error === null) { - yield $normalizedQuery; - } + yield QuerySimulation::stripComments($this->normalizeQueryString($queryString)); } } @@ -375,6 +370,13 @@ private function resolveQueryStringExpr(Expr $queryExpr, Scope $scope, bool $res return null; } + // queries with a dynamic FROM are not resolvable + if (QueryReflection::getRuntimeConfiguration()->isDebugEnabled()) { + if (str_ends_with(rtrim($leftString), 'FROM') && is_numeric(trim($rightString, '"\''))) { + throw new UnresolvableQueryDynamicFromException('Seems the query is too dynamic to be resolved by query simulation'); + } + } + return $leftString . $rightString; } diff --git a/src/UnresolvableQueryDynamicFromException.php b/src/UnresolvableQueryDynamicFromException.php new file mode 100644 index 00000000..13b2cf8d --- /dev/null +++ b/src/UnresolvableQueryDynamicFromException.php @@ -0,0 +1,16 @@ +analyse([__DIR__ . '/data/bug-548.php'], []); + $this->analyse([__DIR__ . '/data/bug-548.php'], [ + [ + 'Unresolvable Query: Seems the query is too dynamic to be resolved by query simulation.', + 10, + UnresolvableQueryDynamicFromException::getTip(), + ], + ]); } public function testBug547(): void { - $this->analyse([__DIR__ . '/data/bug-547.php'], []); + $this->analyse([__DIR__ . '/data/bug-547.php'], [ + [ + 'Unresolvable Query: Seems the query is too dynamic to be resolved by query simulation.', + 10, + UnresolvableQueryDynamicFromException::getTip(), + ], + ]); } public function testBug676(): void diff --git a/tests/rules/data/syntax-error-in-query-method.php b/tests/rules/data/syntax-error-in-query-method.php index 89a5a27f..6f29ab1a 100644 --- a/tests/rules/data/syntax-error-in-query-method.php +++ b/tests/rules/data/syntax-error-in-query-method.php @@ -149,4 +149,12 @@ public function bug458(PDO $pdo) $pdo->query('SELECT * FROM ' . $table . ' LIMIT 1'); } + public function writes(PDO $pdo, int $adaid): void + { + $pdo->query('UPDATE `ada` SET email="test" WHERE adaid = '.$adaid); + $pdo->query('INSERT INTO `ada` SET email="test" WHERE adaid = '.$adaid); + $pdo->query('REPLACE INTO `ada` SET email="test" WHERE adaid = '.$adaid); + $pdo->query('DELETE FROM `ada` WHERE adaid = '.$adaid); + } + } diff --git a/tests/rules/data/unresolvable-query-in-method.php b/tests/rules/data/unresolvable-query-in-method.php index e596a82a..6c1f8e18 100644 --- a/tests/rules/data/unresolvable-query-in-method.php +++ b/tests/rules/data/unresolvable-query-in-method.php @@ -38,4 +38,12 @@ public function stringQueryFragment(PDO $pdo, string $string) { $pdo->query('SELECT email FROM ada WHERE '.$string); } + + public function writes(PDO $pdo, int $adaid): void + { + $pdo->query('UPDATE `ada` SET email="test" WHERE adaid = '.$adaid); + $pdo->query('INSERT INTO `ada` SET email="test" WHERE adaid = '.$adaid); + $pdo->query('REPLACE INTO `ada` SET email="test" WHERE adaid = '.$adaid); + $pdo->query('DELETE FROM `ada` WHERE adaid = '.$adaid); + } }