Skip to content

Commit

Permalink
Do not attempt to parse int2vector and oidvector
Browse files Browse the repository at this point in the history
Fixes #68
  • Loading branch information
trowski committed Nov 15, 2024
1 parent 48ee97e commit c9ce9fd
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 22 deletions.
18 changes: 13 additions & 5 deletions src/Internal/PgSqlHandle.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public function __construct(
*/
private static function fetchTypes(\PgSql\Connection $handle): array
{
$result = \pg_query($handle, "SELECT t.oid, t.typcategory, t.typdelim, t.typelem
$result = \pg_query($handle, "SELECT t.oid, t.typcategory, t.typname, t.typdelim, t.typelem
FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON t.typnamespace=n.oid
WHERE t.typisdefined AND n.nspname IN ('pg_catalog', 'public') ORDER BY t.oid");

Expand All @@ -185,10 +185,18 @@ private static function fetchTypes(\PgSql\Connection $handle): array

$types = [];
while ($row = \pg_fetch_array($result, mode: \PGSQL_NUM)) {
[$oid, $type, $delimiter, $element] = $row;
\assert(\is_numeric($oid) && \is_numeric($element), "OID and element type expected to be integers");
\assert(\is_string($type) && \is_string($delimiter), "Unexpected types in type catalog query results");
$types[(int) $oid] = new PgSqlType($type, $delimiter, (int) $element);
[$oid, $typeCategory, $typeName, $delimiter, $element] = $row;

\assert(
\is_numeric($oid) && \is_numeric($element),
"OID and element type expected to be integers",
);
\assert(
\is_string($typeCategory) && \is_string($typeName) && \is_string($delimiter),
"Unexpected types in type catalog query results",
);

$types[(int) $oid] = new PgSqlType($typeCategory, $typeName, $delimiter, (int) $element);
}

return $types;
Expand Down
38 changes: 23 additions & 15 deletions src/Internal/PgSqlResultIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,31 @@ private function cast(int $oid, ?string $value): array|bool|int|float|string|nul

$type = $this->types[$oid] ?? PgSqlType::getDefaultType();

return match ($type->type) {
'A' => ArrayParser::parse( // Array
$value,
fn (string $data) => $this->cast($type->element, $data),
$type->delimiter,
),
'B' => $value === 't', // Boolean
'N' => match ($oid) { // Numeric
700, 701 => (float) $value, // "float4" and "float8" to float
1700 => $value, // Return "numeric" as string to retain precision
790 => $value, // "money" includes currency symbol as string
default => (int) $value, // All other numeric types cast to an integer
return match ($type->category) {
'A' => match ($type->name) { // Array
'int2vector', 'oidvector' => $value, // Deprecated array types
default => ArrayParser::parse(
$value,
fn (string $data) => $this->cast($type->element, $data),
$type->delimiter,
),
},
default => match ($oid) { // String
17 => \pg_unescape_bytea($value),
default => $value, // Return a string for all other types
'B' => match ($value) {
't' => true,
'f' => false,
default => throw new PostgresParseException('Unexpected value for boolean field: ' . $value),
}, // Boolean
'N' => match ($type->name) { // Numeric
'float4', 'float8' => (float) $value,
'int2', 'int4', 'oid' => (int) $value,
'int8' => \PHP_INT_SIZE >= 8 ? (int) $value : $value, // String on 32-bit systems
default => $value, // Return a string for all other numeric types
},
'U' => match ($type->name) {
'bytea' => \pg_unescape_bytea($value),
default => $value,
},
default => $value, // Return a string for all other types
};
}
}
5 changes: 3 additions & 2 deletions src/Internal/PgSqlType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ final class PgSqlType
private static ?self $default = null;

public function __construct(
public readonly string $type,
public readonly string $category,
public readonly string $name,
public readonly string $delimiter,
public readonly int $element,
) {
}

public static function getDefaultType(): self
{
return self::$default ??= new self('S', ',', 0);
return self::$default ??= new self('S', 'text', ',', 0);
}
}

0 comments on commit c9ce9fd

Please sign in to comment.