Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX PHP 8.1 support in MySQLiConnector::query errors #10570

Merged

Conversation

NightJar
Copy link
Contributor

@NightJar NightJar commented Nov 5, 2022

Issue #10613

The default error reporting mode in PHP 8.1 has changed from using errors reported on the connection handle to throwing mysqli_sql_exception. query() makes no allowance for this, and functions up the call stack expect to catch
Silverstripe\ORM\Connect\DatabaseException instead - resulting in the MySQLi exception going all the way up to halt the system.

We can use a try, catch, and finally to retain backwards compatibility, no matter which setting (e.g. PHP version default) someone has enabled.

C.f. https://www.php.net/manual/en/migration81.incompatible.php#migration81.incompatible.mysqli

The default error reporting mode in PHP 8.1 has changed from using
errors reported on the connection handle to throwing
mysqli_sql_exception. query() makes no allowance for this, and
functions up the call stack expect to catch
Silverstripe\ORM\Connect\DatabaseException instead - resulting in the
MySQLi exception going all the way up to halt the system.

We can use a try, catch, and finally to retain backwards compatibility,
no matter which setting (e.g. PHP version default) someone has enabled.
@NightJar
Copy link
Contributor Author

NightJar commented Nov 5, 2022

This fixes an issue for any site with subsites installed being unable to successfully run a dev/build without an existing database (e.g. setting up for development).

@michalkleiner
Copy link
Contributor

michalkleiner commented Nov 8, 2022

@NightJar I thought we were testing on PHP 8.1 before, do you know if there's a test relating to and/or why it was not failing before?

@NightJar
Copy link
Contributor Author

do you know if there's a test

There are no existing tests, this change set adds some.

why it was not failing before?

Probably the same reason there's no change to the use statements atop the file in this change set ;)

I presume because the most common code path is to use prepareStatement rather than query... OR even more simply that the calling codes purpose is to not cause an error.

In the Subsites case this is an issue only because the code may run before the database is ready (e.g. first dev/build on a fresh dev environment).

Copy link
Contributor

@michalkleiner michalkleiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok to me but I'd prefer another set of @silverstripe/core-team eyes over it.

Copy link
Member

@emteknetnz emteknetnz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this.

Looks fine, though small thing would like marking the tests as skipped moved back out of the new private method


if (strtolower(substr($config['type'] ?? '', 0, 5)) !== 'mysql') {
return $this->markTestSkipped('The test only relevant for MySQL');
}

if ($charset) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving the duplicate logic to this new private method is OK, except for the bit where the marking test as skipped if it's it's not running mysql - It makes it far less obvious could you please re-duplicate those bits and move those lines back to the individual tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll put it in setUp instead. This makes it super obvious it runs before each test case.

As review feedback; marking the test as skipped in a private function
obfuscated where the call was happening and made it harder to skimread
the tests. Moving this into a setUp function makes it obvious the check
is run before each test case, and skipped if necessary.
@MasonD
Copy link
Contributor

MasonD commented Jan 18, 2023

preparedQuery actually still has this same problem. There’s a catch in prepareStatement but no catch around $statement->execute() in preparedQuery itself, encountering the same problem as query is having if the sql is syntactically correct but the execution causes an error (for example inserting/updating that causes unique contraint clashes)

Copy link
Member

@emteknetnz emteknetnz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I've re-targeted this PR to 4.13 since it's the oldest currently supported version. I've run a fork on this PR (rebased on 4.13) against silverstripe/installer here which went green

@emteknetnz emteknetnz merged commit 8c3ba81 into silverstripe:4.13 Jul 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants