// Copyright 2024 Dolthub, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package framework import ( "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/doltgresql/core/id" pgtypes "github.com/dolthub/doltgresql/server/types" ) // FunctionInterface is an interface for PostgreSQL functions. type FunctionInterface interface { // GetName returns the name of the function. The name is case-insensitive, so the casing does not matter. GetName() string // GetReturn returns the return type. GetReturn() *pgtypes.DoltgresType // GetParameters returns the parameter types for the function. GetParameters() []*pgtypes.DoltgresType // VariadicIndex returns the index of the variadic parameter, if it exists, or -1 otherwise VariadicIndex() int // GetExpectedParameterCount returns the number of parameters that are valid for this function. GetExpectedParameterCount() int // NonDeterministic returns whether the function is non-deterministic. NonDeterministic() bool // IsCVariadic returns whether this function uses a variadic form restricted to C-language functions. // https://www.postgresql.org/docs/15/xfunc-c.html#id-1.8.3.13.13 IsCVariadic() bool // IsStrict returns whether the function is STRICT, which means if any parameter is NULL, then it returns NULL. // Otherwise, if it's not, the NULL input must be handled by user. IsStrict() bool // IsSRF returns whether the function is a set returning function, meaning whether the // function returns one or more rows as a result. IsSRF() bool // InternalID returns the ID associated with this function. InternalID() id.Id // enforceInterfaceInheritance is a special function that ensures only the expected types inherit this interface. enforceInterfaceInheritance(error) } // AggregateFunctionInterface is an interface for PostgreSQL aggregate functions type AggregateFunctionInterface interface { FunctionInterface // TODO: this maybe needs to take the place of the Callable function NewBuffer([]sql.Expression) (sql.AggregationBuffer, error) } // Function0 is a function that does not take any parameters. type Function0 struct { Name string Return *pgtypes.DoltgresType IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context) (any, error) } // Function1 is a function that takes one parameter. The parameter and return type is passed into the Callable function // when the parameter (and possibly return type) is a polymorphic type. The return type is the last type in the array. type Function1 struct { Name string Return *pgtypes.DoltgresType Parameters [1]*pgtypes.DoltgresType Variadic bool IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn [2]*pgtypes.DoltgresType, val1 any) (any, error) } // Function1N is a function that takes at least one parameter. This is different from a SQL variadic function, as the // additional parameters may have different types (that do not contribute to type deduction like with `anyelement`), and // is only usable by C-language functions (notably built-in ones such as `concat`). The field `paramsAndReturn` works // similarly to standard functions, with the last type being the return type. type Function1N struct { Name string Return *pgtypes.DoltgresType Parameters [1]*pgtypes.DoltgresType IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn []*pgtypes.DoltgresType, val1 any, vals []any) (any, error) } // Function2 is a function that takes two parameters. The parameter and return types are passed into the Callable // function when the parameters (and possibly return type) have at least one polymorphic type. The return type is the // last type in the array. type Function2 struct { Name string Return *pgtypes.DoltgresType Parameters [2]*pgtypes.DoltgresType Variadic bool IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) } // Function2N is a function that takes at least two parameters. This is different from a SQL variadic function, as the // additional parameters may have different types (that do not contribute to type deduction like with `anyelement`), and // is only usable by C-language functions (notably built-in ones such as `concat_ws`). The field `paramsAndReturn` works // similarly to standard functions, with the last type being the return type. type Function2N struct { Name string Return *pgtypes.DoltgresType Parameters [2]*pgtypes.DoltgresType IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn []*pgtypes.DoltgresType, val1 any, val2 any, vals []any) (any, error) } // Function3 is a function that takes three parameters. The parameter and return types are passed into the Callable // function when the parameters (and possibly return type) have at least one polymorphic type. The return type is the // last type in the array. type Function3 struct { Name string Return *pgtypes.DoltgresType Parameters [3]*pgtypes.DoltgresType Variadic bool IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn [4]*pgtypes.DoltgresType, val1 any, val2 any, val3 any) (any, error) } // Function4 is a function that takes four parameters. The parameter and return types are passed into the Callable // function when the parameters (and possibly return type) have at least one polymorphic type. The return type is the // last type in the array. type Function4 struct { Name string Return *pgtypes.DoltgresType Parameters [4]*pgtypes.DoltgresType Variadic bool IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn [5]*pgtypes.DoltgresType, val1 any, val2 any, val3 any, val4 any) (any, error) } // Function5 is a function that takes five parameters. The parameter and return types are passed into the Callable // function when the parameters (and possibly return type) have at least one polymorphic type. The return type is the // last type in the array. type Function5 struct { Name string Return *pgtypes.DoltgresType Parameters [5]*pgtypes.DoltgresType Variadic bool IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn [6]*pgtypes.DoltgresType, val1 any, val2 any, val3 any, val4 any, val5 any) (any, error) } // Function6 is a function that takes six parameters. The parameter and return types are passed into the Callable // function when the parameters (and possibly return type) have at least one polymorphic type. The return type is the // last type in the array. type Function6 struct { Name string Return *pgtypes.DoltgresType Parameters [6]*pgtypes.DoltgresType Variadic bool IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn [7]*pgtypes.DoltgresType, val1 any, val2 any, val3 any, val4 any, val5 any, val6 any) (any, error) } // Function7 is a function that takes seven parameters. The parameter and return types are passed into the Callable // function when the parameters (and possibly return type) have at least one polymorphic type. The return type is the // last type in the array. type Function7 struct { Name string Return *pgtypes.DoltgresType Parameters [7]*pgtypes.DoltgresType Variadic bool IsNonDeterministic bool Strict bool SRF bool Callable func(ctx *sql.Context, paramsAndReturn [8]*pgtypes.DoltgresType, val1 any, val2 any, val3 any, val4 any, val5 any, val6 any, val7 any) (any, error) } var _ FunctionInterface = Function0{} var _ FunctionInterface = Function1{} var _ FunctionInterface = Function1N{} var _ FunctionInterface = Function2{} var _ FunctionInterface = Function2N{} var _ FunctionInterface = Function3{} var _ FunctionInterface = Function4{} var _ FunctionInterface = Function5{} var _ FunctionInterface = Function6{} var _ FunctionInterface = Function7{} // GetName implements the FunctionInterface interface. func (f Function0) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function0) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function0) GetParameters() []*pgtypes.DoltgresType { return nil } func (f Function0) VariadicIndex() int { return -1 } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function0) GetExpectedParameterCount() int { return 0 } // NonDeterministic implements the FunctionInterface interface. func (f Function0) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function0) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function0) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function0) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function0) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function0) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function1) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function1) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function1) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function1) VariadicIndex() int { if f.Variadic { return 0 } else { return -1 } } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function1) GetExpectedParameterCount() int { return 1 } // NonDeterministic implements the FunctionInterface interface. func (f Function1) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function1) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function1) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function1) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function1) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function1) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function1N) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function1N) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function1N) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function1N) VariadicIndex() int { return -1 } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function1N) GetExpectedParameterCount() int { return 1 } // NonDeterministic implements the FunctionInterface interface. func (f Function1N) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function1N) IsCVariadic() bool { return true } // IsStrict implements the FunctionInterface interface. func (f Function1N) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function1N) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function1N) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function1N) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function2) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function2) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function2) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function2) VariadicIndex() int { if f.Variadic { return 1 } else { return -1 } } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function2) GetExpectedParameterCount() int { return 2 } // NonDeterministic implements the FunctionInterface interface. func (f Function2) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function2) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function2) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function2) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function2) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID, f.Parameters[1].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function2) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function2N) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function2N) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function2N) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function2N) VariadicIndex() int { return -1 } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function2N) GetExpectedParameterCount() int { return 2 } // NonDeterministic implements the FunctionInterface interface. func (f Function2N) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function2N) IsCVariadic() bool { return true } // IsStrict implements the FunctionInterface interface. func (f Function2N) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function2N) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function2N) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID, f.Parameters[1].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function2N) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function3) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function3) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function3) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function3) VariadicIndex() int { if f.Variadic { return 2 } else { return -1 } } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function3) GetExpectedParameterCount() int { return 3 } // NonDeterministic implements the FunctionInterface interface. func (f Function3) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function3) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function3) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function3) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function3) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID, f.Parameters[1].ID, f.Parameters[2].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function3) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function4) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function4) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function4) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function4) VariadicIndex() int { if f.Variadic { return 3 } else { return -1 } } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function4) GetExpectedParameterCount() int { return 4 } // NonDeterministic implements the FunctionInterface interface. func (f Function4) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function4) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function4) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function4) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function4) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID, f.Parameters[1].ID, f.Parameters[2].ID, f.Parameters[3].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function4) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function5) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function5) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function5) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function5) VariadicIndex() int { if f.Variadic { return 4 } else { return -1 } } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function5) GetExpectedParameterCount() int { return 5 } // NonDeterministic implements the FunctionInterface interface. func (f Function5) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function5) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function5) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function5) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function5) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID, f.Parameters[1].ID, f.Parameters[2].ID, f.Parameters[3].ID, f.Parameters[4].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function5) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function6) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function6) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function6) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function6) VariadicIndex() int { if f.Variadic { return 5 } else { return -1 } } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function6) GetExpectedParameterCount() int { return 6 } // NonDeterministic implements the FunctionInterface interface. func (f Function6) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function6) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function6) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function6) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function6) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID, f.Parameters[1].ID, f.Parameters[2].ID, f.Parameters[3].ID, f.Parameters[4].ID, f.Parameters[5].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function6) enforceInterfaceInheritance(error) {} // GetName implements the FunctionInterface interface. func (f Function7) GetName() string { return f.Name } // GetReturn implements the FunctionInterface interface. func (f Function7) GetReturn() *pgtypes.DoltgresType { return getTypeIfRowType(f.IsSRF(), f.Return) } // GetParameters implements the FunctionInterface interface. func (f Function7) GetParameters() []*pgtypes.DoltgresType { return f.Parameters[:] } // VariadicIndex implements the FunctionInterface interface. func (f Function7) VariadicIndex() int { if f.Variadic { return 6 } else { return -1 } } // GetExpectedParameterCount implements the FunctionInterface interface. func (f Function7) GetExpectedParameterCount() int { return 7 } // NonDeterministic implements the FunctionInterface interface. func (f Function7) NonDeterministic() bool { return f.IsNonDeterministic } // IsCVariadic implements the FunctionInterface interface. func (f Function7) IsCVariadic() bool { return false } // IsStrict implements the FunctionInterface interface. func (f Function7) IsStrict() bool { return f.Strict } // IsSRF implements the FunctionInterface interface. func (f Function7) IsSRF() bool { return f.SRF } // InternalID implements the FunctionInterface interface. func (f Function7) InternalID() id.Id { return id.NewFunction("pg_catalog", f.Name, f.Parameters[0].ID, f.Parameters[1].ID, f.Parameters[2].ID, f.Parameters[3].ID, f.Parameters[4].ID, f.Parameters[5].ID, f.Parameters[6].ID).AsId() } // enforceInterfaceInheritance implements the FunctionInterface interface. func (f Function7) enforceInterfaceInheritance(error) {} // Func1Aggregate is a function that takes one parameter and is an aggregate function. type Func1Aggregate struct { Function1 NewAggBuffer func([]sql.Expression) (sql.AggregationBuffer, error) } func (f Func1Aggregate) NewBuffer(exprs []sql.Expression) (sql.AggregationBuffer, error) { return f.NewAggBuffer(exprs) } var _ AggregateFunctionInterface = Func1Aggregate{}