Skip to content

Commit adf089d

Browse files
clxmstaabstaabm
authored andcommitted
support conditional errors in prepared statements
1 parent 1727187 commit adf089d

6 files changed

+65
-10
lines changed

.phpunit-phpstan-dba.cache

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,6 +2771,14 @@ Simulated query: SELECT email, adaid, gesperrt, freigabe1u1 FROM ada . WHERE ema
27712771
'code' => 1064,
27722772
)),
27732773
),
2774+
'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE asdsa=\'1\'' =>
2775+
array (
2776+
'error' =>
2777+
staabm\PHPStanDba\Error::__set_state(array(
2778+
'message' => 'Unknown column \'asdsa\' in \'where clause\'',
2779+
'code' => 1054,
2780+
)),
2781+
),
27742782
'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE asdsa=1' =>
27752783
array (
27762784
'error' =>
@@ -3001,5 +3009,9 @@ Simulated query: SELECT email, adaid, gesperrt, freigabe1u1 FROM ada . WHERE ema
30013009
)),
30023010
),
30033011
),
3012+
'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE gesperrt=\'1\'' =>
3013+
array (
3014+
'error' => NULL,
3015+
),
30043016
),
30053017
);

src/QueryReflection/QueryReflection.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,32 @@ public function getResultType(string $queryString, int $fetchType): ?Type
6262
return self::reflector()->getResultType($queryString, $fetchType);
6363
}
6464

65+
/**
66+
* @return iterable<string>
67+
*/
68+
public function resolvePreparedQueryStrings(Expr $queryExpr, Type $parameterTypes, Scope $scope): iterable
69+
{
70+
$type = $scope->getType($queryExpr);
71+
72+
if ($type instanceof UnionType) {
73+
$parameters = $this->resolveParameters($parameterTypes);
74+
if (null === $parameters) {
75+
return null;
76+
}
77+
78+
foreach (TypeUtils::getConstantStrings($type) as $constantString) {
79+
$queryString = $constantString->getValue();
80+
$queryString = $this->replaceParameters($queryString, $parameters);
81+
yield $queryString;
82+
}
83+
}
84+
85+
$queryString = $this->resolvePreparedQueryString($queryExpr, $parameterTypes, $scope);
86+
if (null !== $queryString) {
87+
yield $queryString;
88+
}
89+
}
90+
6591
public function resolvePreparedQueryString(Expr $queryExpr, Type $parameterTypes, Scope $scope): ?string
6692
{
6793
$queryString = $this->resolveQueryString($queryExpr, $scope);

src/Rules/SyntaxErrorInPreparedStatementMethodRule.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,14 @@ private function checkErrors(CallLike $callLike, Scope $scope): array
9696
$parameterTypes = $scope->getType($args[1]->value);
9797

9898
$queryReflection = new QueryReflection();
99-
$queryString = $queryReflection->resolvePreparedQueryString($queryExpr, $parameterTypes, $scope);
100-
if (null === $queryString) {
101-
return [];
102-
}
99+
foreach ($queryReflection->resolvePreparedQueryStrings($queryExpr, $parameterTypes, $scope) as $queryString) {
100+
$error = $queryReflection->validateQueryString($queryString);
103101

104-
$error = $queryReflection->validateQueryString($queryString);
105-
if (null !== $error) {
106-
return [
107-
RuleErrorBuilder::message('Query error: '.$error->getMessage().' ('.$error->getCode().').')->line($callLike->getLine())->build(),
108-
];
102+
if (null !== $error) {
103+
return [
104+
RuleErrorBuilder::message('Query error: '.$error->getMessage().' ('.$error->getCode().').')->line($callLike->getLine())->build(),
105+
];
106+
}
109107
}
110108

111109
return [];

tests/SyntaxErrorInPreparedStatementMethodRuleTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ public function testSyntaxErrorInQueryRule(): void
4949
"Query error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL/MariaDB server version for the right syntax to use near 'freigabe1u1 FROM ada LIMIT 0' at line 1 (1064).",
5050
107,
5151
],
52+
[
53+
"Query error: Unknown column 'asdsa' in 'where clause' (1054).",
54+
122,
55+
],
5256
]);
5357
}
5458
}

tests/data/syntax-error-in-prepared-statement.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,19 @@ public function syntaxErrorInDoctrineDbal(\Doctrine\DBAL\Connection $conn, $type
106106
$conn->executeCacheQuery('SELECT email adaid WHERE gesperrt freigabe1u1 FROM ada', [], $types, $qcp);
107107
$conn->executeStatement('SELECT email adaid WHERE gesperrt freigabe1u1 FROM ada', []);
108108
}
109+
110+
public function conditionalSyntaxError(Connection $connection)
111+
{
112+
$query = 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada';
113+
114+
if (rand(0, 1)) {
115+
// valid condition
116+
$query .= ' WHERE gesperrt=?';
117+
} else {
118+
// unknown column
119+
$query .= ' WHERE asdsa=?';
120+
}
121+
122+
$connection->preparedQuery($query, [1]);
123+
}
109124
}

tests/data/syntax-error-in-query.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public function noErrorOnQueriesContainingPlaceholders(\Doctrine\DBAL\Connection
8888
$conn->query('SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE adaid=?');
8989
}
9090

91-
public function conditionalSyntaxErrors(PDO $pdo)
91+
public function conditionalSyntaxError(PDO $pdo)
9292
{
9393
$query = 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada';
9494

0 commit comments

Comments
 (0)