-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Open
Description
We should consider how to make recursive CTEs behave more consistently across dialects.
Key differences:
- Syntax keyword: Some engines require WITH RECURSIVE (Postgres, MySQL, SQLite), others use plain WITH for recursive CTEs.
- Column list rules: Some engines require an explicit column list for recursive CTEs (Oracle is the common case).
- Recursion limits: Most engines have a default recursion cap you can change (MySQL, MariaDB, SQL Server). Hitting the limit fails the query.
- Cycle handling: Some engines have built-in cycle helpers; others don’t, so you must add your own stop condition.
- Ordering: Ordering inside the CTE body is often restricted; stable ordering should happen in the outer SELECT.
- Type inference: Column types usually come from the anchor part; some engines need explicit casts.
Related issue
- position of with/CTE (top-level or together with subquery) #3779: "position of with/CTE (top-level or together with subquery)". It reports that MySQL allows WITH inside subqueries, but MSSQL requires WITH at the top level. It also notes that some MySQL compilers don't include with() for update, so users monkey-patch it. This matters here because any cross-dialect plan for recursive CTEs must decide where WITH is allowed and how the compiler should place it per dialect.
Goal (if we ever do this)
Make results more consistent, or at least make the differences very clear, so the same recursive query behaves as close as possible across dialects.
Possible dialect-specific approach (high level)
-
PostgreSQL:
- Keep WITH RECURSIVE.
- If no column list is provided, infer from the anchor query (current behaviour is fine).
- Keep as the reference dialect for docs and examples.
-
MySQL 8+ / MariaDB 10.2+:
- Use WITH RECURSIVE explicitly.
- Expose or document the recursion limit (
cte_max_recursion_depth) so users know why a query might fail. - Encourage adding a termination condition in the recursive part.
-
SQLite 3.8.3+:
- Use WITH RECURSIVE.
- Be clear about performance limits and planner differences.
-
MSSQL:
- Use WITH (no RECURSIVE keyword).
- If the user doesn’t provide a column list, consider adding one when needed.
- Note the default recursion limit and how to override it.
-
Oracle:
- Use WITH (no RECURSIVE keyword).
- Always require or inject an explicit column list for recursive CTEs.
- Make sure the anchor part and recursive part have compatible types (cast if needed).
Potential follow-up
We can add a capability matrix and a small dialect adapter for recursive CTEs, or at least tighten the docs with these differences.