Skip to content

Commit caa9824

Browse files
staabmclxmstaab
andauthored
fixed detection of syntax errors in prepared statements on konwn parameter types (#91)
Co-authored-by: Markus Staab <[email protected]>
1 parent b5956d6 commit caa9824

File tree

6 files changed

+127
-79
lines changed

6 files changed

+127
-79
lines changed

.phpstan-dba.cache

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@
430430
)),
431431
),
432432
),
433-
'SELECT email, adaid FROM ada WHERE adaid = 1' =>
433+
'SELECT email, adaid FROM ada WHERE adaid = \'1\'' =>
434434
array (
435435
'error' => NULL,
436436
'result' =>
@@ -523,7 +523,7 @@
523523
)),
524524
),
525525
),
526-
'SELECT email, adaid FROM ada WHERE adaid = 1 and email = \'[email protected]\'' =>
526+
'SELECT email, adaid FROM ada WHERE adaid = \'1\' and email = \'[email protected]\'' =>
527527
array (
528528
'error' => NULL,
529529
'result' =>
@@ -616,7 +616,7 @@
616616
)),
617617
),
618618
),
619-
'SELECT email, adaid FROM ada WHERE adaid = 1 and email = :email' =>
619+
'SELECT email, adaid FROM ada WHERE adaid = \'1\' and email = :email' =>
620620
array (
621621
'error' =>
622622
staabm\PHPStanDba\Error::__set_state(array(
@@ -628,7 +628,7 @@
628628
3 => NULL,
629629
),
630630
),
631-
'SELECT email, adaid FROM ada WHERE adaid = 1 and email = ?' =>
631+
'SELECT email, adaid FROM ada WHERE adaid = \'1\' and email = ?' =>
632632
array (
633633
'error' =>
634634
staabm\PHPStanDba\Error::__set_state(array(
@@ -769,19 +769,7 @@
769769
)),
770770
),
771771
),
772-
'SELECT email, adaid FROM ada WHERE email <=> :email' =>
773-
array (
774-
'error' =>
775-
staabm\PHPStanDba\Error::__set_state(array(
776-
'message' => '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 \':email LIMIT 0\' at line 1',
777-
'code' => 1064,
778-
)),
779-
'result' =>
780-
array (
781-
3 => NULL,
782-
),
783-
),
784-
'SELECT email, adaid FROM ada WHERE email <=> NULL' =>
772+
'SELECT email, adaid FROM ada WHERE email <=> \'\'' =>
785773
array (
786774
'error' => NULL,
787775
'result' =>
@@ -874,6 +862,18 @@
874862
)),
875863
),
876864
),
865+
'SELECT email, adaid FROM ada WHERE email <=> :email' =>
866+
array (
867+
'error' =>
868+
staabm\PHPStanDba\Error::__set_state(array(
869+
'message' => '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 \':email LIMIT 0\' at line 1',
870+
'code' => 1064,
871+
)),
872+
'result' =>
873+
array (
874+
3 => NULL,
875+
),
876+
),
877877
'SELECT email, adaid FROM ada WHERE email = \'[email protected]\'' =>
878878
array (
879879
'error' => NULL,

.phpunit-phpstan-dba.cache

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,32 @@
22
'schemaVersion' => 'v3-rename-props',
33
'records' =>
44
array (
5+
'
6+
SELECT email adaid
7+
WHERE gesperrt = \'1\' AND email LIKE \'%@example.com\'
8+
FROM ada
9+
LIMIT 1
10+
' =>
11+
array (
12+
'error' =>
13+
staabm\PHPStanDba\Error::__set_state(array(
14+
'message' => '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 \'FROM ada LIMIT 0\' at line 3',
15+
'code' => 1064,
16+
)),
17+
),
518
'
619
SELECT email, adaid
720
FROM ada
8-
WHERE gesperrt = 1 AND email LIKE \'%@example%\'
21+
WHERE gesperrt = \'1\' AND email LIKE \'%@example%\'
22+
LIMIT 1
23+
' =>
24+
array (
25+
'error' => NULL,
26+
),
27+
'
28+
SELECT email, adaid
29+
FROM ada
30+
WHERE gesperrt = \'1\' AND email LIKE NULL
931
LIMIT 1
1032
' =>
1133
array (
@@ -417,7 +439,7 @@
417439
)),
418440
),
419441
),
420-
'SELECT email, adaid FROM ada WHERE adaid = 1' =>
442+
'SELECT email, adaid FROM ada WHERE adaid = \'1\'' =>
421443
array (
422444
'error' => NULL,
423445
'result' =>
@@ -510,7 +532,7 @@
510532
)),
511533
),
512534
),
513-
'SELECT email, adaid FROM ada WHERE adaid = 1 and email = \'[email protected]\'' =>
535+
'SELECT email, adaid FROM ada WHERE adaid = \'1\' and email = \'[email protected]\'' =>
514536
array (
515537
'error' => NULL,
516538
'result' =>
@@ -708,19 +730,7 @@
708730
)),
709731
),
710732
),
711-
'SELECT email, adaid FROM ada WHERE email <=> :email' =>
712-
array (
713-
'error' =>
714-
staabm\PHPStanDba\Error::__set_state(array(
715-
'message' => '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 \':email LIMIT 0\' at line 1',
716-
'code' => 1064,
717-
)),
718-
'result' =>
719-
array (
720-
3 => NULL,
721-
),
722-
),
723-
'SELECT email, adaid FROM ada WHERE email <=> NULL' =>
733+
'SELECT email, adaid FROM ada WHERE email <=> \'\'' =>
724734
array (
725735
'error' => NULL,
726736
'result' =>
@@ -813,6 +823,18 @@
813823
)),
814824
),
815825
),
826+
'SELECT email, adaid FROM ada WHERE email <=> :email' =>
827+
array (
828+
'error' =>
829+
staabm\PHPStanDba\Error::__set_state(array(
830+
'message' => '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 \':email LIMIT 0\' at line 1',
831+
'code' => 1064,
832+
)),
833+
'result' =>
834+
array (
835+
3 => NULL,
836+
),
837+
),
816838
'SELECT email, adaid FROM ada WHERE email = \'[email protected]\'' =>
817839
array (
818840
'error' => NULL,
@@ -918,7 +940,7 @@
918940
3 => NULL,
919941
),
920942
),
921-
'SELECT email, adaid FROM ada WHERE gesperrt = 1' =>
943+
'SELECT email, adaid FROM ada WHERE gesperrt = \'1\'' =>
922944
array (
923945
'error' => NULL,
924946
),

src/QueryReflection/QueryReflection.php

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,10 @@
77
use PhpParser\Node\Expr;
88
use PhpParser\Node\Expr\BinaryOp\Concat;
99
use PHPStan\Analyser\Scope;
10-
use PHPStan\Type\BooleanType;
1110
use PHPStan\Type\Constant\ConstantArrayType;
1211
use PHPStan\Type\Constant\ConstantIntegerType;
1312
use PHPStan\Type\Constant\ConstantStringType;
14-
use PHPStan\Type\ConstantScalarType;
15-
use PHPStan\Type\FloatType;
16-
use PHPStan\Type\IntegerType;
17-
use PHPStan\Type\IntersectionType;
18-
use PHPStan\Type\MixedType;
19-
use PHPStan\Type\StringType;
2013
use PHPStan\Type\Type;
21-
use PHPStan\Type\UnionType;
2214
use staabm\PHPStanDba\DbaException;
2315
use staabm\PHPStanDba\Error;
2416

@@ -106,34 +98,8 @@ public function resolveQueryString(Expr $queryExpr, Scope $scope): ?string
10698
}
10799

108100
$type = $scope->getType($queryExpr);
109-
if ($type instanceof ConstantScalarType) {
110-
return (string) $type->getValue();
111-
}
112-
113-
$integerType = new IntegerType();
114-
if ($integerType->isSuperTypeOf($type)->yes()) {
115-
return '1';
116-
}
117-
118-
$booleanType = new BooleanType();
119-
if ($booleanType->isSuperTypeOf($type)->yes()) {
120-
return '1';
121-
}
122-
123-
if ($type->isNumericString()->yes()) {
124-
return '1';
125-
}
126101

127-
$floatType = new FloatType();
128-
if ($floatType->isSuperTypeOf($type)->yes()) {
129-
return '1.0';
130-
}
131-
132-
if ($type instanceof MixedType || $type instanceof StringType || $type instanceof IntersectionType || $type instanceof UnionType) {
133-
return null;
134-
}
135-
136-
throw new DbaException(sprintf('Unexpected expression type %s', \get_class($type)));
102+
return QuerySimulation::simulateParamValueType($type);
137103
}
138104

139105
private function getQueryType(string $query): ?string
@@ -166,17 +132,9 @@ public function resolveParameters(Type $parameterTypes): ?array
166132
$placeholderName = ':'.$placeholderName;
167133
}
168134

169-
if ($valueTypes[$i] instanceof ConstantScalarType) {
170-
$parameters[$placeholderName] = $valueTypes[$i]->getValue();
171-
} else {
172-
return null;
173-
}
135+
$parameters[$placeholderName] = QuerySimulation::simulateParamValueType($valueTypes[$i]);
174136
} elseif ($keyType instanceof ConstantIntegerType) {
175-
if ($valueTypes[$i] instanceof ConstantScalarType) {
176-
$parameters[$keyType->getValue()] = $valueTypes[$i]->getValue();
177-
} else {
178-
return null;
179-
}
137+
$parameters[$keyType->getValue()] = QuerySimulation::simulateParamValueType($valueTypes[$i]);
180138
}
181139
}
182140

src/QueryReflection/QuerySimulation.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,54 @@
44

55
namespace staabm\PHPStanDba\QueryReflection;
66

7+
use PHPStan\Type\BooleanType;
8+
use PHPStan\Type\ConstantScalarType;
9+
use PHPStan\Type\FloatType;
10+
use PHPStan\Type\IntegerType;
11+
use PHPStan\Type\IntersectionType;
12+
use PHPStan\Type\MixedType;
13+
use PHPStan\Type\StringType;
14+
use PHPStan\Type\Type;
15+
use PHPStan\Type\UnionType;
16+
use staabm\PHPStanDba\DbaException;
17+
718
/**
819
* @internal
920
*/
1021
final class QuerySimulation
1122
{
23+
public static function simulateParamValueType(Type $paramType): ?string
24+
{
25+
if ($paramType instanceof ConstantScalarType) {
26+
return (string) $paramType->getValue();
27+
}
28+
29+
$integerType = new IntegerType();
30+
if ($integerType->isSuperTypeOf($paramType)->yes()) {
31+
return '1';
32+
}
33+
34+
$booleanType = new BooleanType();
35+
if ($booleanType->isSuperTypeOf($paramType)->yes()) {
36+
return '1';
37+
}
38+
39+
if ($paramType->isNumericString()->yes()) {
40+
return '1';
41+
}
42+
43+
$floatType = new FloatType();
44+
if ($floatType->isSuperTypeOf($paramType)->yes()) {
45+
return '1.0';
46+
}
47+
48+
if ($paramType instanceof MixedType || $paramType instanceof StringType || $paramType instanceof IntersectionType || $paramType instanceof UnionType) {
49+
return null;
50+
}
51+
52+
throw new DbaException(sprintf('Unexpected expression type %s', \get_class($paramType)));
53+
}
54+
1255
public static function simulate(string $queryString): ?string
1356
{
1457
$queryString = self::stripTraillingLimit($queryString);

tests/SyntaxErrorInPreparedStatementMethodRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ public function testSyntaxErrorInQueryRule(): void
2929
"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).",
3030
17,
3131
],
32+
[
33+
"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 'FROM ada LIMIT 0' at line 3 (1064).",
34+
22,
35+
],
36+
[
37+
"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 'FROM ada LIMIT 0' at line 3 (1064).",
38+
29,
39+
],
3240
]);
3341
}
3442
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@ public function syntaxErrorInConstruct()
1717
$stmt = new PreparedStatement('SELECT email adaid WHERE gesperrt freigabe1u1 FROM ada', []);
1818
}
1919

20+
public function syntaxErrorOnKnownParamType(Connection $connection, int $i, bool $bool)
21+
{
22+
$connection->preparedQuery('
23+
SELECT email adaid
24+
WHERE gesperrt = ? AND email LIKE ?
25+
FROM ada
26+
LIMIT 1
27+
', [$i, '%@example.com']);
28+
29+
$connection->preparedQuery('
30+
SELECT email adaid
31+
WHERE gesperrt = ? AND email LIKE ?
32+
FROM ada
33+
LIMIT 1
34+
', [$bool, '%@example.com']);
35+
}
36+
2037
public function noErrorOnMixedParams(Connection $connection, $unknownType)
2138
{
2239
$connection->preparedQuery('

0 commit comments

Comments
 (0)