summaryrefslogtreecommitdiff
path: root/vendor/doctrine/dbal/src/Driver/PgSQL/Result.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/doctrine/dbal/src/Driver/PgSQL/Result.php')
-rw-r--r--vendor/doctrine/dbal/src/Driver/PgSQL/Result.php240
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
3declare(strict_types=1);
4
5namespace Doctrine\DBAL\Driver\PgSQL;
6
7use Doctrine\DBAL\Driver\FetchUtils;
8use Doctrine\DBAL\Driver\PgSQL\Exception\UnexpectedValue;
9use Doctrine\DBAL\Driver\Result as ResultInterface;
10use PgSql\Result as PgSqlResult;
11
12use function array_keys;
13use function array_map;
14use function assert;
15use function hex2bin;
16use function pg_affected_rows;
17use function pg_fetch_all;
18use function pg_fetch_all_columns;
19use function pg_fetch_assoc;
20use function pg_fetch_row;
21use function pg_field_name;
22use function pg_field_type;
23use function pg_free_result;
24use function pg_num_fields;
25use function substr;
26
27use const PGSQL_ASSOC;
28use const PGSQL_NUM;
29use const PHP_INT_SIZE;
30
31final 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}