Skip to content

fix(model): keep comma-bearing SQL functions intact in select and group by - #4637

Merged
bpamiri merged 1 commit into
developfrom
fix/4634-comma-functions-select
Oct 23, 2026
Merged

bpamiri merged 1 commit into
developfrom
fix/4634-comma-functions-select

Conversation

@bpamiri

@bpamiri bpamiri commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #4634. select= expressions containing SQL functions with commas (CONCAT, IF, COALESCE, SUBSTRING, …) were corrupted when combined with include= (and the distinct group-by path), producing invalid SQL such as MySQL 1064.

Two defects in vendor/wheels/model/sql.cfm:

  1. Duplicated duplicate-prefix pass. $createSQLFieldList called $createSQLFieldListDuplicatePrefix() and then immediately ran a second, inline copy of the same 64-line body. Removed the redundant inline block.
  2. ListToArray split inside function arguments. $createSQLFieldListDuplicatePrefix() and the distinct branch of $groupByClause() split the clause on every comma, so CONCAT(IF(ISNULL(authors.firstname)=1, '', ...), authors.firstname) AS firstname became fragments; the tail fragment was treated as a duplicate property (firstname) and dropped, truncating the select. Both now use the existing $splitOutsideFunctions(list, ","), which keeps parentheses groups together. $splitOutsideFunctions() already trims each item.

SQL that does not contain comma-bearing functions is unchanged: the only difference for ordinary lists is that the helper skips empty segments (an empty select item was already a no-op through ListAppend). The full model/database suites plus the engine matrix below cover that.

Reproduction (before → after)

Model finder with include="author" and:

select = "CONCAT(IF(ISNULL(authors.firstname)=1, '', CONCAT(authors.firstname, ' ')), authors.firstname) AS firstname"
clause before (origin/develop) after
$selectClause SELECT CONCAT(IF(ISNULL(authors.firstname)=1, '', CONCAT(authors.firstname, ' ')) — tail , authors.firstname) AS firstname dropped SELECT CONCAT(IF(ISNULL(authors.firstname)=1, '', CONCAT(authors.firstname, ' ')), authors.firstname) AS firstname
$selectClause with a leading id SELECT "c_o_r_e_posts"."id",CONCAT(IF(ISNULL(authors.firstname)=1, '', CONCAT(authors.firstname, ' ')) full expression preserved after the id
$groupByClause(distinct=true) with id, (SELECT …) AS subname GROUP BY "c_o_r_e_posts"."id", ' ') FROM c_o_r_e_authors) — split subquery fragments leaked GROUP BY "c_o_r_e_posts"."id" — subquery item skipped as designed

Regression specs

New vendor/wheels/tests/specs/model/CommaFunctionSelectSpec.cfc (4 specs), failing on the parent commit and passing with the fix:

  • function expression survives the include duplicate-prefix pass;
  • the expression tail is not dropped when a plain select item precedes it (asserts the clause ends with the expression);
  • several comma-bearing functions side by side stay intact;
  • a distinct group-by does not receive split subquery fragments.

Verified failing-then-passing: with the production diff stashed, 0 passed / 4 failed; with the fix, 4 passed.

Tests

  • bash tools/test-local.sh model → 1506 passed
  • bash tools/test-local.sh database → 189 passed
  • tools/test-matrix.sh lucee7 sqlite,h2 → sqlite 7325 passed, h2 7292 passed; 0 failed / 0 errored
  • tools/test-matrix.sh lucee6,adobe2023,adobe2025,boxlang sqlite → lucee6 7324, adobe2023 7319, adobe2025 7320, boxlang 7325; all 0 failed / 0 errored
  • bash tools/rustcfml/run-suite.sh → RustCFML v0.741.0: 7297 passed, 0 failed, 0 errors, 182 skipped, 0 new vs baseline (the local SimpleLockRestartSpec flakes that usually show up on this host did not reproduce in this run)
  • PR CI runs the required contexts on this head.

Changelog

changelog.d/4634-comma-sql-functions.fixed.md.

Fixes #4634

…up by

#4634: with include=, the duplicate-prefix pass split the select clause with
ListToArray, so an expression such as
CONCAT(IF(ISNULL(titel.ausgabe)=1, '', CONCAT(titel.ausgabe, ' ')), kontakt.nachname)
was split into fragments, the tail was treated as a duplicate property and
dropped, and the generated SQL was invalid. Remove the second, duplicated
inline copy of that pass in $createSQLFieldList and split both it and the
distinct group-by item list with $splitOutsideFunctions(), which keeps
function arguments together. SQL without comma-bearing functions is unchanged.

Regression specs cover the reported expression shape, a plain select item
before it, several comma-bearing functions side by side, and a distinct
group-by that must not receive split subquery fragments.

Signed-off-by: Peter Amiri <peter@alurium.com>
@bpamiri
bpamiri merged commit 1df65b2 into develop Oct 23, 2026
23 checks passed
@bpamiri
bpamiri deleted the fix/4634-comma-functions-select branch October 23, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix: $createSQLFieldListDuplicatePrefix and $groupByClause corrupt select clauses containing SQL functions with commas

1 participant