From 436e2e9e59cb70d0ae3cdcfdc8dc73a87cd1d4b3 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 7 Nov 2024 16:04:25 +0100 Subject: [PATCH] Remove use of PDOStatement stub and and generic PDOStatement result type (#700) --- config/PdoStatement.stub | 25 - config/dba.neon | 1 - config/stubFiles.neon | 1 - src/PdoReflection/PdoStatementObjectType.php | 93 ++- src/PdoReflection/PdoStatementReflection.php | 2 +- .../default/data/pdo-default-fetch-types.php | 12 +- tests/default/data/pdo-fetch-types.php | 24 +- tests/default/data/pdo-mysql.php | 28 +- tests/default/data/pdo-pgsql.php | 8 +- tests/default/data/pdo-prepare.php | 71 +- tests/default/data/pdo-quote.php | 24 +- tests/default/data/pdo-stmt-execute.php | 25 +- tests/default/data/pdo-stmt-fetch.php | 8 +- .../default/data/pdo-stmt-set-fetch-mode.php | 24 +- tests/default/data/pdo.php | 143 +++-- tests/default/data/query-alias.php | 4 +- tests/default/data/typemix-mysql.php | 45 +- tests/default/data/typemix-pgsql.php | 26 +- tests/defaultFetchAssoc/data/modes.php | 34 +- tests/defaultFetchNumeric/data/modes.php | 22 +- tests/sqlAst/data/sql-ast-narrowing.php | 606 +++++++++++++----- .../stringify/data/ast-narrowed-stringify.php | 8 +- tests/stringify/data/stringify.php | 3 +- 23 files changed, 906 insertions(+), 331 deletions(-) delete mode 100644 config/PdoStatement.stub diff --git a/config/PdoStatement.stub b/config/PdoStatement.stub deleted file mode 100644 index 6e06c0f1c..000000000 --- a/config/PdoStatement.stub +++ /dev/null @@ -1,25 +0,0 @@ - - * @implements IteratorAggregate - * - * @link https://php.net/manual/en/class.pdostatement.php - */ -class PDOStatement implements Traversable, IteratorAggregate -{ - /** - * @template T - * @param class-string $class - * @param array $ctorArgs - * @return false|T - */ - public function fetchObject($class = \stdclass::class, array $ctorArgs = array()) {} - - /** - * @return array{name: string, table?: string, native_type?: string, len: int, flags: array, precision: int<0, max>, pdo_type: PDO::PARAM_* }|false - */ - public function getColumnMeta(int $column) {} -} diff --git a/config/dba.neon b/config/dba.neon index ddad76a65..f2dcc9b87 100644 --- a/config/dba.neon +++ b/config/dba.neon @@ -6,7 +6,6 @@ includes: parameters: featureToggles: skipCheckGenericClasses: - - PDOStatement - Doctrine\DBAL\Result - Doctrine\DBAL\Statement diff --git a/config/stubFiles.neon b/config/stubFiles.neon index 9fe695e9a..ce21f3e06 100644 --- a/config/stubFiles.neon +++ b/config/stubFiles.neon @@ -1,4 +1,3 @@ parameters: stubFiles: - DoctrineDbal.stub - - PdoStatement.stub diff --git a/src/PdoReflection/PdoStatementObjectType.php b/src/PdoReflection/PdoStatementObjectType.php index 50546a98e..456be50bf 100644 --- a/src/PdoReflection/PdoStatementObjectType.php +++ b/src/PdoReflection/PdoStatementObjectType.php @@ -5,12 +5,13 @@ namespace staabm\PHPStanDba\PdoReflection; use PDOStatement; +use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Type\ArrayType; use PHPStan\Type\BenevolentUnionType; use PHPStan\Type\Constant\ConstantArrayTypeBuilder; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\FloatType; -use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntegerType; use PHPStan\Type\MixedType; @@ -21,30 +22,37 @@ use PHPStan\Type\UnionType; use staabm\PHPStanDba\QueryReflection\QueryReflector; -class PdoStatementObjectType extends GenericObjectType +class PdoStatementObjectType extends ObjectType { - /** - * @var Type - */ - private $bothType; + private ?Type $bothType; /** - * @param QueryReflector::FETCH_TYPE* $fetchType + * @var null|QueryReflector::FETCH_TYPE* */ - public function __construct(Type $bothType, int $fetchType) - { - $this->bothType = $bothType; + private ?int $fetchType; - $rowTypeInFetchMode = $this->reduceBothType($bothType, $fetchType); - - parent::__construct(PDOStatement::class, [$rowTypeInFetchMode]); + public function getRowType(): Type + { + if ($this->bothType === null || $this->fetchType === null) { + throw new ShouldNotHappenException(); + } + return $this->reduceBothType($this->bothType, $this->fetchType); } - public function getRowType(): Type + public function getIterableValueType(): Type { - $genericTypes = $this->getTypes(); + return $this->getRowType(); + } - return $genericTypes[0]; + /** + * @param QueryReflector::FETCH_TYPE* $fetchType + */ + public static function newWithBothAndFetchType(Type $bothType, int $fetchType): self + { + $new = new self(PDOStatement::class); + $new->bothType = $bothType; + $new->fetchType = $fetchType; + return $new; } /** @@ -52,7 +60,10 @@ public function getRowType(): Type */ public function newWithFetchType(int $fetchType): self { - return new self($this->bothType, $fetchType); + $new = new self($this->getClassName(), $this->getSubtractedType()); + $new->bothType = $this->bothType; + $new->fetchType = $fetchType; + return $new; } /** @@ -116,23 +127,57 @@ public static function createDefaultType(int $fetchType): Type switch ($fetchType) { case QueryReflector::FETCH_TYPE_CLASS: - return new GenericObjectType(PDOStatement::class, [new ObjectType('stdClass')]); + return self::newWithBothAndFetchType(new ObjectType('stdClass'), $fetchType); case QueryReflector::FETCH_TYPE_KEY_VALUE: $arrayBuilder = ConstantArrayTypeBuilder::createEmpty(); $arrayBuilder->setOffsetValueType(new ConstantIntegerType(0), new MixedType()); $arrayBuilder->setOffsetValueType(new ConstantIntegerType(1), new MixedType()); - return new GenericObjectType(PDOStatement::class, [$arrayBuilder->getArray()]); + return self::newWithBothAndFetchType($arrayBuilder->getArray(), $fetchType); case QueryReflector::FETCH_TYPE_NUMERIC: - return new GenericObjectType(PDOStatement::class, [new ArrayType(IntegerRangeType::fromInterval(0, null), $pdoScalar)]); + return self::newWithBothAndFetchType(new ArrayType(IntegerRangeType::fromInterval(0, null), $pdoScalar), $fetchType); case QueryReflector::FETCH_TYPE_ASSOC: - return new GenericObjectType(PDOStatement::class, [new ArrayType(new StringType(), $pdoScalar)]); + return self::newWithBothAndFetchType(new ArrayType(new StringType(), $pdoScalar), $fetchType); case QueryReflector::FETCH_TYPE_BOTH: - return new GenericObjectType(PDOStatement::class, [new ArrayType($arrayKey, $pdoScalar)]); + return self::newWithBothAndFetchType(new ArrayType($arrayKey, $pdoScalar), $fetchType); case QueryReflector::FETCH_TYPE_COLUMN: - return new GenericObjectType(PDOStatement::class, [$pdoScalar]); + return self::newWithBothAndFetchType($pdoScalar, $fetchType); + } + + return self::newWithBothAndFetchType(new MixedType(), $fetchType); + } + + // differentiate objects based on the local properties, + // to make sure TypeCombinator::union() will not normalize separate objects away. + // this means we need to implement equals() and isSuperTypeOf(). + public function equals(Type $type): bool + { + if ( + $type instanceof self + && $type->fetchType !== null + && $type->bothType !== null + && $this->bothType !== null + ) { + return $type->fetchType === $this->fetchType && $type->bothType->equals($this->bothType); + } + + return parent::equals($type); + } + + public function isSuperTypeOf(Type $type): TrinaryLogic + { + if ( + $type instanceof self + && $type->fetchType !== null + && $type->bothType !== null + && $this->bothType !== null + ) { + return TrinaryLogic::createFromBoolean( + $type->fetchType === $this->fetchType + && $type->bothType->equals($this->bothType) + ); } - return new GenericObjectType(PDOStatement::class, [new MixedType()]); + return parent::isSuperTypeOf($type); } } diff --git a/src/PdoReflection/PdoStatementReflection.php b/src/PdoReflection/PdoStatementReflection.php index e09972997..36ecb42af 100644 --- a/src/PdoReflection/PdoStatementReflection.php +++ b/src/PdoReflection/PdoStatementReflection.php @@ -87,7 +87,7 @@ public function createGenericStatement(iterable $queryStrings, int $reflectionFe $bothType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); if (null !== $bothType) { - $genericObjects[] = new PdoStatementObjectType($bothType, $reflectionFetchType); + $genericObjects[] = PdoStatementObjectType::newWithBothAndFetchType($bothType, $reflectionFetchType); } } diff --git a/tests/default/data/pdo-default-fetch-types.php b/tests/default/data/pdo-default-fetch-types.php index 3f89c9575..e80ba0971 100644 --- a/tests/default/data/pdo-default-fetch-types.php +++ b/tests/default/data/pdo-default-fetch-types.php @@ -10,7 +10,6 @@ class HelloWorld public function defaultFetchType(PDO $pdo, string $q): void { $stmt = $pdo->query($q); - assertType('PDOStatement>', $stmt); foreach ($stmt as $row) { assertType('array', $row); } @@ -19,45 +18,38 @@ public function defaultFetchType(PDO $pdo, string $q): void public function specifiedFetchTypes(PDO $pdo, string $q): void { $stmt = $pdo->query($q, PDO::FETCH_CLASS); - assertType('PDOStatement', $stmt); foreach ($stmt as $row) { assertType('stdClass', $row); } $stmt = $pdo->query($q, PDO::FETCH_OBJ); - assertType('PDOStatement', $stmt); foreach ($stmt as $row) { assertType('stdClass', $row); } $stmt = $pdo->query($q, PDO::FETCH_KEY_PAIR); - assertType('PDOStatement', $stmt); foreach ($stmt as $row) { assertType('array{mixed, mixed}', $row); } $stmt = $pdo->query($q, PDO::FETCH_ASSOC); - assertType('PDOStatement>', $stmt); foreach ($stmt as $row) { assertType('array', $row); } $stmt = $pdo->query($q, PDO::FETCH_NUM); - assertType('PDOStatement, float|int|string|null>>', $stmt); // could be list foreach ($stmt as $row) { - assertType('array, float|int|string|null>', $row); + assertType('array, float|int|string|null>', $row); // could be list } $stmt = $pdo->query($q, PDO::FETCH_BOTH); - assertType('PDOStatement>', $stmt); foreach ($stmt as $row) { assertType('array', $row); } $stmt = $pdo->query($q, PDO::FETCH_COLUMN); - assertType('PDOStatement', $stmt); // could be PDOStatement foreach ($stmt as $row) { - assertType('mixed', $row); // could be float|int|string|null + assertType('array', $row); // could be array } } } diff --git a/tests/default/data/pdo-fetch-types.php b/tests/default/data/pdo-fetch-types.php index 200370f8e..e052a67ea 100644 --- a/tests/default/data/pdo-fetch-types.php +++ b/tests/default/data/pdo-fetch-types.php @@ -11,24 +11,36 @@ public function supportedFetchTypes(PDO $pdo) { // default fetch-type is BOTH $stmt = $pdo->query('SELECT email, adaid FROM ada'); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_NUM); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_BOTH); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_OBJ); - assertType('PDOStatement>', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } } public function unsupportedFetchTypes(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_COLUMN); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } } } diff --git a/tests/default/data/pdo-mysql.php b/tests/default/data/pdo-mysql.php index c2bb85ee1..0d6170410 100644 --- a/tests/default/data/pdo-mysql.php +++ b/tests/default/data/pdo-mysql.php @@ -10,16 +10,19 @@ class Foo public function execute(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada WHERE email <=> :email'); - assertType('PDOStatement', $stmt); $stmt->execute([':email' => null]); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } } public function aggregateFunctions(PDO $pdo) { $query = 'SELECT MAX(adaid), MIN(adaid), COUNT(adaid), AVG(adaid) FROM ada WHERE adaid = 1'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement|null, MIN(adaid): int<-32768, 32767>|null, COUNT(adaid): int, AVG(adaid): numeric-string|null}>', $stmt); + foreach ($stmt as $row) { + assertType('array{MAX(adaid): int<-32768, 32767>|null, MIN(adaid): int<-32768, 32767>|null, COUNT(adaid): int, AVG(adaid): numeric-string|null}', $row); + } } public function placeholderInDataPrepared(PDO $pdo) @@ -27,16 +30,18 @@ public function placeholderInDataPrepared(PDO $pdo) // double quotes within the query $query = 'SELECT adaid FROM ada WHERE email LIKE ":gesperrt%"'; $stmt = $pdo->prepare($query); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); $stmt->execute(); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } // single quotes within the query $query = "SELECT adaid FROM ada WHERE email LIKE ':gesperrt%'"; $stmt = $pdo->prepare($query); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); $stmt->execute(); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } public function placeholderInDataQuery(PDO $pdo) @@ -44,7 +49,9 @@ public function placeholderInDataQuery(PDO $pdo) // double quotes within the query $query = 'SELECT adaid FROM ada WHERE email LIKE ":gesperrt%"'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } } public function bug541(PDO $pdo) @@ -52,8 +59,9 @@ public function bug541(PDO $pdo) $query = 'SELECT email, adaid FROM ada'; $query .= 'WHERE email <=> :email'; $stmt = $pdo->prepare($query); - assertType('PDOStatement', $stmt); $stmt->execute([':email' => null]); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } } } diff --git a/tests/default/data/pdo-pgsql.php b/tests/default/data/pdo-pgsql.php index 06d36a2bf..e040fb203 100644 --- a/tests/default/data/pdo-pgsql.php +++ b/tests/default/data/pdo-pgsql.php @@ -10,13 +10,17 @@ class Foo public function pgsqlTypes(PDO $pdo) { $stmt = $pdo->query('SELECT * FROM typemix', PDO::FETCH_ASSOC); - assertType('PDOStatement, c_varchar5: string, c_varchar25: string|null, c_varchar255: string, c_date: string|null, c_time: string|null, c_datetime: string|null, c_timestamp: string|null, c_text: string|null, c_enum: mixed, c_bit255: int, c_bit25: int|null, c_bit: int|null, c_int: int<-2147483648, 2147483647>, c_smallint: int<-32768, 32767>, c_bigint: int, c_float: float, c_boolean: bool, c_json: string, c_json_nullable: string|null, c_jsonb: string, c_jsonb_nullable: string|null}>', $stmt); + foreach ($stmt as $row) { + assertType('array{pid: int<1, 2147483647>, c_varchar5: string, c_varchar25: string|null, c_varchar255: string, c_date: string|null, c_time: string|null, c_datetime: string|null, c_timestamp: string|null, c_text: string|null, c_enum: mixed, c_bit255: int, c_bit25: int|null, c_bit: int|null, c_int: int<-2147483648, 2147483647>, c_smallint: int<-32768, 32767>, c_bigint: int, c_float: float, c_boolean: bool, c_json: string, c_json_nullable: string|null, c_jsonb: string, c_jsonb_nullable: string|null}', $row); + } } public function aggregateFunctions(PDO $pdo) { $query = 'SELECT MAX(adaid), MIN(adaid), COUNT(adaid), AVG(adaid) FROM ada WHERE adaid = 1'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement|null, min: int<-32768, 32767>|null, count: int, avg: float|null}>', $stmt); + foreach ($stmt as $row) { + assertType('array{max: int<-32768, 32767>|null, min: int<-32768, 32767>|null, count: int, avg: float|null}', $row); + } } } diff --git a/tests/default/data/pdo-prepare.php b/tests/default/data/pdo-prepare.php index 4ac808d0c..50e660a94 100644 --- a/tests/default/data/pdo-prepare.php +++ b/tests/default/data/pdo-prepare.php @@ -10,11 +10,10 @@ class Foo public function prepareSelected(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada'); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); $stmt->execute(); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); assertType('int<-32768, 32767>', $row['adaid']); assertType('string', $row['email']); } @@ -28,11 +27,17 @@ public function unionParam(PDO $pdo, $adaid, $email) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada WHERE adaid = ?'); $stmt->execute([$adaid]); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE email = ?'); $stmt->execute([$email]); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } } public function queryBranches(PDO $pdo, bool $bool) @@ -42,24 +47,30 @@ public function queryBranches(PDO $pdo, bool $bool) } else { $query = "SELECT email, adaid FROM ada WHERE email='test@example.org'"; } - $stmt = $pdo->prepare($query); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } } public function placeholderInData(PDO $pdo) { $query = "SELECT adaid FROM ada WHERE email LIKE 'hello?%'"; $stmt = $pdo->prepare($query); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); $stmt->execute(); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } $query = "SELECT adaid FROM ada WHERE email LIKE '%questions ?%'"; $stmt = $pdo->prepare($query); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); $stmt->execute(); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } public function arrayParam(PDO $pdo) @@ -67,7 +78,10 @@ public function arrayParam(PDO $pdo) $query = 'SELECT adaid FROM ada WHERE adaid IN (:adaids)'; $stmt = $pdo->prepare($query); $stmt->execute(['adaids' => [1, 2, 3]]); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } public function unspecifiedArray(PDO $pdo, array $idsToUpdate, string $time) @@ -78,7 +92,10 @@ public function unspecifiedArray(PDO $pdo, array $idsToUpdate, string $time) 'ids' => $idsToUpdate, 'time' => $time, ]); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } /** @@ -92,7 +109,10 @@ public function unspecifiedList(PDO $pdo, array $idsToUpdate, string $time) 'ids' => $idsToUpdate, 'time' => $time, ]); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } /** @@ -106,7 +126,10 @@ public function specifiedList(PDO $pdo, array $idsToUpdate, string $time) 'ids' => $idsToUpdate, 'time' => $time, ]); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } /** @@ -119,7 +142,10 @@ public function numberType(PDO $pdo, $idsToUpdate) $stmt->execute([ 'ids' => $idsToUpdate, ]); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } /** @@ -133,7 +159,10 @@ public function specifiedArray(PDO $pdo, array $idsToUpdate, string $time) 'ids' => $idsToUpdate, 'time' => $time, ]); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } /** @@ -147,7 +176,10 @@ public function specifiedIterable(PDO $pdo, iterable $idsToUpdate, string $time) 'ids' => $idsToUpdate, 'time' => $time, ]); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } public function noInferenceOnBug196(PDO $pdo, array $minorPhpVersions, \DateTimeImmutable $updateDate) @@ -161,8 +193,11 @@ public function noInferenceOnBug196(PDO $pdo, array $minorPhpVersions, \DateTime 'SELECT '.implode(', ', $sumQueries).' FROM ada WHERE adaid = :package' ); $stmt->execute(['package' => 'abc']); + // this query is too dynamic for being analyzed. // make sure we don't infer a wrong type. - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } } } diff --git a/tests/default/data/pdo-quote.php b/tests/default/data/pdo-quote.php index e9e4d9d6a..611919847 100644 --- a/tests/default/data/pdo-quote.php +++ b/tests/default/data/pdo-quote.php @@ -59,22 +59,34 @@ public function quote(PDO $pdo, int $i, float $f, $n, string $s, $nonE, string $ public function quotedArguments(PDO $pdo, int $i, float $f, $n, string $s, $nonE, string $numericString) { $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$pdo->quote((string) $i), PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$pdo->quote((string) $f), PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$pdo->quote((string) $n), PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$pdo->quote($numericString), PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } // when quote() cannot return a numeric-string, we can't infer the precise result-type $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$pdo->quote($s), PDO::FETCH_ASSOC); - assertType('PDOStatement>', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$pdo->quote($nonE), PDO::FETCH_ASSOC); - assertType('PDOStatement>', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } } } diff --git a/tests/default/data/pdo-stmt-execute.php b/tests/default/data/pdo-stmt-execute.php index ca889137d..4ad74a7ca 100644 --- a/tests/default/data/pdo-stmt-execute.php +++ b/tests/default/data/pdo-stmt-execute.php @@ -10,29 +10,34 @@ class Foo public function execute(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada WHERE adaid = :adaid'); - assertType('PDOStatement', $stmt); $stmt->execute([':adaid' => 1]); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt = $pdo->prepare('SELECT email, adaid FROM ada WHERE adaid = :adaid'); - assertType('PDOStatement', $stmt); $stmt->execute(['adaid' => 1]); // prefixed ":" is optional - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt = $pdo->prepare('SELECT email, adaid FROM ada WHERE email = :email'); - assertType('PDOStatement', $stmt); $stmt->execute([':email' => 'email@example.org']); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt = $pdo->prepare('SELECT email, adaid FROM ada WHERE adaid = ?'); - assertType('PDOStatement', $stmt); $stmt->execute([1]); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt = $pdo->prepare('SELECT email, adaid FROM ada WHERE adaid = ? and email = ?'); - assertType('PDOStatement', $stmt); $stmt->execute([1, 'email@example.org']); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } } public function executeWithBindCalls(PDO $pdo) diff --git a/tests/default/data/pdo-stmt-fetch.php b/tests/default/data/pdo-stmt-fetch.php index 2eaa6f90a..1384a58d0 100644 --- a/tests/default/data/pdo-stmt-fetch.php +++ b/tests/default/data/pdo-stmt-fetch.php @@ -12,7 +12,9 @@ public function fetchAll(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada'); $stmt->execute(); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } // default fetch-mode is BOTH $all = $stmt->fetchAll(); @@ -53,7 +55,9 @@ public function fetch(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada'); $stmt->execute(); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } // default fetch-mode is BOTH $all = $stmt->fetch(); diff --git a/tests/default/data/pdo-stmt-set-fetch-mode.php b/tests/default/data/pdo-stmt-set-fetch-mode.php index 9a5d45726..8de4b9c20 100644 --- a/tests/default/data/pdo-stmt-set-fetch-mode.php +++ b/tests/default/data/pdo-stmt-set-fetch-mode.php @@ -11,10 +11,14 @@ public function setFetchModeNum(PDO $pdo) { $query = 'SELECT email, adaid FROM ada'; $stmt = $pdo->query($query); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt->setFetchMode(PDO::FETCH_NUM); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } $result = $stmt->fetch(PDO::FETCH_NUM); assertType('array{string, int<-32768, 32767>}|false', $result); @@ -24,10 +28,14 @@ public function setFetchModeAssoc(PDO $pdo) { $query = 'SELECT email, adaid FROM ada'; $stmt = $pdo->query($query); - assertType('PDOStatement, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, 0: string, adaid: int<-32768, 32767>, 1: int<-32768, 32767>}', $row); + } $stmt->setFetchMode(PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $result = $stmt->fetch(PDO::FETCH_ASSOC); assertType('array{email: string, adaid: int<-32768, 32767>}|false', $result); @@ -37,10 +45,14 @@ public function setFetchModeOnQuery(PDO $pdo) { $query = 'SELECT email, adaid FROM ada'; $stmt = $pdo->query($query, PDO::FETCH_NUM); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } $stmt->setFetchMode(PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $result = $stmt->fetch(PDO::FETCH_NUM); assertType('array{string, int<-32768, 32767>}|false', $result); diff --git a/tests/default/data/pdo.php b/tests/default/data/pdo.php index 103425359..0f29688a1 100644 --- a/tests/default/data/pdo.php +++ b/tests/default/data/pdo.php @@ -15,9 +15,8 @@ class Foo public function querySelected(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); - foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); assertType('int<-32768, 32767>', $row['adaid']); assertType('string', $row['email']); } @@ -26,16 +25,22 @@ public function querySelected(PDO $pdo) public function queryVariants(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada LIMIT 1', PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada LIMIT 1, 10', PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } } public function queryWithNullColumn(PDO $pdo) { $stmt = $pdo->query('SELECT eladaid FROM ak', PDO::FETCH_ASSOC); - assertType('PDOStatement|null}>', $stmt); + foreach ($stmt as $row) { + assertType('array{eladaid: int<-2147483648, 2147483647>|null}', $row); + } } public function syntaxError(PDO $pdo) @@ -52,48 +57,72 @@ public function syntaxError(PDO $pdo) public function concatedQuerySelected(PDO $pdo, int $int, string $string, float $float, bool $bool, $numericString, $nonEmptyString, $mixed) { $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$int, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.self::INT, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } // requires phpstan 1.4.6+ $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid IN('.implode(',', [self::INT, 3]).')', PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query("SELECT email, adaid FROM ada WHERE email='".self::FOO."'", PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$numericString, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$bool, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } // ---- $stmt = $pdo->query('SELECT akid FROM ak WHERE eadavk>'.$float, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); // akid is not an auto-increment + foreach ($stmt as $row) { + assertType('array{akid: int<-2147483648, 2147483647>}', $row); // akid is not an auto-increment + } $stmt = $pdo->query('SELECT akid FROM ak WHERE eadavk>'.self::FLOAT, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); // akid is not an auto-increment + foreach ($stmt as $row) { + assertType('array{akid: int<-2147483648, 2147483647>}', $row); // akid is not an auto-increment + } // ---- queries, for which we cannot infer the return type $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE '.$string, PDO::FETCH_ASSOC); - assertType('PDOStatement>', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE '.$nonEmptyString, PDO::FETCH_ASSOC); - assertType('PDOStatement>', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE '.$mixed, PDO::FETCH_ASSOC); - assertType('PDOStatement>', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } } public function dynamicQuery(PDO $pdo, string $query) { $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement>', $stmt); + foreach ($stmt as $row) { + assertType('array', $row); + } } public function insertQuery(PDO $pdo) @@ -114,14 +143,18 @@ public function queryBranches(PDO $pdo, bool $bool, int $adaid) { $query = 'SELECT email, adaid FROM ada'; $stmt = $pdo->query($query, PDO::FETCH_NUM); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } if ($bool) { $query .= ' WHERE adaid='.$adaid; } $stmt = $pdo->query($query, PDO::FETCH_NUM); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } } public function updateQuery(PDO $pdo) @@ -138,65 +171,89 @@ public function updateQuery(PDO $pdo) public function unionParam(PDO $pdo, $adaid, $email) { $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid = '.$adaid, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $stmt = $pdo->query("SELECT email, adaid FROM ada WHERE email = '".$email."'", PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } } public function placeholderInData(PDO $pdo) { $query = "SELECT adaid FROM ada WHERE email LIKE 'hello?%'"; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } $query = "SELECT adaid FROM ada WHERE email LIKE '%questions ?%'"; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } $query = "SELECT adaid FROM ada WHERE email LIKE ':gesperrt%'"; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } } public function offsetAfterLimit(PDO $pdo, int $limit, int $offset) { $query = 'SELECT adaid FROM ada LIMIT '.$limit.' OFFSET '.$offset; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } } public function readlocks(PDO $pdo, int $limit, int $offset) { $query = 'SELECT adaid FROM ada LIMIT '.$limit.' OFFSET '.$offset.' FOR UPDATE'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } $query = 'SELECT adaid FROM ada LIMIT '.$limit.' FOR SHARE'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } } public function readForUpdateSkipLocked(PDO $pdo) { $query = 'SELECT adaid FROM ada LIMIT 1 FOR UPDATE SKIP LOCKED'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } $query = 'SELECT adaid FROM ada LIMIT 1 FOR SHARE SKIP LOCKED'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } } public function readForUpdateNowait(PDO $pdo) { $query = 'SELECT adaid FROM ada LIMIT 1 FOR UPDATE NOWAIT'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } $query = 'SELECT adaid FROM ada LIMIT 1 FOR SHARE NOWAIT'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{adaid: int<-32768, 32767>}', $row); + } } /** @@ -207,35 +264,47 @@ public function mixInUnionParam(PDO $pdo, $adaid, $gesperrt) { // union of simulatable and simulatable is simulatable $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid = '.$adaid, PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } // union of simulatable and non-simulatable is simulatable $stmt = $pdo->query("SELECT email, adaid FROM ada WHERE gesperrt = '".$gesperrt."'", PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } } public function queryEncapsedString(PDO $pdo, int $adaid) { $stmt = $pdo->query("SELECT email, adaid FROM ada WHERE adaid=$adaid", PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $fn = function (): int { return self::INT; }; $stmt = $pdo->query("SELECT email, adaid FROM ada WHERE adaid={$fn()}", PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } } public function taintStaticEscaped(PDO $pdo, string $s) { $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.Escaper::staticEscape($s), PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } } public function taintEscaped(PDO $pdo, string $s) { $escaper = new Escaper(); $stmt = $pdo->query('SELECT email, adaid FROM ada WHERE adaid='.$escaper->escape($s), PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } } } diff --git a/tests/default/data/query-alias.php b/tests/default/data/query-alias.php index 2ddfa5482..e6d3c5021 100644 --- a/tests/default/data/query-alias.php +++ b/tests/default/data/query-alias.php @@ -13,6 +13,8 @@ public function leftJoinQuery(PDO $pdo) $query = 'SELECT a.email, b.adaid FROM ada a LEFT JOIN ada b ON a.adaid=b.adaid'; $stmt = $pdo->query($query, PDO::FETCH_ASSOC); - assertType('PDOStatement|null}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>|null}', $row); + } } } diff --git a/tests/default/data/typemix-mysql.php b/tests/default/data/typemix-mysql.php index 29cc4da92..b09f4d10c 100644 --- a/tests/default/data/typemix-mysql.php +++ b/tests/default/data/typemix-mysql.php @@ -62,6 +62,49 @@ public function typemixMysqli(mysqli $mysqli) public function typemixPdoMysql(PDO $pdo) { $stmt = $pdo->query('SELECT * FROM typemix', PDO::FETCH_ASSOC); - assertType('PDOStatement<' . self::MYSQL_DATATYPES . '>', $stmt); + + foreach($stmt as $value) { + assertType('int<0, 4294967295>', $value['pid']); + assertType('string', $value['c_char5']); + assertType('string', $value['c_varchar255']); + assertType('string|null', $value['c_varchar25']); + assertType('string', $value['c_varbinary255']); + assertType('string|null', $value['c_varbinary25']); + assertType('string|null', $value['c_date']); + assertType('string|null', $value['c_time']); + assertType('string|null', $value['c_datetime']); + assertType('string|null', $value['c_timestamp']); + assertType('int<0, 2155>|null', $value['c_year']); + assertType('string|null', $value['c_tiny_text']); + assertType('string|null', $value['c_medium_text']); + assertType('string|null', $value['c_text']); + assertType('string|null', $value['c_long_text']); + assertType('string', $value['c_enum']); + assertType('string', $value['c_set']); + assertType('int|null', $value['c_bit']); + assertType('int<-2147483648, 2147483647>', $value['c_int']); + assertType('int<-128, 127>', $value['c_tinyint']); + assertType('int<-128, 127>|null', $value['c_nullable_tinyint']); + assertType('int<-32768, 32767>', $value['c_smallint']); + assertType('int<-8388608, 8388607>', $value['c_mediumint']); + assertType('int', $value['c_bigint']); + assertType('float', $value['c_double']); + assertType('float', $value['c_real']); + assertType('float', $value['c_float']); + assertType('int<-128, 127>', $value['c_boolean']); + assertType('string', $value['c_blob']); + assertType('string', $value['c_tinyblob']); + assertType('string', $value['c_mediumblog']); + assertType('string', $value['c_longblob']); + assertType('int<0, 255>', $value['c_unsigned_tinyint']); + assertType('int<0, 4294967295>', $value['c_unsigned_int']); + assertType('int<0, 65535>', $value['c_unsigned_smallint']); + assertType('int<0, 16777215>', $value['c_unsigned_mediumint']); + assertType('int<0, max>', $value['c_unsigned_bigint']); + assertType('string|null', $value['c_json']); + assertType('string', $value['c_json_not_null']); + assertType('numeric-string|null', $value['c_decimal']); + assertType('numeric-string', $value['c_decimal_not_null']); + } } } diff --git a/tests/default/data/typemix-pgsql.php b/tests/default/data/typemix-pgsql.php index 369497c2e..bbc9db5e2 100644 --- a/tests/default/data/typemix-pgsql.php +++ b/tests/default/data/typemix-pgsql.php @@ -43,6 +43,30 @@ public function typemixMysqli(mysqli $mysqli) public function typemixPdoPgsql(PDO $pdo) { $stmt = $pdo->query('SELECT * FROM typemix', PDO::FETCH_ASSOC); - assertType('PDOStatement<' . self::PGSQL_DATATYPES . '>', $stmt); + + foreach($stmt as $value) { + assertType('int<1, 2147483647>', $value['pid']); + assertType('string', $value['c_varchar5']); + assertType('string|null', $value['c_varchar25']); + assertType('string', $value['c_varchar255']); + assertType('string|null', $value['c_date']); + assertType('string|null', $value['c_time']); + assertType('string|null', $value['c_datetime']); + assertType('string|null', $value['c_timestamp']); + assertType('string|null', $value['c_text']); + assertType('mixed', $value['c_enum']); + assertType('int', $value['c_bit255']); + assertType('int|null', $value['c_bit25']); + assertType('int|null', $value['c_bit']); + assertType('int<-2147483648, 2147483647>', $value['c_int']); + assertType('int<-32768, 32767>', $value['c_smallint']); + assertType('int', $value['c_bigint']); + assertType('float', $value['c_float']); + assertType('bool', $value['c_boolean']); + assertType('string', $value['c_json']); + assertType('string|null', $value['c_json_nullable']); + assertType('string', $value['c_jsonb']); + assertType('string|null', $value['c_jsonb_nullable']); + } } } diff --git a/tests/defaultFetchAssoc/data/modes.php b/tests/defaultFetchAssoc/data/modes.php index 96f8d4cc7..4b79a56c5 100644 --- a/tests/defaultFetchAssoc/data/modes.php +++ b/tests/defaultFetchAssoc/data/modes.php @@ -11,7 +11,10 @@ class Foo public function assocModeQuery(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } + $result = $stmt->fetch(); assertType('array{email: string, adaid: int<-32768, 32767>}|false', $result); } @@ -19,9 +22,15 @@ public function assocModeQuery(PDO $pdo) public function assocModeFetch(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } + $stmt->execute(); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } + $result = $stmt->fetch(); assertType('array{email: string, adaid: int<-32768, 32767>}|false', $result); } @@ -29,9 +38,14 @@ public function assocModeFetch(PDO $pdo) public function assocModeFetchOverridden(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } + $stmt->execute(); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $result = $stmt->fetch(PDO::FETCH_NUM); assertType('array{string, int<-32768, 32767>}|false', $result); } @@ -39,7 +53,10 @@ public function assocModeFetchOverridden(PDO $pdo) public function assocModeQueryFetchOverridden(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } + $result = $stmt->fetch(PDO::FETCH_NUM); assertType('array{string, int<-32768, 32767>}|false', $result); } @@ -47,7 +64,10 @@ public function assocModeQueryFetchOverridden(PDO $pdo) public function assocModeQueryOverridden(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_NUM); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } + $result = $stmt->fetch(PDO::FETCH_NUM); assertType('array{string, int<-32768, 32767>}|false', $result); } diff --git a/tests/defaultFetchNumeric/data/modes.php b/tests/defaultFetchNumeric/data/modes.php index 849daf85d..2abc4bf8e 100644 --- a/tests/defaultFetchNumeric/data/modes.php +++ b/tests/defaultFetchNumeric/data/modes.php @@ -11,7 +11,9 @@ class Foo public function numericModeQuery(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } $result = $stmt->fetch(); assertType('array{string, int<-32768, 32767>}|false', $result); } @@ -19,9 +21,10 @@ public function numericModeQuery(PDO $pdo) public function numericModeFetch(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); $stmt->execute(); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } $result = $stmt->fetch(); assertType('array{string, int<-32768, 32767>}|false', $result); } @@ -29,9 +32,10 @@ public function numericModeFetch(PDO $pdo) public function numericModeFetchOverridden(PDO $pdo) { $stmt = $pdo->prepare('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); $stmt->execute(); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } $result = $stmt->fetch(PDO::FETCH_ASSOC); assertType('array{email: string, adaid: int<-32768, 32767>}|false', $result); } @@ -39,7 +43,9 @@ public function numericModeFetchOverridden(PDO $pdo) public function numericModeQueryFetchOverridden(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada'); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{string, int<-32768, 32767>}', $row); + } $result = $stmt->fetch(PDO::FETCH_ASSOC); assertType('array{email: string, adaid: int<-32768, 32767>}|false', $result); } @@ -47,7 +53,9 @@ public function numericModeQueryFetchOverridden(PDO $pdo) public function numericModeQueryOverridden(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid FROM ada', PDO::FETCH_ASSOC); - assertType('PDOStatement}>', $stmt); + foreach ($stmt as $row) { + assertType('array{email: string, adaid: int<-32768, 32767>}', $row); + } $result = $stmt->fetch(PDO::FETCH_ASSOC); assertType('array{email: string, adaid: int<-32768, 32767>}|false', $result); } diff --git a/tests/sqlAst/data/sql-ast-narrowing.php b/tests/sqlAst/data/sql-ast-narrowing.php index 7cab5a135..bdefcf629 100644 --- a/tests/sqlAst/data/sql-ast-narrowing.php +++ b/tests/sqlAst/data/sql-ast-narrowing.php @@ -10,22 +10,32 @@ class Foo public function whereIsNotNull(PDO $pdo): void { $stmt = $pdo->query('SELECT c_json FROM typemix'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string|null, 0: string|null}', $row); + } $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_json IS NOT NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string, 0: string}', $row); + } // condition in parentheses $stmt = $pdo->query('SELECT c_json FROM typemix WHERE (c_json IS NOT NULL)'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string, 0: string}', $row); + } // selected with an alias $stmt = $pdo->query('SELECT c_json as col FROM typemix WHERE c_json IS NOT NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{col: string, 0: string}', $row); + } // affects input to a function $stmt = $pdo->query('SELECT ifnull(null, c_json) as col FROM typemix WHERE c_json IS NOT NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{col: string, 0: string}', $row); + } // selected with an asterisk $stmt = $pdo->query('SELECT * FROM typemix WHERE c_json IS NOT NULL'); @@ -33,37 +43,53 @@ public function whereIsNotNull(PDO $pdo): void // compound where condition (AND) $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_json IS NOT NULL AND c_int=1'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string, 0: string}', $row); + } // compound where condition (OR) $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_json IS NOT NULL OR c_int=1'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string|null, 0: string|null}', $row); + } // subquery does not impact outer where condition $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_text IN (SELECT c_json FROM typemix WHERE c_json IS NOT NULL)'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string|null, 0: string|null}', $row); + } } public function whereIsNull(PDO $pdo): void { // empty intersection $stmt = $pdo->query('SELECT c_json_not_null FROM typemix WHERE c_json_not_null IS NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json_not_null: *NEVER*, 0: *NEVER*}', $row); + } $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_json IS NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: null, 0: null}', $row); + } // condition in parentheses $stmt = $pdo->query('SELECT c_json FROM typemix WHERE (c_json IS NULL)'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: null, 0: null}', $row); + } // selected with an alias $stmt = $pdo->query('SELECT c_json as col FROM typemix WHERE c_json IS NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{col: null, 0: null}', $row); + } // affects input to a function $stmt = $pdo->query('SELECT ifnull(c_json, "default") as col FROM typemix WHERE c_json IS NULL'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: 'default', 0: 'default'}", $row); + } // selected with an asterisk $stmt = $pdo->query('SELECT * FROM typemix WHERE c_json IS NULL'); @@ -71,145 +97,222 @@ public function whereIsNull(PDO $pdo): void // compound where condition (AND) $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_json IS NULL AND c_int=1'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: null, 0: null}', $row); + } // compound where condition (OR) $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_json IS NULL OR c_int=1'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string|null, 0: string|null}', $row); + } // subquery does not impact outer where condition $stmt = $pdo->query('SELECT c_json FROM typemix WHERE c_text IN (SELECT c_json FROM typemix WHERE c_json IS NULL)'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{c_json: string|null, 0: string|null}', $row); + } } public function noFromTable(PDO $pdo): void { $stmt = $pdo->query('SELECT 3'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{3: 3, 0: 3}', $row); + } $stmt = $pdo->query('SELECT 3 as col'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType('array{col: 3, 0: 3}', $row); + } } public function count(PDO $pdo): void { $stmt = $pdo->query('SELECT count(*) as myemail from ada'); - assertType('PDOStatement, 0: int<0, max>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{myemail: int<0, max>, 0: int<0, max>}', $row); + } $stmt = $pdo->query('SELECT count(email) as myemail from ada'); - assertType('PDOStatement, 0: int<0, max>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{myemail: int<0, max>, 0: int<0, max>}', $row); + } $stmt = $pdo->query('SELECT count(email) as myemail, count(email) from ada'); - assertType('PDOStatement, 0: int<0, max>, count(email): int<0, max>, 1: int<0, max>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{myemail: int<0, max>, 0: int<0, max>, count(email): int<0, max>, 1: int<0, max>}', $row); + } } public function coalesce(PDO $pdo): void { $stmt = $pdo->query('SELECT COALESCE(null, eladaid) as col from ak'); - assertType('PDOStatement|null, 0: int<-2147483648, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType('array{col: int<-2147483648, 2147483647>|null, 0: int<-2147483648, 2147483647>|null}', $row); + } $stmt = $pdo->query('SELECT COALESCE(null, eladaid, null, akid, null) as col from ak'); - assertType('PDOStatement, 0: int<-2147483648, 2147483647>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{col: int<-2147483648, 2147483647>, 0: int<-2147483648, 2147483647>}', $row); + } $stmt = $pdo->query('SELECT COALESCE(freigabe1u1) as col from ada'); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{col: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } // can't return 500, as freigabe1u1 cannot be null $stmt = $pdo->query('SELECT COALESCE(freigabe1u1, 500) as col from ada'); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType('array{col: int<-32768, 32767>, 0: int<-32768, 32767>}', $row); + } } public function ifnull(PDO $pdo): void { $stmt = $pdo->query('SELECT ifnull(null, "default") as col'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: 'default', 0: 'default'}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_int, "default") as col from typemix'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType('array{col: lowercase-string&numeric-string, 0: lowercase-string&numeric-string}', $row); + } $stmt = $pdo->query('SELECT ifnull(c_nullable_tinyint, "default") as col from typemix'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: 'default'|(lowercase-string&numeric-string), 0: 'default'|(lowercase-string&numeric-string)}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_nullable_tinyint, 5000) as col from typemix'); - assertType('PDOStatement, 0: 5000|int<-128, 127>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: 5000|int<-128, 127>, 0: 5000|int<-128, 127>}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_int, c_float) as col from typemix'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: float, 0: float}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_float, 123.23) as col from typemix'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: float, 0: float}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_int, 123.23) as col from typemix'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: lowercase-string&numeric-string, 0: lowercase-string&numeric-string}", $row); + } $stmt = $pdo->query('SELECT ifnull(123.23, c_int) as col from typemix'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: '123.23', 0: '123.23'}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_smallint, c_smallint) as col from typemix'); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-32768, 32767>, 0: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_smallint, c_tinyint) as col from typemix'); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-32768, 32767>, 0: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_tinyint, c_smallint) as col from typemix'); - assertType('PDOStatement, 0: int<-128, 127>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-128, 127>, 0: int<-128, 127>}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_nullable_tinyint, c_smallint) as col from typemix'); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-32768, 32767>, 0: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT ifnull(c_nullable_tinyint, c_nullable_tinyint) as col from typemix'); - assertType('PDOStatement|null, 0: int<-128, 127>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-128, 127>|null, 0: int<-128, 127>|null}", $row); + } $stmt = $pdo->query('SELECT IFNULL(MAX(eladaid),0)+1 as priority from ak'); - assertType('PDOStatement', $stmt); // could be more precise integer range + foreach ($stmt as $row) { + // could be more precise integer range + assertType("array{priority: int, 0: int}", $row); + } } public function nullif(PDO $pdo): void { $stmt = $pdo->query('SELECT nullif(2, 2) as col'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT nullif(2, 3) as col'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: 2, 0: 2}", $row); + } // Test an integer range against a constant int inside the range $stmt = $pdo->query('SELECT nullif(c_tinyint, 3) as col from typemix'); - assertType('PDOStatement|null, 0: int<-128, 127>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-128, 127>|null, 0: int<-128, 127>|null}", $row); + } // Test an integer range against a constant int outside the range $stmt = $pdo->query('SELECT nullif(c_tinyint, 5000) as col from typemix'); - assertType('PDOStatement, 0: int<-128, 127>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-128, 127>, 0: int<-128, 127>}", $row); + } // Test an integer range against a constant string $stmt = $pdo->query('SELECT nullif(c_tinyint, "default") as col from typemix'); - assertType('PDOStatement, 0: int<-128, 127>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-128, 127>, 0: int<-128, 127>}", $row); + } $stmt = $pdo->query('SELECT nullif(c_tinyint, c_tinyint) as col from typemix'); - assertType('PDOStatement|null, 0: int<-128, 127>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-128, 127>|null, 0: int<-128, 127>|null}", $row); + } $stmt = $pdo->query('SELECT nullif(c_tinyint, c_smallint) as col from typemix'); - assertType('PDOStatement|null, 0: int<-128, 127>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-128, 127>|null, 0: int<-128, 127>|null}", $row); + } $stmt = $pdo->query('SELECT nullif(c_smallint, c_tinyint) as col from typemix'); - assertType('PDOStatement|null, 0: int<-32768, 32767>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<-32768, 32767>|null, 0: int<-32768, 32767>|null}", $row); + } } public function if(PDO $pdo): void { $stmt = $pdo->query('SELECT if(freigabe1u1 > 100, "a", 1) as col from ada'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: 1|'a', 0: 1|'a'}", $row); + } $stmt = $pdo->query('SELECT if(freigabe1u1 > 100, freigabe1u1, "nope") as col from ada'); - assertType("PDOStatement, 0: 'nope'|int<-32768, 32767>}>", $stmt); // could be 'nope'|int<100, 127> + foreach ($stmt as $row) { + assertType("array{col: 'nope'|int<-32768, 32767>, 0: 'nope'|int<-32768, 32767>}", $row); // could be 'nope'|int<100, 127> + } $stmt = $pdo->query('SELECT if(freigabe1u1 > 100, if(gesperrt <> 1, "a", "b"), "other") as col from ada'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: 'a'|'b'|'other', 0: 'a'|'b'|'other'}", $row); + } } public function caseWhen(PDO $pdo): void { $stmt = $pdo->query("SELECT CASE 1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'more' END as val from ada"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{val: 'more'|'one'|'two', 0: 'more'|'one'|'two'}", $row); + } $stmt = $pdo->query("SELECT CASE @@ -217,263 +320,416 @@ public function caseWhen(PDO $pdo): void WHEN freigabe1u1 = 50 THEN 'normal' ELSE freigabe1u1 END as val from ada"); - assertType("PDOStatement, 0: 'big-one'|'normal'|int<-32768, 32767>}>", $stmt); // could be 'big-one'|'normal'|int<-128, 49> + foreach ($stmt as $row) { + // could be 'big-one'|'normal'|int<-128, 49> + assertType("array{val: 'big-one'|'normal'|int<-32768, 32767>, 0: 'big-one'|'normal'|int<-32768, 32767>}", $row); + } } public function concat(PDO $pdo): void { $stmt = $pdo->query('SELECT concat(akid, 5000) as col from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-empty-string&numeric-string, 0: non-empty-string&numeric-string}", $row); + } $stmt = $pdo->query('SELECT concat(eladaid, 5000) as col from ak'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: (non-empty-string&numeric-string)|null, 0: (non-empty-string&numeric-string)|null}", $row); + } $stmt = $pdo->query('SELECT concat(eladaid, akid) as col from ak'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: (non-empty-string&numeric-string)|null, 0: (non-empty-string&numeric-string)|null}", $row); + } $stmt = $pdo->query('SELECT concat(eladaid, null) as col from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT concat("abc", akid, 5000) as col from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-falsy-string, 0: non-falsy-string}", $row); + } } public function concat_ws(PDO $pdo): void { $stmt = $pdo->query('SELECT concat_ws(akid, 5000) as col from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-empty-string&numeric-string, 0: non-empty-string&numeric-string}", $row); + } $stmt = $pdo->query('SELECT concat_ws(eladaid, 5000) as col from ak'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-empty-string&numeric-string, 0: non-empty-string&numeric-string}", $row); + } $stmt = $pdo->query('SELECT concat_ws(eladaid, akid) as col from ak'); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-empty-string&numeric-string, 0: non-empty-string&numeric-string}", $row); + } $stmt = $pdo->query('SELECT concat_ws(eladaid, null) as col from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-empty-string&numeric-string, 0: non-empty-string&numeric-string}", $row); + } $stmt = $pdo->query('SELECT concat_ws("abc", akid, 5000) as col from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-falsy-string, 0: non-falsy-string}", $row); + } } public function posIntReturn(PDO $pdo): void { $stmt = $pdo->query('SELECT length(akid) as col from ak'); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<0, max>, 0: int<0, max>}", $row); + } $stmt = $pdo->query('SELECT char_length(eladaid) as col from ak'); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<0, max>, 0: int<0, max>}", $row); + } $stmt = $pdo->query('SELECT character_length(eladaid) as col from ak'); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<0, max>, 0: int<0, max>}", $row); + } $stmt = $pdo->query('SELECT octet_length(eladaid) as col from ak'); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{col: int<0, max>, 0: int<0, max>}", $row); + } $stmt = $pdo->query("SELECT FIELD('Bb', 'Aa', 'Bb', 'Cc', 'Dd', 'Ff') as field from ak"); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{field: int<0, max>, 0: int<0, max>}", $row); + } } public function instr(PDO $pdo): void { $stmt = $pdo->query("SELECT instr('foobarbar', 'bar') as field from ak"); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{field: int<0, max>, 0: int<0, max>}", $row); + } $stmt = $pdo->query("SELECT instr(eladaid, 'bar') as field from ak"); - assertType("PDOStatement|null, 0: int<0, max>|null}>", $stmt); + foreach ($stmt as $row) { + assertType("array{field: int<0, max>|null, 0: int<0, max>|null}", $row); + } $stmt = $pdo->query("SELECT instr(akid, 'bar') as field from ak"); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{field: int<0, max>, 0: int<0, max>}", $row); + } $stmt = $pdo->query("SELECT locate('foo', eladaid, 'bar') as field from ak"); - assertType("PDOStatement|null, 0: int<0, max>|null}>", $stmt); + foreach ($stmt as $row) { + assertType("array{field: int<0, max>|null, 0: int<0, max>|null}", $row); + } $stmt = $pdo->query("SELECT locate(eladaid, 'bar') as field from ak"); - assertType("PDOStatement|null, 0: int<0, max>|null}>", $stmt); + foreach ($stmt as $row) { + assertType("array{field: int<0, max>|null, 0: int<0, max>|null}", $row); + } $stmt = $pdo->query("SELECT locate(akid, 'bar') as field from ak"); - assertType("PDOStatement, 0: int<0, max>}>", $stmt); + foreach ($stmt as $row) { + assertType("array{field: int<0, max>, 0: int<0, max>}", $row); + } } public function strcase(PDO $pdo): void { $stmt = $pdo->query("SELECT lcase(c_varbinary255) as field from typemix"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: string, 0: string}", $row); + } $stmt = $pdo->query("SELECT ucase(c_varbinary25) as field from typemix"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: string|null, 0: string|null}", $row); + } $stmt = $pdo->query("SELECT lower(c_varbinary255) as field from typemix"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: string, 0: string}", $row); + } $stmt = $pdo->query("SELECT lower(c_varbinary25) as field from typemix"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: string|null, 0: string|null}", $row); + } $stmt = $pdo->query("SELECT lower(null) as field from ak"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: null, 0: null}", $row); + } $stmt = $pdo->query("SELECT lower('foobarbar') as field from ak"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: 'foobarbar', 0: 'foobarbar'}", $row); + } $stmt = $pdo->query("SELECT lower('FOO') as field from ak"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: 'foo', 0: 'foo'}", $row); + } $stmt = $pdo->query("SELECT upper('foobarbar') as field from ak"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: 'FOOBARBAR', 0: 'FOOBARBAR'}", $row); + } $stmt = $pdo->query("SELECT upper('fooBARbar') as field from ak"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: 'FOOBARBAR', 0: 'FOOBARBAR'}", $row); + } $stmt = $pdo->query("SELECT lower(upper('foobarbar')) as field from ak"); - assertType("PDOStatement", $stmt); + foreach ($stmt as $row) { + assertType("array{field: 'foobarbar', 0: 'foobarbar'}", $row); + } $stmt = $pdo->query('SELECT lower(concat(akid, 5000)) as col from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{col: non-empty-string&numeric-string, 0: non-empty-string&numeric-string}", $row); + } } public function avg(PDO $pdo): void { $stmt = $pdo->query('SELECT avg(freigabe1u1) as avg from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: numeric-string|null, 0: numeric-string|null}", $row); + } $stmt = $pdo->query('SELECT avg(eladaid) as avg from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: numeric-string|null, 0: numeric-string|null}", $row); + } $stmt = $pdo->query('SELECT avg(coalesce(eladaid, 9999999999999999)) as avg from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: numeric-string|null, 0: numeric-string|null}", $row); + } $stmt = $pdo->query('SELECT avg(email) as avg from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: float|null, 0: float|null}", $row); + } // Test numeric-string input $stmt = $pdo->query('SELECT avg(concat("0")) as avg from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: float|null, 0: float|null}", $row); + } // Test non-falsy-string input $stmt = $pdo->query('SELECT avg(concat("foo")) as avg from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: float|null, 0: float|null}", $row); + } $stmt = $pdo->query('SELECT avg(ifnull(email, adaid)) as avg from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: float|null, 0: float|null}", $row); + } $stmt = $pdo->query('SELECT avg(null) as avg from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT avg(c_tinyint) as avg from typemix GROUP BY c_int'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: numeric-string, 0: numeric-string}", $row); + } $stmt = $pdo->query('SELECT avg(c_nullable_tinyint) as avg from typemix GROUP BY c_int'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{avg: numeric-string|null, 0: numeric-string|null}", $row); + } } public function minMax(PDO $pdo): void { $stmt = $pdo->query('SELECT min(freigabe1u1) as min from ada'); - assertType('PDOStatement|null, 0: int<-32768, 32767>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{min: int<-32768, 32767>|null, 0: int<-32768, 32767>|null}", $row); + } $stmt = $pdo->query('SELECT max(freigabe1u1) as max from ada'); - assertType('PDOStatement|null, 0: int<-32768, 32767>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{max: int<-32768, 32767>|null, 0: int<-32768, 32767>|null}", $row); + } $stmt = $pdo->query('SELECT min(eladaid) as min from ak'); - assertType('PDOStatement|null, 0: int<-2147483648, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{min: int<-2147483648, 2147483647>|null, 0: int<-2147483648, 2147483647>|null}", $row); + } $stmt = $pdo->query('SELECT max(eladaid) as max from ak'); - assertType('PDOStatement|null, 0: int<-2147483648, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{max: int<-2147483648, 2147483647>|null, 0: int<-2147483648, 2147483647>|null}", $row); + } $stmt = $pdo->query('SELECT min(email) as min from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{min: string|null, 0: string|null}", $row); + } $stmt = $pdo->query('SELECT max(email) as max from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{max: string|null, 0: string|null}", $row); + } $stmt = $pdo->query('SELECT min(ifnull(email, adaid)) as min from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{min: string|null, 0: string|null}", $row); + } $stmt = $pdo->query('SELECT max(ifnull(email, adaid)) as max from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{max: string|null, 0: string|null}", $row); + } $stmt = $pdo->query('SELECT min(null) as min from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{min: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT max(null) as max from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{max: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT min(c_tinyint) as min from typemix GROUP BY c_int'); - assertType('PDOStatement, 0: int<-128, 127>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{min: int<-128, 127>, 0: int<-128, 127>}", $row); + } $stmt = $pdo->query('SELECT max(c_tinyint) as max from typemix GROUP BY c_int'); - assertType('PDOStatement, 0: int<-128, 127>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{max: int<-128, 127>, 0: int<-128, 127>}", $row); + } $stmt = $pdo->query('SELECT min(c_nullable_tinyint) as min from typemix GROUP BY c_int'); - assertType('PDOStatement|null, 0: int<-128, 127>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{min: int<-128, 127>|null, 0: int<-128, 127>|null}", $row); + } $stmt = $pdo->query('SELECT max(c_nullable_tinyint) as max from typemix GROUP BY c_int'); - assertType('PDOStatement|null, 0: int<-128, 127>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{max: int<-128, 127>|null, 0: int<-128, 127>|null}", $row); + } } public function isNull(PDO $pdo): void { $stmt = $pdo->query('SELECT isnull(akid) as n1 from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{n1: 0, 0: 0}", $row); + } $stmt = $pdo->query('SELECT isnull(eladaid) as n1 from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{n1: 0|1, 0: 0|1}", $row); + } } public function abs(PDO $pdo): void { $stmt = $pdo->query('SELECT abs(null) as abs from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{abs: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT abs(freigabe1u1) as abs from ada'); - assertType('PDOStatement, 0: int<0, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{abs: int<0, 32767>, 0: int<0, 32767>}", $row); + } $stmt = $pdo->query('SELECT abs(eladaid) as abs from ak'); - assertType('PDOStatement|null, 0: int<0, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{abs: int<0, 2147483647>|null, 0: int<0, 2147483647>|null}", $row); + } } public function round(PDO $pdo): void { $stmt = $pdo->query('SELECT round(null) as abs from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{abs: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT round(freigabe1u1) as abs from ada'); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{abs: int<-32768, 32767>, 0: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT round(1.12, 1) as abs from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{abs: float|int, 0: float|int}", $row); + } } public function sum(PDO $pdo): void { $stmt = $pdo->query('SELECT sum(null) as sum from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{sum: null, 0: null}", $row); + } $stmt = $pdo->query('SELECT sum(akid) as sum from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{sum: int|null, 0: int|null}", $row); + } $stmt = $pdo->query('SELECT sum(eladaid) as sum from ak'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{sum: int|null, 0: int|null}", $row); + } $stmt = $pdo->query('SELECT sum(c_double) as sum from typemix'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{sum: float|null, 0: float|null}", $row); + } $stmt = $pdo->query('SELECT sum(c_tinyint) as sum from typemix GROUP BY c_int'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{sum: int, 0: int}", $row); + } $stmt = $pdo->query('SELECT sum(c_nullable_tinyint) as sum from typemix GROUP BY c_int'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{sum: int|null, 0: int|null}", $row); + } } public function strReplace(PDO $pdo) { $stmt = $pdo->query("SELECT REPLACE('www.mysql.com', 'w', 'Ww') as str from ada"); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{str: non-empty-string, 0: non-empty-string}", $row); + } $stmt = $pdo->query("SELECT REPLACE(email, 'w', 'Ww') as str from ada"); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{str: string, 0: string}", $row); + } $stmt = $pdo->query("SELECT REPLACE('www.mysql.com', 'w', c_varchar25) as str from typemix"); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{str: string|null, 0: string|null}", $row); + } $stmt = $pdo->query("SELECT REPLACE('www.mysql.com', c_varchar25, 'Ww') as str from typemix"); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{str: non-empty-string|null, 0: non-empty-string|null}", $row); + } $stmt = $pdo->query("SELECT REPLACE(c_varchar25, 'w', 'Ww') as str from typemix"); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{str: string|null, 0: string|null}", $row); + } } public function joinNullableInCondition(PDO $pdo): void @@ -481,94 +737,142 @@ public function joinNullableInCondition(PDO $pdo): void // nullable column gets non-nullable on inner join // join condition intersects integer-ranges $stmt = $pdo->query('SELECT adaid, eladaid from ada join ak on (adaid = eladaid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>, 1: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT adaid, eladaid from ada inner join ak on (adaid = eladaid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>, 1: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT adaid, eladaid from ada left join ak on (adaid = eladaid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}", $row); + } $stmt = $pdo->query('SELECT adaid, eladaid from ada left outer join ak on (adaid = eladaid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}", $row); + } } public function joinNonNullableInCondition(PDO $pdo): void { $stmt = $pdo->query('SELECT adaid, akid from ada join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, akid: int<-32768, 32767>, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, akid: int<-32768, 32767>, 1: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT adaid, akid from ada inner join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, akid: int<-32768, 32767>, 1: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, akid: int<-32768, 32767>, 1: int<-32768, 32767>}", $row); + } $stmt = $pdo->query('SELECT adaid, akid from ada left join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, akid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, akid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}", $row); + } $stmt = $pdo->query('SELECT adaid, akid from ada left outer join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, akid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, akid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null}", $row); + } } public function joinSelectOutsideCondition(PDO $pdo): void { // nullable col from joined table $stmt = $pdo->query('SELECT adaid, eladaid from ada join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}", $row); + } $stmt = $pdo->query('SELECT adaid, eladaid from ada inner join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}", $row); + } $stmt = $pdo->query('SELECT adaid, eladaid from ada left join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}", $row); + } $stmt = $pdo->query('SELECT adaid, eladaid from ada left outer join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-2147483648, 2147483647>|null, 1: int<-2147483648, 2147483647>|null}", $row); + } // non-nullable col from joined table $stmt = $pdo->query('SELECT adaid, eadavk from ada join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eadavk: numeric-string, 1: numeric-string}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eadavk: numeric-string, 1: numeric-string}", $row); + } $stmt = $pdo->query('SELECT adaid, eadavk from ada inner join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eadavk: numeric-string, 1: numeric-string}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eadavk: numeric-string, 1: numeric-string}", $row); + } $stmt = $pdo->query('SELECT adaid, eadavk from ada left join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eadavk: numeric-string|null, 1: numeric-string|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eadavk: numeric-string|null, 1: numeric-string|null}", $row); + } $stmt = $pdo->query('SELECT adaid, eadavk from ada left outer join ak on (adaid = akid)'); - assertType('PDOStatement, 0: int<-32768, 32767>, eadavk: numeric-string|null, 1: numeric-string|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eadavk: numeric-string|null, 1: numeric-string|null}", $row); + } } public function joinWhereCondition(PDO $pdo): void { $stmt = $pdo->query('SELECT c_json FROM typemix LEFT JOIN ada ON (c_int = adaid) WHERE c_json IS NOT NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{c_json: string, 0: string}", $row); + } $stmt = $pdo->query('SELECT c_json FROM typemix RIGHT JOIN ada ON (c_int = adaid) WHERE c_json IS NOT NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{c_json: string, 0: string}", $row); + } $stmt = $pdo->query('SELECT c_json FROM ada LEFT JOIN typemix ON (c_json = c_json) WHERE c_json IS NOT NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{c_json: string, 0: string}", $row); + } $stmt = $pdo->query('SELECT c_json FROM ada RIGHT JOIN typemix ON (c_json = c_json) WHERE c_json IS NOT NULL'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{c_json: string, 0: string}", $row); + } } public function multipleJoins(PDO $pdo): void { $stmt = $pdo->query('SELECT adaid, eladaid, c_int, c_char5 from ada inner join ak on adaid = eladaid inner join typemix on adaid = c_int'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>, 1: int<-32768, 32767>, c_int: int<-32768, 32767>, 2: int<-32768, 32767>, c_char5: string, 3: string}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>, 1: int<-32768, 32767>, c_int: int<-32768, 32767>, 2: int<-32768, 32767>, c_char5: string, 3: string}", $row); + } $stmt = $pdo->query('SELECT adaid, eladaid, c_int, c_char5 from ada left join ak on adaid = eladaid left join typemix on adaid = c_int'); - assertType('PDOStatement, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null, c_int: int<-32768, 32767>|null, 2: int<-32768, 32767>|null, c_char5: string|null, 3: string|null}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>, eladaid: int<-32768, 32767>|null, 1: int<-32768, 32767>|null, c_int: int<-32768, 32767>|null, 2: int<-32768, 32767>|null, c_char5: string|null, 3: string|null}", $row); + } } public function ignoredAstQueries(PDO $pdo): void { // in reality akid would be same type adaid (int<-32768, 32767>) $stmt = $pdo->query('SELECT akid from ada inner join (select akid from ak)t on akid = adaid'); - assertType('PDOStatement, 0: int<-2147483648, 2147483647>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{akid: int<-2147483648, 2147483647>, 0: int<-2147483648, 2147483647>}", $row); + } $stmt = $pdo->query('SELECT adaid from ada cross join ak'); - assertType('PDOStatement, 0: int<-32768, 32767>}>', $stmt); + foreach ($stmt as $row) { + assertType("array{adaid: int<-32768, 32767>, 0: int<-32768, 32767>}", $row); + } } } diff --git a/tests/stringify/data/ast-narrowed-stringify.php b/tests/stringify/data/ast-narrowed-stringify.php index 566458430..93c566355 100644 --- a/tests/stringify/data/ast-narrowed-stringify.php +++ b/tests/stringify/data/ast-narrowed-stringify.php @@ -10,9 +10,13 @@ class SqlAstNarrowing public function count(PDO $pdo): void { $stmt = $pdo->query('SELECT count(email) as myemail from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{myemail: numeric-string, 0: numeric-string}", $row); + } $stmt = $pdo->query('SELECT count(email) as myemail, count(email) from ada'); - assertType('PDOStatement', $stmt); + foreach ($stmt as $row) { + assertType("array{myemail: numeric-string, 0: numeric-string, count(email): numeric-string, 1: numeric-string}", $row); + } } } diff --git a/tests/stringify/data/stringify.php b/tests/stringify/data/stringify.php index 1a7f6533e..012c07213 100644 --- a/tests/stringify/data/stringify.php +++ b/tests/stringify/data/stringify.php @@ -10,9 +10,8 @@ class Foo public function stringifyTypes(PDO $pdo) { $stmt = $pdo->query('SELECT email, adaid, gesperrt, freigabe1u1 FROM ada', PDO::FETCH_ASSOC); - assertType('PDOStatement', $stmt); - foreach ($stmt as $row) { + assertType("array{email: string, adaid: numeric-string, gesperrt: numeric-string, freigabe1u1: numeric-string}", $row); assertType('numeric-string', $row['adaid']); assertType('string', $row['email']); assertType('numeric-string', $row['gesperrt']);