vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php line 327

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