Skip to content

Fix findCount()/exists() wrapping a raw CTE (WITH clause) for SQL Server#3850

Merged
rbygrave merged 1 commit into
masterfrom
feature/sql-server-cte-parse
Jul 14, 2026
Merged

Fix findCount()/exists() wrapping a raw CTE (WITH clause) for SQL Server#3850
rbygrave merged 1 commit into
masterfrom
feature/sql-server-cte-parse

Conversation

@rbygrave

Copy link
Copy Markdown
Member

SQL Server does not support a WITH clause (CTE) nested inside a subquery or derived table - only at the start of a statement. buildRowCountQuery() and buildExistsQuery() wrap raw sql as select count(*) from (<sql>) / select case when exists(<sql>) then ..., which breaks when starts with a CTE header (e.g. RawSqlBuilder.withPlaceholders() queries), causing "Incorrect syntax near the keyword 'with'" on SQL Server.

Add CQueryBuilder.topLevelSelectStart()/splitCteHeader() to detect and hoist a leading WITH clause in front of the wrapping SELECT rather than wrapping it along with the rest of the query. This is a no-op for the common case (no leading CTE) and is portable across platforms.

  • ebean-core: CQueryBuilder - hoist leading CTE header in wrapSelectCount()/wrapSelectExists()
  • Add unit tests in CQueryBuilderTest reproducing the exact failing SQL

SQL Server does not support a WITH clause (CTE) nested inside a subquery
or derived table - only at the start of a statement. buildRowCountQuery()
and buildExistsQuery() wrap raw sql as `select count(*) from (<sql>)` /
`select case when exists(<sql>) then ...`, which breaks when <sql> starts
with a CTE header (e.g. RawSqlBuilder.withPlaceholders() queries), causing
"Incorrect syntax near the keyword 'with'" on SQL Server.

Add CQueryBuilder.topLevelSelectStart()/splitCteHeader() to detect and
hoist a leading WITH clause in front of the wrapping SELECT rather than
wrapping it along with the rest of the query. This is a no-op for the
common case (no leading CTE) and is portable across platforms.

- ebean-core: CQueryBuilder - hoist leading CTE header in
  wrapSelectCount()/wrapSelectExists()

- Add unit tests in CQueryBuilderTest reproducing the exact failing SQL
@rbygrave rbygrave added this to the 18.3.0 milestone Jul 14, 2026
@rbygrave rbygrave self-assigned this Jul 14, 2026
@rbygrave rbygrave merged commit 791ac13 into master Jul 14, 2026
2 checks passed
@rbygrave rbygrave deleted the feature/sql-server-cte-parse branch July 14, 2026 03:11
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.

2 participants