Problem/Motivation

At the moment there are a lot of problems when you are the developer/maintainer of a contrib database driver. Normally when you are working on a contrib module and you have a problem, you look at how something similar is solved by the by core supported modules and use that solution for you contrib module. The problem for contrib database driver developers/maintainers is that solution does not work for them. In Drupal core there are a lot of specific for a database driver exceptions. Contrib database drivers are not allowed (for good reasons) to have the same exception added in core. That makes solving some problems almost impossible for contrib database drivers.

Proposed resolution

Move the by core supported database drivers to their own module (this issue). In following issues the specific exceptions in core for the by core supported database driver will be moved to the module part of the database drivers. When doing so we need to solve how to have those exception in a module instead of in regular core code. When do this for the by core supported database driver, the contrib database drivers can use the same solution.

Remaining tasks

TBD

User interface changes

None

API changes

The Database API and the Schema API are part of the public API. The implementation of those API's by the by core supported database drivers (MySQL, PostgreSQL and SQLite) are however NOT part of the public API. Therefor this patch does not contain any API changes.

Data model changes

None

Release notes snippet

The core supported database drivers, MySQL, PostgreSQL and SQLite, have been moved to their own modules. The modules are installed when the 9.4.0 update is run. Code that uses core supplied database classes will continue to work but these classes are deprecated and will be removed in Drupal 11. Custom and contrib drivers will need to supply a module parameter when encoding database connections as URLs.

CommentFileSizeAuthor
#149 3129043-10.0.x.patch340.9 KBalexpott
#98 3129043-98-move-driver-classes.patch113.5 KBdaffie
#93 interdiff_91-93.txt24.87 KBmondrake
#93 3129043-93.patch528.07 KBmondrake
#91 diff_3129043_90-91.txt1.99 KBankithashetty
#91 3129043-91.patch336.57 KBankithashetty
#90 rawdiff.txt47.17 KBravi.shankar
#90 3129043-90.patch336.69 KBravi.shankar
#87 reroll_diff_3129043_84-87.txt1.65 KBankithashetty
#87 3129043-87.patch339 KBankithashetty
#85 3129043-84.patch339.07 KBdaffie
#78 interdiff-3129043-69-77.txt34.57 KBdaffie
#77 3129043-77.patch339.07 KBdaffie
#75 3129043-75.patch522.26 KBdaffie
#75 3129043-75-move-driver-classes.patch111.24 KBdaffie
#75 3129043-75-add-bc-layer.patch34.57 KBdaffie
#69 3129043-69.patch111.27 KBmondrake
#69 interdiff_59-69.txt8.04 KBmondrake
#65 interdiff_59-65.txt20.65 KBmondrake
#65 3129043-65.patch117.34 KBmondrake
#62 diff.txt5.2 KBmondrake
#59 3129043-59.patch108.94 KBdaffie
#59 interdiff-3129043-54-59.txt614 bytesdaffie
#54 3129043-54.patch108.9 KBdaffie
#54 interdiff-3129043-51-54.txt4.77 KBdaffie
#51 3129043-51.patch108.59 KBdaffie
#45 3129043-45.patch109.87 KBdaffie
#39 interdiff-3129043-37-39.txt4.08 KBdaffie
#39 3129043-39.patch85.78 KBdaffie
#39 3129043-39-without-update-to-Core-Site-Setting-should-fail-testing.patch83.66 KBdaffie
#37 3129043-37.patch81.38 KBdaffie
#37 interdiff-3129043-35-37.txt8.6 KBdaffie
#35 3129043-35.patch95.56 KBdaffie
#32 3129043-32.patch96.09 KBdaffie
#32 interdiff-3129043-30-32.txt1.5 KBdaffie
#30 3129043-30.patch94.38 KBdaffie
#30 interdiff-3129043-28-30.txt2.16 KBdaffie
#28 3129043-28.patch92.52 KBdaffie
#28 interdiff-3129043-22-28.txt14.84 KBdaffie
#22 3129043-22.patch90.62 KBdaffie
#22 interdiff-3129043-16-22.txt1.84 KBdaffie
#17 3129043-16.patch91.46 KBdaffie
#17 interdiff-3129043-15-16.txt1.04 KBdaffie
#15 3129043-15.patch91.03 KBdaffie
#15 interdiff-3129043-11-15.txt721 bytesdaffie
#11 3129043-11.patch90.17 KBdaffie
#11 interdiff-3129043-6-11.txt3.52 KBdaffie
#6 3129043-6.patch87.13 KBdaffie
#6 interdiff-3129043-5-6.txt572 bytesdaffie
#5 3129043-5.patch87.09 KBdaffie
#5 interdiff-3129043-4-5.txt421 bytesdaffie
#4 3129043-4.patch87.09 KBdaffie
#4 interdiff-3129043-3-4.txt1.4 KBdaffie
#3 3129043-3.patch85.86 KBdaffie
#3 interdiff-3129043-2-3.txt5.96 KBdaffie
#2 3129043-2.patch82.87 KBdaffie

Issue fork drupal-3129043

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

daffie created an issue. See original summary.

daffie’s picture

Status: Active » Needs review
StatusFileSize
new82.87 KB
daffie’s picture

StatusFileSize
new5.96 KB
new85.86 KB

Fixed a couple of tests.

The problem why there test failing is that when we moved the by core supported database drivers to a module, they now need the variable $root for the loading of the PSR-4 namespace.

Some tests result into errors like: "Error: Call to undefined function Drupal\Core\drupal_valid_test_ua()".

daffie’s picture

StatusFileSize
new1.4 KB
new87.09 KB
daffie’s picture

StatusFileSize
new421 bytes
new87.09 KB
daffie’s picture

StatusFileSize
new572 bytes
new87.13 KB

Make the 3 new database driver modules hidden. It should now pass Drupal\Tests\system\Functional\Module\InstallUninstallTest.

alexpott’s picture

There's some interesting conceptual things we need to work out.

  • Is such a module enabled? The way the db code works atm that's not at all necessary.
  • If such a module is installable and it's being used in the db driver then we need to mark it required because we don't want someone to think they can uninstall it

I think I'm happy for it to be a special case that database drivers are something from a module that does not need to be installed. But we certainly need to document that. So +1 to the code db driver modules being hidden as installing them makes no sense. Some db drivers have provided extra module like functionality and service replacements. They need installing.

+++ b/core/lib/Drupal/Core/Database/Install/Tasks.php
@@ -297,6 +297,13 @@ public function getFormOptions(array $database) {
+    $form['advanced_options']['autoload'] = [
+      '#type' => 'textfield',
+      '#title' => t('Autoload'),
+      '#default_value' => empty($database['autoload']) ? '' : $database['autoload'],
+      '#size' => 45,
+    ];

What is the use-case? This doesn't feel at all like something a user should ever configure. And also out-of-scope for this change.

mondrake’s picture

#7 OTOH a non-core driver, in the current order, must implement at least a service to support date management functions via a backend overridable service. So another option would be for forcing at install time the installation of the ‘module’ that the driver resides in, and locking it as non-uninstallable.

mondrake’s picture

mondrake’s picture

daffie’s picture

StatusFileSize
new3.52 KB
new90.17 KB

Some more test fixes.

mondrake’s picture

daffie’s picture

There are problems getting to pass the test Drupal\Tests\Scripts\TestSiteApplicationTest. Maybe the work in #2962157: TestSiteApplicationTest requires a database despite being a unit test helps.

daffie’s picture

StatusFileSize
new721 bytes
new91.03 KB

This should fix Drupal\Tests\Scripts\TestSiteApplicationTest. It should fix the failure: "PHP Fatal error: Uncaught Error: Call to undefined function Drupal\Core\drupal_valid_test_ua() in /var/www/html/core/lib/Drupal/Core/DrupalKernel.php:378"

alexpott’s picture

+++ b/core/modules/system/tests/modules/driver_test/driver_test.info.yml
@@ -3,3 +3,7 @@ type: module
+dependencies:
+  - drupal:mysql
+  - drupal:pgsql

So this is where I have some issues. I think we need a proviso that drivers should be completely self contained and not rely on any module code. The way the container and therefore the autoloader is affected by the way we boot mandates this. The only reason the drivers in driver_test could extend the core drivers is because code in Drupal\Core is always autoloadable. Now it's in a place where it's not.

daffie’s picture

StatusFileSize
new1.04 KB
new91.46 KB

Removing:

+++ b/core/lib/Drupal/Core/Database/Install/Tasks.php
@@ -297,6 +297,13 @@ public function getFormOptions(array $database) {
+    $form['advanced_options']['autoload'] = [
+      '#type' => 'textfield',
+      '#title' => t('Autoload'),
+      '#default_value' => empty($database['autoload']) ? '' : $database['autoload'],
+      '#size' => 45,
+    ];

I had added that to fix the installer tests. There was never a use-case for. My apologies for the confusion.

daffie’s picture

I think we need a proviso that drivers should be completely self contained and not rely on any module code.

Great idea. And how do I do that?

alexpott’s picture

@daffie well we need to document it. It's enforced by the way db driver autoloading works. If you extend the core mysql connection class everything we jsut break because the system won't be able to autoload the core mysql connection class when it's in a module.

daffie’s picture

If you extend the core mysql connection class everything we just break because the system won't be able to autoload the core mysql connection class when it's in a module.

I get that. What I do not understand is how I can extend the by core supported database driver for PostgreSQL in my https://www.drupal.org/project/pgsql_fallback without directly extending the driver classes of the by core supported driver? What is the technical solution? I get the we in the end need to document the solution, but what is the solution???

The last submitted patch, 15: 3129043-15.patch, failed testing. View results

daffie’s picture

StatusFileSize
new1.84 KB
new90.62 KB

Changed the test TestSetupTraitTest back to being a UnitTest.

The last submitted patch, 17: 3129043-16.patch, failed testing. View results

alexpott’s picture

What I do not understand is how I can extend the by core supported database driver for PostgreSQL

You don't. You copy the classes and change what you need to. The classes shouldn't be viewed as API. They are an implementation of an API. If you copy the classes we can change core's implementation without ever having to worry about the impacts on contrib and custom. Which for something as low level as a db driver that's a very good thing.

Status: Needs review » Needs work

The last submitted patch, 22: 3129043-22.patch, failed testing. View results

daffie’s picture

Status: Needs work » Needs review

I have got all tests fixed with the exception of Drupal\FunctionalTests\Installer\InstallerNonDefaultDatabaseDriverTest. It fails with the following error:

Drupal\FunctionalTests\Installer\InstallerNonDefaultDatabaseDriverTest::testInstalled
Exception: Error: Class 'Drupal\mysql\Driver\Database\mysql\Connection' not found
include()() (Line: 10)

That is because the database driver for Drupal\mysql\Driver\Database\mysql does not get autoloaded. I see 2 possible solutions:
1. We autoload every database driver in the code base.
2. We enable the module that is the provider of the current database driver and all modules that it is dependent on.

I prefer option 2, because the module that is providing the database driver needs to be enabled to have driver specific tests, plugins and stuff like that. Originally I was hoping that we could do that in a followup issue.

alexpott’s picture

@daffie

We enable the module that is the provider of the current database driver and all modules that it is dependent on.

As I've been trying to point out we shouldn't do this. Either the driver_test classes have a hard wired include to get around the autolaoding. Or we do not allow drivers to extend each other. And therefore driver_test classes need to have the driver specific classes too. #3124354: Remove unnecessary classes from the database drivers makes this a bit more palatable.

daffie’s picture

Issue tags: +Needs change record
StatusFileSize
new14.84 KB
new92.52 KB

Added a fix for the Drupal\FunctionalTests\Installer\InstallerNonDefaultDatabaseDriverTest. The solution has come from @alexpott. Thank you for that.

alexpott’s picture

+++ b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysql/Delete.php
@@ -2,6 +2,8 @@
+include_once dirname(__DIR__, 8) . '/mysql/src/Driver/Database/mysql/Delete.php';

neat... not seen the second arg to dirname - ah it was added in PHP 7 - nice and only quite recently possible for us to adopt.... we should tidy up all the dirname(dirname( in core :) and we definitely need #3124354: Remove unnecessary classes from the database drivers -

daffie’s picture

StatusFileSize
new2.16 KB
new94.38 KB
+++ b/core/lib/Drupal/Core/Database/Database.php
@@ -472,6 +472,21 @@ public static function convertDbUrlToConnectionInfo($url, $root) {
+    // Add the module key for the by core supported database drivers when the
+    // module key is not set.
+    if (in_array($driver, ['mysql', 'pgsql', 'sqlite'], TRUE)) {
+      if (isset($url_components['query'])) {
+        parse_str($url_components['query'], $query);
+        if (!isset($query['module'])) {
+          $url_components['query'] .= '&module=' . $driver;
+        }
+      }
+      else {
+        $url_components['query'] = 'module=' . $driver;
+      }
+    }

Added extra testing for this piece of code.

daffie’s picture

Issue summary: View changes
Issue tags: -Needs change record

Added a change record.

daffie’s picture

StatusFileSize
new1.5 KB
new96.09 KB

Forgot to update default.settings.php

daffie’s picture

neat... not seen the second arg to dirname - ah it was added in PHP 7 - nice and only quite recently possible for us to adopt.... we should tidy up all the dirname(dirname( in core :)

Nice to see that the learning stuff between @alexpott and me is not always a one way street. :) Followup created in #3129508: Change multiple dirname()'s into a single dirname() with the use of the second parameter of dirname().

daffie’s picture

Issue summary: View changes
daffie’s picture

alexpott’s picture

+++ b/core/composer.json
@@ -186,9 +189,6 @@
-            "lib/Drupal/Core/Database/Driver/mysql/Connection.php",
-            "lib/Drupal/Core/Database/Driver/pgsql/Connection.php",
-            "lib/Drupal/Core/Database/Driver/sqlite/Connection.php",

Hmmm it is a shame to lose this optimisation to class loading.

There's a big breaking change here - we moving classes out of core - and we're not deprecating them. That makes this change disruptive. The only way I can think of making this less disruptive is if the new modules provided aliases for the old classes. But even this is problematic because these aliases would only be available much later than the old classes would be. The other problem is that we can't leave the old classes there because then the drivers will be discovered.

daffie’s picture

StatusFileSize
new8.6 KB
new81.38 KB
+++ b/core/composer.json
@@ -186,9 +189,6 @@
-            "lib/Drupal/Core/Database/Driver/mysql/Connection.php",
-            "lib/Drupal/Core/Database/Driver/pgsql/Connection.php",
-            "lib/Drupal/Core/Database/Driver/sqlite/Connection.php",
+            "modules/mysql/src/Driver/Database/mysql/Connection.php",
+            "modules/pgsql/src/Driver/Database/pgsql/Connection.php",
+            "modules/sqlite/src/Driver/Database/sqlite/Connection.php",

@alexpott: Does it help when we change the patch as above? Or are we then still losing the class loading optimalisation?

For making this change less disruptive: In #3124354-36: Remove unnecessary classes from the database drivers @catch said: "The inability to properly deprecate them is not great, and we also can't do that for class_alias." I do not see how we can make this patch less disruptive.

Rerolling the patch, because #3124354: Remove unnecessary classes from the database drivers has landed. New patch is 14 KB smaller!

alexpott’s picture

If I apply this patch to an existing site it breaks because in settings.php I have

$databases['default']['default'] = array (
  'database' => 'drupal8alt',
  'username' => 'username',
  'password' => 'password',
  'prefix' => '',
  'host' => 'localhost',
  'port' => '',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
);

So I see lots of

Warning: include(/Users/alex/dev/sites/drupal8alt.dev/vendor/composer/../../core/lib/Drupal/Core/Database/Driver/mysql/Connection.php): failed to open stream: No such file or directory in include() (line 444 of /Users/alex/dev/sites/drupal8alt.dev/vendor/composer/ClassLoader.php).

We need a BC layer to account for this.

Also we need to make the chosen database driver module required. The easiest way to do this will be in system_system_info_alter(). I think this might mean you can make the modules visible again since they won't be uninstallable if they are being used.

daffie’s picture

StatusFileSize
new83.66 KB
new85.78 KB
new4.08 KB

@alexpott: Great find in comment #38.

Added BC layer for comment #38.

daffie’s picture

Also we need to make the chosen database driver module required. The easiest way to do this will be in system_system_info_alter(). I think this might mean you can make the modules visible again since they won't be uninstallable if they are being used.

1. My original plan was to automatically enable the module that is providing the current database driver in a followup. See: #3129534: Automatically enable the module that is providing the current database driver. We can also do it in this issue, only the current patch is almost 90 KB and it is also not necessary for moving the by core supported database drivers to their own module.
2. If we do it the way you are suggestion, when in the installation process will that module then be enabled. Is it going to be enabled right after the when the system module is enabled or much later? I would like that module to be able to override every possible backend service, plugin and the EntityStorage.

daffie’s picture

Talked to @alexpott on Slack and he was adamant that the module that is providing the current database driver must be enabled, "because explaining that we have code loading from a module that is not installed is hard".
His suggestion is to do #3129534: Automatically enable the module that is providing the current database driver for the contrib and test database drivers first.
He also said that: "I think we need to enable the module and I think we need to install it prior to system" module, because "the system module declares schema and therefore depends on the database driver".

daffie’s picture

Title: Move the by core supported database drivers to their own module » [PP-2] Move the by core supported database drivers to their own module
Status: Needs review » Postponed
Related issues: +#2664322: key_value table is only used by a core service but it depends on system install
daffie’s picture

Title: [PP-2] Move the by core supported database drivers to their own module » [PP-1] Move the by core supported database drivers to their own module
daffie’s picture

StatusFileSize
new109.87 KB

The added patch contains the move the by core supported database drivers to their own module and automatically enable the module when the module is providing the current database driver. There are a number of reasons to that in a single patch:
1. In the validator Drupal/Core/Extension/ModuleRequiredByDatabaseDriverUninstallValidator is a workaround in the method validate() necessary for the two issue solution. The workaround is added in #3129534: Automatically enable the module that is providing the current database driver and removed in this issue.
2. The added testing in #3129534: Automatically enable the module that is providing the current database driver is all changed. It can now be done far more simple.
3. Doing it in 1 patch fixes the problem as described by @Beakerboy in #3129534-29: Automatically enable the module that is providing the current database driver. The testbot results for contrib database drivers will not become in a state where a lot of tests will fail when #3129534: Automatically enable the module that is providing the current database driver has landed and this issue has not.

Unfortunately, I was not able to create an interdiff file.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

mondrake’s picture

Just a couple of comments, skimming at the latest patch:

1. I think we should provide BC, cannot just move the classes. Maybe we can move the classes and still have an alias to them in place of current ones.
2. Why not to move all three drivers to a single module (even to the system module, maybe?) instead of one module per driver?

catch’s picture

Title: [PP-1] Move the by core supported database drivers to their own module » Move the by core supported database drivers to their own module
Status: Postponed » Needs review
daffie’s picture

Assigned: Unassigned » daffie
mondrake’s picture

Title: Move the by core supported database drivers to their own module » Move core database drivers to a module of their own

Not a native speaker, but I think this title is simpler :)

daffie’s picture

StatusFileSize
new108.59 KB

Difference with the previous patch:

  1. The previous patch is a combination patch with the patch from #3129534: Automatically enable the module that is providing the current database driver.
  2. The 3 new modules have now a .module file with in it a implementation of the hook_help();
  3. The 3 added modules no longer have the setting hidden: true;
  4. Added system_post_update_enable_provider_database_driver() for enabling the module that is providing the current database driver;
  5. The warning message for when the module that is providing the current database driver is not enabled has changed a bit. The problem is that the warning message is blocking the execution of the hook_post_update_NAME that will enable that same module;
  6. Added the test Drupal\Tests\system\Functional\Update\UpdateEnableProviderDatabaseDriverTest to check the post update hook system_post_update_enable_provider_database_driver();
  7. The patch had also to be rerolled. Therefore no interdiff.txt is added.
daffie’s picture

My response to @mondrake questions from comment #47:

I think we should provide BC, cannot just move the classes. Maybe we can move the classes and still have an alias to them in place of current ones.

I have had the same question myself and @alexpott answed that the Database API is public, however the drivers are not and therefore can be moved without leaving an alias behind.

Why not to move all three drivers to a single module (even to the system module, maybe?) instead of one module per driver?

I would very much like to create a level playing field for all database drivers (core and contrib). And yes, putting all 3 by core supported database drivers in a single module is an option. For putting them in the system module, I would like the by core supported database driver module(s) to be an example for the contrib ones and putting them in the system module will make in confusing which parts are for the database drivers and which are not. There is already a lot of stuff in the system module.

mondrake’s picture

Thank you for answering my questions in #47, @daffie. That all makes sense.

The patch is great. The one thing that makes me wonder is updating existing sites - I see that an update function for instaling the driver module exists which is great, still the settings.php content for the database settings for new sites will be different from the one of existing sites. How do we go for that? do we keep a BC layer forever or are we going to inform the site admins that their setup is outdated at some point?

A few points, many nits, in detail:

  1. +++ b/core/includes/install.inc
    @@ -174,7 +174,7 @@ function drupal_get_database_types() {
    -  $files = $file_system->scanDirectory(DRUPAL_ROOT . '/core/lib/Drupal/Core/Database/Driver', $mask, ['recurse' => FALSE]);
    +  $files = [];
       if (is_dir(DRUPAL_ROOT . '/drivers/lib/Drupal/Driver/Database')) {
         $files += $file_system->scanDirectory(DRUPAL_ROOT . '/drivers/lib/Drupal/Driver/Database/', $mask, ['recurse' => FALSE]);
       }
    

    it is purposeless to initalise $files to emtpy array, just make $files = instead of $files += two lines below

  2. +++ b/core/lib/Drupal/Core/Database/Database.php
    @@ -461,6 +461,21 @@ public static function convertDbUrlToConnectionInfo($url, $root) {
    +    // Add the module key for the by core supported database drivers when the
    +    // module key is not set.
    

    see initial comment - shall we add a todo to remove this when we'll be able to assume that the module key is always set? or, can we somehow tamper with connection_info so that the key is always set when initialising?

  3. +++ b/core/lib/Drupal/Core/Database/Database.php
    @@ -473,23 +488,18 @@ public static function convertDbUrlToConnectionInfo($url, $root) {
         if (!$module) {
           // Determine the connection class to use. Discover if the URL has a valid
    -      // driver scheme. Try with Drupal 8 style custom drivers first, since
    -      // those can override/extend the core ones.
    -      $connection_class = $custom_connection_class = "Drupal\\Driver\\Database\\{$driver}\\Connection";
    -      if (!class_exists($connection_class)) {
    -        // If the URL is not relative to a custom driver, try with core ones.
    -        $connection_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Connection";
    -      }
    +      // driver scheme for a Drupal 8 style custom driver.
    +      $connection_class = "Drupal\\Driver\\Database\\{$driver}\\Connection";
         }
     
         if (!class_exists($connection_class)) {
    

    same comment as above

  4. +++ b/core/lib/Drupal/Core/Database/Database.php
    @@ -634,8 +644,8 @@ protected static function getDatabaseDriverNamespace(array $connection_info) {
    -    // Fallback for Drupal 7 settings.php.
    -    return 'Drupal\\Core\\Database\\Driver\\' . $connection_info['driver'];
    +    // Fallback for Drupal 7 settings.php when the namespace is not provided.
    +    return 'Drupal\\' . $connection_info['driver'] . '\\Driver\\Database\\' . $connection_info['driver'];
    

    Drupal 7 syntax still a problem?

  5. +++ b/core/lib/Drupal/Core/Database/StatementInterface.php
    @@ -7,13 +7,13 @@
    + * class Drupal\oracle\Driver\Database\oracle\Statement extends PDOStatement implements Drupal\Core\Database\StatementInterface {}
    ...
    + * class Drupal\oracle\Driver\Database\oracle\Statement implements Iterator, Drupal\Core\Database\StatementInterface {}
    

    I'd use mymodule mydriver instead of oracle to make it clear in the example what's what

  6. +++ b/core/lib/Drupal/Core/Site/Settings.php
    @@ -162,6 +162,43 @@ public static function initialize($app_root, $site_path, &$class_loader) {
    +        // Backwards compatibility layer for Drupal 8 style database connection
    +        // array's. Those do not have the autoload key set for the by Drupal
    +        // core supported database drivers.
    ...
    +        // Backwards compatibility layer for Drupal 8 style database connection
    +        // array's. Those have the wrong namespace key set or not set at all for
    +        // the by Drupal core supported database drivers.
    +        if (empty($info['namespace']) || (strpos($info['namespace'], 'Drupal\\Core\\Database\\Driver\\') === 0)) {
    +          switch (strtolower($info['driver'])) {
    

    see above

  7. +++ b/core/modules/config/tests/src/Functional/ConfigImportAllTest.php
    @@ -87,10 +87,15 @@ public function testInstallUninstall() {
    +    sort($expected_modules);
    ...
    +    sort($validation_modules);
    

    no need to sort expected and actual values for assertEquals, you can use assertEqualsCanonicalising (I think)

  8. +++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php
    @@ -120,4 +123,31 @@ protected function visitInstaller() {
    +    $this->assertEquals(new Extension($this->root, 'module', "core/modules/$module/$module.info.yml", "$module.module"), $module_handler->getModule($module));
    

    I'd find more readable to associate new Extension(...) to a, say, $expected_extension local variable and use that in the assertEquals

daffie’s picture

StatusFileSize
new4.77 KB
new108.9 KB

@mondrake: Thank you for your review.

The one thing that makes me wonder is updating existing sites - I see that an update function for instaling the driver module exists which is great, still the settings.php content for the database settings for new sites will be different from the one of existing sites. How do we go for that? do we keep a BC layer forever or are we going to inform the site admins that their setup is outdated at some point?

I think that making site owners change the settings in settings.php will result that a small percentage of site owners do something wrong and that will result in their website will loose the connection to the database. And there are about a million Drupal website out there, so even a small percentage is still a big number. To me this can be avoided by adding a BC layer and keeping that until Drupal gets rid of the settings.php file. It is only a very small BC layer. We shall have to check that in settings.php the namespace and the autoload settings are not always set. For me, that is something I can live with.

For #53.1: Fixed!

For #53.2: See above. I talked about a year ago with @alexpott about database connection urls and would like to get rid of them and replace them with something else. I only cannot remember with what. For me, just keep it working until then.

For #53.3: This comment is for Drupal 8 style custom drivers. The ones that live in the directory /drivers/lib/Drupal/Driver/Database/. They are already deprecated and can be removed in D10. We need to keep it working until then.

For #53.4: Fixed.

For #53.5: Fixed.

For #53.6: See above.

For #53.7: Fixed. I did not know that that assetion existed. Learned something new.

For #53.8: Fixed.

mondrake’s picture

+++ b/core/includes/install.inc
@@ -174,9 +174,9 @@ function drupal_get_database_types() {
+  $files = [];

this can be removed

mondrake’s picture

#54.3 then I think we should have a @todo for removal in D10

daffie’s picture

@mondrake: When we do what you are suggesting, then when the if-statement is false, the variable $files will not be set. Is that ok for the following foreach loop?

mondrake’s picture

#57 I missed that, sorry, OK then.

daffie’s picture

StatusFileSize
new614 bytes
new108.94 KB

Rerolled and added the @todo for #54.3.

fgm’s picture

Any reason these would need to be "modules", especially as they have these weird properties of being hidden and not having to be installed. We already have multiple extension types, maybe a "dbdriver" type along with module, themes and profiles would be a cleaner way, not breaking module semantics about visibility and enabling/installing ?

daffie’s picture

@fgm: In the current patch will the modules, who are providing the by core supported database drivers, be visible. As it should be able to do a migration from a different type of database then the one that is used by Drupal to store its data. At the moment only the module that is providing the current database driver will be enabled by default. The module that is providing the database driver for the migration source will not be enabled by default when the databases are of different types (for instance MySQL and PostgreSQL). When the migration is finished can the module with the database driver for the migration source be disabled.
For using a different extension type for storing database drivers: the core committers decided that fixed location inside a module would be the best way to solve it. See: #3120096: Support contrib database driver directories in a fixed location in a module.

mondrake’s picture

StatusFileSize
new5.2 KB

I went through again and I think there could be a few more changes to be done; added in a diff file not break the patches flow and so they can be discussed. It's close to RTBC from me.

mondrake’s picture

+++ b/core/lib/Drupal/Core/Database/Database.php
@@ -229,11 +229,6 @@ abstract class Database {
-    // Fallback for Drupal 7 settings.php when the namespace is not provided.
-    if (empty($info['namespace'])) {
-      $info['namespace'] = 'Drupal\\' . $info['driver'] . '\\Driver\\Database\\' . $info['driver'];
-    }
-

I think we can remove those given the changes in Settings

mondrake’s picture

Actually, #62 does not work... :)

Will post again when I have a working diff

mondrake’s picture

StatusFileSize
new117.34 KB
new20.65 KB

So, made some changes, mainly to ensure that Database::convertDbUrlToConnectionInfo() and Database::getConnectionInfoAsUrl() manage the 'module' addition both.

Had to take the patch from #2992274-18: Installer tests fail if contrib driver hides database credentials form fields to get this working.

At this stage, in a pure looking forward context, the 'namespace' key would be optional, only for BC, since any new db driver will be part of a module and therefore you can build the namespace with the 'module' and the 'driver' keys only. Maybe we can deprecate it?

Status: Needs review » Needs work

The last submitted patch, 65: 3129043-65.patch, failed testing. View results

mondrake’s picture

Assigned: daffie » mondrake

working on some cleanup, @daffie hope you do not mind

daffie’s picture

working on some cleanup, @daffie hope you do not mind

Fine by me. ;-)

A couple of points about the latest patch:

  1. +++ b/core/tests/Drupal/Tests/Core/Database/UrlConversionTest.php
    @@ -308,6 +322,8 @@ public function providerGetConnectionInfoAsUrl() {
    +      'module' => 'mysql',
    +      'namespace' => 'Drupal\\mysql\\Driver\\Database\\mysql',
    
    @@ -319,21 +335,27 @@ public function providerGetConnectionInfoAsUrl() {
    +      'module' => 'mysql',
    +      'namespace' => 'Drupal\\mysql\\Driver\\Database\\mysql',
    ...
    +      'module' => 'sqlite',
    +      'namespace' => 'Drupal\\sqlite\\Driver\\Database\\sqlite',
    ...
    +      'module' => 'sqlite',
    +      'namespace' => 'Drupal\\sqlite\\Driver\\Database\\sqlite',
    

    When we have connection info array and we change it to a connection url, it should work without the 'module' and/or 'namespace' keys set.
    The problem is that we have sites that started as a D7 site and upgraded to a D9.1 site. They do not have those keys set and now are we going to expects those keys to be set. That will result in a BC break.

  2. I know you very much like the solution from #2992274: Installer tests fail if contrib driver hides database credentials form fields. The only problem is that @alexpott does not like your solution as he said in #20. Therefore we cannot use that solution.
  3. In #3120096: Support contrib database driver directories in a fixed location in a module the decision was made to use the 'namespace' and 'autoload' keys. My first solution was to add the 'module' key and that was turned down.

All I would like to do in this issue is to move the by core supported database drivers to their own module and change as little as possible. In D9 we still have to support the database drivers that have to be copied to the 'drivers' directory. Those are deprecated and will be removed before D10. Lets wait for D10 to start changing the 'module', 'namespace' and 'autoload' keys. Then are all database drivers provided by a module and we will have only one namespace formula. It will then be a lot easier to get the 'best' solution.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new8.04 KB
new111.27 KB

the decision was made to use the 'namespace' and 'autoload' keys

oh I missed that. And your approach makes sense to me.

So I suppose my changes should be limited to the attached. No need for #2992274: Installer tests fail if contrib driver hides database credentials form fields since we are not adding the module key in createConnectionOptionsFromUrl.

Interdiff vs #59. Please disregard #62 and #65.

mondrake’s picture

Assigned: mondrake » Unassigned
daffie’s picture

The changes that @mondrake made on the patch in comment #69 are for me RTBC. Thank you for your help on this issue!

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

I think I can RTBC this, this patch is 99% @daffie's and I just made some minor changes.

catch’s picture

Any reason these would need to be "modules", especially as they have these weird properties of being hidden and not having to be installed. We already have multiple extension types, maybe a "dbdriver" type along with module, themes and profiles would be a cleaner way, not breaking module semantics about visibility and enabling/installing ?

Profiles aren't a genuine third extension type, they're an extension of modules, issues like #820054: Add support for recommends[] and fix install profile dependency special casing, #3053521: Allow core.extension.yml to have empty profile on install site from existing configuration, #1676196: Install profiles are registered as modules are dealing with some of these inconsistencies.

If we made database drivers into a third extension type, then they'd still need to be able to register services on the container etc. (this is the reason they're being made modules at all) - and we'd still need them to be installable/uninstallable to be able to do this. So issues around running code when uninstalled, having them installable/uninstallable but hidden etc. would still be there - just a bit more siphoned into a different extension type. But that extension type would need to re-implement a lot of module functionality so it may not end up being any cleaner.

There's an old (won't fix) issue to allow themes to register services #2002606: Allow themes to provide services.yml. We ended up allowing themes to depend on modules instead #2937955: Themes can declare dependencies on modules.

Short version is I agree that them being modules adds some complexity/special casing to the module system, but I'm not sure trying to make them an independent extension type will remove any complexity overall - it's as likely to push it up into the extension system in general.

We might want a meta issue to look again at profiles vs. themes vs. modules (and now database drivers) though since those discussions are quite scattered and some are a decade old now.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/Site/Settings.php
    @@ -162,6 +162,43 @@ public static function initialize($app_root, $site_path, &$class_loader) {
    +        // Backwards compatibility layer for Drupal 8 style database connection
    +        // array's. Those do not have the 'autoload' key set for core database
    +        // drivers.
    +        if (empty($info['autoload'])) {
    +          switch (strtolower($info['driver'])) {
    +            case 'mysql':
    +              $info['autoload'] = 'core/modules/mysql/src/Driver/Database/mysql/';
    +              break;
    +
    +            case 'pgsql':
    +              $info['autoload'] = 'core/modules/pgsql/src/Driver/Database/pgsql/';
    +              break;
    +
    +            case 'sqlite':
    +              $info['autoload'] = 'core/modules/sqlite/src/Driver/Database/sqlite/';
    +              break;
    +          }
    +        }
    +        // Backwards compatibility layer for Drupal 8 style database connection
    +        // array's. Those have the wrong 'namespace' key set, or not set at all
    +        // for core supported database drivers.
    +        if (empty($info['namespace']) || (strpos($info['namespace'], 'Drupal\\Core\\Database\\Driver\\') === 0)) {
    +          switch (strtolower($info['driver'])) {
    +            case 'mysql':
    +              $info['namespace'] = 'Drupal\\mysql\\Driver\\Database\\mysql';
    +              break;
    +
    +            case 'pgsql':
    +              $info['namespace'] = 'Drupal\\pgsql\\Driver\\Database\\pgsql';
    +              break;
    +
    +            case 'sqlite':
    +              $info['namespace'] = 'Drupal\\sqlite\\Driver\\Database\\sqlite';
    +              break;
    +          }
    +        }
    

    Do we need a follow-up to discuss how to deprecate this code and help people change their settings.php?

  2. +++ b/core/modules/mysql/src/Driver/Database/mysql/Install/Tasks.php
    similarity index 98%
    rename from core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
    
    rename from core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
    rename to core/modules/mysql/src/Driver/Database/mysql/Schema.php
    
    rename to core/modules/mysql/src/Driver/Database/mysql/Schema.php
    index e05f10c86e..15752cbef0 100644
    
    index e05f10c86e..15752cbef0 100644
    --- a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
    
    --- a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
    +++ b/core/modules/mysql/src/Driver/Database/mysql/Schema.php
    
    +++ b/core/modules/mysql/src/Driver/Database/mysql/Schema.php
    +++ b/core/modules/mysql/src/Driver/Database/mysql/Schema.php
    @@ -1,6 +1,6 @@
    
    @@ -1,6 +1,6 @@
     <?php
     
    -namespace Drupal\Core\Database\Driver\mysql;
    +namespace Drupal\mysql\Driver\Database\mysql;
    

    We're moving these classes with no BC layer. That's a break.

    Is there any discussion of this on the issue? I think we need to leave a class here that extends the new class and is deprecated. In #24 I wrote...

    You copy the classes and change what you need to. The classes shouldn't be viewed as API. They are an implementation of an API. If you copy the classes we can change core's implementation without ever having to worry about the impacts on contrib and custom. Which for something as low level as a db driver that's a very good thing.

    which is true for the new module module classes but unfortunately I don't think is true for the existing classes which are part of the Drupal\Core namespace.

  3. The patch also needs a reroll
daffie’s picture

Status: Needs work » Needs review
StatusFileSize
new34.57 KB
new111.24 KB
new522.26 KB

For #74.1: I think we have 2 options. The first one is not having site owners change their settings.php file. That is very easy for them and for Core a little bit more difficult. We will now have 2 different types of connection info array's: the ones with the settings "autoload" and "namespace" set an the older ones without those settings set. To me it looks very easy for Core to support both connection info array's. The overhead is very minimal in code as in execution time. The other option is to have site owners update their settings.php file. For the sites hosted on Acquia and similar companies, will it be easy. Only for site owners with little knowledge of Drupal and cheaper hosting will have more problems. We shall have to tell them which keys to add and where. Also that the namespace key value needs to be done with double backslashes. We also have to hope that they will not change anything else in the settings.php file what way cause problems. If we make this required in D10, will those who do not have the added settings loose their database connection? It will also need a big communication effort from the Drupal community to inform all site owners to add those keys. And when something goes wrong, who will get the blame? Yes, it will be Drupal's fault. For me it is easy, lets go with the first option.

I have added 3 patch files with this comment. The problem is that when I do it all in one patch file, the driver files will be deleted and created instead of renamed. Their git links will get broken and the patch file size will be 500kb. That is not reviewable any more. When you do the same only with 2 patch files the git links will not get broken and the combined patch file size will be 150kb. The first patch file is the rerolled version from comment #69, which moves the driver classes to their own modules. The second patch file will create the BC layer as requested by @alexpott in comment #74.2. The other problem with a single patch file is that when anything changes in one of the database driver classes, the single patch file needs to be rerolled. Not so for the double patch files.

alexpott’s picture

@daffie I think if you have

[diff]
        renames = copies
        renameLimit = 7000

in your .gitconfig file you'll get a more reasonable overall patch size - when I recreate the patch it comes out at 339K - still big but I think better then maintaining multiple patches.

daffie’s picture

StatusFileSize
new339.07 KB

I already had the setting "renames = copies" and I added the second setting. Now the patch file is much smaller.

@alexpott: Thanks!

daffie’s picture

StatusFileSize
new34.57 KB
mondrake’s picture

+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\mysql\Driver\Database\mysql\Connection as MysqlConnection;
+
+@trigger_error('\Drupal\Core\Database\Driver\mysql\Connection is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. The MySQL database driver has been moved to the mysql module. See https://www.drupal.org/node/3129492', E_USER_DEPRECATED);
+
+/**
+ * MySQL implementation of \Drupal\Core\Database\Connection.
+ *
+ * @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. The MySQL
+ *   database driver has been moved to the mysql module.
+ *
+ * @see https://www.drupal.org/node/3129492
+ */
+class Connection extends MysqlConnection {}

how about just using class_alias?

<?php

@trigger_error('\Drupal\Core\Database\Driver\mysql\Connection is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. The MySQL database driver has been moved to the mysql module. See https://www.drupal.org/node/3129492', E_USER_DEPRECATED);

class_alias("Drupal\mysql\Driver\Database\mysql\Connection", "Drupal\Core\Database\Driver\mysql\Connection");
daffie’s picture

@mondrake: Good idea. Only the testbot does not like your solution. I am getting PHPCBF errors, like:

Checking core/lib/Drupal/Core/Database/Driver/mysql/Connection.php


FILE: ...w/html/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 1 | ERROR | [x] Missing file doc comment
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 116ms; Memory: 4MB
alexpott’s picture

#79 doesn't work unfortunately. I'd love to add a parameter to class_alias to trigger a user deprecation and then we could have file will class_aliases loaded as part of the static file map. See https://www.schmengler-se.de/en/2016/09/php-using-class_alias-to-maintai...

daffie’s picture

I'd love to add a parameter to class_alias to trigger a user deprecation

we could have file will class_aliases loaded as part of the static file map

It all sounds great, and after reading the linked page twice, do I have no idea how to do that and I get the impression that is a lot more code then the current solution. If you @alexpott, think you have a better idea how to do it, could you post some code examples or create a patch?

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

Ah sorry @daffie, thanks @alexpott. So it's not possible to alias at the same time as loading the potential class.. I missed that. IIUC #81 means that we could put the aliases in a deprecated class loading php file to be loaded by composer, but as things stand that would not allow for triggering deprecation errors. So the only option seems inheritance like #77 which implements that and adds tests.

I think this can go back to RTBC; #74.1 is for a followup I believe.

mondrake’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll
daffie’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs reroll
StatusFileSize
new339.07 KB

Rerolled.

mondrake’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll
ankithashetty’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new339 KB
new1.65 KB

Re-rolled the patch in #85, thanks!

daffie’s picture

Status: Needs review » Reviewed & tested by the community

@mondrake: Thank you for posting that the patch needed a reroll.
@ankithashetty: Thank you for the reroll.

The reroll was needed, because #2510438: Remove 'all' index from {key_value_expire} - serves no purpose and negatively impacts performance has landed.
The reroll look good to me. Back to RTBC.

mondrake’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll
ravi.shankar’s picture

StatusFileSize
new336.69 KB
new47.17 KB

Added reroll of patch #87.

ankithashetty’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new336.57 KB
new1.99 KB

Fixed custom command errors in #90, thanks!

Status: Needs review » Needs work

The last submitted patch, 91: 3129043-91.patch, failed testing. View results

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new528.07 KB
new24.87 KB

It'd probably be easier to move this issue to MR workflow.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mondrake’s picture

I wonder whether #3214234: Add core/class_aliases.php could now make the class aliasing for BC simpler.

mondrake’s picture

Rerolled and changed to MR workflow.

daffie’s picture

StatusFileSize
new113.5 KB

I have rerolled the first part of the main patch (it passes the testbot for all 3 databases #3215116-40: [IGNORE] Testing). The second part is for adding the BC layer. The second patch can be found in my comment #75.

@mondrake: If you want to do it a bit different, that is fine too.

mondrake’s picture

Thanks @daffie, I think the MR should be up to a working reroll of #93 now, with BC and deprecation tests included.

daffie’s picture

Status: Needs review » Needs work

@mondrake The MR looks good, just some minor stuff that needs to be fixed.

mondrake’s picture

Status: Needs work » Needs review

All fixed.

daffie’s picture

Status: Needs review » Needs work

@mondrake: You forgot to change the deprecation message for the class Drupal\Core\Database\Driver\pgsql\Install\Tasks. All the other changes look good.

mondrake’s picture

Status: Needs work » Needs review

Ops.

daffie’s picture

Status: Needs review » Reviewed & tested by the community

The reroll now looks good to me.
Back to RTBC.

daffie’s picture

Priority: Normal » Major

This issue is a major change for the database drivers as they are moved to their own modules. This issue is blocking the moving of database specific code to the database module where it belongs. Just like contrib database drivers must do. As the by core supported database driver are or better should be the example for contrib database drivers. Therefor changing the priority of the issue to major.

mondrake’s picture

Rerolled. This one is a pretty nasty one to reroll if there are changes to drivers' code in HEAD.

daffie’s picture

@mondrake: Do you still think that rerolling is easier with a MR than with a patch? By the way, that you for the reroll.

mondrake’s picture

#107 I do, generally speaking. With this issue, the problem is that some classes are copied in a different directory structure AND changed at the source to keep the deprecation triggers. This does not work well with git on the repo, apparently: the changes to the 'old' sources are not tracked to the 'new' locations.

mondrake’s picture

Rerolled

mondrake’s picture

Fixing ComposerIntegrationTest::testComposerLockHash is a moving target, especially close to new releases when dependencies are updated frequently. I'd rather wait for a 'go' by core committers on the patch overall, and then do the final fix (along with any deprecation message update for versions).

mondrake’s picture

mondrake’s picture

Rerolled

mondrake’s picture

Rerolled

mondrake’s picture

Rerolled

mondrake’s picture

Rerolled

mondrake’s picture

Changed target branch to 9.4.x.

mondrake’s picture

Version: 9.3.x-dev » 9.4.x-dev
mondrake’s picture

Reroll

mondrake’s picture

Assigned: Unassigned » mondrake
Status: Reviewed & tested by the community » Needs work

Updating deprecation messages.

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review

Changed deprecation messages for deprecating in 9.4 and removing in 11.

daffie’s picture

Status: Needs review » Needs work

Updated the CR with how the use statement to database driver specific classes should be replaced. As requested by @alexpott.

daffie’s picture

Status: Needs work » Needs review
daffie’s picture

Status: Needs review » Reviewed & tested by the community

All the deprecations has changed to 9.4.0 and will be removed before 11.0.0.
The testbot is happy again.
Back to RTBC.

mondrake’s picture

Rerolled

mondrake’s picture

Rerolled.

mondrake’s picture

Rerolled

mondrake’s picture

SQLite failure on PHP 8.1 is unrelated.

beakerboy’s picture

Should each core database’s DateSqlInterface implementations get moved into the respective modules as well?
For example:
core/modules/views/src/Plugin/views/query/SqliteDateSql.php

beakerboy’s picture

Running this branch with sqlsrv, I receive the following failure:

Drupal\FunctionalTests\Installer\InstallerTest::testInstalled
The file specified by the given app root, relative path and file name (/opt/drupal/core/modules/sqlsrv/sqlsrv.info.yml) do not exist. in /opt/drupal/core/lib/Drupal/Core/Extension/Extension.php:67

/opt/drupal/vendor/phpunit/phpunit/src/Framework/TestResult.php:737

Line 137 of InstallerTest.php is assuming that database drivers under test are in the core modules.

mondrake’s picture

#129 yes! But I’d leave that to a follow-up, there will be lots of stuff to do after this gets committed. See for example #3231950: Split Database tests in 'core' ones and 'driver specific' ones.

Also, see #2657888: Add Date function support in DBTNG for an alternative approach.

mondrake’s picture

Tests are now back green on all DBs in 9.4.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

#130 looks like a problem that this patch needs to address - this should not be causing us to look in core for contrib database drivers.

daffie’s picture

Status: Needs work » Needs review

Fixed the InstallerTest for making it work with contrib database drivers.

beakerboy’s picture

Status: Needs review » Reviewed & tested by the community

My #130 issue has been resolved, so back to RTBC. Thanks for all the hard work!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Added a review with some actions to the MR.

The other thing I'm wondering about is migrations. How does this affect migrating from a different database provider eg. sqlite to mysql? This is mentioned in #61 but I can't glean the ramifications of this change on that.

daffie’s picture

Assigned: Unassigned » daffie

Working on this.

mondrake’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

Needs another reroll, unfortunately.

Also a requested comment in the code is missing, plus answer to #136, which I cannot answer.

Do not know if it's the same thing, but was wondering what would happen if a site had multiple database entries on different database types in settings.php. Would the update function need to enable ALL the modules affected?

daffie’s picture

Replied to the remarks of @mondrake.

mondrake’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll

This addresses #139, howeevr now I realise that probably calling \Database::getConnection() with key and target is possibly not a good idea, since there could be stale entries in $databases, and those would fail.

mondrake’s picture

Addressed my own concern in #141, by avoiding actually opening connections.

daffie’s picture

Status: Needs review » Reviewed & tested by the community

The other thing I'm wondering about is migrations. How does this affect migrating from a different database provider eg. sqlite to mysql? This is mentioned in #61 but I can't glean the ramifications of this change on that.

I can remember that we (@alexpott and myself) have discused this on Slack a long time ago. I can remember that the problem was not only for migrations, but also for other modules that can add database connections, like Drush and others. One problem was that those second modules stay enabled by default and that was something that @alexpott did not like at the time. Therefor he did not what those second modules enabled by default. Another point was that this would hardly ever happen. If he has changed his mind then we need to auto enabled the module that is providing the source database connection for migrations.

My description from comment #61 is still valid. The change to system_post_update_enable_provider_database_driver() makes this all database connections that are active have their modules enabled when the update is run. For all database connections that are added after that moment, this is not the case.

All the changes in the MR look good to me.
All the threads are solved.
Back to RTBC.

@mondrake: Thank you again for the rebase.

mondrake’s picture

I tested a slightly modified version of the MR with the DruDbal experimental db driver module, and it works correctly.

The change is in adding a couple of dump watches in UpdateEnableProviderDatabaseDriverTest, to inspect provider and list of installed modules before/after the post_update execution:

   public function testPostUpdateEnableProviderDatabaseDriverHook() {
     $connection = Database::getConnection();
     $provider = $connection->getProvider();
-
+dump([
+  '********** PRE',
+  'provider' => $provider,
+  'allConnectionsInfo' => Database::getAllConnectionInfo(),
+  'installed_modules' => implode(', ', array_keys(\Drupal::moduleHandler()->getModuleList())),
+]);
     $this->assertFalse(\Drupal::moduleHandler()->moduleExists($provider));

     // Running the updates enables the module that is providing the database
@@ -40,6 +45,10 @@ public function testPostUpdateEnableProviderDatabaseDriverHook() {
     $this->runUpdates();

     $this->assertTrue(\Drupal::moduleHandler()->moduleExists($provider));
+dump([
+  '********** POST',
+  'installed_modules' => implode(', ', array_keys(\Drupal::moduleHandler()->getModuleList())),
+]);
   }

 }

The test run result indicates that the contrib module gets installed too as part of the post_update:

Before:

array:4 [
  0 => "********** PRE"
  "provider" => "drudbal"
  "allConnectionsInfo" => array:2 [
    "simpletest_original_default" => array:1 [
      "default" => array:10 [
        "driver" => "dbal"
        "host" => "0.0.0.0"
        "database" => "drudbal"
        "prefix" => ""
        "namespace" => "Drupal\drudbal\Driver\Database\dbal"
        "port" => 3306
        "username" => "root"
        "password" => ""
        "dbal_driver" => "pdo_mysql"
        "autoload" => "modules/contrib/drudbal/src/Driver/Database/dbal/"
      ]
    ]
    "default" => array:1 [
      "default" => array:12 [
        "driver" => "dbal"
        "host" => "0.0.0.0"
        "database" => "drudbal"
        "prefix" => "test63429526"
        "namespace" => "Drupal\drudbal\Driver\Database\dbal"
        "port" => 3306
        "username" => "root"
        "password" => ""
        "dbal_driver" => "pdo_mysql"
        "autoload" => "modules/contrib/drudbal/src/Driver/Database/dbal/"
        "charset" => "utf8mb4"
        "init_commands" => array:1 [
          "sql_mode" => "SET sql_mode = 'ANSI,TRADITIONAL'"
        ]
      ]
    ]
  ]
  "installed_modules" => "automated_cron, block, block_content, breakpoint, ckeditor, color, comment, config, contact, contextual, datetime, dblog, editor, entity_reference, field, field_ui, file, filter, help, history, image, link, menu_ui, node, options, page_cache, path, path_alias, quickedit, rdf, search, shortcut, system, taxonomy, text, toolbar, tour, user, views_ui, menu_link_content, views, standard"
]

After:

array:2 [
  0 => "********** POST"
  "installed_modules" => "automated_cron, block, block_content, breakpoint, ckeditor, color, comment, config, contact, contextual, datetime, dblog, drudbal, editor, field, field_ui, file, filter, help, history, image, link, menu_ui, node, options, page_cache, path, path_alias, quickedit, rdf, search, shortcut, system, taxonomy, text, toolbar, tour, user, views_ui, menu_link_content, views, standard"
]

you can see the 'drudbal' module got installed.

Now, the test will probably not work with contrib drivers that are NOT encapsulated into a module yet, but to me this is more a benefit than not.

mondrake’s picture

Title: Move core database drivers to a module of their own » Move core database drivers to modules of their own
mondrake’s picture

Status: Reviewed & tested by the community » Needs work

Viceversa, ExistingDrupal8StyleDatabaseConnectionInSettingsPhpTest can only reasonably work with mysql, pgsql or sqlite drivers.

mondrake’s picture

Status: Needs work » Needs review

Fixed #146.

daffie’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me.
Back to RTBC.

alexpott’s picture

StatusFileSize
new340.9 KB

Here's a patch for 10.0.x - there are conflicts in composer.lock and core/tests/Drupal/KernelTests/Core/Database/TransactionTest.php

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 934f42a and pushed to 10.0.x. Thanks!
Committed c18f8d6 and pushed to 9.4.x. Thanks!

  • alexpott committed 934f42a on 10.0.x
    Issue #3129043 by mondrake, daffie, ankithashetty, ravi.shankar,...

  • alexpott committed c18f8d6 on 9.4.x
    Issue #3129043 by mondrake, daffie, ankithashetty, ravi.shankar,...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

effulgentsia’s picture

A lot of great work here! But:

+++ b/core/lib/Drupal/Core/Site/Settings.php
@@ -162,6 +162,43 @@ public static function initialize($app_root, $site_path, &$class_loader) {
+        if (empty($info['autoload'])) {
+          switch (strtolower($info['driver'])) {
+            case 'mysql':
+              $info['autoload'] = 'core/modules/mysql/src/Driver/Database/mysql/';

This is too aggressive because it also autoloads to this directory for the Drupal\Driver namespace which is not sensible and creates errors for https://www.drupal.org/project/mysql56.

I opened #3284502: [regression] Drupal 9.4 breaks BC via incorrect autoloading of \Drupal\Driver\* overrides of core db drivers to fix that.

greg boggs’s picture

After installing the latest version of Drupal 9 for the security release today, I get this error on config import

The following reasons prevent the modules from being uninstalled: The module 'MySQL' is providing the database driver 'mysql'.

When I view my config differences, it shows that I'm removing mysql: 0 in core extensions. If I add mysql: 0 to my core extensions file, everything works normally.

nicholass’s picture

Just to document this for others, this change has broken our sites on our hosting company Acquia due to them having some include logic that was including the old core DB drivers, I have a ticket with them to work on the issue. But other hosting companies may have similar problems.

After 9.4 were getting Error: Class "Drupal\mysql\Driver\Database\mysql\Connection" not found even with the new mysql module enabled.

function acquia_hosting_db_choose_active($db_info = NULL, $name = 'default', &$databases = NULL, &$conf = NULL) {
// Drupal 9 specific DB files.
require_once DRUPAL_ROOT . '/core/lib/Drupal/Core/Database/Database.php';
require_once DRUPAL_ROOT . '/core/lib/Drupal/Core/Database/Connection.php';

Note: This isn't a bug with 9.4 but just an unexpected side effect of this update having moved the location of mysql drivers

rajab natshah’s picture

After a new build and new drush site:install for a new site ( not on update )

mkdir -p /var/www/html/dev
cd /var/www/html/dev/
composer create-project drupal/recommended-project d940x1 -vvv
cd /var/www/html/dev/d940x1/
composer require drush/drush
cd /var/www/html/dev/d940x1/web
../vendor/drush/drush/drush site:install standard --yes --account-name="webmaster" --account-pass="dD.123123ddd" --account-mail="webmaster@example.com" --db-url="mysql://root:rootpw@127.0.0.1/dev_d940x1" --locale="en"

Trying to do any other drush commands like
../vendor/drush/drush/drush user-create newuser --mail="person@example.com" --password="dD.123123ddd"

Facing issues with a number of contrib modules

[error]  TypeError: ############ Argument #1 ($database) must be of type Drupal\Core\Database\Driver\mysql\Connection, Drupal\mysql\Driver\Database\mysql\Connection given

But the Drupal\Core\Database\Driver\mysql\Connection is used not the Drupal\mysql\Driver\Database\mysql\Connection

And the message from the Mysql Driver Legacy Test

\\Drupal\\Core\\Database\\Driver\\mysql\\Connection is deprecated in drupal:9.4.0 and is removed from drupal:11.0.0. The MySQL database driver has been moved to the mysql module. See https://www.drupal.org/node/3129492'

The MySQL module

 drush en mysql
 [notice] Already enabled: MySQL

What is the next move for this change? Have that fixed in all used modules?
Change from Drupal\Core\Database\Driver\mysql\Connection to Drupal\mysql\Driver\Database\mysql\Connection

xjm’s picture

@Greg Boggs, @Rajab Natshah, @NicholasS, commenting on a closed issue won't help much because we don't receive notifications of updates for closed issues. Any time you encounter a regression from a change, you are better off opening a new critical or major bug report about it.

See these issues:

If none of those address the problems you're encountering, open new issues referencing this one, and add the "9.4.0 update" issue tag to help us find it among regressions for this release.

Thanks for your reports!

effulgentsia’s picture

I opened #3290936: Argument #1 ($database) must be of type Drupal\Core\Database\Driver\mysql\Connection, Drupal\mysql\Driver\Database\mysql\Connection given for #159.

@Rajab Natshah: please comment there with any additional info you find about it. Also see my suggestion there to see if appending ?module=mysql fixes the site:install for you. E.g., --db-url="mysql://root:rootpw@127.0.0.1/dev_d940x1?module=mysql".

xjm’s picture

Status: Closed (fixed) » Needs work
Issue tags: +Needs release note, +9.4.0 release notes
Related issues: +#3291224: Issues missing and broken link in 9.4.0 release notes

This is kind of the definition of a potentially disruptive change, and should have had a release note. We've added links to the related regressions to the release note, but we should also have one that explains the change itself, what will happen as a result, etc. A release note for it has also been requested in #3291224: Issues missing and broken link in 9.4.0 release notes.

Thanks!

alexpott’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs release note

Added a release note.

xjm’s picture

Issue summary: View changes

Linking the CR.

xjm’s picture

Status: Needs review » Fixed
joegl’s picture

Per xjm's comment I've created a new issue: https://www.drupal.org/project/drupal/issues/3292510

larowlan’s picture

In default.settings.php we have this comment:

 * The general format for the $databases array is as follows:
 * @code
 * $databases['default']['default'] = $info_array;
 * $databases['default']['replica'][] = $info_array;
 * $databases['default']['replica'][] = $info_array;
 * $databases['extra']['default'] = $info_array;
 * @endcode

Note the use of [] for replicas.
But it looks like the new code in \Drupal\Core\Site\Settings::initialize that adds in the namespaces, doesn't handle the array format

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

bkosborne’s picture

For some reason, sites in Acquia Site Factory (maybe Acquia Cloud Enterprise as well, not sure), this database update hook does not enable the MySQL module. It also doesn't get enabled when new sites are installed. It doesn't appear to be causing any problems, as I guess like I read in this issue, it's not technically required to have the module that provides a DB driver to be enabled. The status report page also doesn't show the error message indicating that the MySQL module needs to be installed.

This is because in Acquia, the 'autoload' key in the database connection string is not set. I don't know why, or how important that is. I opened a support ticket w/ Acquia just in case, because it seems like this might be problematic in the future.

daffie’s picture

Hi @bkosborne, sorry to hear have problems related to this issue. Technically the mysql module does not have to be installed at the current time, but that shall change. Therefor the mysql module should already be enabled. Or any other database driver module you may use.
As your problem are related with the Acquia site factory, my suggestion to you is to contact Acquia and let them fix the problem.