Wrap a table-valued function in a derived table after LATERAL. Fix #1277 - #1278
Open
azabluda wants to merge 2 commits into
Open
Wrap a table-valued function in a derived table after LATERAL. Fix #1277#1278azabluda wants to merge 2 commits into
azabluda wants to merge 2 commits into
Conversation
azabluda
force-pushed
the
fix/1277-lateral-table-valued-function
branch
from
September 7, 2026 22:02
90f0088 to
2459a34
Compare
…hey need Committed red on purpose, so the fix that follows is measured against a failing suite rather than asserted. All 14 carry [NotSupportedOnFirebirdFact]. The store supports every one of them; only the generated SQL is malformed, which is FirebirdSQL#1277. A correlated queryable function reaches the store as a LATERAL derived table, and LATERAL is Firebird 4 and later, so both the tests and the objects they need are gated on ServerLessThan4(). The gate is the same early return the Associations and ComplexType tests here already use, behind one helper rather than repeated fourteen times. The fixture guard is required rather than tidy. "GetCustomerOrderCountByYearOnlyFrom2000" is 39 characters and Firebird 3 caps identifiers at 31, so creating it there fails the seed with "Name longer than database column size" and takes every test in the class down with it, including ones that pass today. That second gap was hidden behind the first. The fixture never created "AddValues", "GetCustomerOrderCountByYear" or "GetCustomerOrderCountByYearOnlyFrom2000", and nothing noticed, because every test that uses them was skipped. They are ported from the definitions in EF Core's own UdfDbFunctionSqlServerTests fixture, in Firebird form: the two table-valued ones become selectable procedures, as the two already in this fixture are, and year(...) becomes extract(year from ...). UdfDbFunctionFbTests on Firebird 5.0.3: Passed 82 -> 84, Failed 0 -> 12, Skipped 24 -> 10, Total 106. Twelve fail at the LATERAL source with the store's own parse error: FbException: Dynamic SQL Error Token unknown - line 3, column 14 Two pass with no product change at all, so their skips were already stale: QF_Select_Correlated_Subquery_In_Anonymous QF_Correlated_Func_Call_With_Navigation Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rebirdSQL#1277 VisitCrossApply and VisitOuterApply already know that Firebird will not take a bare source after LATERAL: both special-case a TableExpression and emit (SELECT * FROM "T") AS "t". The same branch was missing for a TableValuedFunctionExpression, so a correlated queryable function was emitted as a bare call and the statement did not parse: JOIN LATERAL "GetCustomerOrderCountByYear"("c"."Id") AS "g" ON TRUE -> Dynamic SQL Error, Token unknown It now emits the wrapped form, with the alias on the derived table so the rest of the statement keeps referring to it unchanged: JOIN LATERAL (SELECT * FROM "GetCustomerOrderCountByYear"("c"."Id")) AS "g" ON TRUE Argument rendering goes through the existing GenerateList helper rather than a new loop. UdfDbFunctionFbTests: Failed 12 -> 0, Passed 84 -> 96, Skipped 10, Total 106. No other test moved. The whole functional suite is Passed 14167, Failed 0, Skipped 1113, Total 15280, and FirebirdSql.EntityFrameworkCore.Firebird.Tests is Passed 102, Failed 0. Verified against Firebird 5.0.3. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
azabluda
force-pushed
the
fix/1277-lateral-table-valued-function
branch
from
September 7, 2026 22:41
2459a34 to
23c3cf5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1277.
The defect
VisitCrossApplyandVisitOuterApplyalready know that Firebird will not take a bare source afterLATERAL: both special-case aTableExpressionand emit(SELECT * FROM "T") AS "t". The same branch was missing for aTableValuedFunctionExpression, so a correlated queryable function came out as a bare call and the statement did not parse.It now emits the wrapped form, with the alias on the derived table so the rest of the statement keeps referring to it unchanged:
Argument rendering goes through the existing
GenerateListhelper rather than a new loop.Two commits, and the first is red on purpose
1. Un-skip the 14 correlated queryable-function tests, and create what they need.
Passed 82 -> 84, Failed 0 -> 12, Skipped 24 -> 10.2. The fix.
Failed 12 -> 0, Passed 84 -> 96.Split this way so the fix is measured against a failing suite rather than asserted, and so each half can be reviewed on its own.
Two things you may not expect in here
The fixture was missing three objects.
AddValues,GetCustomerOrderCountByYearandGetCustomerOrderCountByYearOnlyFrom2000were never created, and nothing noticed, because every test that uses them was skipped. With the SQL fixed, those ten tests stop failing onToken unknownand start failing onProcedure unknown. They are ported from the definitions in EF Core's ownUdfDbFunctionSqlServerTestsfixture, in Firebird form: the two table-valued ones become selectable procedures, as the two already in this fixture are, andyear(...)becomesextract(year from ...).Two of the fourteen skips were already stale.
QF_Select_Correlated_Subquery_In_AnonymousandQF_Correlated_Func_Call_With_Navigationpass with no product change at all.Firebird versions
A correlated queryable function reaches the store as a
LATERALderived table, andLATERALis Firebird 4 and later, so both the 14 tests and the three fixture objects are gated onServerLessThan4()— the same early returnNavigationsCollectionFbTestandComplexTypeQueryFbTestalready use.The fixture guard is required rather than tidy.
GetCustomerOrderCountByYearOnlyFrom2000is 39 characters and Firebird 3 caps identifiers at 31, so creating it there fails the seed withName longer than database column sizeand takes every test in the class down with it, including ones that pass today.What was run
UdfDbFunctionFbTests, run locally:Full suites on 5.0.3:
FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTestsPassed 14167, Failed 0, Skipped 1113, Total 15280;FirebirdSql.EntityFrameworkCore.Firebird.TestsPassed 102, Failed 0.FB30, FB40 and FB50 are all green against
Tests-EFCoreandTests-EFCore-Functional, run in my fork: https://github.com/azabluda/NETProvider/actions/runs/34167549531Both wrapped and implicit forms were also run directly against the store by hand before the issue was filed.
AI usage
Per CONTRIBUTING: this change was written with Claude Code. I reviewed it, ran it and stand behind it. Both commits carry a
Co-Authored-Bytrailer.