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;
124 * The original column name if an alias did exist
126 public string $orgname;
131 public string $table;
134 * The original table name
136 public string $orgtable;
143 public int $charsetnr;
146 * The number of decimals used (for integer fields)
150 public int $decimals;
153 * The width of the field, as specified in the table definition.
160 * A field only used by the Results class
162 public string|
null $internalMediaType = null;
165 * @psalm-param object{
181 public function __construct(object $field)
183 $type = $field->type
;
184 $this->mappedType
= $this->getMappedInternalType($type);
186 $flags = $field->flags
;
187 $this->isMultipleKey
= (bool) ($flags & MYSQLI_MULTIPLE_KEY_FLAG
);
188 $this->isPrimaryKey
= (bool) ($flags & MYSQLI_PRI_KEY_FLAG
);
189 $this->isUniqueKey
= (bool) ($flags & MYSQLI_UNIQUE_KEY_FLAG
);
190 $this->isNotNull
= (bool) ($flags & MYSQLI_NOT_NULL_FLAG
);
191 $this->isUnsigned
= (bool) ($flags & MYSQLI_UNSIGNED_FLAG
);
192 $this->isZerofill
= (bool) ($flags & MYSQLI_ZEROFILL_FLAG
);
193 $this->isBlob
= (bool) ($flags & MYSQLI_BLOB_FLAG
);
194 $this->isEnum
= (bool) ($flags & MYSQLI_ENUM_FLAG
);
195 $this->isSet = (bool) ($flags & MYSQLI_SET_FLAG
);
197 // as flags 32768 can be NUM_FLAG or GROUP_FLAG
198 // reference: https://www.php.net/manual/en/mysqli-result.fetch-fields.php
199 // so check field type instead of flags
200 $this->isNumeric
= $this->isType(self
::TYPE_INT
) ||
$this->isType(self
::TYPE_REAL
);
202 // MYSQLI_PART_KEY_FLAG => 'part_key',
203 // MYSQLI_TIMESTAMP_FLAG => 'timestamp',
204 // MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
206 $this->isMappedTypeBit
= $this->isType(self
::TYPE_BIT
);
207 $this->isMappedTypeGeometry
= $this->isType(self
::TYPE_GEOMETRY
);
208 $this->isMappedTypeTimestamp
= $this->isType(self
::TYPE_TIMESTAMP
);
210 $this->name
= $field->name
;
211 $this->orgname
= $field->orgname
;
212 $this->table
= $field->table
;
213 $this->orgtable
= $field->orgtable
;
214 $this->charsetnr
= $field->charsetnr
;
215 $this->decimals
= $field->decimals
;
216 $this->length
= $field->length
;
218 // 63 is the number for the MySQL charset "binary"
220 $type === MYSQLI_TYPE_TINY_BLOB ||
221 $type === MYSQLI_TYPE_BLOB ||
222 $type === MYSQLI_TYPE_MEDIUM_BLOB ||
223 $type === MYSQLI_TYPE_LONG_BLOB ||
224 $type === MYSQLI_TYPE_VAR_STRING ||
225 $type === MYSQLI_TYPE_STRING
226 ) && $this->charsetnr
== 63;
230 * @see https://dev.mysql.com/doc/connectors/en/apis-php-mysqli.constants.html
232 * @psalm-return self::TYPE_*|null
234 private function getMappedInternalType(int $type): int|
null
236 return match ($type) {
237 MYSQLI_TYPE_DECIMAL
=> self
::TYPE_REAL
,
238 MYSQLI_TYPE_NEWDECIMAL
=> self
::TYPE_REAL
,
239 MYSQLI_TYPE_TINY
=> self
::TYPE_INT
,
240 MYSQLI_TYPE_SHORT
=> self
::TYPE_INT
,
241 MYSQLI_TYPE_LONG
=> self
::TYPE_INT
,
242 MYSQLI_TYPE_FLOAT
=> self
::TYPE_REAL
,
243 MYSQLI_TYPE_DOUBLE
=> self
::TYPE_REAL
,
244 MYSQLI_TYPE_NULL
=> self
::TYPE_NULL
,
245 MYSQLI_TYPE_TIMESTAMP
=> self
::TYPE_TIMESTAMP
,
246 MYSQLI_TYPE_LONGLONG
=> self
::TYPE_INT
,
247 MYSQLI_TYPE_INT24
=> self
::TYPE_INT
,
248 MYSQLI_TYPE_DATE
=> self
::TYPE_DATE
,
249 MYSQLI_TYPE_TIME
=> self
::TYPE_TIME
,
250 MYSQLI_TYPE_DATETIME
=> self
::TYPE_DATETIME
,
251 MYSQLI_TYPE_YEAR
=> self
::TYPE_YEAR
,
252 MYSQLI_TYPE_NEWDATE
=> self
::TYPE_DATE
,
253 MYSQLI_TYPE_ENUM
=> self
::TYPE_UNKNOWN
,
254 MYSQLI_TYPE_SET
=> self
::TYPE_UNKNOWN
,
255 MYSQLI_TYPE_TINY_BLOB
=> self
::TYPE_BLOB
,
256 MYSQLI_TYPE_MEDIUM_BLOB
=> self
::TYPE_BLOB
,
257 MYSQLI_TYPE_LONG_BLOB
=> self
::TYPE_BLOB
,
258 MYSQLI_TYPE_BLOB
=> self
::TYPE_BLOB
,
259 MYSQLI_TYPE_VAR_STRING
=> self
::TYPE_STRING
,
260 MYSQLI_TYPE_STRING
=> self
::TYPE_STRING
,
261 // MySQL returns MYSQLI_TYPE_STRING for CHAR
262 // and MYSQLI_TYPE_CHAR === MYSQLI_TYPE_TINY
263 // so this would override TINYINT and mark all TINYINT as string
264 // see https://github.com/phpmyadmin/phpmyadmin/issues/8569
265 //$typeAr[MYSQLI_TYPE_CHAR] = self::TYPE_STRING;
266 MYSQLI_TYPE_GEOMETRY
=> self
::TYPE_GEOMETRY
,
267 MYSQLI_TYPE_BIT
=> self
::TYPE_BIT
,
268 MYSQLI_TYPE_JSON
=> self
::TYPE_JSON
,
273 public function isNotNull(): bool
275 return $this->isNotNull
;
278 public function isNumeric(): bool
280 return $this->isNumeric
;
283 public function isBinary(): bool
285 return $this->isBinary
;
288 public function isBlob(): bool
290 return $this->isBlob
;
293 public function isPrimaryKey(): bool
295 return $this->isPrimaryKey
;
298 public function isUniqueKey(): bool
300 return $this->isUniqueKey
;
303 public function isMultipleKey(): bool
305 return $this->isMultipleKey
;
308 public function isUnsigned(): bool
310 return $this->isUnsigned
;
313 public function isZerofill(): bool
315 return $this->isZerofill
;
318 public function isEnum(): bool
320 return $this->isEnum
;
323 public function isSet(): bool
329 * Checks that it is type DATE/TIME/DATETIME
331 public function isDateTimeType(): bool
333 return $this->isType(self
::TYPE_DATE
)
334 ||
$this->isType(self
::TYPE_TIME
)
335 ||
$this->isType(self
::TYPE_DATETIME
)
336 ||
$this->isType(self
::TYPE_TIMESTAMP
);
340 * Checks that it contains time
341 * A "DATE" field returns false for example
343 public function isTimeType(): bool
345 return $this->isType(self
::TYPE_TIME
)
346 ||
$this->isType(self
::TYPE_TIMESTAMP
)
347 ||
$this->isType(self
::TYPE_DATETIME
);
351 * Get the mapped type as a string
353 * @return string Empty when nothing could be matched
355 public function getMappedType(): string
357 return match ($this->mappedType
) {
358 self
::TYPE_GEOMETRY
=> 'geometry',
359 self
::TYPE_BIT
=> 'bit',
360 self
::TYPE_JSON
=> 'json',
361 self
::TYPE_REAL
=> 'real',
362 self
::TYPE_INT
=> 'int',
363 self
::TYPE_BLOB
=> 'blob',
364 self
::TYPE_UNKNOWN
=> 'unknown',
365 self
::TYPE_NULL
=> 'null',
366 self
::TYPE_STRING
=> 'string',
367 self
::TYPE_DATE
=> 'date',
368 self
::TYPE_TIME
=> 'time',
369 self
::TYPE_TIMESTAMP
=> 'timestamp',
370 self
::TYPE_DATETIME
=> 'datetime',
371 self
::TYPE_YEAR
=> 'year',
377 * Check if it is the mapped type
379 * @phpstan-param self::TYPE_* $type
381 public function isType(int $type): bool
383 return $this->mappedType
=== $type;
387 * Check if it is NOT the mapped type
389 * @phpstan-param self::TYPE_* $type
391 public function isNotType(int $type): bool
393 return $this->mappedType
!== $type;