Description
While implementing the tests for UDFs (yeah I'm a bit late to the party...), I came across some odd quoting/schema logic for SQL functions that causes a problem in PostgreSQL - this was implemented in #9558. I understand the problems it was meant to solve, but that doesn't really work from a cross-database perspective.
So in https://github.com/aspnet/EntityFrameworkCore/blob/ea9b3d84f9028a8a5eb35ae02babd50836947163/src/EFCore.Relational/Query/Sql/DefaultQuerySqlGenerator.cs#L1548, it seems that GenerateSqlFunctionName()
passes the function name through DelimitIdentifier()
only if a schema has been defined on it. This in itself is a bit strange - why should function name quoting depend on whether a schema has been defined for that function? Note that in PostgreSQL function names behave exactly like other identifiers (e.g. table names) and need to be quoted if they contain upper-case letters.
The way things are implemented in SQL Server, it turns out that functions implicitly have a schema - SqlServerDbFunctionConvention
sets the DefaultSchema
of all functions to be dbo
(#9303). This makes generated SQL contain [dbo].[FunctionName](...)
instead of a simpler/leaner [FunctionName]
. This seems to go against EF Core's principle of generating clean, concise SQL that resembles what we'd write by hand; after all why specify dbo
everywhere for functions but not for tables? Is this some sort of SQL Server-specific requirement?
Setting up the same convention in Npgsql (with default schema public
) makes the 1st problem go away for some cases, since functions now have a schema by default. But it doesn't handle the case where the user explicitly sets an empty schema, like for IsDate
in the tests - since there's no schema there's no quoting, and PostgreSQL fails to find isdate
after converting the name to lowercase.
For now, my approach is to override DefaultQuerySqlGenerator.GenerateSqlFunctionName()
to make it always quote. This creates an issue for some built-in function which EF Core generates upper-case (e.g. SUM
), so I have a hardcoded list of built-in functions that aren't to be quoted (this would be obviated if EF Core starts generating lower-case sum()
instead of SUM()
). I'm also modifying all my expression translators to generate function names in lower-case (e.g. lower()
instead of LOWER()
).
I realize this is a bit late to be raising this (we should have thought about PostgreSQL when doing UDFs and #9558), just letting you know.
/cc @pmiddleton