fix(db): tolerate duplicate column names when counting tree lists#5771
Conversation
|
@e107help: All the acceptance tests are failing now: Could you look into this and make sure we're not regressing? |
f26da04 to
d45b2ab
Compare
e_tree_model::countResults() builds the pagination total by wrapping the list query in a derived table. MySQL and MariaDB allow a top-level "SELECT t1.*, t2.*" to repeat a column name but reject duplicate names inside a derived table, so any admin list joining two tables that share a column failed with "1060 Duplicate column name". The Users list hit this whenever user.user_timezone (an orphan 0.7.x column left on upgraded sites) coexisted with user_extended.user_timezone. A multi-wildcard projection contributes nothing to COUNT(*), so when the projection expands two or more "alias.*" wildcards it is replaced with a constant before wrapping. The leading projection is located with a parenthesis- and quote-aware scan for the first top-level FROM, so a correlated subquery in the projection (e.g. the Book/Chapter list's chapter_page_count) is never mistaken for the real FROM. Every other query, including single-wildcard and DISTINCT projections, is wrapped verbatim. Adds unit coverage for the projection rewrite and the verbatim paths, plus end-to-end guards that count both a duplicate-column join and a correlated-subquery list without error. Fixes #5761
d45b2ab to
79b6f9f
Compare
|
@Deltik Good catch on the acceptance failure, and sorry for the runaround. Owning this one properly. The syntax error you flagged. My first cut reduced the count projection with a non-greedy SELECT a.*, ... ,
(SELECT COUNT(*) FROM `#page` p WHERE p.page_chapter = a.chapter_id) AS chapter_page_count
FROM `#page_chapters` AS a ...The regex cheerfully stopped at the subquery's So I've stopped leaning on one clever regex:
A second snag the CI matrix then turned up. Once that fix was in, the older-engine runs failed with Where it stands now (
Thanks for the patience on this one. |

Fixes #5761.
Ahoj @Jimmi08, and thank you for the cracking write-up. Your diagnosis was bang on, so this takes the first of the two paths you laid out.
The bug
e_tree_model::countResults()builds the list-pagination total by wrapping the list query verbatim in a derived table:MySQL and MariaDB happily let a top-level
SELECT u.*, ue.*repeat a column name, but they reject duplicate names inside a derived table. So the momente107_userande107_user_extendedboth carryuser_timezone(the orphan 0.7.x column on upgraded sites, or any plugin that adds auser_*column to the user table), the count throws1060 Duplicate column namewhile the list query itself still runs. That is why it toggled with the predefined timezone field.It is not timezone- or users-specific: any admin list selecting
t1.*, t2.*from two tables that share a column name hits it.The fix
The count now routes through a new
buildCountQuery()helper. Neither the projection nor a trailingORDER BYchangesCOUNT(*)unless the query isDISTINCT, so for non-DISTINCT queries the derived table is reduced to a single constant column before wrapping:DISTINCTqueries pass through untouched, since there the projection is significant to the row count. Dropping theORDER BYalso rescues the forum/chapters... CASE ... END AS Sort ... ORDER BY Sortquery, where reducing the projection alone would leaveORDER BY Sortpointing at an alias that no longer exists.Tests
e107_tests/tests/unit/TreeModelTest.phpgains four string-transform tests plus an end-to-endtestCountResultsToleratesDuplicateColumnNamesthat creates two tables sharinguser_timezoneand counts across them. That last one fails onmasterwith the exact1060 Duplicate column name 'user_timezone', and passes here. The full unit suite stays green.What this deliberately leaves alone
Your second suggestion (dropping the orphan
e107_user.user_timezonein the 0.7.x upgrade routine, and fixing thecopy_user_timezone()catch-22 so it re-flags the orphan once the extended field exists) is a destructiveALTERon live user data, and it only covers the upgraded-site case, not plugin-added columns. This count fix is complete on its own, so that migration question is better tracked as a separate follow-up than folded in here.