diff --git a/.phpstan-dba-mysqli.cache b/.phpstan-dba-mysqli.cache index 6c9604223..8522d1a72 100644 --- a/.phpstan-dba-mysqli.cache +++ b/.phpstan-dba-mysqli.cache @@ -1,6 +1,6 @@ 'v8-trim-queries', - 'schemaHash' => 'e7af3addf6476bf35bda4893b0b4e1e6', + 'schemaHash' => 'fc85743b94657f20850e7a591108f2c5', 'records' => array ( 'SELECT @@ -332,386 +332,11 @@ )), ), ), - 'SELECT - coalesce(COLUMN_NAME, "") as COLUMN_NAME, - coalesce(EXTRA, "") as EXTRA, - COLUMN_TYPE - FROM information_schema.columns - WHERE table_name = \'1970-01-01\' AND table_schema = DATABASE()' => - array ( - 'result' => - array ( - 5 => - PHPStan\Type\Constant\ConstantArrayType::__set_state(array( - 'allArrays' => NULL, - 'nextAutoIndexes' => - array ( - 0 => 3, - ), - 'keyTypes' => - array ( - 0 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_NAME', - 'isClassString' => false, - )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 2 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'EXTRA', - 'isClassString' => false, - )), - 3 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 1, - )), - 4 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_TYPE', - 'isClassString' => false, - )), - 5 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 2, - )), - ), - 'valueTypes' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\StringType::__set_state(array( - )), - 2 => - PHPStan\Type\StringType::__set_state(array( - )), - 3 => - PHPStan\Type\StringType::__set_state(array( - )), - 4 => - PHPStan\Type\StringType::__set_state(array( - )), - 5 => - PHPStan\Type\StringType::__set_state(array( - )), - ), - 'optionalKeys' => - array ( - ), - 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 1, - )), - 2 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 2, - )), - 3 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_NAME', - 'isClassString' => false, - )), - 4 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_TYPE', - 'isClassString' => false, - )), - 5 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'EXTRA', - 'isClassString' => false, - )), - ), - )), - 'itemType' => - PHPStan\Type\StringType::__set_state(array( - )), - )), - ), - ), - 'SELECT - coalesce(COLUMN_NAME, "") as COLUMN_NAME, - coalesce(EXTRA, "") as EXTRA, - COLUMN_TYPE - FROM information_schema.columns - WHERE table_name = ? AND table_schema = DATABASE()' => - array ( - 'result' => - array ( - 5 => NULL, - ), - ), - 'SELECT - MD5( - GROUP_CONCAT( - CONCAT( - COALESCE(COLUMN_NAME, ""), - COALESCE(EXTRA, ""), - COLUMN_TYPE, - IS_NULLABLE - ) - ) - ) AS dbsignature, - 1 AS grouper - FROM - information_schema.columns - WHERE - table_schema = DATABASE() - GROUP BY - grouper' => - array ( - 'result' => - array ( - 5 => - PHPStan\Type\Constant\ConstantArrayType::__set_state(array( - 'allArrays' => NULL, - 'nextAutoIndexes' => - array ( - 0 => 2, - ), - 'keyTypes' => - array ( - 0 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'dbsignature', - 'isClassString' => false, - )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 2 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'grouper', - 'isClassString' => false, - )), - 3 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 1, - )), - ), - 'valueTypes' => - array ( - 0 => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => false, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\NullType::__set_state(array( - )), - ), - )), - 1 => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => false, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\NullType::__set_state(array( - )), - ), - )), - 2 => - PHPStan\Type\IntegerType::__set_state(array( - )), - 3 => - PHPStan\Type\IntegerType::__set_state(array( - )), - ), - 'optionalKeys' => - array ( - ), - 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 1, - )), - 2 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'dbsignature', - 'isClassString' => false, - )), - 3 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'grouper', - 'isClassString' => false, - )), - ), - )), - 'itemType' => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => false, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\IntegerType::__set_state(array( - )), - 2 => - PHPStan\Type\NullType::__set_state(array( - )), - ), - )), - )), - 3 => - PHPStan\Type\Constant\ConstantArrayType::__set_state(array( - 'allArrays' => NULL, - 'nextAutoIndexes' => - array ( - 0 => 0, - ), - 'keyTypes' => - array ( - 0 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'dbsignature', - 'isClassString' => false, - )), - 1 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'grouper', - 'isClassString' => false, - )), - ), - 'valueTypes' => - array ( - 0 => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => false, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\NullType::__set_state(array( - )), - ), - )), - 1 => - PHPStan\Type\IntegerType::__set_state(array( - )), - ), - 'optionalKeys' => - array ( - ), - 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'dbsignature', - 'isClassString' => false, - )), - 1 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'grouper', - 'isClassString' => false, - )), - ), - )), - 'itemType' => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => false, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\IntegerType::__set_state(array( - )), - 2 => - PHPStan\Type\NullType::__set_state(array( - )), - ), - )), - )), - ), - ), - 'SELECT adaid FROM ada LIMIT 1 FOR SHARE' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada LIMIT 1 FOR SHARE NOWAIT' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada LIMIT 1 FOR SHARE SKIP LOCKED' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada LIMIT 1 FOR UPDATE NOWAIT' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada LIMIT 1 FOR UPDATE SKIP LOCKED' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada LIMIT 1 OFFSET 1' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada LIMIT 1 OFFSET 1 FOR UPDATE' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada WHERE email LIKE \'%questions ?%\'' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada WHERE email LIKE \':gesperrt%\'' => - array ( - 'error' => NULL, - ), - 'SELECT adaid FROM ada WHERE email LIKE \'hello?%\'' => + 'SELECT * FROM `ada` WHERE adaid = 1' => array ( 'error' => NULL, ), - 'SELECT akid FROM ak WHERE eadavk>1.0' => - array ( - 'error' => NULL, - ), - 'SELECT akid FROM ak WHERE eadavk>1.1' => - array ( - 'error' => NULL, - ), - 'SELECT column_name, column_default, is_nullable -FROM information_schema.columns -WHERE table_name = \'1970-01-01\'' => + 'SELECT * FROM `ada` WHERE email = \'test@example.com\';' => array ( 'result' => array ( @@ -720,13 +345,13 @@ WHERE table_name = \'1970-01-01\'' => 'allArrays' => NULL, 'nextAutoIndexes' => array ( - 0 => 3, + 0 => 4, ), 'keyTypes' => array ( 0 => PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_NAME', + 'value' => 'adaid', 'isClassString' => false, )), 1 => @@ -735,7 +360,7 @@ WHERE table_name = \'1970-01-01\'' => )), 2 => PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_DEFAULT', + 'value' => 'gesperrt', 'isClassString' => false, )), 3 => @@ -744,47 +369,44 @@ WHERE table_name = \'1970-01-01\'' => )), 4 => PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'IS_NULLABLE', + 'value' => 'email', 'isClassString' => false, )), 5 => PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( 'value' => 2, )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), ), 'valueTypes' => array ( 0 => - PHPStan\Type\StringType::__set_state(array( + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, )), 1 => - PHPStan\Type\StringType::__set_state(array( + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, )), 2 => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\NullType::__set_state(array( - )), - ), + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, )), 3 => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\NullType::__set_state(array( - )), - ), + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, )), 4 => PHPStan\Type\StringType::__set_state(array( @@ -792,6 +414,16 @@ WHERE table_name = \'1970-01-01\'' => 5 => PHPStan\Type\StringType::__set_state(array( )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), ), 'optionalKeys' => array ( @@ -814,46 +446,80 @@ WHERE table_name = \'1970-01-01\'' => 'value' => 2, )), 3 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_DEFAULT', - 'isClassString' => false, + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, )), 4 => PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'COLUMN_NAME', + 'value' => 'adaid', 'isClassString' => false, )), 5 => PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'IS_NULLABLE', + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', 'isClassString' => false, )), ), )), 'itemType' => PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, + 'sortedTypes' => false, 'types' => array ( 0 => - PHPStan\Type\StringType::__set_state(array( + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, )), 1 => - PHPStan\Type\NullType::__set_state(array( + PHPStan\Type\StringType::__set_state(array( )), ), )), )), ), ), - 'SELECT column_name, column_default, is_nullable -FROM information_schema.columns -WHERE table_name = ?' => + 'SELECT * FROM ada GROUP BY doesNotExist' => array ( - 'result' => - array ( - 5 => NULL, - ), + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'group statement\'', + 'code' => 1054, + )), + ), + 'SELECT * FROM ada ORDER BY doesNotExist' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'order clause\'', + 'code' => 1054, + )), + ), + 'SELECT * FROM ada WHERE doesNotExist=1' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'where clause\'', + 'code' => 1054, + )), + ), + 'SELECT * FROM unknown_table' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Table \'phpstan_dba.unknown_table\' doesn\'t exist', + 'code' => 1146, + )), ), 'SELECT column_name, column_default, is_nullable FROM information_schema.columns @@ -1001,9 +667,13 @@ WHERE table_name = ?' => 5 => NULL, ), ), - 'SELECT eladaid FROM ak' => + 'SELECT doesNotExist, adaid, gesperrt, freigabe1u1 FROM ada' => array ( - 'error' => NULL, + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'field list\'', + 'code' => 1054, + )), ), 'SELECT email adaid WHERE gesperrt freigabe1u1 FROM ada' => array ( @@ -1013,154 +683,45 @@ WHERE table_name = ?' => 'code' => 1064, )), ), - 'SELECT email, adaid FROM ada' => - array ( - 'result' => - array ( - 5 => - PHPStan\Type\Constant\ConstantArrayType::__set_state(array( - 'allArrays' => NULL, - 'nextAutoIndexes' => - array ( - 0 => 2, - ), - 'keyTypes' => - array ( - 0 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, - )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 2 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'adaid', - 'isClassString' => false, - )), - 3 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 1, - )), - ), - 'valueTypes' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\StringType::__set_state(array( - )), - 2 => - PHPStan\Type\IntegerRangeType::__set_state(array( - 'min' => -32768, - 'max' => 32767, - )), - 3 => - PHPStan\Type\IntegerRangeType::__set_state(array( - 'min' => -32768, - 'max' => 32767, - )), - ), - 'optionalKeys' => - array ( - ), - 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 1, - )), - 2 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'adaid', - 'isClassString' => false, - )), - 3 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, - )), - ), - )), - 'itemType' => - PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => false, - 'types' => - array ( - 0 => - PHPStan\Type\StringType::__set_state(array( - )), - 1 => - PHPStan\Type\IntegerRangeType::__set_state(array( - 'min' => -32768, - 'max' => 32767, - )), - ), - )), - )), - ), - ), - 'SELECT email, adaid FROM ada LIMIT 1' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid FROM ada LIMIT 1, 10' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid FROM ada WHERE adaid = 1' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid FROM ada WHERE adaid = 2' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid FROM ada WHERE adaid = 3' => + 'SELECT email, adaid FROM ada GROUP BY xy LIMIT 1' => array ( - 'error' => NULL, + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'xy\' in \'group statement\'', + 'code' => 1054, + )), ), - 'SELECT email, adaid FROM ada WHERE adaid IN(1,3)' => + 'SELECT email, adaid FROM ada WHERE email=\'my_other_table\' LIMIT 1' => array ( 'error' => NULL, ), - 'SELECT email, adaid FROM ada WHERE adaid=' => + 'SELECT email, adaid GROUP BY xy FROM ada LIMIT 1' => array ( 'error' => staabm\PHPStanDba\Error::__set_state(array( - '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 \'LIMIT 0\' at line 1', + '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 1', 'code' => 1064, )), ), - 'SELECT email, adaid FROM ada WHERE adaid=1' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid FROM ada WHERE email = \'test@example.org\'' => + 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada' => array ( 'error' => NULL, ), - 'SELECT email, adaid FROM ada WHERE email = \'webmaster@example.org\'' => + 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada LIMIT 1' => array ( 'error' => NULL, ), - 'SELECT email, adaid FROM ada WHERE email=\'foo\'' => + 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE email=\'my_other_table\' LIMIT 1' => array ( 'error' => NULL, ), - 'SELECT email, adaid FROM ada WHERE gesperrt = \'1\'' => + 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE asdsa=1' => array ( - 'error' => NULL, + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'asdsa\' in \'where clause\'', + 'code' => 1054, + )), ), ), 'runtimeConfig' => diff --git a/.phpstan-dba-pdo-mysql.cache b/.phpstan-dba-pdo-mysql.cache index 5516075c0..c5544ecca 100644 --- a/.phpstan-dba-pdo-mysql.cache +++ b/.phpstan-dba-pdo-mysql.cache @@ -714,7 +714,7 @@ WHERE table_name = \'1970-01-01\'' => )), 2 => PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, + 'sortedTypes' => false, 'types' => array ( 0 => @@ -727,7 +727,7 @@ WHERE table_name = \'1970-01-01\'' => )), 3 => PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, + 'sortedTypes' => false, 'types' => array ( 0 => @@ -784,7 +784,7 @@ WHERE table_name = \'1970-01-01\'' => )), 'itemType' => PHPStan\Type\UnionType::__set_state(array( - 'sortedTypes' => true, + 'sortedTypes' => false, 'types' => array ( 0 => diff --git a/README.md b/README.md index 74c8c514e..285a03691 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ This extension provides the following features: * result set type-inferrence * inspect sql queries, detect errors and placeholder/bound value mismatches +* query plan analysis to detect performance issues * builtin support for `doctrine/dbal`, `mysqli`, and `PDO` * API to configure the same features for your custom sql based database access layer @@ -49,6 +50,7 @@ $cacheFile = __DIR__.'/.phpstan-dba.cache'; $config = new RuntimeConfiguration(); // $config->debugMode(true); // $config->stringifyTypes(true); +// $config->analyzeQueryPlans(true); // TODO: Put your database credentials here $mysqli = new mysqli('hostname', 'username', 'password', 'database'); @@ -97,6 +99,7 @@ includes: - [Runtime configuration](https://github.com/staabm/phpstan-dba/blob/main/docs/configuration.md) - [Record and Replay](https://github.com/staabm/phpstan-dba/blob/main/docs/record-and-replay.md) +- [Query Plan Analysis](https://github.com/staabm/phpstan-dba/blob/main/docs/query-plan-analysis.md) - [Custom Query APIs Support](https://github.com/staabm/phpstan-dba/blob/main/docs/rules.md) - [MySQL Support](https://github.com/staabm/phpstan-dba/blob/main/docs/mysql.md) - [PGSQL Support](https://github.com/staabm/phpstan-dba/blob/main/docs/pgsql.md) diff --git a/config/dba.neon b/config/dba.neon index eeb939704..7e2b6268c 100644 --- a/config/dba.neon +++ b/config/dba.neon @@ -56,3 +56,33 @@ services: functionNames: - 'Deployer\runMysqlQuery#0' - 'mysqli_query#1' + + - + class: staabm\PHPStanDba\Rules\QueryPlanAnalyzerRule + tags: [phpstan.rules.rule] + arguments: + classMethods: + # prepared statement methods + - 'Doctrine\DBAL\Connection::executeQuery#0' + - 'Doctrine\DBAL\Connection::executeCacheQuery#0' + - 'Doctrine\DBAL\Connection::executeStatement#0' + - 'Doctrine\DBAL\Connection::fetchAssociative#0' + - 'Doctrine\DBAL\Connection::fetchNumeric#0' + - 'Doctrine\DBAL\Connection::fetchOne#0' + - 'Doctrine\DBAL\Connection::fetchAllNumeric#0' + - 'Doctrine\DBAL\Connection::fetchAllAssociative#0' + - 'Doctrine\DBAL\Connection::fetchAllKeyValue#0' + - 'Doctrine\DBAL\Connection::fetchAllAssociativeIndexed#0' + - 'Doctrine\DBAL\Connection::fetchFirstColumn#0' + - 'Doctrine\DBAL\Connection::iterateNumeric#0' + - 'Doctrine\DBAL\Connection::iterateAssociative#0' + - 'Doctrine\DBAL\Connection::iterateKeyValue#0' + - 'Doctrine\DBAL\Connection::iterateAssociativeIndexed#0' + - 'Doctrine\DBAL\Connection::iterateColumn#0' + - 'Doctrine\DBAL\Connection::executeUpdate#0' # deprecated in doctrine + # regular statements + - 'PDO::query#0' + - 'PDO::prepare#0' + - 'mysqli::query#0' + - 'Doctrine\DBAL\Connection::query#0' # deprecated in doctrine + - 'Doctrine\DBAL\Connection::exec#0' # deprecated in doctrine diff --git a/docs/mysql.md b/docs/mysql.md index d0dffe000..d93b7ee38 100644 --- a/docs/mysql.md +++ b/docs/mysql.md @@ -24,6 +24,7 @@ $cacheFile = __DIR__.'/.phpstan-dba.cache'; $config = new RuntimeConfiguration(); // $config->debugMode(true); // $config->stringifyTypes(true); +// $config->analyzeQueryPlans(true); // TODO: Put your database credentials here $mysqli = new mysqli('hostname', 'username', 'password', 'database'); diff --git a/docs/query-plan-analysis.md b/docs/query-plan-analysis.md new file mode 100644 index 000000000..a8ba343de --- /dev/null +++ b/docs/query-plan-analysis.md @@ -0,0 +1,32 @@ +# Query Plan Analysis + +Within your `phpstan-dba-bootstrap.php` file, you can optionally enable query plan analysis. +When enabled, `phpstan-dba` will error when queries are not using indices or queries are inefficient. + +Passing `true` will enable the feature: + +```php +$config = new RuntimeConfiguration(); +$config->analyzeQueryPlans(true); +``` + +For more fine grained control, you can pass a positive-integer describing the number of unindexed reads a query is allowed to execute before being considered inefficient. +This will only affect queries which already use an index. + +```php +$config = new RuntimeConfiguration(); +$config->analyzeQueryPlans(100000); +``` + +To disable the effiency analysis but just check for queries not using indices at all, pass `0`. + +```php +$config = new RuntimeConfiguration(); +$config->analyzeQueryPlans(0); +``` + +**Note:** For a meaningful performance analysis it is vital to utilize a database, which containts data and schema as similar as possible to the production database. + +**Note:** "Query Plan Analysis" requires an active database connection. + +**Note:** ["Query Plan Analysis" is not yet supported on the PGSQL driver](https://github.com/staabm/phpstan-dba/issues/378) diff --git a/docs/record-and-replay.md b/docs/record-and-replay.md index b45edf42e..685ed8e4a 100644 --- a/docs/record-and-replay.md +++ b/docs/record-and-replay.md @@ -23,6 +23,7 @@ $cacheFile = __DIR__.'/.phpstan-dba.cache'; $config = new RuntimeConfiguration(); // $config->debugMode(true); // $config->stringifyTypes(true); +// $config->analyzeQueryPlans(true); QueryReflection::setupReflector( new ReplayQueryReflector( diff --git a/src/Analyzer/QueryPlanAnalyzerMysql.php b/src/Analyzer/QueryPlanAnalyzerMysql.php new file mode 100644 index 000000000..ace7d6e40 --- /dev/null +++ b/src/Analyzer/QueryPlanAnalyzerMysql.php @@ -0,0 +1,100 @@ +connection = $connection; + } + + /** + * @param non-empty-string $query + */ + public function analyze(string $query): QueryPlanResult + { + if ($this->connection instanceof PDO) { + $stmt = $this->connection->query('EXPLAIN '.$query); + + // @phpstan-ignore-next-line + return $this->buildResult($stmt); + } else { + $result = $this->connection->query('EXPLAIN '.$query); + if ($result instanceof \mysqli_result) { + return $this->buildResult($result); + } + } + + throw new ShouldNotHappenException(); + } + + /** + * @param \IteratorAggregate $it + */ + private function buildResult($it): QueryPlanResult + { + $result = new QueryPlanResult(); + + $allowedUnindexedReads = QueryReflection::getRuntimeConfiguration()->getNumberOfAllowedUnindexedReads(); + if (false === $allowedUnindexedReads) { + throw new ShouldNotHappenException(); + } + + $allowedRowsNotRequiringIndex = QueryReflection::getRuntimeConfiguration()->getNumberOfRowsNotRequiringIndex(); + if (false === $allowedRowsNotRequiringIndex) { + throw new ShouldNotHappenException(); + } + + foreach ($it as $row) { + // we cannot analyse tables without rows -> mysql will just return 'no matching row in const table' + if (null === $row['table']) { + continue; + } + + if (null === $row['key'] && $row['rows'] > $allowedRowsNotRequiringIndex) { + // derived table aka. a expression that generates a table within the scope of a query FROM clause + // is a temporary table, which indexes cannot be created for. + if ('derived' === strtolower($row['select_type'])) { + continue; + } + + $result->addRow($row['table'], QueryPlanResult::NO_INDEX); + } else { + if (null !== $row['type'] && 'all' === strtolower($row['type']) && $row['rows'] > $allowedRowsNotRequiringIndex) { + $result->addRow($row['table'], QueryPlanResult::TABLE_SCAN); + } elseif (true === $allowedUnindexedReads && $row['rows'] > self::DEFAULT_UNINDEXED_READS_THRESHOLD) { + $result->addRow($row['table'], QueryPlanResult::UNINDEXED_READS); + } elseif (\is_int($allowedUnindexedReads) && $row['rows'] > $allowedUnindexedReads) { + $result->addRow($row['table'], QueryPlanResult::UNINDEXED_READS); + } + } + } + + return $result; + } +} diff --git a/src/Analyzer/QueryPlanResult.php b/src/Analyzer/QueryPlanResult.php new file mode 100644 index 000000000..d49943a7a --- /dev/null +++ b/src/Analyzer/QueryPlanResult.php @@ -0,0 +1,72 @@ + + */ + private $result = []; + + /** + * @param self::* $result + * + * @return void + */ + public function addRow(string $table, string $result) + { + $this->result[$table] = $result; + } + + /** + * @return string[] + */ + public function getTablesNotUsingIndex(): array + { + $tables = []; + foreach ($this->result as $table => $result) { + if (self::NO_INDEX === $result) { + $tables[] = $table; + } + } + + return $tables; + } + + /** + * @return string[] + */ + public function getTablesDoingTableScan(): array + { + $tables = []; + foreach ($this->result as $table => $result) { + if (self::TABLE_SCAN === $result) { + $tables[] = $table; + } + } + + return $tables; + } + + /** + * @return string[] + */ + public function getTablesDoingUnindexedReads(): array + { + $tables = []; + foreach ($this->result as $table => $result) { + if (self::UNINDEXED_READS === $result) { + $tables[] = $table; + } + } + + return $tables; + } +} diff --git a/src/QueryReflection/BasePdoQueryReflector.php b/src/QueryReflection/BasePdoQueryReflector.php index c1c753344..ce874df97 100644 --- a/src/QueryReflection/BasePdoQueryReflector.php +++ b/src/QueryReflection/BasePdoQueryReflector.php @@ -18,7 +18,7 @@ /** * @phpstan-type ColumnMeta array{name: string, table: string, native_type: string, len: int, flags: array, precision: int<0, max>, pdo_type: PDO::PARAM_* } */ -abstract class BasePdoQueryReflector implements QueryReflector +abstract class BasePdoQueryReflector implements QueryReflector, RecordingReflector { private const PSQL_SYNTAX_ERROR = '42601'; private const PSQL_INVALID_TEXT_REPRESENTATION = '22P02'; @@ -159,6 +159,11 @@ protected function emulateFlags(string $nativeType, string $tableName, string $c return $this->emulateFlags($nativeType, $tableName, $columnName); } + public function getDatasource() + { + return $this->pdo; + } + /** @return PDOException|list|null */ abstract protected function simulateQuery(string $queryString); diff --git a/src/QueryReflection/MysqliQueryReflector.php b/src/QueryReflection/MysqliQueryReflector.php index b5be93086..584d24588 100644 --- a/src/QueryReflection/MysqliQueryReflector.php +++ b/src/QueryReflection/MysqliQueryReflector.php @@ -15,7 +15,7 @@ use staabm\PHPStanDba\Error; use staabm\PHPStanDba\TypeMapping\MysqliTypeMapper; -final class MysqliQueryReflector implements QueryReflector +final class MysqliQueryReflector implements QueryReflector, RecordingReflector { private const MYSQL_SYNTAX_ERROR_CODE = 1064; private const MYSQL_UNKNOWN_COLUMN_IN_FIELDLIST = 1054; @@ -150,4 +150,9 @@ private function simulateQuery(string $queryString) $this->db->rollback(); } } + + public function getDatasource() + { + return $this->db; + } } diff --git a/src/QueryReflection/QueryReflection.php b/src/QueryReflection/QueryReflection.php index 446fec1e8..e93191afa 100644 --- a/src/QueryReflection/QueryReflection.php +++ b/src/QueryReflection/QueryReflection.php @@ -14,6 +14,8 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeUtils; use PHPStan\Type\UnionType; +use staabm\PHPStanDba\Analyzer\QueryPlanAnalyzerMysql; +use staabm\PHPStanDba\Analyzer\QueryPlanResult; use staabm\PHPStanDba\DbaException; use staabm\PHPStanDba\Error; use staabm\PHPStanDba\UnresolvableQueryException; @@ -407,4 +409,42 @@ public function extractNamedPlaceholders(string $queryString): array return []; } + + /** + * @return iterable + */ + public function analyzeQueryPlan(Scope $scope, Expr $queryExpr, ?Type $parameterTypes): iterable + { + $reflector = self::reflector(); + + if (!$reflector instanceof RecordingReflector) { + throw new DbaException('Query plan analysis is only supported with a recording reflector'); + } + if ($reflector instanceof PdoPgSqlQueryReflector) { + throw new DbaException('Query plan analysis is not yet supported with the pdo-pgsql reflector, see https://github.com/staabm/phpstan-dba/issues/378'); + } + + $ds = $reflector->getDatasource(); + if (null === $ds) { + throw new DbaException(sprintf('Unable to create datasource from %s', \get_class($reflector))); + } + $queryPlanAnalyzer = new QueryPlanAnalyzerMysql($ds); + + $queryResolver = new QueryResolver(); + foreach ($queryResolver->resolve($scope, $queryExpr, $parameterTypes) as $queryString) { + if ('' === $queryString) { + continue; + } + + if ('SELECT' !== self::getQueryType($queryString)) { + continue; + } + + if ($reflector->validateQueryString($queryString) instanceof Error) { + continue; + } + + yield $queryPlanAnalyzer->analyze($queryString); + } + } } diff --git a/src/QueryReflection/QueryResolver.php b/src/QueryReflection/QueryResolver.php new file mode 100644 index 000000000..45fe38b4b --- /dev/null +++ b/src/QueryReflection/QueryResolver.php @@ -0,0 +1,38 @@ + + * + * @throws UnresolvableQueryException + */ + public function resolve(Scope $scope, Expr $queryExpr, ?Type $parameterTypes): iterable + { + $queryReflection = new QueryReflection(); + + $parameters = null; + if (null !== $parameterTypes) { + $parameters = $queryReflection->resolveParameters($parameterTypes) ?? []; + } + + if (null === $parameters) { + $queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope); + } else { + $queryStrings = $queryReflection->resolvePreparedQueryStrings($queryExpr, $parameterTypes, $scope); + } + + foreach ($queryStrings as $queryString) { + yield $queryString; + } + } +} diff --git a/src/QueryReflection/RecordingQueryReflector.php b/src/QueryReflection/RecordingQueryReflector.php index 79320cce7..168b5594e 100644 --- a/src/QueryReflection/RecordingQueryReflector.php +++ b/src/QueryReflection/RecordingQueryReflector.php @@ -7,7 +7,7 @@ use PHPStan\Type\Type; use staabm\PHPStanDba\Error; -final class RecordingQueryReflector implements QueryReflector +final class RecordingQueryReflector implements QueryReflector, RecordingReflector { /** * @var ReflectionCache @@ -54,4 +54,13 @@ public function getResultType(string $queryString, int $fetchType): ?Type return $resultType; } + + public function getDatasource() + { + if ($this->reflector instanceof RecordingReflector) { + return $this->reflector->getDatasource(); + } + + return null; + } } diff --git a/src/QueryReflection/RecordingReflector.php b/src/QueryReflection/RecordingReflector.php new file mode 100644 index 000000000..aed2b0d45 --- /dev/null +++ b/src/QueryReflection/RecordingReflector.php @@ -0,0 +1,18 @@ +createRecordingReflector()->getResultType($queryString, $fetchType); } } + + public function getDatasource() + { + return $this->createRecordingReflector()->getDatasource(); + } } diff --git a/src/QueryReflection/RuntimeConfiguration.php b/src/QueryReflection/RuntimeConfiguration.php index cacacaf65..ba0ac01e2 100644 --- a/src/QueryReflection/RuntimeConfiguration.php +++ b/src/QueryReflection/RuntimeConfiguration.php @@ -5,6 +5,7 @@ namespace staabm\PHPStanDba\QueryReflection; use PHPStan\Php\PhpVersion; +use staabm\PHPStanDba\Analyzer\QueryPlanAnalyzerMysql; final class RuntimeConfiguration { @@ -39,6 +40,14 @@ final class RuntimeConfiguration * @var bool */ private $stringifyTypes = false; + /** + * @var bool|0|positive-int + */ + private $numberOfAllowedUnindexedReads = false; + /** + * @var false|positive-int + */ + private $numberOfRowsNotRequiringIndex = false; public static function create(): self { @@ -70,6 +79,13 @@ public function defaultFetchMode(int $mode): self return $this; } + /** + * When enabled, a DbaException will be thrown in case a sql query cannot be analyzed. + * + * Otherwise these queries will be ignored. + * + * @return $this + */ public function debugMode(bool $mode): self { $this->debugMode = $mode; @@ -88,6 +104,42 @@ public function stringifyTypes(bool $stringify): self return $this; } + /** + * Enables query plan analysis, which indicates performance problems. + * + * Requires a active database connection. + * + * @param bool|0|positive-int $numberOfAllowedUnindexedReads `true` to enable analysis with QueryPlanAnalyzerMysql::DEFAULT_UNINDEXED_READS_THRESHOLD. `false` to disable analysis. + * Otherwise the number of reads a query is allowed to execute, before it is considered inefficient. + * `0` disables the efficiency checks but still scans for queries not using an index. + * @param positive-int $numberOfRowsNotRequiringIndex number of reads a query is allowed to execute, without requiring a index + * + * @return $this + */ + public function analyzeQueryPlans($numberOfAllowedUnindexedReads = true, $numberOfRowsNotRequiringIndex = QueryPlanAnalyzerMysql::DEFAULT_SMALL_TABLE_THRESHOLD): self + { + $this->numberOfAllowedUnindexedReads = $numberOfAllowedUnindexedReads; + $this->numberOfRowsNotRequiringIndex = $numberOfRowsNotRequiringIndex; + + return $this; + } + + /** + * @return bool|0|positive-int + */ + public function getNumberOfAllowedUnindexedReads() + { + return $this->numberOfAllowedUnindexedReads; + } + + /** + * @return false|positive-int + */ + public function getNumberOfRowsNotRequiringIndex() + { + return $this->numberOfRowsNotRequiringIndex; + } + public function isDebugEnabled(): bool { return $this->debugMode; diff --git a/src/Rules/QueryPlanAnalyzerRule.php b/src/Rules/QueryPlanAnalyzerRule.php new file mode 100644 index 000000000..8d94798e2 --- /dev/null +++ b/src/Rules/QueryPlanAnalyzerRule.php @@ -0,0 +1,162 @@ + + */ +final class QueryPlanAnalyzerRule implements Rule +{ + /** + * @var list + */ + private $classMethods; + + /** + * @param list $classMethods + */ + public function __construct(array $classMethods) + { + $this->classMethods = $classMethods; + } + + public function getNodeType(): string + { + return CallLike::class; + } + + public function processNode(Node $callLike, Scope $scope): array + { + if ($callLike instanceof MethodCall) { + if (!$callLike->name instanceof Node\Identifier) { + return []; + } + + $methodReflection = $scope->getMethodReflection($scope->getType($callLike->var), $callLike->name->toString()); + } elseif ($callLike instanceof New_) { + if (!$callLike->class instanceof FullyQualified) { + return []; + } + $methodReflection = $scope->getMethodReflection(new ObjectType($callLike->class->toCodeString()), '__construct'); + } else { + return []; + } + + if (null === $methodReflection) { + return []; + } + + $unsupportedMethod = true; + $queryArgPosition = null; + foreach ($this->classMethods as $classMethod) { + sscanf($classMethod, '%[^::]::%[^#]#%s', $className, $methodName, $queryArgPosition); + + if ($methodName === $methodReflection->getName() && + ($methodReflection->getDeclaringClass()->getName() === $className || $methodReflection->getDeclaringClass()->isSubclassOf($className))) { + $unsupportedMethod = false; + break; + } + } + + if ($unsupportedMethod) { + return []; + } + + $args = $callLike->getArgs(); + + if (!\array_key_exists($queryArgPosition, $args)) { + return []; + } + + if ($scope->getType($args[$queryArgPosition]->value) instanceof MixedType) { + return []; + } + + return $this->analyze($callLike, $scope); + } + + /** + * @param MethodCall|New_ $callLike + * + * @return RuleError[] + */ + private function analyze(CallLike $callLike, Scope $scope): array + { + $args = $callLike->getArgs(); + + if (\count($args) < 1) { + return []; + } + + if (false === QueryReflection::getRuntimeConfiguration()->getNumberOfAllowedUnindexedReads()) { + return []; + } + + $queryExpr = $args[0]->value; + + if ($scope->getType($queryExpr) instanceof MixedType) { + return []; + } + + $parameterTypes = null; + if (\count($args) > 1) { + $parameterTypes = $scope->getType($args[1]->value); + } + + $ruleErrors = []; + $queryReflection = new QueryReflection(); + $proposal = "\n\nConsider optimizing the query.\nIn some cases this is not a problem and this error should be ignored."; + foreach ($queryReflection->analyzeQueryPlan($scope, $queryExpr, $parameterTypes) as $queryPlanResult) { + $notUsingIndex = $queryPlanResult->getTablesNotUsingIndex(); + if (\count($notUsingIndex) > 0) { + foreach ($notUsingIndex as $table) { + $ruleErrors[] = RuleErrorBuilder::message( + sprintf( + "Query is not using an index on table '%s'.".$proposal, + $table + )) + ->line($callLike->getLine()) + ->build(); + } + } else { + foreach ($queryPlanResult->getTablesDoingTableScan() as $table) { + $ruleErrors[] = RuleErrorBuilder::message( + sprintf( + "Query is using a full-table-scan on table '%s'.".$proposal, + $table + )) + ->line($callLike->getLine()) + ->tip('see Mysql Docs https://dev.mysql.com/doc/refman/8.0/en/table-scan-avoidance.html') + ->build(); + } + + foreach ($queryPlanResult->getTablesDoingUnindexedReads() as $table) { + $ruleErrors[] = RuleErrorBuilder::message( + sprintf( + "Query is triggering too many unindexed-reads on table '%s'.".$proposal, + $table + )) + ->line($callLike->getLine()) + ->build(); + } + } + } + + return $ruleErrors; + } +} diff --git a/tests/default/config/.phpstan-dba-pdo-mysql.cache b/tests/default/config/.phpstan-dba-pdo-mysql.cache index 695a6ffc6..620e34e6d 100644 --- a/tests/default/config/.phpstan-dba-pdo-mysql.cache +++ b/tests/default/config/.phpstan-dba-pdo-mysql.cache @@ -3274,10 +3274,6 @@ FROM ada' => 'message' => 'SQLSTATE[42000]: Syntax error or access violation: 1064 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', 'code' => '42000', )), - 'result' => - array ( - 5 => NULL, - ), ), 'SELECT email, adaid FROM ada' => array ( diff --git a/tests/rules/QueryPlanAnalyzerRuleTest.php b/tests/rules/QueryPlanAnalyzerRuleTest.php new file mode 100644 index 000000000..0d7471da8 --- /dev/null +++ b/tests/rules/QueryPlanAnalyzerRuleTest.php @@ -0,0 +1,80 @@ + + */ +class QueryPlanAnalyzerRuleTest extends RuleTestCase +{ + /** + * @var bool|0|positive-int + */ + private $numberOfAllowedUnindexedReads; + /** + * @var positive-int + */ + private $numberOfRowsNotRequiringIndex; + + protected function tearDown(): void + { + QueryReflection::getRuntimeConfiguration()->analyzeQueryPlans(false); + } + + protected function getRule(): Rule + { + QueryReflection::getRuntimeConfiguration()->analyzeQueryPlans($this->numberOfAllowedUnindexedReads, $this->numberOfRowsNotRequiringIndex); + + return self::getContainer()->getByType(QueryPlanAnalyzerRule::class); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__.'/../../config/dba.neon', + ]; + } + + public function testNotUsingIndex(): void + { + if ('pdo-pgsql' === getenv('DBA_REFLECTOR')) { + $this->markTestSkipped('query plan analyzer is not yet implemented for pgsql'); + } + + if ('recording' !== getenv('DBA_MODE')) { + $this->markTestSkipped('query plan analyzer requires a active database connection'); + } + + $this->numberOfAllowedUnindexedReads = true; + $this->numberOfRowsNotRequiringIndex = 2; + + $this->analyse([__DIR__.'/data/query-plan-analyzer.php'], [ + [ + "Query is not using an index on table 'ada'. + +Consider optimizing the query. +In some cases this is not a problem and this error should be ignored.", + 12, + ], + [ + "Query is not using an index on table 'ada'. + +Consider optimizing the query. +In some cases this is not a problem and this error should be ignored.", + 17, + ], + [ + "Query is not using an index on table 'ada'. + +Consider optimizing the query. +In some cases this is not a problem and this error should be ignored.", + 22, + ], + ]); + } +} diff --git a/tests/rules/config/.phpstan-dba-mysqli.cache b/tests/rules/config/.phpstan-dba-mysqli.cache index 90bd7f111..4d45fac36 100644 --- a/tests/rules/config/.phpstan-dba-mysqli.cache +++ b/tests/rules/config/.phpstan-dba-mysqli.cache @@ -75,6 +75,312 @@ 5 => NULL, ), ), + 'SELECT * FROM `ada` WHERE adaid = 1' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT * FROM `ada` WHERE email = \'test@example.com\';' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), 'SELECT * FROM ada GROUP BY doesNotExist' => array ( 'error' => @@ -87,37 +393,363 @@ 5 => NULL, ), ), - 'SELECT * FROM ada ORDER BY doesNotExist' => + 'SELECT * FROM ada ORDER BY doesNotExist' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'order clause\'', + 'code' => 1054, + )), + 'result' => + array ( + 5 => NULL, + ), + ), + 'SELECT * FROM ada WHERE doesNotExist=1' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'where clause\'', + 'code' => 1054, + )), + 'result' => + array ( + 5 => NULL, + ), + ), + 'SELECT * FROM ada WHERE email = \'1970-01-01\'' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT * FROM unknown_table' => array ( 'error' => staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'Unknown column \'doesNotExist\' in \'order clause\'', - 'code' => 1054, + 'message' => 'Table \'phpstan_dba.unknown_table\' doesn\'t exist', + 'code' => 1146, )), 'result' => array ( 5 => NULL, ), ), - 'SELECT * FROM ada WHERE doesNotExist=1' => + 'SELECT *,adaid FROM `ada` WHERE email = \'test@example.com\';' => array ( - 'error' => - staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'Unknown column \'doesNotExist\' in \'where clause\'', - 'code' => 1054, - )), 'result' => array ( - 5 => NULL, + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 5, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 8 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 8 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 8 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), ), ), - 'SELECT * FROM unknown_table' => + 'SELECT FROM WHERE' => array ( - 'error' => - staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'Table \'phpstan_dba.unknown_table\' doesn\'t exist', - 'code' => 1146, - )), 'result' => array ( 5 => NULL, diff --git a/tests/rules/config/.phpstan-dba-pdo-mysql.cache b/tests/rules/config/.phpstan-dba-pdo-mysql.cache index ca2966b23..3d4f3e503 100644 --- a/tests/rules/config/.phpstan-dba-pdo-mysql.cache +++ b/tests/rules/config/.phpstan-dba-pdo-mysql.cache @@ -75,6 +75,312 @@ 5 => NULL, ), ), + 'SELECT * FROM `ada` WHERE adaid = 1' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT * FROM `ada` WHERE email = \'test@example.com\';' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), 'SELECT * FROM ada GROUP BY doesNotExist' => array ( 'error' => @@ -82,42 +388,352 @@ 'message' => 'SQLSTATE[42S22]: Column not found: 1054 Unknown column \'doesNotExist\' in \'group statement\'', 'code' => '42S22', )), + ), + 'SELECT * FROM ada ORDER BY doesNotExist' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'SQLSTATE[42S22]: Column not found: 1054 Unknown column \'doesNotExist\' in \'order clause\'', + 'code' => '42S22', + )), + ), + 'SELECT * FROM ada WHERE doesNotExist=1' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'SQLSTATE[42S22]: Column not found: 1054 Unknown column \'doesNotExist\' in \'where clause\'', + 'code' => '42S22', + )), + ), + 'SELECT * FROM ada WHERE email = \'1970-01-01\'' => + array ( 'result' => array ( - 5 => NULL, + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), ), ), - 'SELECT * FROM ada ORDER BY doesNotExist' => + 'SELECT * FROM unknown_table' => array ( 'error' => staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'SQLSTATE[42S22]: Column not found: 1054 Unknown column \'doesNotExist\' in \'order clause\'', - 'code' => '42S22', + 'message' => 'SQLSTATE[42S02]: Base table or view not found: 1146 Table \'phpstan_dba.unknown_table\' doesn\'t exist', + 'code' => '42S02', )), - 'result' => - array ( - 5 => NULL, - ), ), - 'SELECT * FROM ada WHERE doesNotExist=1' => + 'SELECT *,adaid FROM `ada` WHERE email = \'test@example.com\';' => array ( - 'error' => - staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'SQLSTATE[42S22]: Column not found: 1054 Unknown column \'doesNotExist\' in \'where clause\'', - 'code' => '42S22', - )), 'result' => array ( - 5 => NULL, + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 5, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 8 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 8 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 8 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), ), ), - 'SELECT * FROM unknown_table' => + 'SELECT FROM WHERE' => array ( - 'error' => - staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'SQLSTATE[42S02]: Base table or view not found: 1146 Table \'phpstan_dba.unknown_table\' doesn\'t exist', - 'code' => '42S02', - )), 'result' => array ( 5 => NULL, @@ -200,10 +816,6 @@ 'message' => 'SQLSTATE[42S22]: Column not found: 1054 Unknown column \'doesNotExist\' in \'field list\'', 'code' => '42S22', )), - 'result' => - array ( - 5 => NULL, - ), ), 'SELECT email FROM ada WHERE gesperrt=:gesperrt' => array ( @@ -276,11 +888,6 @@ 'message' => 'SQLSTATE[42000]: Syntax error or access violation: 1064 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', 'code' => '42000', )), - 'result' => - array ( - 5 => NULL, - 3 => NULL, - ), ), 'SELECT email adaid gesperrt freigabe1u1 FROM ada' => array ( @@ -539,10 +1146,6 @@ 'message' => 'SQLSTATE[42000]: Syntax error or access violation: 1064 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 1', 'code' => '42000', )), - 'result' => - array ( - 5 => NULL, - ), ), 'SELECT email, adaid GROUP BY xy FROM ada WHERE email=\'my_other_table\' LIMIT 1' => array ( diff --git a/tests/rules/config/.phpunit-phpstan-dba-mysqli.cache b/tests/rules/config/.phpunit-phpstan-dba-mysqli.cache index 2e45270ed..5321a920a 100644 --- a/tests/rules/config/.phpunit-phpstan-dba-mysqli.cache +++ b/tests/rules/config/.phpunit-phpstan-dba-mysqli.cache @@ -75,6 +75,468 @@ 5 => NULL, ), ), + 'SELECT * FROM `ada` WHERE adaid = 1' => + array ( + 'error' => NULL, + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT * FROM `ada` WHERE email = \'1970-01-01\'' => + array ( + 'error' => NULL, + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT * FROM `ada` WHERE email = \'test@example.com\';' => + array ( + 'error' => NULL, + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), 'SELECT * FROM ada GROUP BY doesNotExist' => array ( 'error' => @@ -87,41 +549,368 @@ 5 => NULL, ), ), - 'SELECT * FROM ada ORDER BY doesNotExist' => + 'SELECT * FROM ada ORDER BY doesNotExist' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'order clause\'', + 'code' => 1054, + )), + 'result' => + array ( + 5 => NULL, + ), + ), + 'SELECT * FROM ada WHERE doesNotExist=1' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'Unknown column \'doesNotExist\' in \'where clause\'', + 'code' => 1054, + )), + 'result' => + array ( + 5 => NULL, + ), + ), + 'SELECT * FROM ada WHERE email = \'1970-01-01\'' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT * FROM unknown_table' => array ( 'error' => staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'Unknown column \'doesNotExist\' in \'order clause\'', - 'code' => 1054, + 'message' => 'Table \'phpstan_dba.unknown_table\' doesn\'t exist', + 'code' => 1146, )), 'result' => array ( 5 => NULL, ), ), - 'SELECT * FROM ada WHERE doesNotExist=1' => + 'SELECT *,adaid FROM `ada` WHERE email = \'test@example.com\';' => array ( - 'error' => - staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'Unknown column \'doesNotExist\' in \'where clause\'', - 'code' => 1054, - )), 'result' => array ( - 5 => NULL, + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 5, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 8 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 8 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 8 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), ), ), - 'SELECT * FROM unknown_table' => + 'SELECT FROM WHERE' => array ( 'error' => staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'Table \'phpstan_dba.unknown_table\' doesn\'t exist', - 'code' => 1146, + '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 WHERE LIMIT 0\' at line 1', + 'code' => 1064, )), - 'result' => - array ( - 5 => NULL, - ), ), 'SELECT adaid FROM ada WHERE email = \'1970-01-01\'' => array ( diff --git a/tests/rules/config/.phpunit-phpstan-dba-pdo-mysql.cache b/tests/rules/config/.phpunit-phpstan-dba-pdo-mysql.cache index 2b191b5d8..f6b483443 100644 --- a/tests/rules/config/.phpunit-phpstan-dba-pdo-mysql.cache +++ b/tests/rules/config/.phpunit-phpstan-dba-pdo-mysql.cache @@ -39,40 +39,312 @@ 5 => NULL, ), ), - 'SELECT - ada.*, - COALESCE(NULLIF(email, ""), email) AS email - FROM ada - INNER JOIN ak ON (ak.adaid = ada.adaid AND ak.akid = \'1\') - WHERE adaid = 1 ORDER BY COALESCE(NULLIF(email, ""), email) ASC' => - array ( - 'result' => - array ( - 5 => NULL, - ), - ), - 'SELECT - ada.*, - COALESCE(NULLIF(email, ""), email) AS email - FROM ada - INNER JOIN ak ON (ak.adaid = ada.adaid AND ak.akid = :akid) - WHERE adaid = 1 ORDER BY COALESCE(NULLIF(email, ""), email) ASC' => + 'SELECT * FROM `ada` WHERE adaid = 1' => array ( + 'error' => NULL, 'result' => array ( - 5 => NULL, + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), ), ), - 'SELECT - ada.*, - COALESCE(NULLIF(email, ""), email) AS email - FROM ada - INNER JOIN ak ON (ak.adaid = ada.adaid AND ak.akid = ?) - WHERE adaid = 1 ORDER BY COALESCE(NULLIF(email, ""), email) ASC' => + 'SELECT * FROM `ada` WHERE email = \'test@example.com\';' => array ( + 'error' => NULL, 'result' => array ( - 5 => NULL, + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), ), ), 'SELECT * FROM ada GROUP BY doesNotExist' => @@ -111,12 +383,345 @@ 5 => NULL, ), ), - 'SELECT * FROM unknown_table' => + 'SELECT * FROM ada WHERE email = \'1970-01-01\'' => + array ( + 'error' => NULL, + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 4, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT * FROM unknown_table' => + array ( + 'error' => + staabm\PHPStanDba\Error::__set_state(array( + 'message' => 'SQLSTATE[42S02]: Base table or view not found: 1146 Table \'phpstan_dba.unknown_table\' doesn\'t exist', + 'code' => '42S02', + )), + 'result' => + array ( + 5 => NULL, + ), + ), + 'SELECT *,adaid FROM `ada` WHERE email = \'test@example.com\';' => + array ( + 'error' => NULL, + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'nextAutoIndexes' => + array ( + 0 => 5, + ), + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 8 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 4 => + PHPStan\Type\StringType::__set_state(array( + )), + 5 => + PHPStan\Type\StringType::__set_state(array( + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 8 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + ), + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => true, + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 4, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 8 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'sortedTypes' => false, + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -32768, + 'max' => 32767, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), + 'SELECT FROM WHERE' => array ( 'error' => staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'SQLSTATE[42S02]: Base table or view not found: 1146 Table \'phpstan_dba.unknown_table\' doesn\'t exist', - 'code' => '42S02', + 'message' => 'SQLSTATE[42000]: Syntax error or access violation: 1064 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 WHERE LIMIT 0\' at line 1', + 'code' => '42000', )), 'result' => array ( @@ -259,17 +864,6 @@ 'code' => '42000', )), ), - 'SELECT email adaid - WHERE gesperrt = \'1\' AND email LIKE \'%@example.com\' - FROM ada - LIMIT 1' => - array ( - 'error' => - staabm\PHPStanDba\Error::__set_state(array( - 'message' => 'SQLSTATE[42000]: Syntax error or access violation: 1064 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', - 'code' => '42000', - )), - ), 'SELECT email adaid WHERE gesperrt freigabe1u1 FROM ada' => array ( 'error' => @@ -379,90 +973,6 @@ array ( 'error' => NULL, ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - FOR UPDATE' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\'' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\' - FOR UPDATE' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\' - OFFSET \'1\'' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\' - OFFSET \'1\' - FOR SHARE' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\' - OFFSET \'1\' - FOR UPDATE' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\' - OFFSET 1' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\', \'1\'' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' - LIMIT \'1\', \'1\'' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' AND email LIKE \'%@example%\' - LIMIT 1' => - array ( - 'error' => NULL, - ), - 'SELECT email, adaid - FROM ada - WHERE gesperrt = \'1\' AND email LIKE NULL - LIMIT 1' => - array ( - 'error' => NULL, - ), 'SELECT email, adaid FROM ada GROUP BY xy LIMIT 1' => array ( 'error' => @@ -991,11 +1501,6 @@ array ( 'error' => NULL, ), - 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada - WHERE (gesperrt=\'1\' AND freigabe1u1=1) OR (gesperrt=\'1\' AND freigabe1u1=0)' => - array ( - 'error' => NULL, - ), 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada LIMIT 1' => array ( 'error' => NULL, diff --git a/tests/rules/data/query-plan-analyzer.php b/tests/rules/data/query-plan-analyzer.php new file mode 100644 index 000000000..ce9de7dbb --- /dev/null +++ b/tests/rules/data/query-plan-analyzer.php @@ -0,0 +1,42 @@ +query("SELECT * FROM `ada` WHERE email = 'test@example.com';"); + } + + public function noindexDbal(Connection $conn): void + { + $conn->executeQuery("SELECT *,adaid FROM `ada` WHERE email = 'test@example.com';"); + } + + public function noindexPreparedDbal(Connection $conn, string $email): void + { + $conn->executeQuery('SELECT * FROM ada WHERE email = ?', [$email]); + } + + public function syntaxError(Connection $conn): void + { + $conn->executeQuery('SELECT FROM WHERE'); + } + + public function indexed(PDO $pdo, int $adaid): void + { + $pdo->query('SELECT * FROM `ada` WHERE adaid = '.$adaid); + } + + 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/schema.sql b/tests/schema.sql index abd893ef1..94ef0de7e 100644 --- a/tests/schema.sql +++ b/tests/schema.sql @@ -12,6 +12,12 @@ CREATE TABLE `ada` ( ALTER TABLE `ada` ADD PRIMARY KEY (`adaid`); +INSERT INTO `ada` (`adaid`, `gesperrt`, `email`, `freigabe1u1`) +VALUES + (1, 0, 'test@example.com', 0), + (3, 0, 'test@example.com', 0), + (2, 1, 'another@example.com', 1); + CREATE TABLE `ak` ( `akid` int(11) NOT NULL DEFAULT '0',