borinquenkid opened a new pull request, #16735:
URL: https://github.com/apache/grails-core/pull/16735

   ## Summary
   
   Fixes #16717, and does the first two steps of #16616: one lexical scanner 
for the query package, and one reading per HQL query.
   
   Three scanners in `org.grails.orm.hibernate.query` each decided on their own 
what to skip: `HqlQueryContext.indexOfTopLevel` and `getCommas` (no `--` 
comments, no backquotes in the comma count), `SqlRestriction.scan` (quotes and 
comments only), and `SqlProjection.splitColumns` (brackets, dollar quotes, both 
comment kinds, but quotes tested before the bracket state). Every recent bug of 
this family was a rule mismatch between them: #16597, #16712 and now the second 
half of #16717.
   
   `SqlText` now owns the rules once, and reads the text once: when an instance 
is created, each character is classified as plain text, quoted text or comment, 
and each plain character gets its parenthesis depth, so every later question 
walks those two arrays and nothing rescans the string. The rules: string 
literals and quoted identifiers with a doubled quote for the quote, `[bracket 
identifiers]` with `]]` and dollar-quoted strings in native SQL, line and block 
comments, and parentheses when a top-level position is asked for. It offers 
`indexOfTopLevel`, `splitTopLevel`, `countTopLevel`, `plainIndexes`, 
`unwrapOuterParentheses`, `withoutTrailingComments` and `endsInLineComment`, in 
an `HQL` or `SQL` dialect. The three scanners delegate to it; the callers' 
specs are unchanged and pass.
   
   **One reading per HQL query.** `HqlQueryContext.prepare` used to read the 
same query four times through separate static helpers: normalise it, count its 
projections, take its single projection clause, find its root alias, each one 
lowercasing and scanning the text again, and `getTarget` normalised the already 
normalised text once more. The new `HqlText` is one reading: it lowercases 
once, scans once with `SqlText`, finds the `select` and `from` once, and 
derives the projection count, the select clause, the root alias, the normalized 
form and the result type of that normalized form from those positions, without 
reading the normalized text at all. `prepare` creates one `HqlText` and takes 
the query text and the target class from it. The static helpers the spec calls 
remain as thin entry points over `HqlText`, so `HqlQueryContextSpec` keeps its 
64 cases as the safety net, and `HqlTextSpec` shows the one-reading contract on 
a table of queries. Two behaviours improve as a side effect: 
 the HQL projection count now ignores a comma inside a comment or a backquoted 
identifier, and the HQL keyword search skips `--` comments, as Copilot noted on 
#16719.
   
   The two defects of #16717:
   
   - **A column alias with a space broke the count over the projection.** 
`JpaProjectionAdapter` gave a subquery selection a generated alias only when it 
had none, so `createCriteria().count { projections { sqlProjection ... } }`, 
which counts over the projection as a derived table, rendered `derived1_0(box 
width)` and H2 rejected it. Nothing reads a subquery's selections by alias, so 
every subquery selection now gets a generated one, and the derived table reads 
`derived1_0(col_0)`; the main query keeps the caller's alias for `order` and 
results. (A paged `list(max:)` was never affected: its total counts the 
entity's ids and leaves the projection out.)
   - **An apostrophe inside a bracket identifier swallowed the SQL.** 
`splitColumns` tested quotes before the bracket state, so `width as [box's 
width], height as total` was one column. Inside brackets only brackets count 
now.
   
   `unwrapOuterParentheses` is there for #16719, whose root-query unwrapping 
becomes a call to it at the start of `HqlText`'s reading; the union-branch case 
of #16712 is a row in `SqlTextSpec` already (left as it is, by design, since 
the parentheses do not enclose the whole query).
   
   ## Verification
   
   - `HqlTextSpec`: one reading per query gives the projection count, clause, 
root alias, normalized form and target for a table of queries, including 
comments and a literal with a comma.
   - `SqlTextSpec`: one table per capability, with the apostrophe in a bracket, 
`]]`, nested subscripts, dollar quotes, both comment kinds with separators 
inside, escaped quotes, keywords inside names and literals, a `with` clause, 
nested and unbalanced parentheses, the union branches, and `?` placeholders in 
every hiding place.
   - `SqlProjectionSpec` and `HqlQueryContextSpec` gain the rows the fix adds; 
`HibernateCriteriaBuilderSqlProjectionSpec` gains a `count {}` over a 
`sqlProjection` aliased `box width`, which fails with the H2 syntax error 
before the fix and asserts the generated alias in the captured SQL after it.
   - `:grails-data-hibernate7-core:test`, `checkstyleMain`, `codenarcTest`: see 
the CI run.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to