3 declare(strict_types
=1);
10 use const MYSQLI_BLOB_FLAG
;
11 use const MYSQLI_ENUM_FLAG
;
12 use const MYSQLI_MULTIPLE_KEY_FLAG
;
13 use const MYSQLI_NOT_NULL_FLAG
;
14 use const MYSQLI_PRI_KEY_FLAG
;
15 use const MYSQLI_SET_FLAG
;
16 use const MYSQLI_TYPE_BIT
;
17 use const MYSQLI_TYPE_BLOB
;
18 use const MYSQLI_TYPE_DATE
;
19 use const MYSQLI_TYPE_DATETIME
;
20 use const MYSQLI_TYPE_DECIMAL
;
21 use const MYSQLI_TYPE_DOUBLE
;
22 use const MYSQLI_TYPE_ENUM
;
23 use const MYSQLI_TYPE_FLOAT
;
24 use const MYSQLI_TYPE_GEOMETRY
;
25 use const MYSQLI_TYPE_INT24
;
26 use const MYSQLI_TYPE_JSON
;
27 use const MYSQLI_TYPE_LONG
;
28 use const MYSQLI_TYPE_LONG_BLOB
;
29 use const MYSQLI_TYPE_LONGLONG
;
30 use const MYSQLI_TYPE_MEDIUM_BLOB
;
31 use const MYSQLI_TYPE_NEWDATE
;
32 use const MYSQLI_TYPE_NEWDECIMAL
;
33 use const MYSQLI_TYPE_NULL
;
34 use const MYSQLI_TYPE_SET
;
35 use const MYSQLI_TYPE_SHORT
;
36 use const MYSQLI_TYPE_STRING
;
37 use const MYSQLI_TYPE_TIME
;
38 use const MYSQLI_TYPE_TIMESTAMP
;
39 use const MYSQLI_TYPE_TINY
;
40 use const MYSQLI_TYPE_TINY_BLOB
;
41 use const MYSQLI_TYPE_VAR_STRING
;
42 use const MYSQLI_TYPE_YEAR
;
43 use const MYSQLI_UNIQUE_KEY_FLAG
;
44 use const MYSQLI_UNSIGNED_FLAG
;
45 use const MYSQLI_ZEROFILL_FLAG
;
47 // Issue #16043 - client API mysqlnd seem not to have MYSQLI_TYPE_JSON defined
48 if (! defined('MYSQLI_TYPE_JSON')) {
49 define('MYSQLI_TYPE_JSON', 245);
53 * Handles fields Metadata
55 * NOTE: Getters are not used in all implementations due to the important cost of getters calls
57 final class FieldMetadata
59 public const TYPE_GEOMETRY
= 1;
60 public const TYPE_BIT
= 2;
61 public const TYPE_JSON
= 3;
62 public const TYPE_REAL
= 4;
63 public const TYPE_INT
= 5;
64 public const TYPE_BLOB
= 6;
65 public const TYPE_UNKNOWN
= -1;
66 public const TYPE_NULL
= 7;
67 public const TYPE_STRING
= 8;
68 public const TYPE_DATE
= 9;
69 public const TYPE_TIME
= 10;
70 public const TYPE_TIMESTAMP
= 11;
71 public const TYPE_DATETIME
= 12;
72 public const TYPE_YEAR
= 13;
75 public bool $isMultipleKey;
78 public bool $isPrimaryKey;
81 public bool $isUniqueKey;
84 public bool $isNotNull;
87 public bool $isUnsigned;
90 public bool $isZerofill;
93 public bool $isNumeric;
99 public bool $isBinary;
107 private int|
null $mappedType;
110 public bool $isMappedTypeBit;
113 public bool $isMappedTypeGeometry;
116 public bool $isMappedTypeTimestamp;
121 * @psalm-var non-empty-string
126 * The original column name if an alias did exist
128 public string $orgname;
133 public string $table;
136 * The original table name
138 public string $orgtable;
145 public int $charsetnr;
148 * The number of decimals used (for integer fields)
152 public int $decimals;
155 * The width of the field, as specified in the table definition.
162 * A field only used by the Results class
164 public string|
null $internalMediaType = null;
167 * @psalm-param object{
168 * name: non-empty-string,
183 public function __construct(object $field)
185 $type = $field->type
;
186 $this->mappedType
= $this->getMappedInternalType($type);
188 $flags = $field->flags
;
189 $this->isMultipleKey
= (bool) ($flags & MYSQLI_MULTIPLE_KEY_FLAG
);
190 $this->isPrimaryKey
= (bool) ($flags & MYSQLI_PRI_KEY_FLAG
);
191 $this->isUniqueKey
= (bool) ($flags & MYSQLI_UNIQUE_KEY_FLAG
);
192 $this->isNotNull
= (bool) ($flags & MYSQLI_NOT_NULL_FLAG
);
193 $this->isUnsigned
= (bool) ($flags & MYSQLI_UNSIGNED_FLAG
);
194 $this->isZerofill
= (bool) ($flags & MYSQLI_ZEROFILL_FLAG
);
195 $this->isBlob
= (bool) ($flags & MYSQLI_BLOB_FLAG
);
196 $this->isEnum
= (bool) ($flags & MYSQLI_ENUM_FLAG
);
197 $this->isSet = (bool) ($flags & MYSQLI_SET_FLAG
);
199 // as flags 32768 can be NUM_FLAG or GROUP_FLAG
200 // reference: https://www.php.net/manual/en/mysqli-result.fetch-fields.php
201 // so check field type instead of flags
202 $this->isNumeric
= $this->isType(self
::TYPE_INT
) ||
$this->isType(self
::TYPE_REAL
);
204 // MYSQLI_PART_KEY_FLAG => 'part_key',
205 // MYSQLI_TIMESTAMP_FLAG => 'timestamp',
206 // MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
208 $this->isMappedTypeBit
= $this->isType(self
::TYPE_BIT
);
209 $this->isMappedTypeGeometry
= $this->isType(self
::TYPE_GEOMETRY
);
210 $this->isMappedTypeTimestamp
= $this->isType(self
::TYPE_TIMESTAMP
);
212 $this->name
= $field->name
;
213 $this->orgname
= $field->orgname
;
214 $this->table
= $field->table
;
215 $this->orgtable
= $field->orgtable
;
216 $this->charsetnr
= $field->charsetnr
;
217 $this->decimals
= $field->decimals
;
218 $this->length
= $field->length
;
220 // 63 is the number for the MySQL charset "binary"
222 $type === MYSQLI_TYPE_TINY_BLOB ||
223 $type === MYSQLI_TYPE_BLOB ||
224 $type === MYSQLI_TYPE_MEDIUM_BLOB ||
225 $type === MYSQLI_TYPE_LONG_BLOB ||
226 $type === MYSQLI_TYPE_VAR_STRING ||
227 $type === MYSQLI_TYPE_STRING
228 ) && $this->charsetnr
== 63;
232 * @see https://dev.mysql.com/doc/connectors/en/apis-php-mysqli.constants.html
234 * @psalm-return self::TYPE_*|null
236 private function getMappedInternalType(int $type): int|
null
238 return match ($type) {
239 MYSQLI_TYPE_DECIMAL
=> self
::TYPE_REAL
,
240 MYSQLI_TYPE_NEWDECIMAL
=> self
::TYPE_REAL
,
241 MYSQLI_TYPE_TINY
=> self
::TYPE_INT
,
242 MYSQLI_TYPE_SHORT
=> self
::TYPE_INT
,
243 MYSQLI_TYPE_LONG
=> self
::TYPE_INT
,
244 MYSQLI_TYPE_FLOAT
=> self
::TYPE_REAL
,
245 MYSQLI_TYPE_DOUBLE
=> self
::TYPE_REAL
,
246 MYSQLI_TYPE_NULL
=> self
::TYPE_NULL
,
247 MYSQLI_TYPE_TIMESTAMP
=> self
::TYPE_TIMESTAMP
,
248 MYSQLI_TYPE_LONGLONG
=> self
::TYPE_INT
,
249 MYSQLI_TYPE_INT24
=> self
::TYPE_INT
,
250 MYSQLI_TYPE_DATE
=> self
::TYPE_DATE
,
251 MYSQLI_TYPE_TIME
=> self
::TYPE_TIME
,
252 MYSQLI_TYPE_DATETIME
=> self
::TYPE_DATETIME
,
253 MYSQLI_TYPE_YEAR
=> self
::TYPE_YEAR
,
254 MYSQLI_TYPE_NEWDATE
=> self
::TYPE_DATE
,
255 MYSQLI_TYPE_ENUM
=> self
::TYPE_UNKNOWN
,
256 MYSQLI_TYPE_SET
=> self
::TYPE_UNKNOWN
,
257 MYSQLI_TYPE_TINY_BLOB
=> self
::TYPE_BLOB
,
258 MYSQLI_TYPE_MEDIUM_BLOB
=> self
::TYPE_BLOB
,
259 MYSQLI_TYPE_LONG_BLOB
=> self
::TYPE_BLOB
,
260 MYSQLI_TYPE_BLOB
=> self
::TYPE_BLOB
,
261 MYSQLI_TYPE_VAR_STRING
=> self
::TYPE_STRING
,
262 MYSQLI_TYPE_STRING
=> self
::TYPE_STRING
,
263 // MySQL returns MYSQLI_TYPE_STRING for CHAR
264 // and MYSQLI_TYPE_CHAR === MYSQLI_TYPE_TINY
265 // so this would override TINYINT and mark all TINYINT as string
266 // see https://github.com/phpmyadmin/phpmyadmin/issues/8569
267 //$typeAr[MYSQLI_TYPE_CHAR] = self::TYPE_STRING;
268 MYSQLI_TYPE_GEOMETRY
=> self
::TYPE_GEOMETRY
,
269 MYSQLI_TYPE_BIT
=> self
::TYPE_BIT
,
270 MYSQLI_TYPE_JSON
=> self
::TYPE_JSON
,
275 public function isNotNull(): bool
277 return $this->isNotNull
;
280 public function isNumeric(): bool
282 return $this->isNumeric
;
285 public function isBinary(): bool
287 return $this->isBinary
;
290 public function isBlob(): bool
292 return $this->isBlob
;
295 public function isPrimaryKey(): bool
297 return $this->isPrimaryKey
;
300 public function isUniqueKey(): bool
302 return $this->isUniqueKey
;
305 public function isMultipleKey(): bool
307 return $this->isMultipleKey
;
310 public function isUnsigned(): bool
312 return $this->isUnsigned
;
315 public function isZerofill(): bool
317 return $this->isZerofill
;
320 public function isEnum(): bool
322 return $this->isEnum
;
325 public function isSet(): bool
331 * Checks that it is type DATE/TIME/DATETIME
333 public function isDateTimeType(): bool
335 return $this->isType(self
::TYPE_DATE
)
336 ||
$this->isType(self
::TYPE_TIME
)
337 ||
$this->isType(self
::TYPE_DATETIME
)
338 ||
$this->isType(self
::TYPE_TIMESTAMP
);
342 * Checks that it contains time
343 * A "DATE" field returns false for example
345 public function isTimeType(): bool
347 return $this->isType(self
::TYPE_TIME
)
348 ||
$this->isType(self
::TYPE_TIMESTAMP
)
349 ||
$this->isType(self
::TYPE_DATETIME
);
353 * Get the mapped type as a string
355 * @return string Empty when nothing could be matched
357 public function getMappedType(): string
359 return match ($this->mappedType
) {
360 self
::TYPE_GEOMETRY
=> 'geometry',
361 self
::TYPE_BIT
=> 'bit',
362 self
::TYPE_JSON
=> 'json',
363 self
::TYPE_REAL
=> 'real',
364 self
::TYPE_INT
=> 'int',
365 self
::TYPE_BLOB
=> 'blob',
366 self
::TYPE_UNKNOWN
=> 'unknown',
367 self
::TYPE_NULL
=> 'null',
368 self
::TYPE_STRING
=> 'string',
369 self
::TYPE_DATE
=> 'date',
370 self
::TYPE_TIME
=> 'time',
371 self
::TYPE_TIMESTAMP
=> 'timestamp',
372 self
::TYPE_DATETIME
=> 'datetime',
373 self
::TYPE_YEAR
=> 'year',
379 * Check if it is the mapped type
381 * @phpstan-param self::TYPE_* $type
383 public function isType(int $type): bool
385 return $this->mappedType
=== $type;
389 * Check if it is NOT the mapped type
391 * @phpstan-param self::TYPE_* $type
393 public function isNotType(int $type): bool
395 return $this->mappedType
!== $type;