Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query: SqlFunctionExpression API review #14882

Closed
smitpatel opened this issue Feb 28, 2019 · 9 comments · Fixed by #16166
Closed

Query: SqlFunctionExpression API review #14882

smitpatel opened this issue Feb 28, 2019 · 9 comments · Fixed by #16166
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@smitpatel
Copy link
Member

In new query pipeline, in order to facilitate creating different function, currently following variations are supported. (Also there niladic version)

Name(…)
dbo.Name(…)
Instance.Name(…)

Following are all the constructors. (You can ignore type, typeMapping, condition parameters, they are metadata)

public SqlFunctionExpression(
            string functionName,
            bool niladic,
            Type type,
            RelationalTypeMapping typeMapping,
            bool condition)
            : this(null, null, functionName, niladic, null, type, typeMapping, condition)
        {
        }

        public SqlFunctionExpression(
            string schema,
            string functionName,
            bool niladic,
            Type type,
            RelationalTypeMapping typeMapping,
            bool condition)
            : this(null, schema, functionName, niladic, null, type, typeMapping, condition)
        {
        }

        public SqlFunctionExpression(
            SqlExpression instance,
            string functionName,
            bool niladic,
            Type type,
            RelationalTypeMapping typeMapping,
            bool condition)
            : this(instance, null, functionName, niladic, null, type, typeMapping, condition)
        {
        }

        public SqlFunctionExpression(
            string functionName,
            IEnumerable<SqlExpression> arguments,
            Type type,
            RelationalTypeMapping typeMapping,
            bool condition)
            : this(null, null, functionName, false, arguments, type, typeMapping, condition)
        {
        }

        public SqlFunctionExpression(
            string schema,
            string functionName,
            IEnumerable<SqlExpression> arguments,
            Type type,
            RelationalTypeMapping typeMapping,
            bool condition)
            : this(null, schema, functionName, false, arguments, type, typeMapping, condition)
        {
        }

        public SqlFunctionExpression(
            SqlExpression instance,
            string functionName,
            IEnumerable<SqlExpression> arguments,
            Type type,
            RelationalTypeMapping typeMapping,
            bool condition)
            : this(instance, null, functionName, false, arguments, type, typeMapping, condition)
        {
        }

Is above is exhaustive? Do we need to support more variations? Is dbo.Name (niladic) or Instance.Name (niladic) is useful or possible or impossible?

cc: @bricelam due to SQLite & Spatial
cc: @roji due to Postgre
cc: @pmiddleton based on all the work with DbFunction + pivot + TVF.

@roji
Copy link
Member

roji commented Feb 28, 2019

Check out especially #12757 for a fascinating (and depressing) discussion... Basically SQL Server seems to require a distinction between system and user functions - this affects both quoting and schema handling. FWIW PostgreSQL could also benefit from this distinction (we'd generate uppercase but unquoted names for system functions, so we can get SUM() instead of sum() in SQL). So it might be a good idea to add IsBuiltin.

Note also the EF6 function definition which also contains IsAggregate and IsComposable. If we really want to go all-out we can also think about PostgreSQL variadic functions (like params in C#), but that's definitely a rare edge-case we can support later.

Just for the added context, I'm not really aware of OOP-style functions in PostgreSQL (i.e. Instance.Name()).

@roji
Copy link
Member

roji commented Feb 28, 2019

(let me know if you think you need any other info)

@bricelam
Copy link
Contributor

Is dbo.Name (niladic) or Instance.Name (niladic) is useful or possible?

Instance.Name (niladic) was added for SQL Server spatial:

  • Geometry.X
  • Geometry.Y
  • Geometry.Z
  • Geometry.M
  • Geometry.SRID
  • Geography.Lat
  • Geography.Long

@bricelam
Copy link
Contributor

dbo.Name (niladic) feels like YAGNI

@smitpatel
Copy link
Member Author

If we really want to go all-out we can also think about PostgreSQL variadic functions (like params in C#), but that's definitely a rare edge-case we can support later.

There is always possibility for any provider/plugin-writer/customer to extend our SQL tree and define a custom SqlFunctionExpression which supports such scenarios. There is no blockers. This is just what we provide "in-the-box".

As for variadic functions, it is just same function with different number of args. I believe at translation time we know exactly how many arguments are there (from LINQ expression tree). Further, we don't have checks on number of args so you can use same functionName and pass in whatever number of args you want to print out. So variadic functions should be supported already.

IsBuiltIn - I will read the "depressing" discussion and think about possible options. 😨
IsAggregate - would be useful for UDFs returning aggregate which can be used inside GroupBy query.
IsComposable - does anyone know what it was for?

@roji
Copy link
Member

roji commented Feb 28, 2019

@divega can probably provide a bit more info on IsComposable.

@pmiddleton
Copy link
Contributor

Yea Sql Server is a pain. Read #12757 to understand all the nuances.

What it boils down to is if we want to guarantee not to produce any potential bad sql we need to know if a custom DbFunction maps back to a UDF or built in function.

It's simple enough to ask for the data, but it just presents an ugly api option to the end user which they won't understand. I'm sure we can write some thoughtfully cryptic documentation which will confuse them even more :)

@smitpatel
Copy link
Member Author

I had chat with @divega about IsComposable flag. It was because those functions also represented stored procedures. Given current support & design of stored proc in EF Core, we don't need that flag as of now. We can add it in future as needed.

@ajcvickers ajcvickers added this to the 3.0.0 milestone Mar 1, 2019
smitpatel added a commit that referenced this issue Jun 19, 2019
Fuctions without arguments passed considered niladic.
Non-niladic functions without arguments must pass empty array of args.
Functions with instance are considered built in.
Functions without schema are considered built in.
Functions with schema are non-built-in (Schema can be null)
To map a DbFunction to built-in function use HasTranslation API

Resolves #12757
Resolves #14882
Resolves #15501
@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jun 19, 2019
smitpatel added a commit that referenced this issue Jun 21, 2019
Fuctions without arguments passed considered niladic.
Non-niladic functions without arguments must pass empty array of args.
Functions with instance are considered built in.
Functions without schema are considered built in.
Functions with schema are non-built-in (Schema can be null)
To map a DbFunction to built-in function use HasTranslation API

Resolves #12757
Resolves #14882
Resolves #15501
@smitpatel
Copy link
Member Author

Added IsBuiltIn flag on SqlFunctionExpression.
Only constructor which takes schema has ability to specify built-in or not. Rest would be assumed to be built-in. Niladic & Instance methods cannot be UDFs. When schema is optional, schema-less ctor can be used to create UDF but user can opt into specifying null schema in the other constructor.

@ajcvickers ajcvickers modified the milestones: 3.0.0, 3.0.0-preview7 Jul 2, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0-preview7, 3.0.0 Nov 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants