Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
621 lars 1
<?php
2
 
3
namespace Doctrine\DBAL\Driver\PgSQL;
4
 
5
use Doctrine\DBAL\Driver\FetchUtils;
6
use Doctrine\DBAL\Driver\PgSQL\Exception\UnexpectedValue;
7
use Doctrine\DBAL\Driver\Result as ResultInterface;
8
use PgSql\Result as PgSqlResult;
9
use TypeError;
10
 
11
use function array_keys;
12
use function array_map;
13
use function assert;
14
use function get_class;
15
use function gettype;
16
use function hex2bin;
17
use function is_object;
18
use function is_resource;
19
use function pg_affected_rows;
20
use function pg_fetch_all;
21
use function pg_fetch_all_columns;
22
use function pg_fetch_assoc;
23
use function pg_fetch_row;
24
use function pg_field_name;
25
use function pg_field_type;
26
use function pg_free_result;
27
use function pg_num_fields;
28
use function sprintf;
29
use function substr;
30
 
31
use const PGSQL_ASSOC;
32
use const PGSQL_NUM;
33
use const PHP_INT_SIZE;
34
 
35
final class Result implements ResultInterface
36
{
37
    /** @var PgSqlResult|resource|null */
38
    private $result;
39
 
40
    /** @param PgSqlResult|resource $result */
41
    public function __construct($result)
42
    {
43
        if (! is_resource($result) && ! $result instanceof PgSqlResult) {
44
            throw new TypeError(sprintf(
45
                'Expected result to be a resource or an instance of %s, got %s.',
46
                PgSqlResult::class,
47
                is_object($result) ? get_class($result) : gettype($result),
48
            ));
49
        }
50
 
51
        $this->result = $result;
52
    }
53
 
54
    public function __destruct()
55
    {
56
        if (! isset($this->result)) {
57
            return;
58
        }
59
 
60
        $this->free();
61
    }
62
 
63
    /** {@inheritdoc} */
64
    public function fetchNumeric()
65
    {
66
        if ($this->result === null) {
67
            return false;
68
        }
69
 
70
        $row = pg_fetch_row($this->result);
71
        if ($row === false) {
72
            return false;
73
        }
74
 
75
        return $this->mapNumericRow($row, $this->fetchNumericColumnTypes());
76
    }
77
 
78
    /** {@inheritdoc} */
79
    public function fetchAssociative()
80
    {
81
        if ($this->result === null) {
82
            return false;
83
        }
84
 
85
        $row = pg_fetch_assoc($this->result);
86
        if ($row === false) {
87
            return false;
88
        }
89
 
90
        return $this->mapAssociativeRow($row, $this->fetchAssociativeColumnTypes());
91
    }
92
 
93
    /** {@inheritdoc} */
94
    public function fetchOne()
95
    {
96
        return FetchUtils::fetchOne($this);
97
    }
98
 
99
    /** {@inheritdoc} */
100
    public function fetchAllNumeric(): array
101
    {
102
        if ($this->result === null) {
103
            return [];
104
        }
105
 
106
        $resultSet = pg_fetch_all($this->result, PGSQL_NUM);
107
        // On PHP 7.4, pg_fetch_all() might return false for empty result sets.
108
        if ($resultSet === false) {
109
            return [];
110
        }
111
 
112
        $types = $this->fetchNumericColumnTypes();
113
 
114
        return array_map(
115
            fn (array $row) => $this->mapNumericRow($row, $types),
116
            $resultSet,
117
        );
118
    }
119
 
120
    /** {@inheritdoc} */
121
    public function fetchAllAssociative(): array
122
    {
123
        if ($this->result === null) {
124
            return [];
125
        }
126
 
127
        $resultSet = pg_fetch_all($this->result, PGSQL_ASSOC);
128
        // On PHP 7.4, pg_fetch_all() might return false for empty result sets.
129
        if ($resultSet === false) {
130
            return [];
131
        }
132
 
133
        $types = $this->fetchAssociativeColumnTypes();
134
 
135
        return array_map(
136
            fn (array $row) => $this->mapAssociativeRow($row, $types),
137
            $resultSet,
138
        );
139
    }
140
 
141
    /** {@inheritdoc} */
142
    public function fetchFirstColumn(): array
143
    {
144
        if ($this->result === null) {
145
            return [];
146
        }
147
 
148
        $postgresType = pg_field_type($this->result, 0);
149
 
150
        return array_map(
151
            fn ($value) => $this->mapType($postgresType, $value),
152
            pg_fetch_all_columns($this->result),
153
        );
154
    }
155
 
156
    public function rowCount(): int
157
    {
158
        if ($this->result === null) {
159
            return 0;
160
        }
161
 
162
        return pg_affected_rows($this->result);
163
    }
164
 
165
    public function columnCount(): int
166
    {
167
        if ($this->result === null) {
168
            return 0;
169
        }
170
 
171
        return pg_num_fields($this->result);
172
    }
173
 
174
    public function free(): void
175
    {
176
        if ($this->result === null) {
177
            return;
178
        }
179
 
180
        pg_free_result($this->result);
181
        $this->result = null;
182
    }
183
 
184
    /** @return array<int, string> */
185
    private function fetchNumericColumnTypes(): array
186
    {
187
        assert($this->result !== null);
188
 
189
        $types     = [];
190
        $numFields = pg_num_fields($this->result);
191
        for ($i = 0; $i < $numFields; ++$i) {
192
            $types[$i] = pg_field_type($this->result, $i);
193
        }
194
 
195
        return $types;
196
    }
197
 
198
    /** @return array<string, string> */
199
    private function fetchAssociativeColumnTypes(): array
200
    {
201
        assert($this->result !== null);
202
 
203
        $types     = [];
204
        $numFields = pg_num_fields($this->result);
205
        for ($i = 0; $i < $numFields; ++$i) {
206
            $types[pg_field_name($this->result, $i)] = pg_field_type($this->result, $i);
207
        }
208
 
209
        return $types;
210
    }
211
 
212
    /**
213
     * @param list<string|null>  $row
214
     * @param array<int, string> $types
215
     *
216
     * @return list<mixed>
217
     */
218
    private function mapNumericRow(array $row, array $types): array
219
    {
220
        assert($this->result !== null);
221
 
222
        return array_map(
223
            fn ($value, $field) => $this->mapType($types[$field], $value),
224
            $row,
225
            array_keys($row),
226
        );
227
    }
228
 
229
    /**
230
     * @param array<string, string|null> $row
231
     * @param array<string, string>      $types
232
     *
233
     * @return array<string, mixed>
234
     */
235
    private function mapAssociativeRow(array $row, array $types): array
236
    {
237
        assert($this->result !== null);
238
 
239
        $mappedRow = [];
240
        foreach ($row as $field => $value) {
241
            $mappedRow[$field] = $this->mapType($types[$field], $value);
242
        }
243
 
244
        return $mappedRow;
245
    }
246
 
247
    /** @return string|int|float|bool|null */
248
    private function mapType(string $postgresType, ?string $value)
249
    {
250
        if ($value === null) {
251
            return null;
252
        }
253
 
254
        switch ($postgresType) {
255
            case 'bool':
256
                switch ($value) {
257
                    case 't':
258
                        return true;
259
                    case 'f':
260
                        return false;
261
                }
262
 
263
                throw UnexpectedValue::new($value, $postgresType);
264
 
265
            case 'bytea':
266
                return hex2bin(substr($value, 2));
267
 
268
            case 'float4':
269
            case 'float8':
270
                return (float) $value;
271
 
272
            case 'int2':
273
            case 'int4':
274
                return (int) $value;
275
 
276
            case 'int8':
277
                return PHP_INT_SIZE >= 8 ? (int) $value : $value;
278
        }
279
 
280
        return $value;
281
    }
282
}