Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Doctrine\DBAL\Schema;
4
 
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
7
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
8
use Doctrine\DBAL\Events;
9
use Doctrine\DBAL\Exception;
10
use Doctrine\DBAL\Exception\DatabaseRequired;
11
use Doctrine\DBAL\Platforms\AbstractPlatform;
12
use Doctrine\DBAL\Result;
13
use Doctrine\Deprecations\Deprecation;
14
use Throwable;
15
 
16
use function array_filter;
17
use function array_intersect;
18
use function array_map;
19
use function array_values;
20
use function assert;
21
use function call_user_func_array;
22
use function count;
23
use function func_get_args;
24
use function is_callable;
25
use function is_string;
26
use function preg_match;
27
use function str_replace;
28
use function strtolower;
29
 
30
/**
31
 * Base class for schema managers. Schema managers are used to inspect and/or
32
 * modify the database schema/structure.
33
 *
34
 * @template T of AbstractPlatform
35
 */
36
abstract class AbstractSchemaManager
37
{
38
    /**
39
     * Holds instance of the Doctrine connection for this schema manager.
40
     *
41
     * @var Connection
42
     */
43
    protected $_conn;
44
 
45
    /**
46
     * Holds instance of the database platform used for this schema manager.
47
     *
48
     * @var T
49
     */
50
    protected $_platform;
51
 
52
    /** @param T $platform */
53
    public function __construct(Connection $connection, AbstractPlatform $platform)
54
    {
55
        $this->_conn     = $connection;
56
        $this->_platform = $platform;
57
    }
58
 
59
    /**
60
     * Returns the associated platform.
61
     *
62
     * @deprecated Use {@link Connection::getDatabasePlatform()} instead.
63
     *
64
     * @return T
65
     */
66
    public function getDatabasePlatform()
67
    {
68
        Deprecation::trigger(
69
            'doctrine/dbal',
70
            'https://github.com/doctrine/dbal/pull/5387',
71
            'AbstractSchemaManager::getDatabasePlatform() is deprecated.'
72
                . ' Use Connection::getDatabasePlatform() instead.',
73
        );
74
 
75
        return $this->_platform;
76
    }
77
 
78
    /**
79
     * Tries any method on the schema manager. Normally a method throws an
80
     * exception when your DBMS doesn't support it or if an error occurs.
81
     * This method allows you to try and method on your SchemaManager
82
     * instance and will return false if it does not work or is not supported.
83
     *
84
     * <code>
85
     * $result = $sm->tryMethod('dropView', 'view_name');
86
     * </code>
87
     *
88
     * @deprecated
89
     *
90
     * @return mixed
91
     */
92
    public function tryMethod()
93
    {
94
        Deprecation::triggerIfCalledFromOutside(
95
            'doctrine/dbal',
96
            'https://github.com/doctrine/dbal/pull/4897',
97
            'AbstractSchemaManager::tryMethod() is deprecated.',
98
        );
99
 
100
        $args   = func_get_args();
101
        $method = $args[0];
102
        unset($args[0]);
103
        $args = array_values($args);
104
 
105
        $callback = [$this, $method];
106
        assert(is_callable($callback));
107
 
108
        try {
109
            return call_user_func_array($callback, $args);
110
        } catch (Throwable $e) {
111
            return false;
112
        }
113
    }
114
 
115
    /**
116
     * Lists the available databases for this connection.
117
     *
118
     * @return string[]
119
     *
120
     * @throws Exception
121
     */
122
    public function listDatabases()
123
    {
124
        $sql = $this->_platform->getListDatabasesSQL();
125
 
126
        $databases = $this->_conn->fetchAllAssociative($sql);
127
 
128
        return $this->_getPortableDatabasesList($databases);
129
    }
130
 
131
    /**
132
     * Returns a list of all namespaces in the current database.
133
     *
134
     * @deprecated Use {@see listSchemaNames()} instead.
135
     *
136
     * @return string[]
137
     *
138
     * @throws Exception
139
     */
140
    public function listNamespaceNames()
141
    {
142
        Deprecation::triggerIfCalledFromOutside(
143
            'doctrine/dbal',
144
            'https://github.com/doctrine/dbal/issues/4503',
145
            'AbstractSchemaManager::listNamespaceNames() is deprecated,'
146
                . ' use AbstractSchemaManager::listSchemaNames() instead.',
147
        );
148
 
149
        $sql = $this->_platform->getListNamespacesSQL();
150
 
151
        $namespaces = $this->_conn->fetchAllAssociative($sql);
152
 
153
        return $this->getPortableNamespacesList($namespaces);
154
    }
155
 
156
    /**
157
     * Returns a list of the names of all schemata in the current database.
158
     *
159
     * @return list<string>
160
     *
161
     * @throws Exception
162
     */
163
    public function listSchemaNames(): array
164
    {
165
        throw Exception::notSupported(__METHOD__);
166
    }
167
 
168
    /**
169
     * Lists the available sequences for this connection.
170
     *
171
     * @param string|null $database
172
     *
173
     * @return Sequence[]
174
     *
175
     * @throws Exception
176
     */
177
    public function listSequences($database = null)
178
    {
179
        if ($database === null) {
180
            $database = $this->getDatabase(__METHOD__);
181
        } else {
182
            Deprecation::trigger(
183
                'doctrine/dbal',
184
                'https://github.com/doctrine/dbal/issues/5284',
185
                'Passing $database to AbstractSchemaManager::listSequences() is deprecated.',
186
            );
187
        }
188
 
189
        $sql = $this->_platform->getListSequencesSQL($database);
190
 
191
        $sequences = $this->_conn->fetchAllAssociative($sql);
192
 
193
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
194
    }
195
 
196
    /**
197
     * Lists the columns for a given table.
198
     *
199
     * In contrast to other libraries and to the old version of Doctrine,
200
     * this column definition does try to contain the 'primary' column for
201
     * the reason that it is not portable across different RDBMS. Use
202
     * {@see listTableIndexes($tableName)} to retrieve the primary key
203
     * of a table. Where a RDBMS specifies more details, these are held
204
     * in the platformDetails array.
205
     *
206
     * @param string      $table    The name of the table.
207
     * @param string|null $database
208
     *
209
     * @return Column[]
210
     *
211
     * @throws Exception
212
     */
213
    public function listTableColumns($table, $database = null)
214
    {
215
        if ($database === null) {
216
            $database = $this->getDatabase(__METHOD__);
217
        } else {
218
            Deprecation::trigger(
219
                'doctrine/dbal',
220
                'https://github.com/doctrine/dbal/issues/5284',
221
                'Passing $database to AbstractSchemaManager::listTableColumns() is deprecated.',
222
            );
223
        }
224
 
225
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
226
 
227
        $tableColumns = $this->_conn->fetchAllAssociative($sql);
228
 
229
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
230
    }
231
 
232
    /**
233
     * @param string      $table
234
     * @param string|null $database
235
     *
236
     * @return Column[]
237
     *
238
     * @throws Exception
239
     */
240
    protected function doListTableColumns($table, $database = null): array
241
    {
242
        if ($database === null) {
243
            $database = $this->getDatabase(__METHOD__);
244
        } else {
245
            Deprecation::trigger(
246
                'doctrine/dbal',
247
                'https://github.com/doctrine/dbal/issues/5284',
248
                'Passing $database to AbstractSchemaManager::listTableColumns() is deprecated.',
249
            );
250
        }
251
 
252
        return $this->_getPortableTableColumnList(
253
            $table,
254
            $database,
255
            $this->selectTableColumns($database, $this->normalizeName($table))
256
                ->fetchAllAssociative(),
257
        );
258
    }
259
 
260
    /**
261
     * Lists the indexes for a given table returning an array of Index instances.
262
     *
263
     * Keys of the portable indexes list are all lower-cased.
264
     *
265
     * @param string $table The name of the table.
266
     *
267
     * @return Index[]
268
     *
269
     * @throws Exception
270
     */
271
    public function listTableIndexes($table)
272
    {
273
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
274
 
275
        $tableIndexes = $this->_conn->fetchAllAssociative($sql);
276
 
277
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
278
    }
279
 
280
    /**
281
     * @param string $table
282
     *
283
     * @return Index[]
284
     *
285
     * @throws Exception
286
     */
287
    protected function doListTableIndexes($table): array
288
    {
289
        $database = $this->getDatabase(__METHOD__);
290
        $table    = $this->normalizeName($table);
291
 
292
        return $this->_getPortableTableIndexesList(
293
            $this->selectIndexColumns(
294
                $database,
295
                $table,
296
            )->fetchAllAssociative(),
297
            $table,
298
        );
299
    }
300
 
301
    /**
302
     * Returns true if all the given tables exist.
303
     *
304
     * The usage of a string $tableNames is deprecated. Pass a one-element array instead.
305
     *
306
     * @param string|string[] $names
307
     *
308
     * @return bool
309
     *
310
     * @throws Exception
311
     */
312
    public function tablesExist($names)
313
    {
314
        if (is_string($names)) {
315
            Deprecation::trigger(
316
                'doctrine/dbal',
317
                'https://github.com/doctrine/dbal/issues/3580',
318
                'The usage of a string $tableNames in AbstractSchemaManager::tablesExist() is deprecated. ' .
319
                'Pass a one-element array instead.',
320
            );
321
        }
322
 
323
        $names = array_map('strtolower', (array) $names);
324
 
325
        return count($names) === count(array_intersect($names, array_map('strtolower', $this->listTableNames())));
326
    }
327
 
328
    /**
329
     * Returns a list of all tables in the current database.
330
     *
331
     * @return string[]
332
     *
333
     * @throws Exception
334
     */
335
    public function listTableNames()
336
    {
337
        $sql = $this->_platform->getListTablesSQL();
338
 
339
        $tables     = $this->_conn->fetchAllAssociative($sql);
340
        $tableNames = $this->_getPortableTablesList($tables);
341
 
342
        return $this->filterAssetNames($tableNames);
343
    }
344
 
345
    /**
346
     * @return list<string>
347
     *
348
     * @throws Exception
349
     */
350
    protected function doListTableNames(): array
351
    {
352
        $database = $this->getDatabase(__METHOD__);
353
 
354
        return $this->filterAssetNames(
355
            $this->_getPortableTablesList(
356
                $this->selectTableNames($database)
357
                    ->fetchAllAssociative(),
358
            ),
359
        );
360
    }
361
 
362
    /**
363
     * Filters asset names if they are configured to return only a subset of all
364
     * the found elements.
365
     *
366
     * @param mixed[] $assetNames
367
     *
368
     * @return mixed[]
369
     */
370
    protected function filterAssetNames($assetNames)
371
    {
372
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
373
        if ($filter === null) {
374
            return $assetNames;
375
        }
376
 
377
        return array_values(array_filter($assetNames, $filter));
378
    }
379
 
380
    /**
381
     * Lists the tables for this connection.
382
     *
383
     * @return list<Table>
384
     *
385
     * @throws Exception
386
     */
387
    public function listTables()
388
    {
389
        $tableNames = $this->listTableNames();
390
 
391
        $tables = [];
392
        foreach ($tableNames as $tableName) {
393
            $tables[] = $this->introspectTable($tableName);
394
        }
395
 
396
        return $tables;
397
    }
398
 
399
    /**
400
     * @return list<Table>
401
     *
402
     * @throws Exception
403
     */
404
    protected function doListTables(): array
405
    {
406
        $database = $this->getDatabase(__METHOD__);
407
 
408
        $tableColumnsByTable      = $this->fetchTableColumnsByTable($database);
409
        $indexColumnsByTable      = $this->fetchIndexColumnsByTable($database);
410
        $foreignKeyColumnsByTable = $this->fetchForeignKeyColumnsByTable($database);
411
        $tableOptionsByTable      = $this->fetchTableOptionsByTable($database);
412
 
413
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
414
        $tables = [];
415
 
416
        foreach ($tableColumnsByTable as $tableName => $tableColumns) {
417
            if ($filter !== null && ! $filter($tableName)) {
418
                continue;
419
            }
420
 
421
            $tables[] = new Table(
422
                $tableName,
423
                $this->_getPortableTableColumnList($tableName, $database, $tableColumns),
424
                $this->_getPortableTableIndexesList($indexColumnsByTable[$tableName] ?? [], $tableName),
425
                [],
426
                $this->_getPortableTableForeignKeysList($foreignKeyColumnsByTable[$tableName] ?? []),
427
                $tableOptionsByTable[$tableName] ?? [],
428
            );
429
        }
430
 
431
        return $tables;
432
    }
433
 
434
    /**
435
     * @deprecated Use {@see introspectTable()} instead.
436
     *
437
     * @param string $name
438
     *
439
     * @return Table
440
     *
441
     * @throws Exception
442
     */
443
    public function listTableDetails($name)
444
    {
445
        Deprecation::trigger(
446
            'doctrine/dbal',
447
            'https://github.com/doctrine/dbal/pull/5595',
448
            '%s is deprecated. Use introspectTable() instead.',
449
            __METHOD__,
450
        );
451
 
452
        $columns     = $this->listTableColumns($name);
453
        $foreignKeys = [];
454
 
455
        if ($this->_platform->supportsForeignKeyConstraints()) {
456
            $foreignKeys = $this->listTableForeignKeys($name);
457
        }
458
 
459
        $indexes = $this->listTableIndexes($name);
460
 
461
        return new Table($name, $columns, $indexes, [], $foreignKeys);
462
    }
463
 
464
    /**
465
     * @param string $name
466
     *
467
     * @throws Exception
468
     */
469
    protected function doListTableDetails($name): Table
470
    {
471
        $database = $this->getDatabase(__METHOD__);
472
 
473
        $normalizedName = $this->normalizeName($name);
474
 
475
        $tableOptionsByTable = $this->fetchTableOptionsByTable($database, $normalizedName);
476
 
477
        if ($this->_platform->supportsForeignKeyConstraints()) {
478
            $foreignKeys = $this->listTableForeignKeys($name);
479
        } else {
480
            $foreignKeys = [];
481
        }
482
 
483
        return new Table(
484
            $name,
485
            $this->listTableColumns($name, $database),
486
            $this->listTableIndexes($name),
487
            [],
488
            $foreignKeys,
489
            $tableOptionsByTable[$normalizedName] ?? [],
490
        );
491
    }
492
 
493
    /**
494
     * An extension point for those platforms where case sensitivity of the object name depends on whether it's quoted.
495
     *
496
     * Such platforms should convert a possibly quoted name into a value of the corresponding case.
497
     */
498
    protected function normalizeName(string $name): string
499
    {
500
        $identifier = new Identifier($name);
501
 
502
        return $identifier->getName();
503
    }
504
 
505
    /**
506
     * Selects names of tables in the specified database.
507
     *
508
     * @throws Exception
509
     *
510
     * @abstract
511
     */
512
    protected function selectTableNames(string $databaseName): Result
513
    {
514
        throw Exception::notSupported(__METHOD__);
515
    }
516
 
517
    /**
518
     * Selects definitions of table columns in the specified database. If the table name is specified, narrows down
519
     * the selection to this table.
520
     *
521
     * @throws Exception
522
     *
523
     * @abstract
524
     */
525
    protected function selectTableColumns(string $databaseName, ?string $tableName = null): Result
526
    {
527
        throw Exception::notSupported(__METHOD__);
528
    }
529
 
530
    /**
531
     * Selects definitions of index columns in the specified database. If the table name is specified, narrows down
532
     * the selection to this table.
533
     *
534
     * @throws Exception
535
     */
536
    protected function selectIndexColumns(string $databaseName, ?string $tableName = null): Result
537
    {
538
        throw Exception::notSupported(__METHOD__);
539
    }
540
 
541
    /**
542
     * Selects definitions of foreign key columns in the specified database. If the table name is specified,
543
     * narrows down the selection to this table.
544
     *
545
     * @throws Exception
546
     */
547
    protected function selectForeignKeyColumns(string $databaseName, ?string $tableName = null): Result
548
    {
549
        throw Exception::notSupported(__METHOD__);
550
    }
551
 
552
    /**
553
     * Fetches definitions of table columns in the specified database and returns them grouped by table name.
554
     *
555
     * @return array<string,list<array<string,mixed>>>
556
     *
557
     * @throws Exception
558
     */
559
    protected function fetchTableColumnsByTable(string $databaseName): array
560
    {
561
        return $this->fetchAllAssociativeGrouped($this->selectTableColumns($databaseName));
562
    }
563
 
564
    /**
565
     * Fetches definitions of index columns in the specified database and returns them grouped by table name.
566
     *
567
     * @return array<string,list<array<string,mixed>>>
568
     *
569
     * @throws Exception
570
     */
571
    protected function fetchIndexColumnsByTable(string $databaseName): array
572
    {
573
        return $this->fetchAllAssociativeGrouped($this->selectIndexColumns($databaseName));
574
    }
575
 
576
    /**
577
     * Fetches definitions of foreign key columns in the specified database and returns them grouped by table name.
578
     *
579
     * @return array<string, list<array<string, mixed>>>
580
     *
581
     * @throws Exception
582
     */
583
    protected function fetchForeignKeyColumnsByTable(string $databaseName): array
584
    {
585
        if (! $this->_platform->supportsForeignKeyConstraints()) {
586
            return [];
587
        }
588
 
589
        return $this->fetchAllAssociativeGrouped(
590
            $this->selectForeignKeyColumns($databaseName),
591
        );
592
    }
593
 
594
    /**
595
     * Fetches table options for the tables in the specified database and returns them grouped by table name.
596
     * If the table name is specified, narrows down the selection to this table.
597
     *
598
     * @return array<string,array<string,mixed>>
599
     *
600
     * @throws Exception
601
     */
602
    protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array
603
    {
604
        throw Exception::notSupported(__METHOD__);
605
    }
606
 
607
    /**
608
     * Introspects the table with the given name.
609
     *
610
     * @throws Exception
611
     */
612
    public function introspectTable(string $name): Table
613
    {
614
        $table = $this->listTableDetails($name);
615
 
616
        if ($table->getColumns() === []) {
617
            throw SchemaException::tableDoesNotExist($name);
618
        }
619
 
620
        return $table;
621
    }
622
 
623
    /**
624
     * Lists the views this connection has.
625
     *
626
     * @return View[]
627
     *
628
     * @throws Exception
629
     */
630
    public function listViews()
631
    {
632
        $database = $this->_conn->getDatabase();
633
        $sql      = $this->_platform->getListViewsSQL($database);
634
        $views    = $this->_conn->fetchAllAssociative($sql);
635
 
636
        return $this->_getPortableViewsList($views);
637
    }
638
 
639
    /**
640
     * Lists the foreign keys for the given table.
641
     *
642
     * @param string      $table    The name of the table.
643
     * @param string|null $database
644
     *
645
     * @return ForeignKeyConstraint[]
646
     *
647
     * @throws Exception
648
     */
649
    public function listTableForeignKeys($table, $database = null)
650
    {
651
        if ($database === null) {
652
            $database = $this->getDatabase(__METHOD__);
653
        } else {
654
            Deprecation::trigger(
655
                'doctrine/dbal',
656
                'https://github.com/doctrine/dbal/issues/5284',
657
                'Passing $database to AbstractSchemaManager::listTableForeignKeys() is deprecated.',
658
            );
659
        }
660
 
661
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);
662
        $tableForeignKeys = $this->_conn->fetchAllAssociative($sql);
663
 
664
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
665
    }
666
 
667
    /**
668
     * @param string      $table
669
     * @param string|null $database
670
     *
671
     * @return ForeignKeyConstraint[]
672
     *
673
     * @throws Exception
674
     */
675
    protected function doListTableForeignKeys($table, $database = null): array
676
    {
677
        if ($database === null) {
678
            $database = $this->getDatabase(__METHOD__);
679
        } else {
680
            Deprecation::trigger(
681
                'doctrine/dbal',
682
                'https://github.com/doctrine/dbal/issues/5284',
683
                'Passing $database to AbstractSchemaManager::listTableForeignKeys() is deprecated.',
684
            );
685
        }
686
 
687
        return $this->_getPortableTableForeignKeysList(
688
            $this->selectForeignKeyColumns(
689
                $database,
690
                $this->normalizeName($table),
691
            )->fetchAllAssociative(),
692
        );
693
    }
694
 
695
    /* drop*() Methods */
696
 
697
    /**
698
     * Drops a database.
699
     *
700
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
701
     *
702
     * @param string $database The name of the database to drop.
703
     *
704
     * @return void
705
     *
706
     * @throws Exception
707
     */
708
    public function dropDatabase($database)
709
    {
710
        $this->_conn->executeStatement(
711
            $this->_platform->getDropDatabaseSQL($database),
712
        );
713
    }
714
 
715
    /**
716
     * Drops a schema.
717
     *
718
     * @throws Exception
719
     */
720
    public function dropSchema(string $schemaName): void
721
    {
722
        $this->_conn->executeStatement(
723
            $this->_platform->getDropSchemaSQL($schemaName),
724
        );
725
    }
726
 
727
    /**
728
     * Drops the given table.
729
     *
730
     * @param string $name The name of the table to drop.
731
     *
732
     * @return void
733
     *
734
     * @throws Exception
735
     */
736
    public function dropTable($name)
737
    {
738
        $this->_conn->executeStatement(
739
            $this->_platform->getDropTableSQL($name),
740
        );
741
    }
742
 
743
    /**
744
     * Drops the index from the given table.
745
     *
746
     * @param Index|string $index The name of the index.
747
     * @param Table|string $table The name of the table.
748
     *
749
     * @return void
750
     *
751
     * @throws Exception
752
     */
753
    public function dropIndex($index, $table)
754
    {
755
        if ($index instanceof Index) {
756
            Deprecation::trigger(
757
                'doctrine/dbal',
758
                'https://github.com/doctrine/dbal/issues/4798',
759
                'Passing $index as an Index object to %s is deprecated. Pass it as a quoted name instead.',
760
                __METHOD__,
761
            );
762
 
763
            $index = $index->getQuotedName($this->_platform);
764
        }
765
 
766
        if ($table instanceof Table) {
767
            Deprecation::trigger(
768
                'doctrine/dbal',
769
                'https://github.com/doctrine/dbal/issues/4798',
770
                'Passing $table as an Table object to %s is deprecated. Pass it as a quoted name instead.',
771
                __METHOD__,
772
            );
773
 
774
            $table = $table->getQuotedName($this->_platform);
775
        }
776
 
777
        $this->_conn->executeStatement(
778
            $this->_platform->getDropIndexSQL($index, $table),
779
        );
780
    }
781
 
782
    /**
783
     * Drops the constraint from the given table.
784
     *
785
     * @deprecated Use {@see dropIndex()}, {@see dropForeignKey()} or {@see dropUniqueConstraint()} instead.
786
     *
787
     * @param Table|string $table The name of the table.
788
     *
789
     * @return void
790
     *
791
     * @throws Exception
792
     */
793
    public function dropConstraint(Constraint $constraint, $table)
794
    {
795
        if ($table instanceof Table) {
796
            Deprecation::trigger(
797
                'doctrine/dbal',
798
                'https://github.com/doctrine/dbal/issues/4798',
799
                'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
800
                __METHOD__,
801
            );
802
 
803
            $table = $table->getQuotedName($this->_platform);
804
        }
805
 
806
        $this->_conn->executeStatement($this->_platform->getDropConstraintSQL(
807
            $constraint->getQuotedName($this->_platform),
808
            $table,
809
        ));
810
    }
811
 
812
    /**
813
     * Drops a foreign key from a table.
814
     *
815
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
816
     * @param Table|string                $table      The name of the table with the foreign key.
817
     *
818
     * @return void
819
     *
820
     * @throws Exception
821
     */
822
    public function dropForeignKey($foreignKey, $table)
823
    {
824
        if ($foreignKey instanceof ForeignKeyConstraint) {
825
            Deprecation::trigger(
826
                'doctrine/dbal',
827
                'https://github.com/doctrine/dbal/issues/4798',
828
                'Passing $foreignKey as a ForeignKeyConstraint object to %s is deprecated.'
829
                . ' Pass it as a quoted name instead.',
830
                __METHOD__,
831
            );
832
 
833
            $foreignKey = $foreignKey->getQuotedName($this->_platform);
834
        }
835
 
836
        if ($table instanceof Table) {
837
            Deprecation::trigger(
838
                'doctrine/dbal',
839
                'https://github.com/doctrine/dbal/issues/4798',
840
                'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
841
                __METHOD__,
842
            );
843
 
844
            $table = $table->getQuotedName($this->_platform);
845
        }
846
 
847
        $this->_conn->executeStatement(
848
            $this->_platform->getDropForeignKeySQL($foreignKey, $table),
849
        );
850
    }
851
 
852
    /**
853
     * Drops a sequence with a given name.
854
     *
855
     * @param string $name The name of the sequence to drop.
856
     *
857
     * @return void
858
     *
859
     * @throws Exception
860
     */
861
    public function dropSequence($name)
862
    {
863
        $this->_conn->executeStatement(
864
            $this->_platform->getDropSequenceSQL($name),
865
        );
866
    }
867
 
868
    /**
869
     * Drops the unique constraint from the given table.
870
     *
871
     * @throws Exception
872
     */
873
    public function dropUniqueConstraint(string $name, string $tableName): void
874
    {
875
        $this->_conn->executeStatement(
876
            $this->_platform->getDropUniqueConstraintSQL($name, $tableName),
877
        );
878
    }
879
 
880
    /**
881
     * Drops a view.
882
     *
883
     * @param string $name The name of the view.
884
     *
885
     * @return void
886
     *
887
     * @throws Exception
888
     */
889
    public function dropView($name)
890
    {
891
        $this->_conn->executeStatement(
892
            $this->_platform->getDropViewSQL($name),
893
        );
894
    }
895
 
896
    /* create*() Methods */
897
 
898
    /** @throws Exception */
899
    public function createSchemaObjects(Schema $schema): void
900
    {
901
        $this->_execSql($schema->toSql($this->_platform));
902
    }
903
 
904
    /**
905
     * Creates a new database.
906
     *
907
     * @param string $database The name of the database to create.
908
     *
909
     * @return void
910
     *
911
     * @throws Exception
912
     */
913
    public function createDatabase($database)
914
    {
915
        $this->_conn->executeStatement(
916
            $this->_platform->getCreateDatabaseSQL($database),
917
        );
918
    }
919
 
920
    /**
921
     * Creates a new table.
922
     *
923
     * @return void
924
     *
925
     * @throws Exception
926
     */
927
    public function createTable(Table $table)
928
    {
929
        $createFlags = AbstractPlatform::CREATE_INDEXES | AbstractPlatform::CREATE_FOREIGNKEYS;
930
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
931
    }
932
 
933
    /**
934
     * Creates a new sequence.
935
     *
936
     * @param Sequence $sequence
937
     *
938
     * @return void
939
     *
940
     * @throws Exception
941
     */
942
    public function createSequence($sequence)
943
    {
944
        $this->_conn->executeStatement(
945
            $this->_platform->getCreateSequenceSQL($sequence),
946
        );
947
    }
948
 
949
    /**
950
     * Creates a constraint on a table.
951
     *
952
     * @deprecated Use {@see createIndex()}, {@see createForeignKey()} or {@see createUniqueConstraint()} instead.
953
     *
954
     * @param Table|string $table
955
     *
956
     * @return void
957
     *
958
     * @throws Exception
959
     */
960
    public function createConstraint(Constraint $constraint, $table)
961
    {
962
        $this->_conn->executeStatement(
963
            $this->_platform->getCreateConstraintSQL($constraint, $table),
964
        );
965
    }
966
 
967
    /**
968
     * Creates a new index on a table.
969
     *
970
     * @param Table|string $table The name of the table on which the index is to be created.
971
     *
972
     * @return void
973
     *
974
     * @throws Exception
975
     */
976
    public function createIndex(Index $index, $table)
977
    {
978
        $this->_conn->executeStatement(
979
            $this->_platform->getCreateIndexSQL($index, $table),
980
        );
981
    }
982
 
983
    /**
984
     * Creates a new foreign key.
985
     *
986
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
987
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
988
     *
989
     * @return void
990
     *
991
     * @throws Exception
992
     */
993
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
994
    {
995
        $this->_conn->executeStatement(
996
            $this->_platform->getCreateForeignKeySQL($foreignKey, $table),
997
        );
998
    }
999
 
1000
    /**
1001
     * Creates a unique constraint on a table.
1002
     *
1003
     * @throws Exception
1004
     */
1005
    public function createUniqueConstraint(UniqueConstraint $uniqueConstraint, string $tableName): void
1006
    {
1007
        $this->_conn->executeStatement(
1008
            $this->_platform->getCreateUniqueConstraintSQL($uniqueConstraint, $tableName),
1009
        );
1010
    }
1011
 
1012
    /**
1013
     * Creates a new view.
1014
     *
1015
     * @return void
1016
     *
1017
     * @throws Exception
1018
     */
1019
    public function createView(View $view)
1020
    {
1021
        $this->_conn->executeStatement(
1022
            $this->_platform->getCreateViewSQL(
1023
                $view->getQuotedName($this->_platform),
1024
                $view->getSql(),
1025
            ),
1026
        );
1027
    }
1028
 
1029
    /* dropAndCreate*() Methods */
1030
 
1031
    /** @throws Exception */
1032
    public function dropSchemaObjects(Schema $schema): void
1033
    {
1034
        $this->_execSql($schema->toDropSql($this->_platform));
1035
    }
1036
 
1037
    /**
1038
     * Drops and creates a constraint.
1039
     *
1040
     * @deprecated Use {@see dropIndex()} and {@see createIndex()},
1041
     *             {@see dropForeignKey()} and {@see createForeignKey()}
1042
     *             or {@see dropUniqueConstraint()} and {@see createUniqueConstraint()} instead.
1043
     *
1044
     * @see dropConstraint()
1045
     * @see createConstraint()
1046
     *
1047
     * @param Table|string $table
1048
     *
1049
     * @return void
1050
     *
1051
     * @throws Exception
1052
     */
1053
    public function dropAndCreateConstraint(Constraint $constraint, $table)
1054
    {
1055
        Deprecation::trigger(
1056
            'doctrine/dbal',
1057
            'https://github.com/doctrine/dbal/pull/4897',
1058
            'AbstractSchemaManager::dropAndCreateConstraint() is deprecated.'
1059
                . ' Use AbstractSchemaManager::dropIndex() and AbstractSchemaManager::createIndex(),'
1060
                . ' AbstractSchemaManager::dropForeignKey() and AbstractSchemaManager::createForeignKey()'
1061
                . ' or AbstractSchemaManager::dropUniqueConstraint()'
1062
                . ' and AbstractSchemaManager::createUniqueConstraint() instead.',
1063
        );
1064
 
1065
        $this->tryMethod('dropConstraint', $constraint, $table);
1066
        $this->createConstraint($constraint, $table);
1067
    }
1068
 
1069
    /**
1070
     * Drops and creates a new index on a table.
1071
     *
1072
     * @deprecated Use {@see dropIndex()} and {@see createIndex()} instead.
1073
     *
1074
     * @param Table|string $table The name of the table on which the index is to be created.
1075
     *
1076
     * @return void
1077
     *
1078
     * @throws Exception
1079
     */
1080
    public function dropAndCreateIndex(Index $index, $table)
1081
    {
1082
        Deprecation::trigger(
1083
            'doctrine/dbal',
1084
            'https://github.com/doctrine/dbal/pull/4897',
1085
            'AbstractSchemaManager::dropAndCreateIndex() is deprecated.'
1086
            . ' Use AbstractSchemaManager::dropIndex() and AbstractSchemaManager::createIndex() instead.',
1087
        );
1088
 
1089
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
1090
        $this->createIndex($index, $table);
1091
    }
1092
 
1093
    /**
1094
     * Drops and creates a new foreign key.
1095
     *
1096
     * @deprecated Use {@see dropForeignKey()} and {@see createForeignKey()} instead.
1097
     *
1098
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties
1099
     *                                         of the foreign key to be created.
1100
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
1101
     *
1102
     * @return void
1103
     *
1104
     * @throws Exception
1105
     */
1106
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
1107
    {
1108
        Deprecation::trigger(
1109
            'doctrine/dbal',
1110
            'https://github.com/doctrine/dbal/pull/4897',
1111
            'AbstractSchemaManager::dropAndCreateForeignKey() is deprecated.'
1112
            . ' Use AbstractSchemaManager::dropForeignKey() and AbstractSchemaManager::createForeignKey() instead.',
1113
        );
1114
 
1115
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
1116
        $this->createForeignKey($foreignKey, $table);
1117
    }
1118
 
1119
    /**
1120
     * Drops and create a new sequence.
1121
     *
1122
     * @deprecated Use {@see dropSequence()} and {@see createSequence()} instead.
1123
     *
1124
     * @return void
1125
     *
1126
     * @throws Exception
1127
     */
1128
    public function dropAndCreateSequence(Sequence $sequence)
1129
    {
1130
        Deprecation::trigger(
1131
            'doctrine/dbal',
1132
            'https://github.com/doctrine/dbal/pull/4897',
1133
            'AbstractSchemaManager::dropAndCreateSequence() is deprecated.'
1134
            . ' Use AbstractSchemaManager::dropSequence() and AbstractSchemaManager::createSequence() instead.',
1135
        );
1136
 
1137
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
1138
        $this->createSequence($sequence);
1139
    }
1140
 
1141
    /**
1142
     * Drops and creates a new table.
1143
     *
1144
     * @deprecated Use {@see dropTable()} and {@see createTable()} instead.
1145
     *
1146
     * @return void
1147
     *
1148
     * @throws Exception
1149
     */
1150
    public function dropAndCreateTable(Table $table)
1151
    {
1152
        Deprecation::trigger(
1153
            'doctrine/dbal',
1154
            'https://github.com/doctrine/dbal/pull/4897',
1155
            'AbstractSchemaManager::dropAndCreateTable() is deprecated.'
1156
            . ' Use AbstractSchemaManager::dropTable() and AbstractSchemaManager::createTable() instead.',
1157
        );
1158
 
1159
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
1160
        $this->createTable($table);
1161
    }
1162
 
1163
    /**
1164
     * Drops and creates a new database.
1165
     *
1166
     * @deprecated Use {@see dropDatabase()} and {@see createDatabase()} instead.
1167
     *
1168
     * @param string $database The name of the database to create.
1169
     *
1170
     * @return void
1171
     *
1172
     * @throws Exception
1173
     */
1174
    public function dropAndCreateDatabase($database)
1175
    {
1176
        Deprecation::trigger(
1177
            'doctrine/dbal',
1178
            'https://github.com/doctrine/dbal/pull/4897',
1179
            'AbstractSchemaManager::dropAndCreateDatabase() is deprecated.'
1180
            . ' Use AbstractSchemaManager::dropDatabase() and AbstractSchemaManager::createDatabase() instead.',
1181
        );
1182
 
1183
        $this->tryMethod('dropDatabase', $database);
1184
        $this->createDatabase($database);
1185
    }
1186
 
1187
    /**
1188
     * Drops and creates a new view.
1189
     *
1190
     * @deprecated Use {@see dropView()} and {@see createView()} instead.
1191
     *
1192
     * @return void
1193
     *
1194
     * @throws Exception
1195
     */
1196
    public function dropAndCreateView(View $view)
1197
    {
1198
        Deprecation::trigger(
1199
            'doctrine/dbal',
1200
            'https://github.com/doctrine/dbal/pull/4897',
1201
            'AbstractSchemaManager::dropAndCreateView() is deprecated.'
1202
            . ' Use AbstractSchemaManager::dropView() and AbstractSchemaManager::createView() instead.',
1203
        );
1204
 
1205
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
1206
        $this->createView($view);
1207
    }
1208
 
1209
    /**
1210
     * Alters an existing schema.
1211
     *
1212
     * @throws Exception
1213
     */
1214
    public function alterSchema(SchemaDiff $schemaDiff): void
1215
    {
1216
        $this->_execSql($this->_platform->getAlterSchemaSQL($schemaDiff));
1217
    }
1218
 
1219
    /**
1220
     * Migrates an existing schema to a new schema.
1221
     *
1222
     * @throws Exception
1223
     */
1224
    public function migrateSchema(Schema $toSchema): void
1225
    {
1226
        $schemaDiff = $this->createComparator()
1227
            ->compareSchemas($this->introspectSchema(), $toSchema);
1228
 
1229
        $this->alterSchema($schemaDiff);
1230
    }
1231
 
1232
    /* alterTable() Methods */
1233
 
1234
    /**
1235
     * Alters an existing tables schema.
1236
     *
1237
     * @return void
1238
     *
1239
     * @throws Exception
1240
     */
1241
    public function alterTable(TableDiff $tableDiff)
1242
    {
1243
        $this->_execSql($this->_platform->getAlterTableSQL($tableDiff));
1244
    }
1245
 
1246
    /**
1247
     * Renames a given table to another name.
1248
     *
1249
     * @param string $name    The current name of the table.
1250
     * @param string $newName The new name of the table.
1251
     *
1252
     * @return void
1253
     *
1254
     * @throws Exception
1255
     */
1256
    public function renameTable($name, $newName)
1257
    {
1258
        $this->_execSql($this->_platform->getRenameTableSQL($name, $newName));
1259
    }
1260
 
1261
    /**
1262
     * Methods for filtering return values of list*() methods to convert
1263
     * the native DBMS data definition to a portable Doctrine definition
1264
     */
1265
 
1266
    /**
1267
     * @param mixed[] $databases
1268
     *
1269
     * @return string[]
1270
     */
1271
    protected function _getPortableDatabasesList($databases)
1272
    {
1273
        $list = [];
1274
        foreach ($databases as $value) {
1275
            $list[] = $this->_getPortableDatabaseDefinition($value);
1276
        }
1277
 
1278
        return $list;
1279
    }
1280
 
1281
    /**
1282
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
1283
     *
1284
     * @deprecated Use {@see listSchemaNames()} instead.
1285
     *
1286
     * @param array<int, array<string, mixed>> $namespaces The list of namespace names
1287
     *                                                     in the native DBMS data definition.
1288
     *
1289
     * @return string[]
1290
     */
1291
    protected function getPortableNamespacesList(array $namespaces)
1292
    {
1293
        Deprecation::triggerIfCalledFromOutside(
1294
            'doctrine/dbal',
1295
            'https://github.com/doctrine/dbal/issues/4503',
1296
            'AbstractSchemaManager::getPortableNamespacesList() is deprecated,'
1297
                . ' use AbstractSchemaManager::listSchemaNames() instead.',
1298
        );
1299
 
1300
        $namespacesList = [];
1301
 
1302
        foreach ($namespaces as $namespace) {
1303
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
1304
        }
1305
 
1306
        return $namespacesList;
1307
    }
1308
 
1309
    /**
1310
     * @param mixed $database
1311
     *
1312
     * @return mixed
1313
     */
1314
    protected function _getPortableDatabaseDefinition($database)
1315
    {
1316
        return $database;
1317
    }
1318
 
1319
    /**
1320
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
1321
     *
1322
     * @deprecated Use {@see listSchemaNames()} instead.
1323
     *
1324
     * @param array<string, mixed> $namespace The native DBMS namespace definition.
1325
     *
1326
     * @return mixed
1327
     */
1328
    protected function getPortableNamespaceDefinition(array $namespace)
1329
    {
1330
        Deprecation::triggerIfCalledFromOutside(
1331
            'doctrine/dbal',
1332
            'https://github.com/doctrine/dbal/issues/4503',
1333
            'AbstractSchemaManager::getPortableNamespaceDefinition() is deprecated,'
1334
                . ' use AbstractSchemaManager::listSchemaNames() instead.',
1335
        );
1336
 
1337
        return $namespace;
1338
    }
1339
 
1340
    /**
1341
     * @param mixed[][] $sequences
1342
     *
1343
     * @return Sequence[]
1344
     *
1345
     * @throws Exception
1346
     */
1347
    protected function _getPortableSequencesList($sequences)
1348
    {
1349
        $list = [];
1350
 
1351
        foreach ($sequences as $value) {
1352
            $list[] = $this->_getPortableSequenceDefinition($value);
1353
        }
1354
 
1355
        return $list;
1356
    }
1357
 
1358
    /**
1359
     * @param mixed[] $sequence
1360
     *
1361
     * @return Sequence
1362
     *
1363
     * @throws Exception
1364
     */
1365
    protected function _getPortableSequenceDefinition($sequence)
1366
    {
1367
        throw Exception::notSupported('Sequences');
1368
    }
1369
 
1370
    /**
1371
     * Independent of the database the keys of the column list result are lowercased.
1372
     *
1373
     * The name of the created column instance however is kept in its case.
1374
     *
1375
     * @param string    $table        The name of the table.
1376
     * @param string    $database
1377
     * @param mixed[][] $tableColumns
1378
     *
1379
     * @return Column[]
1380
     *
1381
     * @throws Exception
1382
     */
1383
    protected function _getPortableTableColumnList($table, $database, $tableColumns)
1384
    {
1385
        $eventManager = $this->_platform->getEventManager();
1386
 
1387
        $list = [];
1388
        foreach ($tableColumns as $tableColumn) {
1389
            $column           = null;
1390
            $defaultPrevented = false;
1391
 
1392
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
1393
                Deprecation::trigger(
1394
                    'doctrine/dbal',
1395
                    'https://github.com/doctrine/dbal/issues/5784',
1396
                    'Subscribing to %s events is deprecated. Use a custom schema manager instead.',
1397
                    Events::onSchemaColumnDefinition,
1398
                );
1399
 
1400
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
1401
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
1402
 
1403
                $defaultPrevented = $eventArgs->isDefaultPrevented();
1404
                $column           = $eventArgs->getColumn();
1405
            }
1406
 
1407
            if (! $defaultPrevented) {
1408
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
1409
            }
1410
 
1411
            if ($column === null) {
1412
                continue;
1413
            }
1414
 
1415
            $name        = strtolower($column->getQuotedName($this->_platform));
1416
            $list[$name] = $column;
1417
        }
1418
 
1419
        return $list;
1420
    }
1421
 
1422
    /**
1423
     * Gets Table Column Definition.
1424
     *
1425
     * @param mixed[] $tableColumn
1426
     *
1427
     * @return Column
1428
     *
1429
     * @throws Exception
1430
     */
1431
    abstract protected function _getPortableTableColumnDefinition($tableColumn);
1432
 
1433
    /**
1434
     * Aggregates and groups the index results according to the required data result.
1435
     *
1436
     * @param mixed[][]   $tableIndexes
1437
     * @param string|null $tableName
1438
     *
1439
     * @return Index[]
1440
     *
1441
     * @throws Exception
1442
     */
1443
    protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
1444
    {
1445
        $result = [];
1446
        foreach ($tableIndexes as $tableIndex) {
1447
            $indexName = $keyName = $tableIndex['key_name'];
1448
            if ($tableIndex['primary']) {
1449
                $keyName = 'primary';
1450
            }
1451
 
1452
            $keyName = strtolower($keyName);
1453
 
1454
            if (! isset($result[$keyName])) {
1455
                $options = [
1456
                    'lengths' => [],
1457
                ];
1458
 
1459
                if (isset($tableIndex['where'])) {
1460
                    $options['where'] = $tableIndex['where'];
1461
                }
1462
 
1463
                $result[$keyName] = [
1464
                    'name' => $indexName,
1465
                    'columns' => [],
1466
                    'unique' => ! $tableIndex['non_unique'],
1467
                    'primary' => $tableIndex['primary'],
1468
                    'flags' => $tableIndex['flags'] ?? [],
1469
                    'options' => $options,
1470
                ];
1471
            }
1472
 
1473
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
1474
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
1475
        }
1476
 
1477
        $eventManager = $this->_platform->getEventManager();
1478
 
1479
        $indexes = [];
1480
        foreach ($result as $indexKey => $data) {
1481
            $index            = null;
1482
            $defaultPrevented = false;
1483
 
1484
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
1485
                Deprecation::trigger(
1486
                    'doctrine/dbal',
1487
                    'https://github.com/doctrine/dbal/issues/5784',
1488
                    'Subscribing to %s events is deprecated. Use a custom schema manager instead.',
1489
                    Events::onSchemaColumnDefinition,
1490
                );
1491
 
1492
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
1493
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
1494
 
1495
                $defaultPrevented = $eventArgs->isDefaultPrevented();
1496
                $index            = $eventArgs->getIndex();
1497
            }
1498
 
1499
            if (! $defaultPrevented) {
1500
                $index = new Index(
1501
                    $data['name'],
1502
                    $data['columns'],
1503
                    $data['unique'],
1504
                    $data['primary'],
1505
                    $data['flags'],
1506
                    $data['options'],
1507
                );
1508
            }
1509
 
1510
            if ($index === null) {
1511
                continue;
1512
            }
1513
 
1514
            $indexes[$indexKey] = $index;
1515
        }
1516
 
1517
        return $indexes;
1518
    }
1519
 
1520
    /**
1521
     * @param mixed[][] $tables
1522
     *
1523
     * @return string[]
1524
     */
1525
    protected function _getPortableTablesList($tables)
1526
    {
1527
        $list = [];
1528
        foreach ($tables as $value) {
1529
            $list[] = $this->_getPortableTableDefinition($value);
1530
        }
1531
 
1532
        return $list;
1533
    }
1534
 
1535
    /**
1536
     * @param mixed $table
1537
     *
1538
     * @return string
1539
     */
1540
    protected function _getPortableTableDefinition($table)
1541
    {
1542
        return $table;
1543
    }
1544
 
1545
    /**
1546
     * @param mixed[][] $views
1547
     *
1548
     * @return View[]
1549
     */
1550
    protected function _getPortableViewsList($views)
1551
    {
1552
        $list = [];
1553
        foreach ($views as $value) {
1554
            $view = $this->_getPortableViewDefinition($value);
1555
 
1556
            if ($view === false) {
1557
                continue;
1558
            }
1559
 
1560
            $viewName        = strtolower($view->getQuotedName($this->_platform));
1561
            $list[$viewName] = $view;
1562
        }
1563
 
1564
        return $list;
1565
    }
1566
 
1567
    /**
1568
     * @param mixed[] $view
1569
     *
1570
     * @return View|false
1571
     */
1572
    protected function _getPortableViewDefinition($view)
1573
    {
1574
        return false;
1575
    }
1576
 
1577
    /**
1578
     * @param mixed[][] $tableForeignKeys
1579
     *
1580
     * @return ForeignKeyConstraint[]
1581
     */
1582
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
1583
    {
1584
        $list = [];
1585
 
1586
        foreach ($tableForeignKeys as $value) {
1587
            $list[] = $this->_getPortableTableForeignKeyDefinition($value);
1588
        }
1589
 
1590
        return $list;
1591
    }
1592
 
1593
    /**
1594
     * @param mixed $tableForeignKey
1595
     *
1596
     * @return ForeignKeyConstraint
1597
     *
1598
     * @abstract
1599
     */
1600
    protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
1601
    {
1602
        return $tableForeignKey;
1603
    }
1604
 
1605
    /**
1606
     * @internal
1607
     *
1608
     * @param string[]|string $sql
1609
     *
1610
     * @return void
1611
     *
1612
     * @throws Exception
1613
     */
1614
    protected function _execSql($sql)
1615
    {
1616
        foreach ((array) $sql as $query) {
1617
            $this->_conn->executeStatement($query);
1618
        }
1619
    }
1620
 
1621
    /**
1622
     * Creates a schema instance for the current database.
1623
     *
1624
     * @deprecated Use {@link introspectSchema()} instead.
1625
     *
1626
     * @return Schema
1627
     *
1628
     * @throws Exception
1629
     */
1630
    public function createSchema()
1631
    {
1632
        Deprecation::triggerIfCalledFromOutside(
1633
            'doctrine/dbal',
1634
            'https://github.com/doctrine/dbal/pull/5613',
1635
            '%s is deprecated. Use introspectSchema() instead.',
1636
            __METHOD__,
1637
        );
1638
 
1639
        $schemaNames = [];
1640
 
1641
        if ($this->_platform->supportsSchemas()) {
1642
            $schemaNames = $this->listNamespaceNames();
1643
        }
1644
 
1645
        $sequences = [];
1646
 
1647
        if ($this->_platform->supportsSequences()) {
1648
            $sequences = $this->listSequences();
1649
        }
1650
 
1651
        $tables = $this->listTables();
1652
 
1653
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames);
1654
    }
1655
 
1656
    /**
1657
     * Returns a {@see Schema} instance representing the current database schema.
1658
     *
1659
     * @throws Exception
1660
     */
1661
    public function introspectSchema(): Schema
1662
    {
1663
        return $this->createSchema();
1664
    }
1665
 
1666
    /**
1667
     * Creates the configuration for this schema.
1668
     *
1669
     * @return SchemaConfig
1670
     *
1671
     * @throws Exception
1672
     */
1673
    public function createSchemaConfig()
1674
    {
1675
        $schemaConfig = new SchemaConfig();
1676
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
1677
 
1678
        $searchPaths = $this->getSchemaSearchPaths();
1679
        if (isset($searchPaths[0])) {
1680
            $schemaConfig->setName($searchPaths[0]);
1681
        }
1682
 
1683
        $params = $this->_conn->getParams();
1684
        if (! isset($params['defaultTableOptions'])) {
1685
            $params['defaultTableOptions'] = [];
1686
        }
1687
 
1688
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
1689
            $params['defaultTableOptions']['charset'] = $params['charset'];
1690
        }
1691
 
1692
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
1693
 
1694
        return $schemaConfig;
1695
    }
1696
 
1697
    /**
1698
     * The search path for namespaces in the currently connected database.
1699
     *
1700
     * The first entry is usually the default namespace in the Schema. All
1701
     * further namespaces contain tables/sequences which can also be addressed
1702
     * with a short, not full-qualified name.
1703
     *
1704
     * For databases that don't support subschema/namespaces this method
1705
     * returns the name of the currently connected database.
1706
     *
1707
     * @deprecated
1708
     *
1709
     * @return string[]
1710
     *
1711
     * @throws Exception
1712
     */
1713
    public function getSchemaSearchPaths()
1714
    {
1715
        Deprecation::triggerIfCalledFromOutside(
1716
            'doctrine/dbal',
1717
            'https://github.com/doctrine/dbal/pull/4821',
1718
            'AbstractSchemaManager::getSchemaSearchPaths() is deprecated.',
1719
        );
1720
 
1721
        $database = $this->_conn->getDatabase();
1722
 
1723
        if ($database !== null) {
1724
            return [$database];
1725
        }
1726
 
1727
        return [];
1728
    }
1729
 
1730
    /**
1731
     * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
1732
     * the type given as default.
1733
     *
1734
     * @internal This method should be only used from within the AbstractSchemaManager class hierarchy.
1735
     *
1736
     * @param string|null $comment
1737
     * @param string      $currentType
1738
     *
1739
     * @return string
1740
     */
1741
    public function extractDoctrineTypeFromComment($comment, $currentType)
1742
    {
1743
        if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match) === 1) {
1744
            return $match[1];
1745
        }
1746
 
1747
        return $currentType;
1748
    }
1749
 
1750
    /**
1751
     * @internal This method should be only used from within the AbstractSchemaManager class hierarchy.
1752
     *
1753
     * @param string|null $comment
1754
     * @param string|null $type
1755
     *
1756
     * @return string|null
1757
     */
1758
    public function removeDoctrineTypeFromComment($comment, $type)
1759
    {
1760
        if ($comment === null) {
1761
            return null;
1762
        }
1763
 
1764
        return str_replace('(DC2Type:' . $type . ')', '', $comment);
1765
    }
1766
 
1767
    /** @throws Exception */
1768
    private function getDatabase(string $methodName): string
1769
    {
1770
        $database = $this->_conn->getDatabase();
1771
 
1772
        if ($database === null) {
1773
            throw DatabaseRequired::new($methodName);
1774
        }
1775
 
1776
        return $database;
1777
    }
1778
 
1779
    public function createComparator(): Comparator
1780
    {
1781
        return new Comparator($this->_platform);
1782
    }
1783
 
1784
    /**
1785
     * @return array<string,list<array<string,mixed>>>
1786
     *
1787
     * @throws Exception
1788
     */
1789
    private function fetchAllAssociativeGrouped(Result $result): array
1790
    {
1791
        $data = [];
1792
 
1793
        foreach ($result->fetchAllAssociative() as $row) {
1794
            $tableName          = $this->_getPortableTableDefinition($row);
1795
            $data[$tableName][] = $row;
1796
        }
1797
 
1798
        return $data;
1799
    }
1800
}