Repository navigation
Conversation
|
Thanks Adrian. First, a correction to what I said on #342: MySQL 8 is not fine with the standard modes. I missed it because no test sorted by a multi-value field. With MySQL 8's defaults ( On the good side, I measured the cost of the Ryan and I talked about where this should go, and here's what he'd like:
With those, a site can turn the standard modes on, on MySQL 8 or MariaDB, and nothing changes for sites that don't. #390 can follow once this is in. -Claude |
|
Hi Adrian, just checking in on this one, no rush. Are you still planning the rework from my last comment: the If you've moved on to other things, that's completely fine too. Just let us know and we can decide how to carry it forward. -Claude |
…h ONLY_FULL_GROUP_BY With the MySQL default SQL modes (ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES), MariaDB rejects a grouped query that selects a column it doesn't group or aggregate (1055), since it doesn't infer functional dependency on a primary key as MySQL 8 does. So a site can't boot: getById() fails in Pages::init(). These queries now aggregate those columns with MIN(). Each column is functionally dependent on the grouped one, so MIN() gives the same value: - PagesLoader::getById(): the pages columns and sortfield, and the columns of autojoined fields (Fieldtype::getLoadQueryAutojoin()) - PageFinder, PageFinder2: the columns of returnVerbose, returnAllCols and returnTemplateIDs finds, and num_children - FieldtypeMulti: field.count's count column - PagesAccess::rebuild(), PagesParents::findParents()/findParentIDs(), PagePaths::updatePagePathsChildren() - DatabaseQuerySelect::aggregateExpression()/isAggregateExpression() for these PW's default $config->dbSqlModes, which removes both modes, is unchanged.
…ly then Per review on processwire#388: default sites send the same SQL as before. - $database->onlyFullGroupBy(), cached per connection: known without a query when $config->dbSqlModes sets, adds or removes the mode (the default removes it), otherwise one SELECT @@sql_mode per connection, and again after sqlMode() changes it. Always false for SQLite and PostgreSQL. - The MIN() wrappers in getById(), the autojoin, field.count, PagesAccess, PagesParents and PagePaths apply only then. - Pages::getPageFinder() returns PageFinder2 when the mode is on, as do the nested finds in FieldtypePage, FieldtypeRepeater and PageRender, which create a PageFinder directly. PageFinder.php is unchanged from dev. - PageFinder2: its wrappers are conditional too, and findParentIDs(), which groups by pages.parent_id, aggregates its ORDER BY (MySQL 8 rejects ORDER BY pages.sort there; MariaDB doesn't check ORDER BY). - Tests: the mode switch, PageFinder2 selection and getById() SQL with the mode off and on; sort=roles, roles.name, -roles.name and roles.title. With the mode on, the PageFinder tests use PageFinder2.
812faee to
9971513
Compare
|
Thanks for the nudge. Yes, the rework is done and pushed (rebased onto dev 3a07228, new commit 9971513):
MySQL 8 found one more failure that MariaDB can't: PageFinder2's WireTests: 113/115 on MySQL 8.4 with -Adrian (via Claude Code) |
Step 1 of splitting #342, as agreed there: only the queries that fail outright under the standard SQL modes. PW's default
$config->dbSqlModes, which removes both modes, is unchanged, and sites that don't turn the modes on send exactly the same SQL as today.The problem. With MySQL's default SQL modes (ONLY_FULL_GROUP_BY and STRICT_TRANS_TABLES), MariaDB rejects a grouped query that selects a column it neither groups nor aggregates (error 1055), as it doesn't infer functional dependency on a primary key. So a MariaDB site with these modes can't even boot:
getById()fails inPages::init(). On MySQL 8, PageFinder's multi-value sorts (sort=roles) fail with 1055 on ORDER BY.The change.
$database->onlyFullGroupBy(), cached per connection. When$config->dbSqlModessets, adds or removes the mode (the default removes it), the answer is known with no query. Otherwise it is oneSELECT @@sql_modeper connection, asked again after$database->sqlMode()changes the mode. It is always false on SQLite and PostgreSQL.MIN(). Each column is functionally dependent on the grouped one, soMIN()returns the same value:PagesLoader::getById(): the pages columns andsortfield.Fieldtype::getLoadQueryAutojoin()does the same for autojoined fields.FieldtypeMulti: the count column offield.count.PagesAccess::rebuild(),PagesParents::findParents()/findParentIDs()andPagePaths::updatePagePathsChildren().PageFinder2: the columns ofreturnVerbose,returnAllColsandreturnTemplateIDsfinds, andnum_children. AlsofindParentIDs(), which groups bypages.parent_id, aggregates its ORDER BY: MySQL 8 rejectsORDER BY pages.sortthere.Pages::getPageFinder()returns PageFinder2, and so do the nested finds inFieldtypePage::getMatchQueryCustom(),FieldtypeRepeater(subfield matches) andPageRender(cache expiry selector), which create aPageFinderdirectly.PageFinder.phpis not changed.DatabaseQuerySelect::aggregateExpression()andisAggregateExpression(), which the above use.Tests:
PageFinder.test.php,testStrictSqlModes()(MySQL/MariaDB). With the mode off, it checks thatonlyFullGroupBy()is false, that$pagesuses the configured PageFinder, and thatgetById()still selectspages.*with noMIN(). With both modes on, it checks thatonlyFullGroupBy()is true, that PageFinder2 is used andgetById()aggregates, and then runs finds, sorts (includingsort=roles,roles.name,-roles.nameandroles.title),findVerboseIDs(), parent and template IDs,count(),num_children,children.count, both kinds of totals,field.count, a page load with a multi-value field autojoined, PagesParents, the PagesAccess rebuild and PagePaths. On SQLite/PostgreSQL it checks thatonlyFullGroupBy()is false.$pagesnever uses PageFinder then.DatabaseQuerySelect.test.php:aggregateExpression()andisAggregateExpression().WireTests (115 tests; WebAccess and WireHttp fail everywhere here, as they need a web server and network):
$config->dbSqlModes = []): 113/115, the same as PageFinder2 forced on with the modes, PageFinder2 alone, and PW's default modes.Size: 502 added lines: 128 of code, 130 of comments and docblocks, 25 blank, and 219 of tests.
Next: #390 (step 2: over-long values under STRICT_TRANS_TABLES), then step 3, the default.
-Adrian (via Claude Code)
🤖 Generated with Claude Code