diff options
Diffstat (limited to 'vendor/doctrine/dbal/src/Driver/PgSQL/Result.php')
-rw-r--r-- | vendor/doctrine/dbal/src/Driver/PgSQL/Result.php | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/vendor/doctrine/dbal/src/Driver/PgSQL/Result.php b/vendor/doctrine/dbal/src/Driver/PgSQL/Result.php new file mode 100644 index 0000000..954758c --- /dev/null +++ b/vendor/doctrine/dbal/src/Driver/PgSQL/Result.php | |||
@@ -0,0 +1,240 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\DBAL\Driver\PgSQL; | ||
6 | |||
7 | use Doctrine\DBAL\Driver\FetchUtils; | ||
8 | use Doctrine\DBAL\Driver\PgSQL\Exception\UnexpectedValue; | ||
9 | use Doctrine\DBAL\Driver\Result as ResultInterface; | ||
10 | use PgSql\Result as PgSqlResult; | ||
11 | |||
12 | use function array_keys; | ||
13 | use function array_map; | ||
14 | use function assert; | ||
15 | use function hex2bin; | ||
16 | use function pg_affected_rows; | ||
17 | use function pg_fetch_all; | ||
18 | use function pg_fetch_all_columns; | ||
19 | use function pg_fetch_assoc; | ||
20 | use function pg_fetch_row; | ||
21 | use function pg_field_name; | ||
22 | use function pg_field_type; | ||
23 | use function pg_free_result; | ||
24 | use function pg_num_fields; | ||
25 | use function substr; | ||
26 | |||
27 | use const PGSQL_ASSOC; | ||
28 | use const PGSQL_NUM; | ||
29 | use const PHP_INT_SIZE; | ||
30 | |||
31 | final class Result implements ResultInterface | ||
32 | { | ||
33 | private ?PgSqlResult $result; | ||
34 | |||
35 | public function __construct(PgSqlResult $result) | ||
36 | { | ||
37 | $this->result = $result; | ||
38 | } | ||
39 | |||
40 | public function __destruct() | ||
41 | { | ||
42 | if (! isset($this->result)) { | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | $this->free(); | ||
47 | } | ||
48 | |||
49 | /** {@inheritDoc} */ | ||
50 | public function fetchNumeric(): array|false | ||
51 | { | ||
52 | if ($this->result === null) { | ||
53 | return false; | ||
54 | } | ||
55 | |||
56 | $row = pg_fetch_row($this->result); | ||
57 | if ($row === false) { | ||
58 | return false; | ||
59 | } | ||
60 | |||
61 | return $this->mapNumericRow($row, $this->fetchNumericColumnTypes()); | ||
62 | } | ||
63 | |||
64 | /** {@inheritDoc} */ | ||
65 | public function fetchAssociative(): array|false | ||
66 | { | ||
67 | if ($this->result === null) { | ||
68 | return false; | ||
69 | } | ||
70 | |||
71 | $row = pg_fetch_assoc($this->result); | ||
72 | if ($row === false) { | ||
73 | return false; | ||
74 | } | ||
75 | |||
76 | return $this->mapAssociativeRow($row, $this->fetchAssociativeColumnTypes()); | ||
77 | } | ||
78 | |||
79 | /** {@inheritDoc} */ | ||
80 | public function fetchOne(): mixed | ||
81 | { | ||
82 | return FetchUtils::fetchOne($this); | ||
83 | } | ||
84 | |||
85 | /** {@inheritDoc} */ | ||
86 | public function fetchAllNumeric(): array | ||
87 | { | ||
88 | if ($this->result === null) { | ||
89 | return []; | ||
90 | } | ||
91 | |||
92 | $types = $this->fetchNumericColumnTypes(); | ||
93 | |||
94 | return array_map( | ||
95 | fn (array $row) => $this->mapNumericRow($row, $types), | ||
96 | pg_fetch_all($this->result, PGSQL_NUM), | ||
97 | ); | ||
98 | } | ||
99 | |||
100 | /** {@inheritDoc} */ | ||
101 | public function fetchAllAssociative(): array | ||
102 | { | ||
103 | if ($this->result === null) { | ||
104 | return []; | ||
105 | } | ||
106 | |||
107 | $types = $this->fetchAssociativeColumnTypes(); | ||
108 | |||
109 | return array_map( | ||
110 | fn (array $row) => $this->mapAssociativeRow($row, $types), | ||
111 | pg_fetch_all($this->result, PGSQL_ASSOC), | ||
112 | ); | ||
113 | } | ||
114 | |||
115 | /** {@inheritDoc} */ | ||
116 | public function fetchFirstColumn(): array | ||
117 | { | ||
118 | if ($this->result === null) { | ||
119 | return []; | ||
120 | } | ||
121 | |||
122 | $postgresType = pg_field_type($this->result, 0); | ||
123 | |||
124 | return array_map( | ||
125 | fn ($value) => $this->mapType($postgresType, $value), | ||
126 | pg_fetch_all_columns($this->result), | ||
127 | ); | ||
128 | } | ||
129 | |||
130 | public function rowCount(): int | ||
131 | { | ||
132 | if ($this->result === null) { | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | return pg_affected_rows($this->result); | ||
137 | } | ||
138 | |||
139 | public function columnCount(): int | ||
140 | { | ||
141 | if ($this->result === null) { | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | return pg_num_fields($this->result); | ||
146 | } | ||
147 | |||
148 | public function free(): void | ||
149 | { | ||
150 | if ($this->result === null) { | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | pg_free_result($this->result); | ||
155 | $this->result = null; | ||
156 | } | ||
157 | |||
158 | /** @return array<int, string> */ | ||
159 | private function fetchNumericColumnTypes(): array | ||
160 | { | ||
161 | assert($this->result !== null); | ||
162 | |||
163 | $types = []; | ||
164 | $numFields = pg_num_fields($this->result); | ||
165 | for ($i = 0; $i < $numFields; ++$i) { | ||
166 | $types[$i] = pg_field_type($this->result, $i); | ||
167 | } | ||
168 | |||
169 | return $types; | ||
170 | } | ||
171 | |||
172 | /** @return array<string, string> */ | ||
173 | private function fetchAssociativeColumnTypes(): array | ||
174 | { | ||
175 | assert($this->result !== null); | ||
176 | |||
177 | $types = []; | ||
178 | $numFields = pg_num_fields($this->result); | ||
179 | for ($i = 0; $i < $numFields; ++$i) { | ||
180 | $types[pg_field_name($this->result, $i)] = pg_field_type($this->result, $i); | ||
181 | } | ||
182 | |||
183 | return $types; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * @param list<string|null> $row | ||
188 | * @param array<int, string> $types | ||
189 | * | ||
190 | * @return list<mixed> | ||
191 | */ | ||
192 | private function mapNumericRow(array $row, array $types): array | ||
193 | { | ||
194 | assert($this->result !== null); | ||
195 | |||
196 | return array_map( | ||
197 | fn ($value, $field) => $this->mapType($types[$field], $value), | ||
198 | $row, | ||
199 | array_keys($row), | ||
200 | ); | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * @param array<string, string|null> $row | ||
205 | * @param array<string, string> $types | ||
206 | * | ||
207 | * @return array<string, mixed> | ||
208 | */ | ||
209 | private function mapAssociativeRow(array $row, array $types): array | ||
210 | { | ||
211 | assert($this->result !== null); | ||
212 | |||
213 | $mappedRow = []; | ||
214 | foreach ($row as $field => $value) { | ||
215 | $mappedRow[$field] = $this->mapType($types[$field], $value); | ||
216 | } | ||
217 | |||
218 | return $mappedRow; | ||
219 | } | ||
220 | |||
221 | private function mapType(string $postgresType, ?string $value): string|int|float|bool|null | ||
222 | { | ||
223 | if ($value === null) { | ||
224 | return null; | ||
225 | } | ||
226 | |||
227 | return match ($postgresType) { | ||
228 | 'bool' => match ($value) { | ||
229 | 't' => true, | ||
230 | 'f' => false, | ||
231 | default => throw UnexpectedValue::new($value, $postgresType), | ||
232 | }, | ||
233 | 'bytea' => hex2bin(substr($value, 2)), | ||
234 | 'float4', 'float8' => (float) $value, | ||
235 | 'int2', 'int4' => (int) $value, | ||
236 | 'int8' => PHP_INT_SIZE >= 8 ? (int) $value : $value, | ||
237 | default => $value, | ||
238 | }; | ||
239 | } | ||
240 | } | ||