Problem/Motivation
Running database queries as async queries lets us run them in parallel instead of sequentially. For pages with multiple "larger" queries this can speed up rendering such a page significantly. The problem is that the 3 by core supported database driver are all PDO drivers which do not support async queries. The PHP MySQLi extension does support async queries.
The other thing we need is PHP 8.1 with the Fiber functionality. Creating a database driver for MySQLi is the first step we need to make to start using async queries in Drupal.
@catch explained it as following:
Let's take something like https://www.drupal.org/dashboard - there's four or five different views on there in blocks.
If you hit a completely cold cache, you have to execute all the views building those blocks, including both the listing query, then rendering the entities within them.
The idea being explored is that for each lazy builder - let's assume we're able to loop over them, you'd render it up until you have to run a views listing query. When it's time to run that query (or whatever appropriate point to delegate to the Fiber), it's done inside a Fiber with a non-blocking query. You then ::suspend() the Fiber and return to the main process, and start the next lazy builder, if that also has to run a views listing query, you'd also run it non blocking and ::suspend(), then you loop over all the lazy builders again to see if the various queries have come back, then render the results for anything that has, then continue polling until everything is rendered.
The page still can't finish rendering until the slowest query is finished, but if you have five slow queries that take 500ms each, then you might be able to run them all at once in the space of 600ms-1s instead of definitely having to run them sequentially in 2.5s. While you're running those simultaneous queries, you can also get on with PHP/CPU-intensive tasks like rendering - assuming we're able to arrange things so that these can be interleaved.
Fibers only allow us to paralellize i/o, not CPU, because there's not any parallel execution at all, so it has to be something like an async MySQL or SOLR query or http request to make any difference, and there has to be something to be getting on with while it's running - either more i/o or something else.
Ideas template
What is the problem to solve?
It is very easy to configure Drupal in such a way that it generates slow database queries, views allows complex joins, sorts, aggregates. Sometimes these queries will be unoptimized, but still run quite quickly on a small dataset or when the database isn't under load, then as sites grow (in size and/or traffic) they start to show problems. We also ship the SQL-based search module in core. Once you add in blocks and layouts, there can be several slow listing queries on a single page.
Equally, Drupal relies a lot of discovery (theme registry, plugins etc.) which tends to be CPU intensive on cache misses and take a long time. And our rendering pipeline, even on only a render cache miss is quite expensive due to the granularity at which we render HTML.
PHP 8.1 added support for Fibers, which allows applications to execute non-blocking operations (like an async MySQL query), and then do something else (execute something else non-blocking, or something CPU intensive) in between firing the query and it being returned. This was previously possible with applications like amphp and reactphp but not in a way that was suitable for Drupal - your application would have to be built around those libraries.
Fibers allows the following:
1. I have a set of things (in Drupal's case, render placeholders are the first and most useful example) that I need to process all together. If one of them executes something asynchronous and suspends a fiber, I can move onto one of the other ones in the meantime. This is #3377570: Add PHP Fibers support to BigPipe and #3383449: Add Fibers support to Drupal\Core\Render\Renderer.
2. I've just fired off something asynchronous, if I've been called within a fiber, I can suspend it, and then when I'm resumed the query/http request etc. might already have been returned. This is what will be added by this issue.
The very, very important thing is that the code in #1 and the code in #2 don't need to explicitly know about each other or have any interdependencies, this way the application can become Fibers-aware cumulatively and any instance of #1 should work with any instance of #2 and vice-versa.
MySQL supports async queries, however PDO does not. We'd therefore add a driver based on MySQLi which does.
Who is this for?
Site builders and developers who want faster websites.
Result: what will be the outcome?
There will be a choice between PDO and MySQLi drivers when running Drupal with a MySQL database. Because we don't currently require mysqli, we can't just switch the current PDO driver over.Very far in the future we might consider deprecating the PDO driver or and moving it to contrib. the MYSQLi driver will probably be experimental to start with.
If the MYSQLi driver is installed, views (and probably search and entity queries) wil execute its query async if called within a fiber and suspend the fiber - this can be automatic without a configuration option. #3379883: [PP-1] Add async query execution support to views
How can we know the desired result is achieved?
Once all the pieces are in place, it should be fairly straightforward to show the performance improvement.
How do we expect this to impact Drupal users (site administrators, developers, or site builders)?
They will get an extra option when installing Drupal, depending on whether they have PDO or mysqli installed or both. Some site admins may want to switch their database driver over (possible by enabling the module then changing the databases array).
What kind of challenges do we expect this to cause with users? Does this break any existing installations / use-cases?
An extra choice on installation if your hosting supports mysqli and pdo, otherwise none. It should not break anything (except for regular bugs) and be transparent otherwise.
Does this add new dependencies to Drupal? If yes, is it available broadly enough or are there other concerns with the dependency?
No hard dependencies, but the MYSQLi driver will depend on the php_mysqli extension.
Is this something users would have to install or is it installed automatically for them?
They'll have to select it unless we eventually deprecate the PDO driver.
Are there reasons to not do this in the pre-existing Mysql module?
We need to continue to support PDO since not all hosting has php_mysqli enabled, so it has to be a new driver. However it might be fine to have both drivers in the same module.
Proposed resolution
Add a new MySQLi database driver.
This would initially be in its own module so it can be experimental. We could probably merge the driver into the main mysql module when it becomes stable.
Done
- test for #90.1
Fix the collation bug affectingBasicSyntaxTestin MySQL 8 (works on 5.7)Fix #89, either here relaxingNamedPlaceholderConverterto also allow placeholder's array keys not to have a colon, or in a separate issue fixing the syntax in the test.- #3364706: Refactor transactions
- #3265086: Implement statement classes using \Iterator to fix memory usage regression and prevent rewinding
-
#3256642: Introduce database driver extensions and autoload database drivers' dependencies
which makes extending one database driver on another database driver a lot easier. - #3347497: Introduce a FetchModeTrait to allow emulating PDO fetch modes
- #3217531: Deprecate usage of Connection::getDriverClass for some classes, and use standard autoloading instead
- #3384997: Rolling back to a savepoint should leave the savepoint in the transaction stack
- #3384999: Introduce a Schema::executeDdlStatement method
- #3487851: Replace \PDO::FETCH_* constants to indicate fetch mode with an enumeration
- #3488467: Introduce a StatementBase abstract class
Remaining tasks
TBD
User interface changes
TBD
API changes
None
Data model changes
None
Release notes snippet
TBD
| Comment | File | Size | Author |
|---|---|---|---|
| #168 | 3259709-nr-bot.txt | 16.47 KB | needs-review-queue-bot |
| #153 | gui post.png | 141.21 KB | mondrake |
| #153 | gui pre.png | 133.34 KB | mondrake |
| #153 | drush post.png | 71.56 KB | mondrake |
| #153 | drush pre.png | 60.21 KB | mondrake |
Issue fork drupal-3259709
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
Comment #2
daffie commentedAdding the release manager review tag as we creating a new module to Drupal.
Comment #3
daffie commentedThe Drupal testbot already has the PHP MySQLi extension enabled.
Comment #4
mondrakeIMHO we should also do #3217531: Deprecate usage of Connection::getDriverClass for some classes, and use standard autoloading instead to reduce bolierplate before starting this
Comment #5
catchI think we need to verify that this will actually be useful, by working on issues for some other parts of #3257726: [meta] Use Fibers for concurrency in core and then checking it does what we think it will do. But in principle adding a new driver as a new module sounds good.
Not sure why we'd do this though?
Comment #6
cilefen commentedDon’t you need product manager review?
Comment #7
catchYep I think so for a new module.
Comment #8
mondrakeStarted something at https://github.com/mondrake/mysqli, copying from mysql. We would also need #3124382: Remove per-table prefixing and #3231950: Split Database tests in 'core' ones and 'driver specific' ones done before, though.
Comment #9
mondrake#8 is more or less working. The driver installs, most Database tests pass. There are issues with the fact that mysqli does not support
inTransaction(), still to work out as much as proper statementrowCount().I will spin off a separate issue to address couple of things that if core addresses will make the mysqli module code simpler.
Comment #10
mondrakeFiled #3260007: Decouple Connection from the wrapped PDO connection to allow alternative clients
Comment #11
mondrakeFTR: there’s also a PHP Async client fo PHP, https://github.com/amphp/mysql
Comment #12
andypostThe most interesting is sqlite client as it could use "bundled bootstrap database" so core could run out of box
Comment #13
mondrakeSo, after a fierce fight with mysqli's limping transaction management functions, now all the group=Database tests are passing for the mysqli module on GitHub. As of next Drush release (>11.0.5), it will also be possible to install Drupal via CLI.
See know limitations, and patches required, in the README.
Comment #14
andypostAs I see https://github.com/php/php-src/pull/7889 also mostly ready, so using mysqli will benefit decoupling from libmysql client libs
Comment #15
andypost@mondrake great work! I think it makes sense to file issue to php-src (at Github) about savepoints, maybe it's a supposed behavior
Comment #16
andypost@mondrake as I see it depends on which kind of library used for mysqli https://github.com/php/php-src/blob/PHP-8.1.2/ext/mysqli/mysqli_nonapi.c...
Comment #17
mondrake@andypost mind opening the issue to php-src? I'm not familiar.
#16 that seems related to savepoints, not rollbacks?
Comment #18
daffie commented@mondrake: Great work with https://github.com/mondrake/mysqli!
Comment #19
user654 commented.
Comment #20
mondrakeNice writeup re differences between PDOMYSql and mysqli, https://websitebeaver.com/php-pdo-vs-mysqli
Comment #21
catchFrom the github repo, it looks like any core inclusion is currently blocked on #3110546: Allow contributed modules (mostly database drivers) to override tests in core and #3256642: Introduce database driver extensions and autoload database drivers' dependencies, so I'm going to mark this PP-2.
None of this would stop us trying out some proof of concept stuff with PHP Fibers though.
Comment #22
mondrakeActually, #3110546: Allow contributed modules (mostly database drivers) to override tests in core is only necessary on GitHub to skip running the ApcuBackendTest on GHA - I couldn't find a away to enable APCu properly there, so I am still skipping it.
However, I would say that to be on a preferrable scenario, we would need two more issues in first:
#3217699: Convert select query extenders to backend-overrideable services - this left harbour one year ago, then sank couple of weeks later, with only limited SAR activities afterwards. It's tagged for framework manager review.
#3217531: Deprecate usage of Connection::getDriverClass for some classes, and use standard autoloading instead - to reduce boilerplate empty classes, which is blocked on the above
Comment #23
mondrakeActually, #3265086: Implement statement classes using \Iterator to fix memory usage regression and prevent rewinding too.
Comment #24
mondrakeComment #25
mondrakeComment #26
mondrakeComment #27
mondrakeComment #28
mondrakeComment #29
mondrakeHaving committed #3217531: Deprecate usage of Connection::getDriverClass for some classes, and use standard autoloading instead, now #3217699: Convert select query extenders to backend-overrideable services is not strictly necessary to get this moving on.
Comment #30
mondrakeComment #31
mondrakeComment #32
catchLast blocker is in.
Comment #33
catchFrom the issue summary:
Why would we need the MySQLi extension for the current PDO-based MySQL driver?
Comment #34
andypostVery probably it means
mysqlndextension which is primary driver for Mysql and it's reused by PDO_mysql at leastComment #35
mondrakeI'm still doing some changes on the mysqli module on GitHub - I'd like to have it pass tests there before moving the code here. Also, I think we should try to refactor there the parser code that was taken from doctrine/dbal to manage converting SQL statements from having named placeholders (':placeholder') to have positional placeholders ('?') - it's overkill for the specific purpose here.
Question: do we want to introduce a new 'mysqli' module, or shall we try to have a single 'mysql' module with two drivers, 'mysql' and 'mysqli'?
Comment #36
catch@lauriii posted some question in slack, added them, and the answers to the issue summary.
Comment #37
catchTwo drivers in the existing module might be simpler, but:
1. Can we make it work where only one option is available due to installed extensions? And also not show drivers that won't work to people?
2. Would there be any need for the new driver to be experimental?
btw depending on the answers to this, there might be issue summary updates needed now.
Comment #38
catchComment #39
catchComment #40
catchComment #41
catchComment #42
gábor hojtsyLauri pinged me to provide feedback as a product manager. These two statements are contradictory and are critical to asses the impact of the proposal I think :)
vs
Comment #43
mondrakeIMHO there's no need to add the PHP MySQLi extension as a requirement to the core (PDO, existing) MySQL database driver.
That will obviously have to be a requirement for the NEW MySQLi driver, though.
The installability of a driver is driven by the
installable()method in theInstall/Tasksclass of each driver.For the existing PDO/MySQL driver it is inheriting from the base class
For the new driver it will be something like
Comment #44
andypostI think in case if both drivers are available some description should explain benefits using mysqli
So on the most of hostings user could contact support to ask more performant driver
If benefits is obvious then we can add some logic to set "preferred driver" at install screen
Comment #45
mondrakeI'll start adding the code from GitHub as a separate module, since I understand the driver may start as experimental, and I do not think we can have a module with a released driver and an experimental one in the same base.
Comment #47
mondrakeOK, now code checks pass. I suppose the next step is to get tests run using the new driver, but I have no clue how this can happen. I assume infra need to do infra things?
Comment #48
andypostI filed #3384661: Upgrade PHP 8.2 image to 8.2.10 and as the new image will pass tests we can and mysqli extension
Comment #49
andypostThe extension already in the CI image
EDIT from container log - PHP settings are
./configure --with-config-file-path=/usr/local/etc/php --with-config-file-scan-dir=/usr/local/etc/php/conf.d --enable-ftp --enable-mbstring --enable-mysqlnd --with-curl --with-libedit --with-zlib --with-kerberos --with-openssl --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-pdo-sqlite --with-pdo-pgsql --enable-phpdbg --with-readline --with-freetype --with-zlib-dir --with-jpeg --with-mcrypt --with-xsl --with-tidy --with-xmlrpc --with-gettext=shared --enable-gd --with-webp --with-avif --with-pear --enable-sockets --enable-exif --with-zip --enable-soap --enable-sysvsem --enable-cgi --enable-sysvshm --enable-shmop --enable-pcntl --enable-bcmath --enable-xmlreader --enable-intl --enable-opcache --with-apxsComment #50
andypost@mondrake I think you can edit drupalci.yml to run only new module's testgroup
Comment #51
mondrake#50 no I think we need first to be able to install using the new driver. I.e. a new test environment option like
Test PHP 8.1 & MySQL 5.7 via MySQLi. Editing drupalci.yml we can only get the new module test to run with the other PDO drivers under the hood.Comment #52
mondrakeAttention - the driver requires minimum PHP 8.1.2 where this was fixed.
Comment #53
andypost@mondrake as I see last CI run https://dispatcher.drupalci.org/job/drupal_patches/201116/testReport/Dat...
there's mysqli tests running fine)
Comment #54
chi commentedPosgres also supports async queries
https://www.php.net/manual/en/function.pg-send-query.php
Is there a chance that Drupal some day would have a driver for it?
Comment #55
catchI've updated the issue summary to remove the bit about the mysqli requirement on the PDO driver and to say we'll start with an experimental module but eventually merge the stable driver into the main mysql module.
@Chi a pgsql driver should be able to build on the work done here, so that seems possible if someone's motivated to work on it.
Comment #56
chi commentedI think mysqli module should implement hook_requirements() and check if PHP MySQLI extension is available.
Comment #57
mondrakeComment #58
mondrake#56 maybe, but I do not think that's relevant. During early installation there's no module concept yet, and installability of a driver is checked as described in #43.
Comment #59
catchWe already recommend PHP 8.1.6 or above. Easy to add a hard requirement on PHP 8.1.6 to the experimental module, but we could probably only add a hook_requirements() warning checking the database settings + PHP version once it's incorporated into the main mysql module.
I wonder if we should try to do the mysqli testing directly on gitlab CI rather than getting a new environment on DrupalCI since it's getting a lot closer to the point where core can switch over entirely - not sure exactly how close though and wouldn't want to artificially hold this up on that either.
Comment #60
catchI did some googling about PDO support for async and found the PDO brainstorming page: https://wiki.php.net/internals/pdo/brainstorming
If that's up-to-date, then it's been discussed, but nothing has happened for years. It's possible that PHP Fibers support will increase demand and might spur some activity, but I think we're looking at more years before it would be supported, if ever.
Should we open a follow-up on how to handle the actual async support? For the BigPipe/Renderer implementations of fibers the main use case is to fire off a single async query, suspend the fiber so the calling code can do something else, then when we're resumed see if it came back. It looks like this might require multiple database connections (since 'something else' could also be executing database queries) so could be a bit tricky.
I can't see us needing or wanting to execute multiple queries async in core although support for that would be good to add at some point, maybe its own issue.
edit: opened the follow-up #3384763: Async database query + fiber support
Comment #61
mondrake##6 Yeah I think better have that as a follow-up, the issue here I think it's to get a mysqli driver that is like-for-like the pdo_mysql one.
Comment #62
daffie commented@mondrake: It looks good. Are you going to be the official maintainer of this new database ddriver?
Comment #63
andypostProbably it will be easier to fix credentials in gitlabci as drupalci_testbot has a lot of things hardcoded
Comment #64
fjgarlin commentedReplied via slack, copying here too:
This is the way we are defining the database and variables for GitlabCI for core: https://git.drupalcode.org/project/gitlab_ci_testbed_for_drupal_core/-/b...
Note that this uses the images generated from https://git.drupalcode.org/project/drupalci_environments but does not use https://git.drupalcode.org/project/drupalci_testbot to run the tests.
We connect the images via the
.gitlab-ci.ymlfile and just call thecore/scripts/run-tests.shfile to run the tests, so everything you need should be able to be set here: https://git.drupalcode.org/project/gitlab_ci_testbed_for_drupal_core/-/b...Comment #65
mondrakeI *think* now on GitlabCI we can run tests on the new driver by only changing the database URL. Just for the sake of getting it run I changed in the MR from the PDO MySQL driver to mysqli, obviously the change would have to be structured moving forward.
Comment #66
mondrakeYes, a failure like
tells us that the pipeline used the new driver for testing.
Comment #67
mondrakeThere are quite a few things to fix looking at the pipeline failures.
Comment #68
mondrakeFound a blocker. Filed #3389202: migrate\Plugin\migrate\id_map\Sql assumes a PDO db driver.
Comment #69
mondrakeThere are update tests failing because the database dumps contain the 'mysql' module installed, but since the test are run with 'mysqli', when updating we get a requirement error 'install the mysqli module that contains the database driver'.
Not sure how to tackle that.
Comment #70
andypostit could use update hook to pass upgrade tests, or it will need common fixture to apply to all this tests
Comment #71
catchI think we've had the same problem when the database driver modules were introduced in the first place, the way to fix it is to re-import the database dump into a real site, install the mysqli module, then re-export the database dump. Then it gets picked up when you try to update from the dump and everything works (or hopefully). You have to rewrite history to make it seem as if the mysqli module existed at the time of the dump - so it might mean manually copying the module folder back to the old commit hash that you import the database dump to, or potentially manually editing the uncompressed dump to add the correct lines etc.
Comment #72
mondrakeThanks for #71 (that's what I was afraid of :))
Tried manually updating the dump files, just to add 'mysqli' to the
system.schemakey_value collection (should suffice? module has no config), then compressing them with$ tar -czf drupal-9.4.0.bare.standard.php.gz drupal-9.4.0.bare.standard.phpBut now the import fails during the update test with
ParseError: syntax error, unexpected character 0x00, expecting end of fileIt could be some wrong way of calling tar?
Just throwing here if anyone has faced this earlier and has a ready-made answer
Comment #73
mondrake#72 actually found #3305003: Create standard steps for creating database dumps.
Comment #74
mondrakeFTR, the changes to the database dumps:
Note - do not use
tarfor the purpose as it fills files with null characters at the endComment #75
mondrakeWe are almost there. There are still a handful of installer test failures, again because an attempted uninstall of the 'mysql' module fails since it is a dependency of the new module, and 2 kernel tests that fail on MySql 8 but not on MySql 5.7.
Comment #76
mondrakeSo, this is passing on MySQL 5.7 now, but not on MySQL 8 because of this test failing:
I cannot reproduce this locally; can it be it's some setting of MySQL8 on the runner?
Also,
Drupal\Tests\mysqli\Kernel\mysqli\LargeQueryTestbehaves erratically, if I remove the dump() in it then the statement errors under destruction (?).Apart from these two, I think this can go through more heavy-lifting reviewing.
Some help would be appreciated on the GitlabCI set-up to make this run independently from the PDO-Mysql tests; the current changes are only a shortcut to make test run with mysqli instead of pdo_mysql.
Comment #77
fjgarlin commentedI added the async job as a separate job and left the others as they were. Note that this issue contains #3392739: _TARGET_DB_TYPE does not exist that will be committed shortly, so we might get a conflict on the rebase. I can take care of it.
Comment #78
catchWe might want to call it 'MYSQLI' instead of 'ASYNC' but otherwise that looks great.
Comment #79
mondrakeNow I understand the logic, thanks a lot @fjgarlin.
How about generalizing more, and instead of DB_ASYNC, add two more variables
_TARGET_DB_DRIVER
_TARGET_DB_DRIVER_MODULE
and use them too in building the database URL?
Comment #80
fjgarlin commented@mondrake - we initially had some more variables around the database type and version, but wanted to simplify the job definition as much as possible, so it's easy to understand and to create new jobs. Having said that, it's an option.
Right now, we only added an optional variable, which I think keeps the simplicity of new jobs. I renamed it as suggested in #78 but feel free to rename it again if there is a better name.
Comment #81
ghost of drupal pastI had some misgivings on user space parsing of SQL but there's nothing better we can do: I hoped we could reuse the parser in PDO. Alas, this is not doable. If you need the grisly details, see below.
PDO::ATTR_EMULATE_PREPARESis set to true, the query gets parsed onexecuteand the parsed query is displayed byPDOStatement::debugDumpParamshowever the parameters are replaced with their values. This happens in ext/pdo/pdo_stmt.c, search for stmt->active_query_string.mysql_handle_preparerthe only time this string is used it is passed outside of PHP, tomysql_stmt_preparewithin the MySQL driver. Sad. Maybe the caller could help? This preparer is called here and it does passstatementas a pointer to the variable, so the caller could in theory do something with it but it does not, the variable is never used again. So unless the MySQL API has a way to read the query out of a prepared statement and PDO exposes this we can not use this parsed result despite it is exactly what we need. Looking at the MySQL API, the documentation says "TheMYSQL_STMTstructure has no members intended for application use" so the only hope is a function but there is none.We could write a small patch to be included in PHP-next which would allow us to drop the userspace parser in D11 or D12. I will try.
Comment #82
mondrakeworking on a unit test for
NamedPlaceholderConverterComment #83
mondrakeAdded tests for
NamedPlaceholderConverter.Comment #84
mondrake@chx thanks for #81.
Clearly,
NamedPlaceholderConverteris not optimal: it destroys and rebuilds a SQL statement that was built already.A solution to try and retrieve from pdo_mysql something to be used by mysqli is for me ... weird. It'd keep PDO as a required PHP extension, and would just move the parsing from our class to PHP internals. If (if, I dunno) that would also require establishing a client connection it would be even more weird.
On the other side, IIUC mysqli is meant to be a very thin client. Expecting it to implement positional placeholders would be against its concept.
Personally, I think we should aim at trying to embed alternative placeholder generation (positional/named) into dynamic queries instead - and avoid reparsing post-factum. It would definitely increase performance. Then, we should be able to still do the placeholder conversion for static queries - allowing an option to be passed to
::query(). But that would be D11 material IMHO.Comment #85
daffie commentedI have talked to @longwave, @alexpott and @catch about the new MySQLi database driver. The plan that we came up with is the following:
Also when users install a new Drupal site they need to see this module as experimental instead of it being a regular module.After talking to @lauriii the decision was that the MySQLi driver needs to be hidden.'driver' => 'mysqlto'driver' => 'mysqli'. Just adding theito mysql. For new site installs the MySQLi database driver becomes the default option.To do in this patch:
Updated the post with that the MySQLi starts with being hidden when the module is experimental.
Comment #86
longwaveFrom a release management point of view the plan in #85 looks good to me. I suggest also opening a plan issue for the mysqli driver with the steps from #85 so we have them documented as what is left after this issue is committed.
Comment #87
daffie commentedI have talked to @laurii in person and as long as the module is hidden for new site install as long as the module is experimental, am I allowed to remove the "Needs product manager review". Updated comment #85.
Comment #88
mondrakeThanks for #85! Looks clear to me. Re. #85.2, I suggest to add #84
to the meta plan suggested in #86.
Comment #89
mondrakeNow, we have a failure in the recently fixed
SqlContentEntityStorageRevisionDataCleanupTest.This is due to this code
The arguments in the queries of this test DO NOT HAVE the colon in front, i.e. it should be
':nid' => 8.Apparently the PDO-based drivers do not care, even if https://www.drupal.org/docs/drupal-apis/database-api/static-queries#plac... examples clearly indicate placeholders should have the colon.
I'm not sure whether we should fix the test, or relax
NamedPlaceholderConverterto also allow placeholder's array keys not to have a colon.Comment #90
mondrakeDone the two points from #85 that are for this issue,
but tests are missing. Any idea/reference on how to do those?
Comment #91
catchJust a note I have #3384763: Async database query + fiber support open for the next step (or next two steps, depending on how much async support we add in one issue vs. two).
Comment #92
mondrakeUpdated IS with a list of todos remaining here; feel free to add what is necessary.
Also help on the points would be appreciated.
Comment #93
mondrakeRe #89 I eventually thought that even if
SqlContentEntityStorageRevisionDataCleanupTestshould be probably fixed, nevertheless it's better allow parameter arrays with keys missing the initial colon, given that PDO seems to be supporting both. So we can support contrib code that might have missed this detail.Comment #94
mondrakeFixed the collation bug affecting
BasicSyntaxTestin MySQL 8. I had to move the test to driver-specific, and for mysqli force conversion of the parameters' values toutf8mb4. Not sure it's the right thing to do but could not find other options. It's an edge case anyway, and could not replicate the issue locally either.Tests are now green on mysqli for both MySQL 5.7 and 8.
Comment #95
mondrakeAdded test to ensure module is experimental and hidden.
Comment #96
daffie commentedComment #97
mondrakePostponing on the referenced issues, that will make the management of the lack of transactional DDL support consistent across the two drivers.
Comment #98
daffie commentedMaybe the module should not be hidden and removed from the database selection during the install process. We want to allow site owners to experiment with the mysqli database driver and therefor the module should be visible on the module list.
Comment #99
mondrakeUhm... I don't remember how it works. Definitely, a 'module' extension is different from a 'database_driver' extension. The list of database to be presented for installation is independent from the modules, simply because there's is even no notion of the 'module' at that stage of the installation process. So, it could be the database driver 'mysqli' is presented for (a grassroot) installation if the PHP mysqli extension is available, even if the module itself is hidden. Then, during the (grassroot) installation, the mysqli module is installed automatically (even if hidden). But since it's hidden, there will be no way to uninstall/install it from the UI (that, when it's accessed, presumes all the installation, config and bootstrap to be complete).
Worth giving a manual test to all this process, I guess.
Then, if the expectation is to just allow changing
'driver' => 'mysql',to'driver' => 'mysqli',in settings.php to play around, then we have more to do - i.e. disallow reading the namespace from settings.php in this case (because that will be still the mysql one, and an existing 'namespace' key in the settings takes priority on the 'driver' key), and allow manually installing the mysqli module (so removing the hidden: true from the module yaml).Comment #100
mondrakeThanks for your reviews and input, @daffie. Would you mind checking back the inline comments and replies and not which ones we can mark as solved from your POV, so we can just keep the open ones to work on?
Comment #101
mondrakeFiled #3399150: [PP-2] Enable dynamic queries to produce SQL with positional placeholders for follow up.
Comment #102
mondrakeRebased, with the exception of database dumps which is a pain in the neck to do; that update IMHO should be done just before commit.
Comment #103
bstan commentedThe mysqli construction approach has limited ability to define an SSL connection, but leveraging the procedural approach allows you to establish options prior to making a connection.
For example:
Comment #104
mondrakeComment #105
catchWhich issue is this postponed on? I can't see anything listed in the issue summary.
Comment #106
amateescu commentedIt's currently postponed on #3384999: Introduce a Schema::executeDdlStatement method per #97.
Comment #107
catchThanks added a note to the issue summary.
Comment #108
daffie commented#3384999: Introduce a Schema::executeDdlStatement method has landed.
Comment #109
andypostLooks it still blocked on #3487851: Replace \PDO::FETCH_* constants to indicate fetch mode with an enumeration
Comment #110
mondrakeI am working on #3488467: Introduce a StatementBase abstract class which I believe would be simplifying the Statement class here.
Comment #112
mondrakeMR!1135 incorporates the changes of #3488467: Introduce a StatementBase abstract class and makes evident the simplification possible on the Statement class.
Comment #113
daffie commentedWe need the following code change to fix the failing Drupal\Tests\help\Functional\HelpTest.
Comment #114
daffie commentedThe NamedPlaceholderConverterTest has been added. Therefore removing the tag "Needs tests".
Comment #115
daffie commentedA lot of update tests are failing because they use
core/modules/system/tests/fixtures/update/drupal-10.3.0.bare.standard.php.gzorcore/modules/system/tests/fixtures/update/drupal-10.3.0.filled.standard.php.gzand the module mysqli has not been included in those fixtures.Comment #116
daffie commentedThe Drupal\Core\EventSubscriber\ConfigImportSubscriber can be fixed with the following code change:
Comment #117
mondrakeComment #120
mondrakeMade some progress. This is now postponed on #3488467: Introduce a StatementBase abstract class.
Comment #121
daffie commented#3488467: Introduce a StatementBase abstract class has landed.
Comment #122
mondrakeComment #123
mondrakeFor review. Fixing fixtures for update tests is a real PITA, so please let's focus on other items for now and let's address them when we are all comfortable with all the rest. Thanks.
Comment #124
mondrakeFiled #3516489: @phpstan-ignore-next-line annotation collides with PHPCS in the Coder issue queue.
Comment #125
mondrakeThere's a smarter way than adding a Schema class override. Working on it.
Comment #126
mondrakeIntroduced a
SchemaPrimaryKeyMustBeDroppedExceptionto abstract the error and drop theSchemaclass.Comment #127
mondrakePre-8.0 MySql ANSI modes were removed in #3421175: Update INSTALL.txt and hook_requirements() etc. with remaining Drupal 11 platform requirements, adjusted Connection::__construct() accordingly.
Comment #128
mondrakeCharset toggling was removed in #3437786: Remove MYSQLND_MINIMUM_VERSION and LIBMYSQLCLIENT_MINIMUM_VERSION checks, adjusted Connection::open() accordingly.
Comment #129
mondrakeFiled https://github.com/drush-ops/drush/issues/6266 in drush issue queue; drush will need some adjustment to make it work with this module when it will be committed to core.
Comment #130
daffie commentedAlmost forgot: @mondrake could you update those fixtures. For me it is almost ready for a RTBC.
Comment #131
mondrake@daffie
Are you talking about the kernel driver-specific tests? If so, they are run for mysqli based on inheritance from the mysql ones, we need not do anything. If something else, can you elaborate?
Comment #132
mondrakeAdded a mock CR... please help filling it in :)
Comment #133
mondrakeI am not familiar with such tests; can anybody point me to an example to work from, in case?
Comment #134
daffie commentedThe test in the namespace
Drupal\FunctionalTests\InstallerI will do that.
For #131: For example core/modules/system/tests/src/Functional/System/DatabaseDriverProvidedByModuleTest.php
Comment #135
mondrake#134 I looked at tests in that namespace, but still I miss what such a test should be written for, here.
Comment #136
daffie commentedYes, you are right. The mysqli driver is hidden and therefore does not show up in the install process. My bad.
I have updated the CR.
Now we just need to update the fixtures and the CI pipeline to be green, then it is RTBC for me.
Comment #137
mondrakeThanks @daffie
Sanity check on #136, before I get hands dirty with db fixtures: apart from Drupal\Tests\mysql\Functional\RequirementsTest, all the other failing tests are update tests that rely on the 10.3 db dump fixtures.
Are we really sure we want to rewrite history and pretend a mysqli module was available in 10.3? In real life no one will ever update from a 10.3 install that already has mysqli installed. So is it right to rewrite history to make the tests happy, or should we just skip somehow the tests?
The situation in #71 was different - there we had the 'modulification' of db drivers that were already present beforehand, here we are introducing a totally new module.
I'll ping @catch for an opinion here too
Comment #138
daffie commentedI am fine with skipping Drupal\Tests\mysql\Functional\RequirementsTest.
Comment #139
mondrake#138 well we are missing a c/p of mysql.install in this module so that the requirements can be rendered... that file was added to core 2 years ago in #2733675: Warning when mysql is not set to READ-COMMITTED but did not get its way into the mysqli module. So the test failure is legitimate I think and we should fix it.
Comment #140
mondrakeIn https://git.drupalcode.org/project/drupal/-/merge_requests/11355/diffs?c..., we are skipping the update tests if the driver is mysqli and the database dump is from drupal-10.3.0.
I think this is more realistic and avoids tampering with database dump fixtures.
Comment #141
daffie commented@mondrake: Skipping the exiting update tests is not a problem. Only we need those fixtures for all the future update tests. Do you want me to do it?
Comment #142
mondrakeThe future update tests, relevant for mysqli, will be those introduced to update from 11.2 to above, right? Because those introduced before 11.2 are not relevant since the module is not released yet.
Then the task will be to add a new database dump for 11.2.0, at that moment including the install of myqli.
But that's a separate issue from here if we agree to proceed as per #140. A new dump will get its own 11.2.0 version name and this check
will no longer skip the test, if the test requires that dump. But it will keep skipping tests using the 10.3.0 dump.
In other words: if we do this, we do not need to change the fixtures now. We can wait for 11.2 to be released.
Comment #143
mondrakePipelines are green, yay.
Comment #144
daffie commentedAll code changes look good to me.
The new database driver is marked as "hidden" and therefore does not show up on in the install process.
The new database driver is marked as "experimental" and therefore not yet fully supported.
The CI pipeline is green for the mysql and the new mysqli drivers.
The IS and the CR are in order.
For me it is RTBC.
For the committer: As the database driver will be added to Drupal 11.2, all update test are skipped. There are no Drupal sites <11.2 with the new MySQLi database driver. The problem is that the first person who want to add an update test to Drupal 11.3 will have to create new fixtures which need to include the mysqli module.
Comment #145
andypostRtbc++ for db dumps there's follow-up #3305003: Create standard steps for creating database dumps
Comment #146
mondrakeDrush problem reported in #129 is actually due to a bug in
Connection::convertDbUrlToConnectionInfo()that is checking existence of a class before the dependent classes can be autoloaded. Fixed here, but this needs to go back to NR for the fix now, sorry.Comment #147
daffie commentedComment #148
mondrakedone, tks
Comment #149
daffie commentedThe change looks good.
Back to RTBC.
Comment #150
mondrakeFound that
mysqli::exec()does not exist while testing manually the GUI installation and database is not yet present.Comment #151
andypostCreating a database is a nice nitpick, back to RTBC
Comment #152
mondrakeTesting manually, I can see the new driver showing up at installation time. The CR says differently, so it needs update. Besides, there is no indication that the driver is experimental or hidden - those are 'module' notions, but at the stage of database selection in the installer modules are not yet a thing. So if you select the mysqli driver for installation, its 'experimentality' is a consequence as the driver is included in the mysqli module that is enabled as part of the install process and is marked experimental.
I will add explicitly '(experimental)' in the driver string for now. In a follow up, we could add an additional Connection method indicating and reporting the db client in use (it being PDO, mysqli, oci8, sqlite3, etc).
Comment #153
mondrakeDone #152. Added pre/post screenshots drush and GUI.
Comment #154
daffie commentedGood that the label "Experimental" was added to the database driver description.
I have updated the CR.
Back to RTBC.
Comment #156
mondrakeOne question inline related to copyright
Comment #157
alexpottFound #3524656: Fix Drupal\Core\Database\Fetch* types as they are wrong while reviewing this one.
Comment #158
alexpottUpdating issue credit.
Comment #159
mondrakeLooking into latest feedback.
Comment #160
mondrakeOk, I think we are safe assuming if anyone is using the
mysqlidriver, we will not support doing magic to fix malformed settings in settings.php like we do for the drivers that were present in Drupal before database drivers became modules.Comment #161
andypostThank you! Let's get it in and discover perf issues in follow-up as jobs on mysqli looks little bit slower
Comment #162
mondrake#161 well for sure
NamedPlaceholderConverterhas its own overhead. But yea... later.Comment #163
mondrakeAdjusting new tests to use attributes.
Comment #164
mondrakeComment #165
andypostback to RTBC as changes reflect latest core commits
Comment #166
mondrakeComment #167
mondrakeComment #168
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #169
mondrakePostponed on #3497431: Deprecate TestDiscovery test file scanning, use PHPUnit API instead
Comment #172
mondrakeMR !12367 was a mistake.
Comment #173
mondrakeUnblocked. Rebased and fixed new CS errors reported.
Comment #174
gábor hojtsyDid not land in 11.2, so updated the CR draft to say 11.3. Also tagging for release highlights for 11.3.
Comment #175
alexpottLet's get this in 11.x nice and early to allow us to work on the follow-ups and get them in 11.3.0 too.
Committed 42b7481 and pushed to 11.x. Thanks!
Comment #177
andyposthelpful follow-up for contributors #3531022: Let run-tests.sh print db type and version in the initial output
Comment #179
damienmckennaWould it be worth a separate issue to simplify the implementation logic so the extra $databases[..]['dependencies'] logic could be automatic based upon the class hierarchy rather than needing to be explicitly defined?
Comment #181
anybodyUnsure if this is truly related and might be caused by this change, but I'd like to draw attention to #3582827: FiberError: Cannot switch fibers in current execution context (Backup Migrate)