Skip to content

Commit 9512e45

Browse files
azabludaclaude
andcommitted
Emit a table-valued function without LATERAL. Fix #1277
VisitCrossApply and VisitOuterApply put LATERAL in front of whatever EF Core hands them. In Firebird's grammar LATERAL is a prefix on a derived table only: <table-primary> ::= <table-or-query-name> [[AS] correlation-name] | [LATERAL] <derived-table> [<correlation-or-recognition>] | <parenthesized-joined-table> <table-or-query-name> ::= table-name | query-name | [package-name.]procedure-name [(<procedure-args>)] A selectable procedure is the other alternative, and its arguments may already reference streams declared earlier in the FROM clause. So a correlated queryable function needs no LATERAL - and cannot have one, which is why it did not parse. JOIN LATERAL "GetCustomerOrderCountByYear"("c"."Id") AS "g" ON TRUE -- Dynamic SQL Error, SQL error code = -104, Token unknown JOIN "GetCustomerOrderCountByYear"("c"."Id") AS "g" ON TRUE -- works, on Firebird 3 as well The two visitors now share one GenerateApplySource, which emits the call as it is emitted anywhere else and keeps LATERAL for the sources that need it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent d5982a1 commit 9512e45

1 file changed

Lines changed: 21 additions & 25 deletions

File tree

src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -285,24 +285,8 @@ protected override void GenerateOrderings(SelectExpression selectExpression)
285285
// Copyright (c) 2002-2021, Npgsql
286286
protected override Expression VisitCrossApply(CrossApplyExpression crossApplyExpression)
287287
{
288-
Sql.Append("JOIN LATERAL ");
289-
290-
if (crossApplyExpression.Table is TableExpression table)
291-
{
292-
// Firebird doesn't support LATERAL JOIN over table, and it doesn't really make sense to do it - but EF Core
293-
// will sometimes generate that.
294-
Sql
295-
.Append("(SELECT * FROM ")
296-
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(table.Name, table.Schema))
297-
.Append(")")
298-
.Append(AliasSeparator)
299-
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(table.Alias));
300-
}
301-
else
302-
{
303-
Visit(crossApplyExpression.Table);
304-
}
305-
288+
Sql.Append("JOIN ");
289+
GenerateApplySource(crossApplyExpression.Table);
306290
Sql.Append(" ON TRUE");
307291
return crossApplyExpression;
308292
}
@@ -312,26 +296,38 @@ protected override Expression VisitCrossApply(CrossApplyExpression crossApplyExp
312296
// Copyright (c) 2002-2021, Npgsql
313297
protected override Expression VisitOuterApply(OuterApplyExpression outerApplyExpression)
314298
{
315-
Sql.Append("LEFT JOIN LATERAL ");
299+
Sql.Append("LEFT JOIN ");
300+
GenerateApplySource(outerApplyExpression.Table);
301+
Sql.Append(" ON TRUE");
302+
return outerApplyExpression;
303+
}
316304

317-
if (outerApplyExpression.Table is TableExpression table)
305+
// LATERAL is only allowed in front of a derived table, so anything that is not one has to
306+
// become one - except a selectable procedure, which is implicitly lateral already.
307+
void GenerateApplySource(TableExpressionBase source)
308+
{
309+
if (source is TableValuedFunctionExpression function)
310+
{
311+
// A selectable procedure takes its arguments from streams earlier in the FROM clause
312+
// without LATERAL, so the call is emitted as it is anywhere else.
313+
Visit(function);
314+
}
315+
else if (source is TableExpression table)
318316
{
319317
// Firebird doesn't support LATERAL JOIN over table, and it doesn't really make sense to do it - but EF Core
320318
// will sometimes generate that.
321319
Sql
322-
.Append("(SELECT * FROM ")
320+
.Append("LATERAL (SELECT * FROM ")
323321
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(table.Name, table.Schema))
324322
.Append(")")
325323
.Append(AliasSeparator)
326324
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(table.Alias));
327325
}
328326
else
329327
{
330-
Visit(outerApplyExpression.Table);
328+
Sql.Append("LATERAL ");
329+
Visit(source);
331330
}
332-
333-
Sql.Append(" ON TRUE");
334-
return outerApplyExpression;
335331
}
336332

337333
protected override void GeneratePseudoFromClause()

0 commit comments

Comments
 (0)