Passed
Push — master ( 9dbdd9...d5a428 )
by Alexander
04:15
created

framework/db/mysql/Schema.php (2 issues)

1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\db\mysql;
9
10
use yii\base\InvalidConfigException;
11
use yii\base\NotSupportedException;
12
use yii\db\Constraint;
13
use yii\db\ConstraintFinderInterface;
14
use yii\db\ConstraintFinderTrait;
15
use yii\db\Exception;
16
use yii\db\Expression;
17
use yii\db\ForeignKeyConstraint;
18
use yii\db\IndexConstraint;
19
use yii\db\TableSchema;
20
use yii\helpers\ArrayHelper;
21
22
/**
23
 * Schema is the class for retrieving metadata from a MySQL database (version 4.1.x and 5.x).
24
 *
25
 * @author Qiang Xue <[email protected]>
26
 * @since 2.0
27
 */
28
class Schema extends \yii\db\Schema implements ConstraintFinderInterface
29
{
30
    use ConstraintFinderTrait;
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public $columnSchemaClass = 'yii\db\mysql\ColumnSchema';
36
    /**
37
     * @var bool whether MySQL used is older than 5.1.
38
     */
39
    private $_oldMysql;
40
41
42
    /**
43
     * @var array mapping from physical column types (keys) to abstract column types (values)
44
     */
45
    public $typeMap = [
46
        'tinyint' => self::TYPE_TINYINT,
47
        'bit' => self::TYPE_INTEGER,
48
        'smallint' => self::TYPE_SMALLINT,
49
        'mediumint' => self::TYPE_INTEGER,
50
        'int' => self::TYPE_INTEGER,
51
        'integer' => self::TYPE_INTEGER,
52
        'bigint' => self::TYPE_BIGINT,
53
        'float' => self::TYPE_FLOAT,
54
        'double' => self::TYPE_DOUBLE,
55
        'real' => self::TYPE_FLOAT,
56
        'decimal' => self::TYPE_DECIMAL,
57
        'numeric' => self::TYPE_DECIMAL,
58
        'tinytext' => self::TYPE_TEXT,
59
        'mediumtext' => self::TYPE_TEXT,
60
        'longtext' => self::TYPE_TEXT,
61
        'longblob' => self::TYPE_BINARY,
62
        'blob' => self::TYPE_BINARY,
63
        'text' => self::TYPE_TEXT,
64
        'varchar' => self::TYPE_STRING,
65
        'string' => self::TYPE_STRING,
66
        'char' => self::TYPE_CHAR,
67
        'datetime' => self::TYPE_DATETIME,
68
        'year' => self::TYPE_DATE,
69
        'date' => self::TYPE_DATE,
70
        'time' => self::TYPE_TIME,
71
        'timestamp' => self::TYPE_TIMESTAMP,
72
        'enum' => self::TYPE_STRING,
73
        'varbinary' => self::TYPE_BINARY,
74
        'json' => self::TYPE_JSON,
75
    ];
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    protected $tableQuoteCharacter = '`';
81
    /**
82
     * {@inheritdoc}
83
     */
84
    protected $columnQuoteCharacter = '`';
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 81
    protected function resolveTableName($name)
90
    {
91 81
        $resolvedName = new TableSchema();
92 81
        $parts = explode('.', str_replace('`', '', $name));
93 81
        if (isset($parts[1])) {
94
            $resolvedName->schemaName = $parts[0];
95
            $resolvedName->name = $parts[1];
96
        } else {
97 81
            $resolvedName->schemaName = $this->defaultSchema;
98 81
            $resolvedName->name = $name;
99
        }
100 81
        $resolvedName->fullName = ($resolvedName->schemaName !== $this->defaultSchema ? $resolvedName->schemaName . '.' : '') . $resolvedName->name;
101 81
        return $resolvedName;
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107 7
    protected function findTableNames($schema = '')
108
    {
109 7
        $sql = 'SHOW TABLES';
110 7
        if ($schema !== '') {
111
            $sql .= ' FROM ' . $this->quoteSimpleTableName($schema);
112
        }
113
114 7
        return $this->db->createCommand($sql)->queryColumn();
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 396
    protected function loadTableSchema($name)
121
    {
122 396
        $table = new TableSchema();
123 396
        $this->resolveTableNames($table, $name);
124
125 396
        if ($this->findColumns($table)) {
126 391
            $this->findConstraints($table);
127 391
            return $table;
128
        }
129
130 15
        return null;
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 54
    protected function loadTablePrimaryKey($tableName)
137
    {
138 54
        return $this->loadTableConstraints($tableName, 'primaryKey');
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 4
    protected function loadTableForeignKeys($tableName)
145
    {
146 4
        return $this->loadTableConstraints($tableName, 'foreignKeys');
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 51
    protected function loadTableIndexes($tableName)
153
    {
154 51
        static $sql = <<<'SQL'
155
SELECT
156
    `s`.`INDEX_NAME` AS `name`,
157
    `s`.`COLUMN_NAME` AS `column_name`,
158
    `s`.`NON_UNIQUE` ^ 1 AS `index_is_unique`,
159
    `s`.`INDEX_NAME` = 'PRIMARY' AS `index_is_primary`
160
FROM `information_schema`.`STATISTICS` AS `s`
161
WHERE `s`.`TABLE_SCHEMA` = COALESCE(:schemaName, DATABASE()) AND `s`.`INDEX_SCHEMA` = `s`.`TABLE_SCHEMA` AND `s`.`TABLE_NAME` = :tableName
162
ORDER BY `s`.`SEQ_IN_INDEX` ASC
163
SQL;
164
165 51
        $resolvedName = $this->resolveTableName($tableName);
166 51
        $indexes = $this->db->createCommand($sql, [
167 51
            ':schemaName' => $resolvedName->schemaName,
168 51
            ':tableName' => $resolvedName->name,
169 51
        ])->queryAll();
170 51
        $indexes = $this->normalizePdoRowKeyCase($indexes, true);
171 51
        $indexes = ArrayHelper::index($indexes, null, 'name');
172 51
        $result = [];
173 51
        foreach ($indexes as $name => $index) {
174 51
            $result[] = new IndexConstraint([
175 51
                'isPrimary' => (bool) $index[0]['index_is_primary'],
176 51
                'isUnique' => (bool) $index[0]['index_is_unique'],
177 51
                'name' => $name !== 'PRIMARY' ? $name : null,
178 51
                'columnNames' => ArrayHelper::getColumn($index, 'column_name'),
179
            ]);
180
        }
181
182 51
        return $result;
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188 13
    protected function loadTableUniques($tableName)
189
    {
190 13
        return $this->loadTableConstraints($tableName, 'uniques');
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     * @throws NotSupportedException if this method is called.
196
     */
197 12
    protected function loadTableChecks($tableName)
0 ignored issues
show
The parameter $tableName is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

197
    protected function loadTableChecks(/** @scrutinizer ignore-unused */ $tableName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
198
    {
199 12
        throw new NotSupportedException('MySQL does not support check constraints.');
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     * @throws NotSupportedException if this method is called.
205
     */
206 12
    protected function loadTableDefaultValues($tableName)
0 ignored issues
show
The parameter $tableName is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

206
    protected function loadTableDefaultValues(/** @scrutinizer ignore-unused */ $tableName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
207
    {
208 12
        throw new NotSupportedException('MySQL does not support default value constraints.');
209
    }
210
211
    /**
212
     * Creates a query builder for the MySQL database.
213
     * @return QueryBuilder query builder instance
214
     */
215 388
    public function createQueryBuilder()
216
    {
217 388
        return new QueryBuilder($this->db);
218
    }
219
220
    /**
221
     * Resolves the table name and schema name (if any).
222
     * @param TableSchema $table the table metadata object
223
     * @param string $name the table name
224
     */
225 396
    protected function resolveTableNames($table, $name)
226
    {
227 396
        $parts = explode('.', str_replace('`', '', $name));
228 396
        if (isset($parts[1])) {
229
            $table->schemaName = $parts[0];
230
            $table->name = $parts[1];
231
            $table->fullName = $table->schemaName . '.' . $table->name;
232
        } else {
233 396
            $table->fullName = $table->name = $parts[0];
234
        }
235 396
    }
236
237
    /**
238
     * Loads the column information into a [[ColumnSchema]] object.
239
     * @param array $info column information
240
     * @return ColumnSchema the column schema object
241
     */
242 392
    protected function loadColumnSchema($info)
243
    {
244 392
        $column = $this->createColumnSchema();
245
246 392
        $column->name = $info['field'];
247 392
        $column->allowNull = $info['null'] === 'YES';
248 392
        $column->isPrimaryKey = strpos($info['key'], 'PRI') !== false;
249 392
        $column->autoIncrement = stripos($info['extra'], 'auto_increment') !== false;
250 392
        $column->comment = $info['comment'];
251
252 392
        $column->dbType = $info['type'];
253 392
        $column->unsigned = stripos($column->dbType, 'unsigned') !== false;
254
255 392
        $column->type = self::TYPE_STRING;
256 392
        if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) {
257 392
            $type = strtolower($matches[1]);
258 392
            if (isset($this->typeMap[$type])) {
259 392
                $column->type = $this->typeMap[$type];
260
            }
261 392
            if (!empty($matches[2])) {
262 391
                if ($type === 'enum') {
263 27
                    preg_match_all("/'[^']*'/", $matches[2], $values);
264 27
                    foreach ($values[0] as $i => $value) {
265 27
                        $values[$i] = trim($value, "'");
266
                    }
267 27
                    $column->enumValues = $values;
268
                } else {
269 391
                    $values = explode(',', $matches[2]);
270 391
                    $column->size = $column->precision = (int) $values[0];
271 391
                    if (isset($values[1])) {
272 101
                        $column->scale = (int) $values[1];
273
                    }
274 391
                    if ($column->size === 1 && $type === 'bit') {
275 6
                        $column->type = 'boolean';
276 391
                    } elseif ($type === 'bit') {
277 27
                        if ($column->size > 32) {
278
                            $column->type = 'bigint';
279 27
                        } elseif ($column->size === 32) {
280
                            $column->type = 'integer';
281
                        }
282
                    }
283
                }
284
            }
285
        }
286
287 392
        $column->phpType = $this->getColumnPhpType($column);
288
289 392
        if (!$column->isPrimaryKey) {
290
            /**
291
             * When displayed in the INFORMATION_SCHEMA.COLUMNS table, a default CURRENT TIMESTAMP is displayed
292
             * as CURRENT_TIMESTAMP up until MariaDB 10.2.2, and as current_timestamp() from MariaDB 10.2.3.
293
             *
294
             * See details here: https://mariadb.com/kb/en/library/now/#description
295
             */
296 387
            if (($column->type === 'timestamp' || $column->type === 'datetime')
297 387
                && preg_match('/^current_timestamp(?:\(([0-9]*)\))?$/i', $info['default'], $matches)) {
298 30
                $column->defaultValue = new Expression('CURRENT_TIMESTAMP' . (!empty($matches[1]) ? '(' . $matches[1] . ')' : ''));
299 384
            } elseif (isset($type) && $type === 'bit') {
300 28
                $column->defaultValue = bindec(trim($info['default'], 'b\''));
301
            } else {
302 383
                $column->defaultValue = $column->phpTypecast($info['default']);
303
            }
304
        }
305
306 392
        return $column;
307
    }
308
309
    /**
310
     * Collects the metadata of table columns.
311
     * @param TableSchema $table the table metadata
312
     * @return bool whether the table exists in the database
313
     * @throws \Exception if DB query fails
314
     */
315 396
    protected function findColumns($table)
316
    {
317 396
        $sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteTableName($table->fullName);
318
        try {
319 396
            $columns = $this->db->createCommand($sql)->queryAll();
320 15
        } catch (\Exception $e) {
321 15
            $previous = $e->getPrevious();
322 15
            if ($previous instanceof \PDOException && strpos($previous->getMessage(), 'SQLSTATE[42S02') !== false) {
323
                // table does not exist
324
                // https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html#error_er_bad_table_error
325 15
                return false;
326
            }
327
            throw $e;
328
        }
329 391
        foreach ($columns as $info) {
330 391
            if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) !== \PDO::CASE_LOWER) {
331 390
                $info = array_change_key_case($info, CASE_LOWER);
332
            }
333 391
            $column = $this->loadColumnSchema($info);
334 391
            $table->columns[$column->name] = $column;
335 391
            if ($column->isPrimaryKey) {
336 364
                $table->primaryKey[] = $column->name;
337 364
                if ($column->autoIncrement) {
338 391
                    $table->sequenceName = '';
339
                }
340
            }
341
        }
342
343 391
        return true;
344
    }
345
346
    /**
347
     * Gets the CREATE TABLE sql string.
348
     * @param TableSchema $table the table metadata
349
     * @return string $sql the result of 'SHOW CREATE TABLE'
350
     */
351 1
    protected function getCreateTableSql($table)
352
    {
353 1
        $row = $this->db->createCommand('SHOW CREATE TABLE ' . $this->quoteTableName($table->fullName))->queryOne();
354 1
        if (isset($row['Create Table'])) {
355 1
            $sql = $row['Create Table'];
356
        } else {
357
            $row = array_values($row);
358
            $sql = $row[1];
359
        }
360
361 1
        return $sql;
362
    }
363
364
    /**
365
     * Collects the foreign key column details for the given table.
366
     * @param TableSchema $table the table metadata
367
     * @throws \Exception
368
     */
369 391
    protected function findConstraints($table)
370
    {
371
        $sql = <<<'SQL'
372 391
SELECT
373
    `kcu`.`CONSTRAINT_NAME` AS `constraint_name`,
374
    `kcu`.`COLUMN_NAME` AS `column_name`,
375
    `kcu`.`REFERENCED_TABLE_NAME` AS `referenced_table_name`,
376
    `kcu`.`REFERENCED_COLUMN_NAME` AS `referenced_column_name`
377
FROM `information_schema`.`REFERENTIAL_CONSTRAINTS` AS `rc`
378
JOIN `information_schema`.`KEY_COLUMN_USAGE` AS `kcu` ON
379
    (
380
        `kcu`.`CONSTRAINT_CATALOG` = `rc`.`CONSTRAINT_CATALOG` OR
381
        (`kcu`.`CONSTRAINT_CATALOG` IS NULL AND `rc`.`CONSTRAINT_CATALOG` IS NULL)
382
    ) AND
383
    `kcu`.`CONSTRAINT_SCHEMA` = `rc`.`CONSTRAINT_SCHEMA` AND
384
    `kcu`.`CONSTRAINT_NAME` = `rc`.`CONSTRAINT_NAME`
385
WHERE `rc`.`CONSTRAINT_SCHEMA` = database() AND `kcu`.`TABLE_SCHEMA` = database()
386
AND `rc`.`TABLE_NAME` = :tableName AND `kcu`.`TABLE_NAME` = :tableName1
387
SQL;
388
389
        try {
390 391
            $rows = $this->db->createCommand($sql, [':tableName' => $table->name, ':tableName1' => $table->name])->queryAll();
391 391
            $constraints = [];
392
393 391
            foreach ($rows as $row) {
394 266
                $constraints[$row['constraint_name']]['referenced_table_name'] = $row['referenced_table_name'];
395 266
                $constraints[$row['constraint_name']]['columns'][$row['column_name']] = $row['referenced_column_name'];
396
            }
397
398 391
            $table->foreignKeys = [];
399 391
            foreach ($constraints as $name => $constraint) {
400 266
                $table->foreignKeys[$name] = array_merge(
401 266
                    [$constraint['referenced_table_name']],
402 391
                    $constraint['columns']
403
                );
404
            }
405
        } catch (\Exception $e) {
406
            $previous = $e->getPrevious();
407
            if (!$previous instanceof \PDOException || strpos($previous->getMessage(), 'SQLSTATE[42S02') === false) {
408
                throw $e;
409
            }
410
411
            // table does not exist, try to determine the foreign keys using the table creation sql
412
            $sql = $this->getCreateTableSql($table);
413
            $regexp = '/FOREIGN KEY\s+\(([^\)]+)\)\s+REFERENCES\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi';
414
            if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) {
415
                foreach ($matches as $match) {
416
                    $fks = array_map('trim', explode(',', str_replace(['`', '"'], '', $match[1])));
417
                    $pks = array_map('trim', explode(',', str_replace(['`', '"'], '', $match[3])));
418
                    $constraint = [str_replace(['`', '"'], '', $match[2])];
419
                    foreach ($fks as $k => $name) {
420
                        $constraint[$name] = $pks[$k];
421
                    }
422
                    $table->foreignKeys[md5(serialize($constraint))] = $constraint;
423
                }
424
                $table->foreignKeys = array_values($table->foreignKeys);
425
            }
426
        }
427 391
    }
428
429
    /**
430
     * Returns all unique indexes for the given table.
431
     *
432
     * Each array element is of the following structure:
433
     *
434
     * ```php
435
     * [
436
     *     'IndexName1' => ['col1' [, ...]],
437
     *     'IndexName2' => ['col2' [, ...]],
438
     * ]
439
     * ```
440
     *
441
     * @param TableSchema $table the table metadata
442
     * @return array all unique indexes for the given table.
443
     */
444 1
    public function findUniqueIndexes($table)
445
    {
446 1
        $sql = $this->getCreateTableSql($table);
447 1
        $uniqueIndexes = [];
448
449 1
        $regexp = '/UNIQUE KEY\s+[`"](.+)[`"]\s*\(([`"].+[`"])+\)/mi';
450 1
        if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) {
451 1
            foreach ($matches as $match) {
452 1
                $indexName = $match[1];
453 1
                $indexColumns = array_map('trim', preg_split('/[`"],[`"]/', trim($match[2], '`"')));
454 1
                $uniqueIndexes[$indexName] = $indexColumns;
455
            }
456
        }
457
458 1
        return $uniqueIndexes;
459
    }
460
461
    /**
462
     * {@inheritdoc}
463
     */
464 17
    public function createColumnSchemaBuilder($type, $length = null)
465
    {
466 17
        return new ColumnSchemaBuilder($type, $length, $this->db);
467
    }
468
469
    /**
470
     * @return bool whether the version of the MySQL being used is older than 5.1.
471
     * @throws InvalidConfigException
472
     * @throws Exception
473
     * @since 2.0.13
474
     */
475
    protected function isOldMysql()
476
    {
477
        if ($this->_oldMysql === null) {
478
            $version = $this->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
479
            $this->_oldMysql = version_compare($version, '5.1', '<=');
480
        }
481
482
        return $this->_oldMysql;
483
    }
484
485
    /**
486
     * Loads multiple types of constraints and returns the specified ones.
487
     * @param string $tableName table name.
488
     * @param string $returnType return type:
489
     * - primaryKey
490
     * - foreignKeys
491
     * - uniques
492
     * @return mixed constraints.
493
     */
494 71
    private function loadTableConstraints($tableName, $returnType)
495
    {
496 71
        static $sql = <<<'SQL'
497
SELECT
498
    `kcu`.`CONSTRAINT_NAME` AS `name`,
499
    `kcu`.`COLUMN_NAME` AS `column_name`,
500
    `tc`.`CONSTRAINT_TYPE` AS `type`,
501
    CASE
502
        WHEN :schemaName IS NULL AND `kcu`.`REFERENCED_TABLE_SCHEMA` = DATABASE() THEN NULL
503
        ELSE `kcu`.`REFERENCED_TABLE_SCHEMA`
504
    END AS `foreign_table_schema`,
505
    `kcu`.`REFERENCED_TABLE_NAME` AS `foreign_table_name`,
506
    `kcu`.`REFERENCED_COLUMN_NAME` AS `foreign_column_name`,
507
    `rc`.`UPDATE_RULE` AS `on_update`,
508
    `rc`.`DELETE_RULE` AS `on_delete`,
509
    `kcu`.`ORDINAL_POSITION` AS `position`
510
FROM
511
    `information_schema`.`KEY_COLUMN_USAGE` AS `kcu`,
512
    `information_schema`.`REFERENTIAL_CONSTRAINTS` AS `rc`,
513
    `information_schema`.`TABLE_CONSTRAINTS` AS `tc`
514
WHERE
515
    `kcu`.`TABLE_SCHEMA` = COALESCE(:schemaName1, DATABASE()) AND `kcu`.`CONSTRAINT_SCHEMA` = `kcu`.`TABLE_SCHEMA` AND `kcu`.`TABLE_NAME` = :tableName
516
    AND `rc`.`CONSTRAINT_SCHEMA` = `kcu`.`TABLE_SCHEMA` AND `rc`.`TABLE_NAME` = :tableName1 AND `rc`.`CONSTRAINT_NAME` = `kcu`.`CONSTRAINT_NAME`
517
    AND `tc`.`TABLE_SCHEMA` = `kcu`.`TABLE_SCHEMA` AND `tc`.`TABLE_NAME` = :tableName2 AND `tc`.`CONSTRAINT_NAME` = `kcu`.`CONSTRAINT_NAME` AND `tc`.`CONSTRAINT_TYPE` = 'FOREIGN KEY'
518
UNION
519
SELECT
520
    `kcu`.`CONSTRAINT_NAME` AS `name`,
521
    `kcu`.`COLUMN_NAME` AS `column_name`,
522
    `tc`.`CONSTRAINT_TYPE` AS `type`,
523
    NULL AS `foreign_table_schema`,
524
    NULL AS `foreign_table_name`,
525
    NULL AS `foreign_column_name`,
526
    NULL AS `on_update`,
527
    NULL AS `on_delete`,
528
    `kcu`.`ORDINAL_POSITION` AS `position`
529
FROM
530
    `information_schema`.`KEY_COLUMN_USAGE` AS `kcu`,
531
    `information_schema`.`TABLE_CONSTRAINTS` AS `tc`
532
WHERE
533
    `kcu`.`TABLE_SCHEMA` = COALESCE(:schemaName2, DATABASE()) AND `kcu`.`TABLE_NAME` = :tableName3
534
    AND `tc`.`TABLE_SCHEMA` = `kcu`.`TABLE_SCHEMA` AND `tc`.`TABLE_NAME` = :tableName4 AND `tc`.`CONSTRAINT_NAME` = `kcu`.`CONSTRAINT_NAME` AND `tc`.`CONSTRAINT_TYPE` IN ('PRIMARY KEY', 'UNIQUE')
535
ORDER BY `position` ASC
536
SQL;
537
538 71
        $resolvedName = $this->resolveTableName($tableName);
539 71
        $constraints = $this->db->createCommand($sql, [
540 71
            ':schemaName' => $resolvedName->schemaName,
541 71
            ':schemaName1' => $resolvedName->schemaName,
542 71
            ':schemaName2' => $resolvedName->schemaName,
543 71
            ':tableName' => $resolvedName->name,
544 71
            ':tableName1' => $resolvedName->name,
545 71
            ':tableName2' => $resolvedName->name,
546 71
            ':tableName3' => $resolvedName->name,
547 71
            ':tableName4' => $resolvedName->name
548 71
        ])->queryAll();
549 71
        $constraints = $this->normalizePdoRowKeyCase($constraints, true);
550 71
        $constraints = ArrayHelper::index($constraints, null, ['type', 'name']);
551
        $result = [
552 71
            'primaryKey' => null,
553
            'foreignKeys' => [],
554
            'uniques' => [],
555
        ];
556 71
        foreach ($constraints as $type => $names) {
557 71
            foreach ($names as $name => $constraint) {
558
                switch ($type) {
559 71
                    case 'PRIMARY KEY':
560 60
                        $result['primaryKey'] = new Constraint([
561 60
                            'columnNames' => ArrayHelper::getColumn($constraint, 'column_name'),
562
                        ]);
563 60
                        break;
564 46
                    case 'FOREIGN KEY':
565 10
                        $result['foreignKeys'][] = new ForeignKeyConstraint([
566 10
                            'name' => $name,
567 10
                            'columnNames' => ArrayHelper::getColumn($constraint, 'column_name'),
568 10
                            'foreignSchemaName' => $constraint[0]['foreign_table_schema'],
569 10
                            'foreignTableName' => $constraint[0]['foreign_table_name'],
570 10
                            'foreignColumnNames' => ArrayHelper::getColumn($constraint, 'foreign_column_name'),
571 10
                            'onDelete' => $constraint[0]['on_delete'],
572 10
                            'onUpdate' => $constraint[0]['on_update'],
573
                        ]);
574 10
                        break;
575 37
                    case 'UNIQUE':
576 37
                        $result['uniques'][] = new Constraint([
577 37
                            'name' => $name,
578 37
                            'columnNames' => ArrayHelper::getColumn($constraint, 'column_name'),
579
                        ]);
580 71
                        break;
581
                }
582
            }
583
        }
584 71
        foreach ($result as $type => $data) {
585 71
            $this->setTableMetadata($tableName, $type, $data);
586
        }
587
588 71
        return $result[$returnType];
589
    }
590
}
591